This is a rather long post detailing some of the things I learned this weekend while creating my first “real” Adobe AIR application that joins my love of programming with another hobby that I have enjoyed for several years.

Those of you that know me very well might remember that one of my hobbies is amateur radio. There are many facets to the ham radio hobby and one of them that I’ve been involved with over the last few years combines radios and GPS data into a real-time position reporting system called Automatic Position Reporting System (APRS). To make a long story short, people equipped to use this system have specialized radios in their vehicles that read positional data from GPS units and transmit it out over certain frequencies periodically. Usually, these information packets eventually find their way to a series of servers that forward the data to connected clients for display on whatever mapping system the client has available locally.

This weekend, I spent some time creating an Adobe AIR application written in HTML and Javascript that connects to one of these servers and plots the position reports on a Google map. I haven’t had a chance to do much development with AIR up to now so I thought this would be a good exercise to see if I could create a usable solution.

The first hurdle was to create some method of translating the raw packet of information (which is a variable length string of text) into its component parts that I could then use. Below is an example of an APRS position report packet.

KI4TDG-9>APT407,WIDE1-1,WIDE2-2,qAR,N5AAA-1:!3546.23N/08654.00W>069/000/A=000800

This looks like a bunch of gibberish I know, but the data formats (there are multiple different types of packets that can be transmitted over the APRS system) are well documented. I wound up creating a Javascript object called APRSPacketParser.js (original name I know, but it works) that had a method called parse() that accepted a raw APRS packet like the one above. This method then used other methods such as extractCall(), extractTimeStamp(), extractPosition() and so on to reduce the raw string into a series of values that I stored in another Javascript object called APRSPositionReport.js. That took about 3 hours or so to write up. Because of the many different types of packet formats, the parser object still needs a lot of work, but for now it works on the 3 most common forms of position reports.

Once that was complete and tested, I created a regular HTML page to get my head around integrating with the Google maps javascript API. Within no time, I was able to have a Google map in my HTML page, centered on my location with a custom zoom level set. Once the map was there, I began experimenting with parsing sample packets I had hard-coded into the page and using the location data stored in the resulting APRSPositionReport object to insert markers on the Google map. So far so good and my total time so far was less than 4 hours worth of work. At this point I decided to quit for the night and try to tackle the AIR bits the next day.

Up to this point, all I’d really accomplished was proving that I could follow the instructions for using the Google maps API and that I could parse some sample packets into position reports. I still had to make all that work inside AIR. Upon creating a new AIR project, I put the HTML and javascript code that I’d been working on into the project and ran it, expecting to see a Google map pop up. Nope! All I got was a blank screen and a message saying that the variable “google” was undefined.

After a couple hours of head scratching and research, I found out about AIR security sandboxes and found some example code on how to successfully use assets in your AIR application that are not part of the project itself. The examples showed how to use the ParentSandboxBridge and ChildSandboxBridge objects to essentially create an “API” between pages to allow data to be shared between two sandboxes with different security levels. At this point, I had my empty Google map displaying inside my AIR application. With a little bit of bug fixing, the javascript code that I had used to create the markers on the map was working and I had 4 sample APRS packets parsed and plotted on the Google map. Total time to this point was somewhere around 7 hours.

Obviously, to be useful, the hard-coded position reports had to go and be replaced with a real-time stream of data from one of the APRS servers. This part was probably the easiest thing I did all weekend. The socket class in AIR makes it absolutely simple to create a TCP socket connection to a server. To create a socket object, I used the following code. The first line creates the object and the remaining lines assign methods to listen to various events that happen with the socket connection.

//Set up socket object that we'll use later when the connect/disconnect 
//buttons are clicked
socket = new air.Socket();
socket.addEventListener(air.Event.CLOSE, closeHandler);
socket.addEventListener(air.Event.CONNECT, connectHandler);
socket.addEventListener(air.IOErrorEvent.IO_ERROR, ioErrorHandler);
socket.addEventListener(air.SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
socket.addEventListener(air.ProgressEvent.SOCKET_DATA, socketDataHandler);

I then created a button labeled “Connect” and set the onClick action to run the javascript method named connect(). The code for that method looked like this:

function connect(){
  if (socket.connected == false) {
    socket.connect("second.aprs.net", 20157);
    writeln("user NOCALL pass -1 vers AirPRS 0.01 filter r/35.625/-86.9847/150");
  }			
}

In my case I needed to connect to the server named “second.aprs.net” on port 20157. The last line of that method uses the writeln() method to send a string of configuration data to the server over the socket connection telling it about the kind of data I want it to send me. The server sends a new line of data across the socket connection each time it receives a position report from an amateur station. At this point, all I had to do was fill in the body of the socketDataHandler() listener method to forward each packet to another method I created that uses the parser to parse the incoming string and dispatch a message to the map to create a marker with the information contained in the APRSPositionReport javascript object created from the raw packet. Total time to this point was about 9 hours.

I spent another 3 or 4 hours adding error trapping and a “console” area to the application that got updated each time a new packet came in from the server so that I could see data flowing into the application.

All in all, I had around 12 hours or so of actual development time in creating a functional, though not very feature rich, application based on the Adobe AIR platform. If you care to take a look at what I’ve done or run the application, I’ve made the application and the source code available for download.

Here’s a screenshot of what the application looks like after it’s been running for a bit to pull in some position reports (click on the image for the full-sized view).

I already have a list of things that I want to add to this such as a preferences pane so that you can set your own center map point, control the radius around the center that you want reports for and so on. I want to use the built-in SQLite functions to store those values which will provide me with another learning opportunity with a different feature of AIR.

4 thoughts on “Experimenting with HTML and Javascript development in Adobe AIR

  1. hello, i build air application with html, css, and javascript code in dreamweaver. did you got the javascript code to centering air application on screen? it’s difficult to search that code.

  2. @Naro I built this by hand using Flash Builder 4 so I’m afraid I can’t help you with questions relating to Dreamweaver as I haven’t used Dreamweaver in over 5 years.

  3. Greg

    Hi, I tried getting it to work and I’m getting errors.

    Error: TypeError: air.Socket is not a constructor
    Source File: …/temp/air/AirPRS.html
    Line: 33

    Any ideas? I’m using Firefox on Linux.

    I was trying to use a Google Maps and just display my callsign on a simple map.

    tnx, 73 Greg, KD3SU

  4. Hey Greg…I have not played with AIR since this little experiment. However, that sounds like an error that would be thrown if the libraries weren’t linked correctly or there’s some kind of case sensitivity issue going on with your code with reference to the actual class names within AIR.

Leave a Reply

Your email address will not be published. Required fields are marked *

*