| By Deanne M. Chance | Article Rating: |
|
| January 23, 2007 04:45 PM EST | Reads: |
15,108 |
Did you ever wonder where your kids are driving around on a Saturday night? Perhaps you are a business owner and need to know where your workforce is located on different job sites. With the help of PowerBuilder, a wireless connection, a GPS receiver, and Microsoft MapPoint, you can track the location of any individual in real-time. This article will show you how.
To get things started you will need a few things:
- PowerBuilder
- A serial-based GPS receiver (Bluetooth will do)
- MS MapPoint 2004
- MS Visual C# (for sockets implementation)
- A static IP address or a router capable of port forwarding
- A wireless connection for the client
- Some time to learn!
First, an introduction to socket-based client/server programming: In this project we will write two components. One will be a server to listen for requests on port 1968. The other will be a client that will read information from the GPS receiver and send it to the server. The message the server will receive will be the client's current latitude and longitude. It will then use this information to plot the current location on a map using MS MapPoint.
You may be wondering why it is necessary to use port 1968. The answer is simple: It is not a well-known port, so we are free to use any number we like provided it is less than 2^8. In this case, I choose 1968 because it was the year I was born, but you can choose any number you like.
Determining Your IP Address
The next part of the equation is to get the IP address of the server. One way you can do this is to visit a site called http://whatsmyipaddress.com. This will give you the IP address the outside world uses to communicate with your computer. However, unless you have a static IP address, your server machine will have been assigned a local address by your router that is not accessible to the outside world. To get around this, you will need to set up port forwarding on the router. For example, if I login to my Linksys router, which is usually at 192.168.1.1, I can choose the applications and gaming tab to specify that I would like all requests to port 1968 to go to the machine my server is listening on. And how to do I know that address? Just use ipconfig at a command line. Here is an example so you get the idea.
Writing the Server
The server component is responsible for listening for requests from the client. In order to "listen" for requests, you will need two pieces of information: the IP address of the server machine and the port you wish to listen on. The IP address can be obtained by running ipconfig at a command line, while the port can be anything you want as long as it is not well known, and is less than 2^8. Note, in the example, I have hard-coded in the IP address and port number. However, in a production implementation, you probably want these values to be user-configurable.
To implement our TCP client/server sockets, we have a couple of choices. One is to use the Win32 API; the other is to create a .NET assembly. In this case, I chose the latter. In essence, what we are doing is calling a .NET assembly from PowerBuilder using COM wrappers. What this allows us to do is to create a class using C#, for example, and create a DLL that we can call from PowerBuilder. Wondering how to do that? See Bruce Armstrong's article at http://pbdj.sys-con.com/read/258395.htm for details. However, in terms of the assembly, I will share my C# code with you in Listing 1 but defer the details of creating the assembly to his article.
You may wonder at this point, now that you have created a .NET assembly, how you use it in PowerBuilder. The following code listing shows how I am calling my assembly from PowerBuilder from a ue_postopen event. Notice that I have hard-coded in the IP address and port number. In a production version you would want these to be user-configurable options.
Integer li_Return
ole_map.object.Units = 1
ioo_map = ole_map.object.NewMap(1)
ioo_listner = CREATE OleObject
li_Return = ioo_Listner.ConnectToNewObject( "DotNetListner.DotNetSocketListner" )
ioo_listner.ipAddr = "192.168.1.108";
ioo_listner.portNumber = 1968;
ioo_listner.Initialize();
Once we have initialized our "socket listener," we will need to retrieve data from the client. We will also need some agreement as to the protocol for the messages it accepts from the client. In this case, I am having the client pass the following information (each separated by a comma): latitude, longitude, user, and current time. For example, here is a sample message that will be received by the server:
42.43608, -89.022857, Chance, 1:22 a.m..
The code for retrieving data from the client is shown below. There are some important points to consider here. One, this is not a multi-threaded application, thus we have the infinite loop. However, I have placed some calls to Yield() to allow for any queued messages to be processed in between data retrievals from the client. Messy, but it works.
Double ldb_lat, ldb_long
do while 1=1
Yield()
ioo_Listner.GetData()
ldb_lat = Double(ioo_Listner.Latitude);
ldb_long = Double(ioo_Listner.Longitude);
Yield()
event post ue_plotdata(ldb_lat, ldb_long)
loop
Finally, once the client has retrieved the current latitude and longitude from the GPS receiver and sent it to the server, we need to plot the current position on the map. There are many mapping solutions out there, from Yahoo! Maps to Google Maps to MS MapPoint. (Figure 1) I choose the latter, primarily because - well, what would happen if your Internet connection went down? There would be no way to make the mapping calls. Given that, the MS MapPoint code for plotting a given latitude and longitude is in Listing 2.
Writing the Client
The client component is responsible for reading information from the GPS receiver and sending it to the server. You will need to decide how often this occurs by programming the timer event. In this case, I chose every five minutes. As far as reading GPS information, this can be done using Win32 API calls that "talk" to the comm port for which the receiver is configured. (Figure 2)
The protocol the receiver uses is called NMEA (for more, see www.gpsinformation.org/dale/nmea.htm). In general, the device sends sentences that describe the current position. Of interest to us is the GPGAA message that includes the current location. NMEA sentences are comma-delimited, so they are prime candidates for easy parsing using an external data window. For this example, I used Ian Thain's NMEA parser, which can be found on Code-Exchange. So, the sequence of events is:
- Read an NMEA sentence from the GPS receiver
- Determine if it is GPGAA
- Convert the data to decimal degrees
- Send the message described above to the server
- Function Long CreateFile(ref string lpszName, long fdwAccess, long fdwShareMode, long lpsa, long fdwCreate, long fdwAttrsAndFlags, long hTemplateFile) Library "Kernel32.dll"
- Function Long CloseHandle(Long hObject) Library "Kernel32.dll"
- Function Long ReadFile(Long hFile, ref string lpBuffer, long nBytesToRead, ref Long & nBytesRead, Long lNull) Library "Kernel32.dll"
- Function Long WriteFile(Long hFile, ref string lpBuffer, long nBytesToWrite, ref Long & nBytesWritten, LONG lNull) Library "Kernel32.dll"
What you can see from this example is that the data is comma delimited. This makes it a prime candidate for easy parsing by storing it in an external data window using the ImportString function. To get at the individual elements, we only need to index them by their position in the data window.
To extract each individual sentence out of the stream to be passed for parsing to the NMEA object, I wrote the wf_get_token function. This will extract a string based on a delimiter. For the NMEA stream, that is the newline character. (Figure 3)
Finally, we need a way to send our message to our server. You can write a .NET assembly by following the example that acts as a client in order to send the GPS information to the client.
One final note: If you plan on connecting to a Bluetooth serial port greater than COM9, you will need to use the syntax "\\.\COMx" as the port name. Just substitute the port number you wish to use for x. The cause of the problem is that CreateFile accepts strings "COM1" - "COM9" as names of devices, but rejects those with two or more digits.
That's it! You have now rolled your own location tracker. If you want to improve it, you might consider tracking more than one device at a time. This could easily be managed by an external data window that contains the user's name and last position. When a new position comes in, simply do a lookup on the user name, update the data window, and plot the new location on the map. Additionally, all the hard-coded references to ports and IP addresses would well be served by user configuration files.
Happy coding!
This article was first published in the ISUG Technical Journal, Jan.-Feb. 2007
Published January 23, 2007 Reads 15,108
Copyright © 2007 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Deanne M. Chance
Ms. Chance graduated in 1996 with a degree in computer science from the University of Illinois. She has been a frequent contributor to the PowerBuilder Developer's Journal and gave a key presentation at Sybase TechWave 2005 entitled "A Real-Time Physical Inventory Solution Using PocketBuilder ASA and a WiFi Connection." She has held several engineering positions, starting a career at Motorola where she focused on mobile I.P. by doing real-time embedded programming for the base radio controller group as part of the iDEN/Nextel project.
![]() |
chance 02/08/07 03:41:17 PM EST | |||
You can find a link to CodeExchange here Look in the special hardware section, look for GPS. There is another GPS project I cooked up which has the NMEA parser with example. Good Luck! |
||||
![]() |
Stuart 02/08/07 09:58:15 AM EST | |||
I can't find the NMEA parser mentioned in your article - do you have a link to the site I could use please? |
||||
![]() |
Anders Borg 02/04/07 04:38:07 PM EST | |||
You mention GPGAA, but don't you mean GPGGA? Could you please provide a link to the NMEA parser at Code-Exchange? I couldn't figure out which site you mean. Many thanks in advance, |
||||
![]() |
Chance 01/27/07 07:49:48 AM EST | |||
Ooops...there is glaring mathematical error in here....2^8 = 256. I think what we were looking for was 2^16. My apologies. |
||||
- SQL Anywhere Server and AJAX
- PowerBuilder Top Feature Picks
- The Difference Between Web Hosting and Cloud Computing
- PowerBuilder 12 and .NET
- Sybase CTO to Speak at 4th International Cloud Computing Expo
- Migrating Legacy Client/Server PowerBuilder Apps
- Why SOA Needs Cloud Computing - Part 1
- PowerDesigner 15: Expanding Data Modeling into Your Enterprise
- Five Reasons to Choose a Private Cloud
- PowerBuilder and .NET: Development Strategy
- SQL Anywhere Server and AJAX
- PowerBuilder Top Feature Picks
- The Difference Between Web Hosting and Cloud Computing
- PowerBuilder 12 and .NET
- Sybase CTO to Speak at 4th International Cloud Computing Expo
- SYS-CON's iPhone Developer Summit Day One ROCKS
- A Review of Key PDF and Font Concepts
- Migrating Legacy Client/Server PowerBuilder Apps
- New Features in PowerBuilder 11.5
- New Features in PowerBuilder 11.5
- Where Are RIA Technologies Headed in 2008?
- PowerBuilder History - How Did It Evolve?
- Custom Common Dialogs Using SetWindowsHookEx
- DDDW Tips and Tricks
- OLE - Extending the Capabilities of PowerBuilder
- DataWindow.NET How To: Data Entry Form
- Book Excerpt: Sybase Adaptive Server Anywhere
- Sybase ASE 12.5 Performance and Tuning
- Working with SOA & Web Services in PowerBuilder
- Office 2003 Toolbar: A New Look For Your Old PowerBuilder App





































