Click here to Skip to main content
Click here to Skip to main content

A GPS tracer application for Windows Mobile CE 5

By , 22 May 2007
Rate this:
Please Sign up or sign in to vote.

Screenshot

Introduction

This is a simple GPS tracer developed for Window Mobile 2005/2003 on Compact Framework 2.0 SDK. So first of all, you need VisualStudio 2005 and Windows Mobile CE 5 SDK. You can develop it on emulator devices or on a real device. As you can see in that photo, I developed that application on a read device: the great Asus MyPal 636N.

Screenshot

How it works: background

The screenshot above shows that the map generated by this application is very simple. It's only your path, and the application is able to:

  • Read data from any NMEA GPS device
  • Read your position and print it to the screen
  • Load and save your path
  • Zoom in/out
  • Pan on your path
  • Center on the map
  • Run in demo mode with randomly generated data

You can save and load it, but for now you can't edit or add other text. About application setup, it's very simple: you have only to setup your COM port. This port must be that same port where your NMEA device is attached via Bluetooth, IrDA or Integrate. Personally, I have an Asus MyPal 636N device, so I have the GPS device built-in on COM5.

Using the code

It's basically composed of three main actors, similar to a simple MVC pattern:

Form (Control): It's the main form of the application, so it contains the Windows UI (menu, controls...)

Reader (Model): It's the class that works with the GPS device, so it allows reading from serial with a threaded method

Mapper (View): It's the actor that parses the GPS NMEA phrases and draws them on-screen; it also allows the user to zoom and pan the map that contains the path

Form

It initializes the application; as you can see it's able to run on 240px X 320px devices.

        public Form1()
        {
            InitializeComponent();
            m_graphics = this.CreateGraphics();
            m_mapper = new Mapper(m_graphics, 0, 30, 240, 300);
            m_rTh = new reader(m_port);
            m_rTh.dataReceived += new reader.DataReceivedEventHandler(parse);
        }

The event registered method is called on the DataReceived event. With m_isDemoMode==True, the application will generate a randoom coordinate.

        public void parse(String readed)
        {
            if (!m_isDemoMode)
            {
                m_mapper.parseAndDraw(readed);
            }
            else
            {
                Random r = new Random();
                String rSecond1 = (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1);
                String rSecond2 = (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1) + "" + 
                                  (int)(r.NextDouble() * 10 - 1);
                String rPrime1 = (int)(r.NextDouble() * 1 - 1) + "";
                String rPrime2 = (int)(r.NextDouble() * 1 - 1) + "";

                m_mapper.drawLatLong("434" + rPrime1 + "." + rSecond1, 
                                     "0111" + rPrime2 + "." + rSecond2);
            }
        }

This is the method that starts and stops the Readed thread.

        private void menuItemRunStop_Click(object sender, EventArgs e)
        {
            if (m_isRunning)
            {
                m_rTh.stop();
            }
            else
            {
                m_rTh.start();
            }
            menuItemRunStop.Checked = !menuItemRunStop.Checked;
            m_isRunning = !m_isRunning;
        }

This is the region that solves problem of panning the map on your touchscreen device. You can enable m_mapper.clearAndDraw() and it will clear the screen before it redraws the moved map.

        #region Panning

        private Point touch;
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (m_mapper != null)
            {
                m_mapper.moveCenter(touch.X - e.X, touch.Y - e.Y);
                m_mapper.draw();//m_mapper.clearAndDraw();
            }
            touch.X = e.X;
            touch.Y = e.Y;
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            touch.X = e.X;
            touch.Y = e.Y;
        }


        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            Form1_MouseMove(sender, e);
            m_mapper.clearAndDraw();
        }

        #endregion

Reader

Event exposed to Form on data received:

        public delegate void DataReceivedEventHandler(string data);
        public event DataReceivedEventHandler dataReceived;

The thread method that reads on serial port:

        private void methodTh()
        {
            m_serialPort1.Open();
            byte[] buffer= new byte[100];
            while (m_run)
            {
                Thread.Sleep(500);
                m_readed = m_serialPort1.ReadLine();
                if (m_readed.Length > 0)
                {
                    dataReceived(m_readed);
                }
            }
        }

These methods allow the Form to start and stop the reader thread:

        public void start()
        {
            if (m_th == null)
            {
                m_th = new Thread(methodTh);
            }
            m_run = true;
            m_th.Start();
        }

        public void stop()
        {
            m_run = false;
            Thread.Sleep(500);
            m_serialPort1.Close();
            if (m_th != null)
            {
                m_th.Abort();
                m_th = null;
            }
        }

Mapper

Now follow me through the Mapper section. This is a simple method that parses the data read from the Reader. It's called by the Form on a DataReceivedEvent.

        public void parseAndDraw(string s)
        {
            string[] Words = s.Split(',');

            m_g.FillRectangle(m_bgBrush, new Rectangle(m_clip.X, 
                                         m_clip.Y + 5, m_clip.Width, 15));
            m_g.DrawString(s, m_font,m_fontBrush, new RectangleF(m_clip.X ,
                           m_clip.Y + 5, m_clip.Width, 15));

            switch (Words[0])
            {
                case "$GPRMC":
                // $GPRMC,170111,A,4338.5810,N,07015.1010,W,000.0,
                //        360.0,060199,017.5,W*73
                    // RMC - Recommended minimum specific GPS/Transit data

                    if (Words[3].Length > 0 && Words[5].Length > 0)
                    {
                        drawLatLong(Words[3], Words[5]);
                    }
                    break;
                case "$GPGSV":
                // $GPGSV,2,1,08,03,17,171,42,06,21,047,44,14,
                //        28,251,45,16,25,292,44*71
                    // GSV - Satellites in view
                    break;
                case "$GPGSA":
                // $GPGGA,170111,4338.581,N,07015.101,W,1,
                          00,2.0,1.1,M,-31.8,M,,*71
                    //GSA - GPS dilution of precision and active satellites
                    break;
                default:
                    break;
            }
        }

The drawLatLong() method allows conversion of the latitude and longitude data. In the example, latitude:43 38.5810 will be converted to 162710 using the formula 43*360+34*60+5810. At the end of parsing and conversion, it will add the data to the private List<POINT> m_points; and later it will call the method draw(). This method will draw all of the lines that were not drawn before. Obviously, on pan or application start this method will draw all points.

public void drawLatLong(string latitude, string longitude)
{

    Point aPoint = new Point();

    aPoint.X = 
      (Convert.ToInt32(latitude.Substring(latitude.Length - 4, 4)));
    aPoint.Y = 
      (Convert.ToInt32(longitude.Substring(longitude.Length - 4, 4)));

    aPoint.X += 
      (Convert.ToInt32(latitude.Substring(latitude.Length - 7, 2))) * 60;
    aPoint.Y += 
      (Convert.ToInt32(longitude.Substring(longitude.Length - 7, 2))) * 60;

    aPoint.X += 
      (Convert.ToInt32(latitude.Substring(latitude.Length - 9, 2))) * 3600;
    aPoint.Y += 
      (Convert.ToInt32(longitude.Substring(longitude.Length - 9, 2))) * 3600;

    m_points.Add(aPoint);
    draw();
}

public void draw()
{
    float xTo = 0;
    float xFrom = 0;
    float yTo = 0;
    float yFrom = 0;
               
    for (int i = m_drawded; i < m_points.Count; i++)
    {
        xTo = (m_points[i].X - m_points[0].X) / m_scale + m_center.X;
        xFrom = (m_points[i - 1].X - 
                 m_points[0].X) / m_scale + m_center.X;
        yTo = (m_points[i].Y - m_points[0].Y) / m_scale + m_center.Y;
        yFrom = (m_points[i - 1].Y - m_points[0].Y) / 
                 m_scale + m_center.Y;
        m_g.DrawLine(m_linePen, (int)xTo, (int)yTo, 
                    (int)xFrom, (int)yFrom);
        m_g.DrawEllipse(m_pointPen, 
                        new Rectangle((int)xFrom - 2, 
                        (int)yFrom - 2, 4, 4));
    }

    m_g.DrawEllipse(m_lastPointPen, 
                    new Rectangle((int)xTo - 2, (int)yTo - 2, 4, 4));
    m_drawded++;
}

At the end, you can see the loadPath(...) and savePath methods. These methods are called by the form that asks the user the filename/location from the windows form dialog m_mapper.loatPath(openFileDialog1.FileName); m_mapper.savePath(saveFileDialog1.FileName);. So this simply loads/saves the private List<POINT> m_points; from/to a file.

        public void loatPath(String filename)
        {
            StreamReader sr = new StreamReader(filename);

            m_points.Clear();
            int n = 0;
            Point p = new Point();
            while (!sr.EndOfStream)
            {

                String readed = sr.ReadLine();
                p.X = Convert.ToInt32(readed);
                readed = sr.ReadLine();
                p.Y = Convert.ToInt32(readed);
                m_points.Add(p);
                n++;
            }
            m_drawded = 1;
            sr.Close();
            clearAndDraw();
        }

        public void savePath(String filename)
        {
            StreamWriter sw = new StreamWriter(filename);

            foreach (Point p in m_points)
            {
                sw.WriteLine(Convert.ToString(p.X));
                sw.WriteLine(Convert.ToString(p.Y));
            }

            sw.Flush();
            sw.Close();
        }

Points of interest

I know that this is a simple project for a skilled developer, but I want to demonstrate that the device development is very simple with VisualStudio2005 and CompactFramework 2.0. It's my first project on the great CodeProject website, so please contact me if you have any doubts or proposals. I'm always available for collaboration.

History

  • Start of development: 8/7/2006
  • First release: 8/9/2006
  • Second release : 8/10/2006
    • Added Center function
    • Now demo mode run without GPS or any serial port
    • Some and various fix
  • Article edited and posted to the main CodeProject.com article base: 5/22/2007

License

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

About the Author

leonardosalvatore
Architect Giuneco http://www.giuneco.it
Italy Italy
IT is not only work, it is a hobbie, for that i post here!

Comments and Discussions

 
Questionconfused Pinmemberslobo3208-Feb-12 23:40 
QuestionWhat about CE 6.0? PinmemberCINOFF9-Jan-12 2:27 
GeneralInverted Looking Pitch PinmemberSephiroth155013-Aug-09 18:17 
GeneralRe: Inverted Looking Pitch Pinmemberleonardosalvatore2-Sep-09 21:39 
Generalquestion about random Pinmembermihai86b7-Apr-09 23:58 
JokeRe: question about random Pinmemberleonardosalvatore8-Apr-09 0:37 
GeneralFake GPS Pinmembermihai86b29-Mar-09 23:57 
I'm trying to make this application work with the FakeGPS tool but it seems that the emulator can't see the COM, when I pres RUN it gives an Exception:COM5 doesn't exist .I've installed FakeGPS on the emulator, installed the settings program and I tried to set the program or the harware port for COM5 and it still doesn't work. Did you ever used this tool, and if yes how did you do it to work.
thanks mate,
GeneralRe: Fake GPS Pinmemberleonardosalvatore30-Mar-09 0:15 
GeneralRe: Fake GPS Pinmembermihai86b30-Mar-09 0:21 
GeneralRe: Fake GPS Pinmemberleonardosalvatore30-Mar-09 0:29 
QuestionMultiple GPS device ? PinmemberAshlesh25-Feb-09 21:10 
AnswerRe: Multiple GPS device ? Pinmemberleonardosalvatore11-Mar-09 1:45 
GeneralCOM Port error - IOException PinmemberVitorX24-Feb-09 16:53 
GeneralRe: COM Port error - IOException Pinmemberleonardosalvatore25-Feb-09 21:05 
GeneralRe: COM Port error - IOException PinmemberVitorX27-Feb-09 1:40 
GeneralRe: COM Port error - IOException Pinmemberleonardosalvatore11-Mar-09 2:00 
QuestionIntermediate driver?? Pinmembervivek_pawar4-Feb-09 21:53 
AnswerRe: Intermediate driver?? Pinmemberleonardosalvatore25-Feb-09 21:03 
GeneralRe: Intermediate driver?? Pinmembervivek_pawar26-Feb-09 1:21 
GeneralRe: Intermediate driver?? Pinmemberleonardosalvatore11-Mar-09 1:47 
GeneralVB Pinmemberunusualfrank29-Dec-08 8:37 
GeneralRe: VB Pinmemberleonardosalvatore29-Dec-08 21:31 
Generalgps in windows mobile6 Pinmemberniktana20-Oct-08 1:03 
GeneralRe: gps in windows mobile6 Pinmemberleonardosalvatore11-Mar-09 1:58 
GeneralRMS PinmemberEdyb25-Aug-08 2:39 
GeneralRe: RMS Pinmemberleonardosalvatore8-Oct-08 5:20 
GeneralGPS receiver and a bletooth connection Pinmemberkalxite14-Jul-08 19:41 
GeneralRe: GPS receiver and a bletooth connection Pinmemberleonardosalvatore15-Jul-08 0:15 
GeneralRe: GPS receiver and a bletooth connection Pinmemberleonardosalvatore15-Jul-08 0:30 
GeneralIntermediate driver Pinmembersolutionator2-Jul-08 22:01 
GeneralRe: Intermediate driver Pinmemberleonardosalvatore15-Jul-08 0:16 
Questionare there any license restrictions? Pinmemberedspencer9-Jun-08 6:09 
AnswerRe: are there any license restrictions? Pinmemberleonardosalvatore15-Jul-08 0:27 
Generalquick.pe.kr Pinmembera1000cc4-Apr-08 11:34 
GeneralRe: quick.pe.kr Pinmemberleonardosalvatore15-Jul-08 0:27 
Generalgood Pinmemberpamauro22-Mar-08 6:41 
GeneralRe: good Pinmemberleonardosalvatore5-Apr-08 0:05 
Generalproblem after deploying your application on Visuall studio 2005's Pocket Pc 2003 SE Emulator Pinmemberjadothebest11-Mar-08 13:51 
GeneralRe: problem after deploying your application on Visuall studio 2005's Pocket Pc 2003 SE Emulator Pinmemberleonardosalvatore11-Mar-08 22:12 
GeneralRe: problem after deploying your application on Visuall studio 2005's Pocket Pc 2003 SE Emulator Pinmemberjadothebest12-Mar-08 5:07 
GeneralRe: problem after deploying your application on Visuall studio 2005's Pocket Pc 2003 SE Emulator Pinmemberjadothebest13-Mar-08 11:11 
GeneralRe: problem after deploying your application on Visuall studio 2005's Pocket Pc 2003 SE Emulator Pinmemberleonardosalvatore15-Jul-08 0:29 
Questionhow to insert a pic (map) Pinmemberkiu26-Feb-08 18:29 
GeneralRe: how to insert a pic (map) Pinmemberleonardosalvatore27-Feb-08 21:11 
GeneralVB.Net version PinmemberMember 471965512-Dec-07 0:42 
GeneralSerial transmission Pinmemberjobin.dm11-Dec-07 5:30 
GeneralRe: Serial transmission Pinmemberleonardosalvatore24-Dec-07 6:22 
GeneralRe: Serial transmission Pinmemberjobin.dm7-Jan-08 2:39 
GeneralRe: Serial transmission Pinmemberleonardosalvatore7-Jan-08 3:05 
GeneralRe: Serial transmission Pinmemberjobin.dm7-Jan-08 3:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 22 May 2007
Article Copyright 2006 by leonardosalvatore
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid