Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Take Your Apps Far and Wide with a GPS Tracking System  : Page 3

You already know that GPS is used extensively in a wide variety of mobile devices in order to track delivery and service vehicles—or any other mobile fleet. This kind of application is not as difficult as you may at first think. Find out how to use Visual Studio to create a GPS tracking app, with maps, that runs on Windows Mobile Pocket PC devices.

Creating the Server Application
With the Pocket PC application completed, it is now time to build the server application. Using Visual Studio 2005, create a new Windows application and name it C:\MapServer. Populate the default Form1 with the following controls (see also Figure 7):
  • GroupBox controls
  • WebBrowser controls
  • Label controls
  • TextBox controls
  • Button controls

Figure 7. Populate the default Form1 with the various controls as shown.

Using Virtual Earth to Display Maps
To display a map of locations returned by the Pocket PC clients, I will use Microsoft's Virtual Earth, a map and search system comprising maps, aerial images, business directories, etc. Using VE, you can search for businesses, addresses, as well as ask for directions. You can access VE at http://local.live.com/.

Microsoft provides a map control that allows developers to embed VE maps into their own applications. You can use it to build a custom solution using VE mapping services. The VE Map control is made up of a JavaScript page and a cascading style sheet. The VE Map control is hosted at http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js. The CSS is located at http://local.live.com/css/MapControl.css.

The first step to using Virtual Earth is to create an HTML file to contain all the necessary JavaScript functions to interact with the VE map.

Tip: To get detailed help and the references to the various methods in the Virtual Map control, download the Virtual Earth SDK. As of this writing, Microsoft Virtual Earth is in version 3.0.
Add an HTML page to the project (right-click on project name in Solution Explorer and then select Add —> New Item… Select HTML Page). Name the HTML page VirtualEarth.html.

Populate the HTML page with the following:

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My Virtual Earth</title> <link href="http://local.live.com/css/MapControl.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script> <script type="text/javascript"> var map = null; //---Go to a particular location on the map--- function goto_map_position(lat, lng) { map.PanToLatLong(new VELatLong(lat,lng)); } //---Load the Map--- function loadMap() { container = document.getElementById("VirtualEarthMap"); container.style.width = 488; container.style.height = 469; //---instantiate the VE map--- map = new VEMap("VirtualEarthMap") map.LoadMap(new VELatLong(38.898748, -77.037684), 12 ,'r' , false); } </script> </head> <body onload="loadMap()" style="margin: 0px"> <div id="VirtualEarthMap"> </div> </body> </html>

The VirtualEarth.html page contains a reference to the VE Map control (.js) as well as the CSS file (.css). It also contains two JavaScript functions:
  • goto_map_position()—Goes to a particular location on the map based on the latitude and longitude specified.
  • loadMap()—Loads the map with the various parameters such as size of the map, zoom level, latitude and longitude, etc. It also attaches event handlers to the various events so that when certain events happen, the appropriate event handler is fired.
You would also need to set the Copy to Output Directory property of VirtualEarth.html to "Copy if newer" (via the Property window) so that the HTML page is deployed during runtime.

Using Sockets for Communication
While you can use Web services to pass the positional information from the Pocket PC to the server, doing so will take up a significant amount of bandwidth. This is because Web services uses XML SOAP packets for information exchange and this XML padding consumes considerable bandwidth consider that all we want to send is latitude and longitude (usually less then 20 bytes) information. Clearly, using Web services over a GPRS connection is not a feasible option (and an expensive one at that). For this reason, I have decided to program sockets directly to pass data to the server.

In Solution Explorer, add a new Class item to the project (right-click on project name and select Add —> New Item…. Select the Class item) and name it as WMClient.vb. Populate the file as follows:

Imports System.Net.Sockets Public Class WMClient Public Event LatLng( _ ByVal ID As Integer, _ ByVal lat As Double, _ ByVal lng As Double) Private _client As TcpClient '---used for sending/receiving data--- Private data() As Byte Public Sub New(ByVal client As TcpClient) _client = client '---start reading data from the client in a separate thread--- ReDim data(_client.ReceiveBufferSize) _client.GetStream.BeginRead(data, 0, _ CInt(_client.ReceiveBufferSize), _ AddressOf ReceiveMessage, Nothing) End Sub Public Sub ReceiveMessage(ByVal ar As IAsyncResult) '---read from client--- Dim bytesRead As Integer Try SyncLock _client.GetStream bytesRead = _client.GetStream.EndRead(ar) End SyncLock '---client has disconnected--- If bytesRead < 1 Then Exit Sub Else '---get the message sent--- Dim messageReceived As String = _ System.Text.Encoding.ASCII. _ GetString(data, 0, bytesRead) Dim field() As String = messageReceived.Split(":") '---raise an event to pass back the lat and lng--- RaiseEvent LatLng( _ field(0), _ Convert.ToDouble(field(1)), _ Convert.ToDouble(field(2))) End If '---continue reading from client--- SyncLock _client.GetStream _client.GetStream.BeginRead(data, 0, _ CInt(_client.ReceiveBufferSize), _ AddressOf ReceiveMessage, Nothing) End SyncLock Catch ex As Exception Console.WriteLine(ex.ToString) End Try End Sub End Class

Basically, the WMClient class does the following:
  • Contains a public event named LatLng. This event is raised when it receives data sent from Windows Mobile clients.
  • Creates a constructor that begins to read incoming data from the connected client
  • Processes incoming data from the ReceiveMessage() subroutine. The LatLng event is raised so that the data can be passed to the calling function (Form1) to update the map.
Coding the Server
Back to Form1, and we are now ready to code the main logic for the server. Switching to the code-behind of Form1, first import the following namespaces:

Imports System.Net.Sockets Imports System.Threading

To programmatically interact with the map displayed within the WebBrowser control, you need to mark the Form1 class as COM-visible using the ComVisibleAttribute class:

<System.Runtime.InteropServices.ComVisibleAttribute(True)> _ Public Class Form1

Next, declare a member variable WMClient to store incoming connections:

<System.Runtime.InteropServices.ComVisibleAttribute(True)> _ Public Class Form1 Dim WithEvents user As WMClient

Next, define the ListenForConnections() subroutine so that the server can continually listen for incoming connections:

Private Sub ListenForConnections () Const portNo As Integer = 3456 Dim localAdd As System.Net.IPAddress = _ System.Net.IPAddress.Parse("") Dim listener As New TcpListener(localAdd, portNo) listener.Start() While True user = New WMClient(listener.AcceptTcpClient) End While End Sub

Author's Note: I am assuming the IP address of the server is Replace this with the IP address of your server. Also, I have chosen the port 3456 to use for the communication.

In the Form1_Load event, you will read the content of the VirtualEarth.html file and load it into the two WebBrowser controls:

Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim fileContents As String fileContents = My.Computer.FileSystem.ReadAllText( _ Application.StartupPath & "\VirtualEarth.html") WebBrowser1.DocumentText = fileContents WebBrowser1.ObjectForScripting = Me WebBrowser2.DocumentText = fileContents WebBrowser2.ObjectForScripting = Me Dim t1 As New Thread(AddressOf ListenForConnections) t1.Start() End Sub

Also, note that I am using a separate thread to invoke the ListenForConnections() subroutine. This is because the ListenForConnections() subroutine is an infinite loop and using a separate thread to invoke it will prevent the UI of the application from freezing.

To handle events raised by the WMClient class, define the LatLng subroutine as the event handler. In this event, you will receive the ID, latitude, and longitude that were sent by the client. This information will be used to update the map, which is serviced by a delegate (you cannot directly update Windows controls in a separate thread):

Private Sub LatLng( _ ByVal ID As Integer, _ ByVal lat As Double, _ ByVal lng As Double) _ Handles user.LatLng '---display map at specific location--- Me.BeginInvoke(New _ mydelegate(AddressOf GotoLocation), _ New Object() {ID, lat, lng}) End Sub

The GotoLocation() subroutine updates the appropriate TextBox as well as the WebBrowser controls. To update the map to display the specified location, you need to invoke the "goto_map_position" JavaScript function that you defined earlier in the HTML file:
Figure 8. This figure shows what the server will look like when it is started during testing.

Private Delegate Sub mydelegate( _ ByVal ID As Integer, _ ByVal lat As Double, _ ByVal lng As Double) Private Sub GotoLocation( _ ByVal ID As Integer, _ ByVal lat As Double, _ ByVal lng As Double) Console.WriteLine(lat & ":" & lng) Dim param() As Object = New Object() {lat, lng} If ID = 1 Then txtLatitude_1.Text = lat txtLongitude_1.Text = lng WebBrowser1.Document.InvokeScript( _ "goto_map_position", param) ElseIf ID = 2 Then txtLatitude_2.Text = lat txtLongitude_2.Text = lng WebBrowser2.Document.InvokeScript( _ "goto_map_position", param) End If End Sub

That's it! You can now test your server by pressing F5. Figure 8 shows what the server will look like when it is started.

But that's not the end of the story. You now need to modify the Pocket PC client application so that it will send the latitude and longitude information to the server.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.