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. 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: 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. It's basically composed of three main actors, similar to a simple MVC pattern: It initializes the application; as you can see it's able to run on 240px X 320px devices. The event registered method is called on the This is the method that starts and stops the This is the region that solves problem of panning the map on your touchscreen device. You can enable Event exposed to The thread method that reads on serial port: These methods allow the Now follow me through the The At the end, you can see the 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. Introduction
How it works: background
Using the code
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
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);
}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);
}
}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;
}m_mapper.clearAndDraw() and it will clear the screen before it redraws the moved map. Collapse
#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();
}
#endregionReader
Form on data received: public delegate void DataReceivedEventHandler(string data);
public event DataReceivedEventHandler dataReceived; 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);
}
}
}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
Mapper section. This is a simple method that parses the data read from the Reader. It's called by the Form on a DataReceivedEvent. Collapse
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;
}
}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. Collapse
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++;
}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. Collapse
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
History
Blog Archive
-
▼
2008
(22)
-
▼
April
(16)
- MOSS Navigation Deep-Dive - Part 2
- MOSS Navigation Deep-Dive - Part 1
- E Books Downloads
- Pocket PC TV Remote Control
- Windows Mobile Remote Controller
- A GPS tracer application for Windows Mobile CE 5
- Speaking Garmin
- Retrieve delayed Stock Quotes via Yahoo Finance on...
- What is this .NET all about ?
- Evolution computations on C#
- History and Evolution of C
- Creative Services
- To Create Dynamic Pages Choose An Advance Programm...
- Web Design And John Q Public
- Retrieving Data from SQL Server Database in XML Fo...
- Why a web service
-
▼
April
(16)