/noSink LocationBased KillerApp

comment(s) 

GPS / NMEA + WinForm + Compact .NET + MapPoint .NET + SQL NotificationServices + XML WebService + MSN Messenger + ASP .NET WebForm + MapPoint 2002 + GoogleAPI - the KitchenSink

http://www.brains-N-brawn.com/noSink 9/3/2002 casey chesnut

for the people out there saying they 'don't know what .NET is' ... this is .NET

Intro

This is my most ambitious project to date (feel free to substitute the word 'insane' for 'ambitious'). If you are on the .NET betaplace scene, then you have certainly seen me around. Have worked with and written detailed dev articles on just about all of them, and it started to add up after a while. Finally reached such a critical mass that I wanted to do a project and combine almost all of those technologies ala 'everything but the kitchen sink' style (thus /noSink) to reinforce what I had learned. Decided to do one of the 'killer app' ideas that everybody has been kicking around, but nobody had implemented yet. Location, Location, Location! ... dynamic location that is (DeltaXY?). As soon as I came up with my idea, I did find out a day later that AT&T does have a pretty sweet implementation called 'FindFriends' (the only one I know of so far). They are doing it on some of the trial GSM phone networks (not in my area), using phone technologies I don't have access to (jealous), with more time (> 1 month) money (> $200 for GPS) and manpower (> 1 person) than me. Err, umm ... regardless, I decided to create my own location-based killer-app in my spare time ...

It uses a PocketPC with a CompactFlash to overlay your current position on maps generated from MapPoint .NET. Then, it will notify you through Pocket MSN Messenger if you walk close to a restaurant/store that is running a lunch special/sale, with a link to view the ad on Pocket IE. Also, it will show you other users that are nearby on the map and allow you to initiate a chat with them through Pocket MSN Messenger.

gear, smartPhones should make it more portable 
the black square is the external GPS antenna,
which connects to the side of the CompactFlash GPS

these are video captures of the end result (also linked below)

GPS software

Ad notification

Viewing an ad

User notification

Preview of Phases

Broke this project up into phases which are outlined below. Each one of these phases is about the same level of effort of my previous individual articles

  1. GPS - serial connection to GPS device, class libraries for parsing NMEA strings, and desktop WinForm app for displaying output
    • i.e. write a simple app to read from a GPS device and display the text results
  2. Pocket GPS - convert above GPS app to run on Pocket PC. Integrate maps. Have it run disconnected and with wireless connection
    • i.e. convert to run on a Pocket PC and then integrate with MapPoint .NET to basically have written a new breed of GPS software
  3. Push Notification - add in SQL Notification Services to receive location-based messages depending on your movement, ads, other peoples location 
    • i.e. make it a 'killer-app'
  4. Pull Notification - semantic web
  5. TBD

Location

To write a location-based app, I needed to know where the h3ll I am. There are only a limited number of ways to get this info

Had already used MapPoint .NET to get lat/long with an address, and the phone-based location is not available ... so that makes the decision easy, GPS. Having absolutely zero experience with GPS (other then checking them out at SAMs club, and annoying the sales girl by continuously raising it up and down to change the altitude) I start looking around. Turns up a friend at work knows more about GPS then I ever want to know, and gets me up to speed so that I can purchase a device. Also, from looking around I find some code where an MS employee had written Compact .NET code to read from another GPS device. Just so happens that I had bought a Pocket PC a couple months ago to work on some other beta code and really wanted to revisit Compact .NET. That narrows my GPS device choices to one that I could hook up to my PocketPC. The hookup choices were CompactFlash GPS device, serial cable to the bottom of my device with an adapter, or serial cable to CompactFlash adapter. Did not see where to purchase a serial cable for the bottom of my PocketPC (Audiovox Maestro), so those flavors were out. Further, through the bottom of my device is how I connect my phone for an internet connection. Also, the CompactFlash serial adapters are not cheap, and I would still have to buy a GPS device with a PC cable, so that was out. Further, that would have been more wires then I would be interested in walking around with. Luckily, ends up there are a number of CompactFlash GPS cards on the market. So I would put the GPS into my CF slot, any maps could go on my SecureDigital card, and I could get a lame 14.4 kbps internet connection with the cable that connects to my cell phone. Which is ultimately what I need, a GPS reading and an internet connection at the same time. Hopefully, this will all be wi-fi'd/bluetooth'd, and then I could have an CompactFlash loaded with MP3s in my PPC, wireless headphones on, wireless GPS clipped to belt, wireless phone with 3G connection on belt, and PocketPC in hand OR once the 3G phones are out and giving locational info then GPS is not needed OR get this all implanted in the 80% of the wasted space in my skull. After writing their tech guys whom manufacture the CompactFlash GPS devices, and finding a helpful one, I purchase their product ... and wait. But I am not good at waiting ... so I skipped to another phase to begin working on its core pieces

PHASE 1) GPS / NMEA + WinForm

This is simple. It is just an off-the-shelf handheld GPS unit connected to my laptop computer with a serial cable. On my notebook, I have a WinForm app that reads the signals from the GPS device and displays some output.

WinForm GPS Reader

Had skipped ahead and basically figured out most everything I needed for SQL Notification Services while waiting for my GPS. Was pretty much stuck, until a good friend on my current contract mentions that he has a GPS device he had barely used from points he had gathered up on his credit card. Brings that in the next day, and I am off running. Couple hours to get a connection between a WinForm app on my desktop computer, and the GPS device connected through a serial cable. Forget where I originally found the code to do the serial communications, but had used it previously to hook up the scrolling marquee in front of my live video feed. All the code does is start listening on COM1,4800,N,8,1 polling the stream every second and dumping out the results. NOTE I will have to rewrite the communication layer for the PocketPC. The results end up being NMEA strings. NMEA is the standard for GPS IO, so that you can use the same software with different devices. It's a bunch of carriage-return delimited strings, with comma-delimited values. There are a number of different NMEA strings returned, each with their own format, but only a handful are really important in my app. A short description of these strings can be found in Figure 1 of this great article. Between that article, and a couple of other online resources, spent the next day making an object model for parsing those strings and hydrating objects with those values. Because I did not want that code breaking on me, spent an extra half a day making sure that it could parse for an eternity without kicking out due to an exception. Most exceptions came from doing Double.Parse() and Int32.Parse, so I wrote my own implementation of these using Double.TryParse and a ParseInteger method that checks each character is a digit, otherwise returning 0. Left that running while I went to workout, and it was still running great when I got back. Then proceeded to move the GPS out of satellite range, and it still kept working, so I marked that off my list. Since my GPS satellite reception was questionable at best, went back and wrote the code to get satellite info. Then, ported the code from the MSDN article for displaying bearing and satellite location for kicks. Wrote my own little display to show altitude change NOTE that code is about the extent of my GDI+ knowledge

running disconnected against file running connected through ghetto window
(NOTE there is hover over text to read)

MapPoint .NET Fiasco

After I had assessed and managed most of the technical risks for this project, I start prepping and gearing up to code. One task being that I needed to get renewed access to the MapPoint .NET web service. Call up and get somebody I had never spoken to before ... they say No! I'm like WTF, but wait for the guy whom I have spoken with before to call me back ... and he says No! Says I have had plenty of time to evaluate MapPoint .NET and that I would have to pay $5000 a year to get a developer seat allowing 2300 hits a day. Yes, I have been on the program for a number of months, but it is not like I have been heavy traffic, nor that I have also been on the Compact .NET, Speech .NET, and SQL Notification Services betas after that initial start date. You are kidding me ... it's not like I have written the most advanced articles and given away my code for FREE on how to use MapPoint .NET for Pocket IE and Compact .NET. It's not like the Compact .NET team released a web services component update after my article detailing the bugs that kept it from working with MapPoint .NET! (Could be unrelated, but it is quite suspect) 'Developers, Developers, Developers ... my a55'. So I fire off a whining email to the mappoint.webservice newsgroup. Get a quick response and a call later and it sounds like they are going to fix me up nicely. Then, the next day comes and they back off what was said on the phone and decide to extend me only 30 days access to complete this project. 30 days, in my spare time, using more then a handful of beta technologies ... h3ll (do they think I just learned to code) ... JK (i like those odds). They do point out a MapPoint Alliance program, which has me signing some NDAs and looks like it would get me through December 2nd, but after that point I would have to cough up the cash. So the moral of the story is ... I have 30 days to develop this (see the timeline at the end). My hope is that they will find some better way to accommodate me after this article, so that I can continue championing their product

GPS Development

This was my 1st exposure to GPS, other then the previously mentioned SAMS Club episode, so I had no clue what a development pain it was going to be. First, GPS does not work indoors. You need line-of-sight to the horizon to get readings from the satellites. So this gives you a good excuse to go outside (not feasible in Texas during August) and get reacquainted with nature, or get a window seat in the office; although a wireless network cloud over the city would be appreciated. I ended up repositioning my desktop PC so that I could trail the serial cable out a window and set the GPS device on the ledge.

 the real world dont jump!

NOTE I have 20 foot high windows in my studio apartment, and they are REALLY heavy despite the -brawn. Nor do they remain open, I have to wedge a hammer or something underneath them to keep them open. NOTE the skyline view outside those 20 foot windows was not helpful for acquiring satellite reception.

ghetto window facing west, blocking signals from the east blocking signals from the southwest, tallest building downtown pittsburgh blocking signals from the west, federal building, somebody asked me what i was doing after taking this picture blocking signals from the north

This brings up the point that GPS does not work great in urban areas with tall, densely packed buildings. Cell phones should not have this problem, although they wont work great in rural areas (GPS will). For my CompactFlash GPS device, ended up ordering an external antenna, which I hope to run out the window, but I have not seen it yet. Next, GPS devices drain batteries like mad. This required a new outing to SAMS Club to buy them in bulk. My CompactFlash one will end up getting power from the USB connection when docked, with the external cable trailing outside ... but when I'm walking around disconnected, will have to see how fast my PocketPC is drained. This compounded the previous problem, such that I would get the window open, set the GPS outside, then lower the window down to a wedge to not splice the serial cable ... and then the batteries would die! Ended up leaving my window open, and then hanging a towel over it so I would not be air-conditioning downtown Pittsburgh using some unused 'Chip-Clips' ... ghetto style!

ghetto window, note the serial cable and chip clips closed for the day, the hammer is to prop the 20 ft window open, and cat burglars below ghetto window, books on the left have been read, ones to the right are pending

Third, the GPS device seemed to work better during the day. At night, I would get less satellite readings and sometimes my position could not be acquired at all. This goes against my nocturnal coding nature. Actually, day/night-time might just be a coincidence, and it could just be the position of the satellites ... not sure if they are stationary or not. A point worth noting from the MSDN article, is that you should save off a file of NMEA strings to simulate against when you don't have connectivity. Ended up using a couple, the one from the MSDN article, one when I was getting good connectivity from my apartment, and another when I would connect, disconnect, lose connectivity, etc ... to test worst case scenario. Finally, these devices seemed to be doing alot more then I thought they were. My initial thought was that the devices just got the strings from the satellite, and then software handled the rest. But from looking at the features that they offer, and the info from the NMEA strings, it looks as if the devices are stateful. So when people complain about the device only holding 200 waypoints, instead of 500, they are actually complaining about the hardware and not the software. This should be helpful for me though, because one feature of the devices is quick coldstarts. Meaning the 1st time you start up a device, it takes a while for the device to acquire the satellites; unless you prep it with some initial location info. Since my sole purpose is not to rewrite GPS software (although I sort of do this in Phase 2), this is a goodness, that I should not have to write that stateful code myself. For my locational based notifications below, I will use software instead of hardware to handle waypoints and such. Although, an alternative method would be to put more of the work on the GPS device ... I think, this is my 3rd day at this point with GPS, so I could be lying to you?

Road Trip

So now it has a UI for bearing, altitude and is reading speed etc ... but my apartment is not moving ... ROAD TRIP! Turn off the live video feed, throw the code over, and grab my notebook and head downstairs. Head to the parking lot outside my building with the 'bassmobile', roll the windows down, turn the volume up and piss off the neighbors while setting things up. Leave the 'bassmobile' running, else the subs and amp drain my battery within 10 minutes. Hook the GPS up and my notebook becomes unusable because the mouse keeps jumping around. Thought it might be the bass, and that the trunk (aka sub compartment) might be rattling so much that it was interfering with the touch pad. Ends up their was a rogue mouse driver listening on COM1 and the GPS device was driving it. Turn that off, and I can work again.

running on the back of my trunk note the .NET Framework bumper sticker ... i dont half-ass anything why it is called the sub compartment, the gps is on the rear deck

Getting better readings outside, but I still need to test speed and bearing, not to mention the exhaust fumes are starting to get to me. Set it up in the cab as copilot, turn on the cruising music, and head for food. Went North and it showed North. Got food ... the people at the drive-thru didn't know what to think: "What are you doing?" "I'm tracking satellites" "Are you a terrorist" "No, and could I get some hot sauce?" "Sure". Headed South, and bearing showed South. Ground speed tested out as well, although don't tip the cops off. Only 1 exception was thrown during the trip, so now I can move on to something else. Altitude remains a little fishy, on my apartment range it would sometimes show me around 160 feet, and other times it would put me a mile above sea level (not in CO, i wish). Also, while driving, it would map out pretty steady, but occasionally it would spike real high or real low, and then level off again. Seems like the GPS should keep a longer history and then have some way to smooth out irregularities ... that's what you get for letting the hardware guys do too much

copilot is setup ... dont code and drive amp warmed up and satellites being tracked cruising speed, extreme bass makes you drive slow pit stop, i won free nachos baby no mr. officer, i had no clue i was going that fast ... this must be broken, im pretty sure i topped out at 3 figures, but didnt hit print screen at the right time

Resources

Serial port communications

justinIO.cs (written by Justin Harrell)

http://www.brains-N-brawn.com/live (C# code sample using justinIO.cs)

GPS NMEA string parsing and Graphical display of GPS data (by Joshua Trupin, MSDN Mag editor)

http://msdn.microsoft.com/msdnmag/issues/01/01/GPS/GPS.asp

http://msdn.microsoft.com/msdnmag/issues/01/01/GPS/figures.asp

PHASE 2) Compact .NET + MapPoint .NET

The architecture has now been pocket-ized. The GPS device connects into my PocketPCs CompactFlash. To get a GPS signal while coding indoors or driving, there is an external antenna I connect to the CompactFlash GPS device and then set out the window or on top of my car. In a connected mode, the PocketPC is cradled to my computer or to a cell phone through a serial adapter cable. With a connection, the Compact Framework .NET app can request lat/longs, routes, and maps from MapPoint .NET according to the GPS device output. This info is stored on the PocketPC device so that it can operate in a disconnected manner, with just the PocketPC and the CompactFlash GPS attached. The lighting bolt designates a wireless connection.

/noMadMap++

A couple of 'my coolest article ever's ago, previous to the hands free Speech .NET articles (which are now surpassed by this one), /noMadMap was the coolest thing I had ever written. If you missed it, it was my test of the Compact .NET Framework calling out to a legit web service. That web service being MapPoint .NET. In short, it stored addresses, would find lat/long for those addresses, generate routes, and maps between those locations. Was my 2nd run-in with MapPoint .NET and my 1st with the beta of Compact .NET. The outcome of that article was I found some possible bugs in the (de)serialization of SOAP messages, which were fixed by the Web Service component update that was released when the CF .NET team released their VB .NET code for calling MapPoint .NET. Since that app matches up so close to my current scheme, decided to reuse that code base, cleaning up some of the hacks I was forced to code previously. Had to beef it up to display lat/long values to give me more visibility, as well as save off bounding rectangles for maps, possibly text directions and waypoints too. Then, I would integrate the GPS by writing the communications code, move the NMEA code into a class lib, and redo the GDI+ within the limitations of the PPC. Next, I will integrate the wireless map retrieving functionality. Finally, I might try to trick it up with some audio based on routes

addresses tab directions tab maps tab settings tab
these videos explain the updated noMadMap tab pages (NOTE you need audio)

CompactFlash GPS

Psyche ... the external antenna shows up 1st ... d4mn. Was all set to code too. Oh well, I cut my losses and crack open /noMadMap. Start rearranging the GUI. Make room for the 'Address' page to display a read-only lat/long dump as well as a GPS button to turn it on and off. Tie that to a small communications class wrapper that will support file simulation as well as readings from the device. Port the GpsRead class lib used to parse NMEA strings above over to the pocketPc, with minimal changes and have it dumping out fake lat/long readings to the textboxes created earlier. Next day ... the CompactFlash GPS finally arrives! Open up the box and find that it comes with all this lame software ... set it aside, because i wont be needing that; nor do i want it to corrupt my own ideas of what it should do. Look for the quickstart info sheet and see that they have a small .exe i can throw on my PPC and it will dump out basic info from the GPS to show that it is working. Insert the CF GPS in my PPC, and insert that in its cradle, then hook the external antenna up to the GPS and run it out ghetto window. This setup actually works great, because you can get readings from the GPS through the CF communications without having to be outside. The external antenna also has a magnet to hook onto the top of a car while driving ... highly recommended. Minute later, and I have some satellites popping up on the PPC screen as well as a lat/long reading. Ok, i know the hardware is good, so i delete that .exe as well.

CF COM

So I have no clue how to communicate with a CF device, but it just so happens that an MS guy had posted some code to a newsgroup to do just that. Go and find that post again and take a look at the code. Similar to the SerialIO class I had used on my notebook, with the main difference being PInvoke calls to WinCE APIs. No clue what any of those calls mean, but the interface is clean, so I grab that code and divvy it up into my GpsCom class that was only doing file simulations up to this point. Could not get readings from the device, but the hack around it was to make it try to connect a couple times in a loop. Typically failed the 1st time on my device, but then would connect on the 2nd try. Got a code update from the MS guy that might have fixed this, but I have not integrated that change since my schedule is pretty tight. Regardless, I now have lat/long readings showing up on my 'Address' page, from the actual device

XSD

Using the pseudo-typed datasets of CF .NET to store addresses from noMadMap v1. Extend that to store mapping info as well, because when requesting a map from MapPoint .NET, it also returns a chunk of info like centerPoint, boundingRectangle, height, width, scale, etc... All sorts of info that is relevant to hook with a GPS feed on the client :) Once I can overlay my position, this will also allow me to start the GPS device and then select which archived map to view without having a wireless connection. Could even have a filter button, that would only display maps that had a bounding rectangle containing the current GPS lat/long. Sprint just started announcing their 3G vision though, so the wireless connection gripe should slowly go away, at least once the phones have WiFi or Bluetooth connections. Also, just heard of a Pittsburgh Starbucks getting a WiFi connection so I will definitely head that way, although my GPS device being CF kind of sucks here, because my WiFi card is also CF ... the scenario being enter address or use GPS to get lat/long. Then use WiFi to get lat/long and/or map from MapPoint. Finally, put GPS back in to see my position overlayed on that map. Until then, I can hook up my phone with a serial adapter cable to my PocketPC to get a weak 14.4 kbps connection, just enough for me to kick off the GPS and get a lat/long reading, then request a map from MapPoint .NET centered on my current location

WGS 84 (Decimal / Degrees)

With the bounding rectangle from MapPoint .NET server being in lat/long and my own lat/long coordinates from the GPS device, I figure all I have to do is request a map and then overlay my position after doing a pixel conversion. So I do just that, and display a map ... but discover that my point is nowhere within the bounds of the map returned my MapPoint. What the h3ll! At 1st, I attack MapPoint .NET, since I'm still pissed about having to whine to get connected again ... but then I realize I am an idiot. When parsing the NMEA strings, I see that they return a value like 4026.6533. I was like, why did they put the decimal in the wrong place and just divided by 100 to fix it :) Wrong! Ends up that lat/long can be displayed in decimals or degrees and that you have to convert between the two, although the values are deceptively similar without conversion. From seeing other peoples commented out code and newsgroup postings, this seems to be a common mistake. Write that algorithm, and the above position in degrees, becomes 40.4442467 in decimal format. Now overlay that position on my map, and its dead center. Start walking West, and it shows my representative dot heading North. D4mn! Revisit my decimal lat/long code again and fix that minor bug, and while I am there, also realize that I need to so some additional calculations based on whether the lat/long is positive or negative to do the pixel placement on the screen. Think this code is correct, but would love to travel to the 4 quadrants of the world to test it out ... that is if my airlines would quit declaring bankruptcy :(

Bearing

Following the dot representing me is lame, and a coworker had already requested a directional arrow, so I start writing that code. Make some .gifs (i mean .pngs ... lame) and start overlaying those on the map. Realize that the minimal GDI+ that I had just taught myself on the desktop version of this app is no help on CF .NET, because GDI+ does not exist on PocketPCs. Luckily, there is a large amount of posts on the public newsgroup and I found out how to do transparancy to display the arrow only, showing the direction I am heading. Run a file simulation, and arrows are pointing all over the place as expected. Then I head to the gym to go workout, and it is dot only again. No clue why it is not working, so I need some more output. Create a 'GPS' tab page to dump out most of the info from the desktop version of the app (lat/long/altitude/speed/bearing/satellites etc...). From that, I see that my speed and bearing are remaining at 0. Make another textbox to dump the actual NMEA strings too, as well as a file archive of the GPS output, and I can see that speed and bearing are not being calculated correctly; so the error must be in my NMEA parser class. Update that code, and I have an arrow pointing my way now. Not happy with the NMEA spec, or people's implementation of the spec; I have 3 sources of data ... 1 file from the MSDN article, a couple files form my friends handheld Garmin, and now my own CF GPS; and although there is a spec, I keep having to tweak the parsing code to keep it working and then regression test etc. Should revisit my classes to have a PreParse() method that would scrub each string accordingly, before I parse the data out

gps tab centerpoint map
videos showing new GPS tab, and a centerpoint map with position overlayed

Accuracy

Another day of me testing it walking to/from work and the gym, and I am somewhat happy with it. Need to go and test it in some less dense area where I can get better line of sight to the satellites. With the buildings downtown it is kind of jumpy. Meaning it works good at intersections, but between them it might randomly get a signal and show my location in the middle of a building. Also, it seems to error a little to the left on longitude, not to mention there is a minimum of 3 meters of error from the GPS itself. Latitude seems to be pretty well represented on my current scale, although longitude is a number of pixels to the left no matter if I am to the left or right of the CenterPoint. Have checked my lat/long to pixel conversion code and it seems to be correct. If it is not my code, then it is either a bad reading from my GPS or bad map data. I don't think Pittsburgh has had any earthquakes lately, so plate tectonics should not be an issue? Finally, speed, altitude and bearing are not that reliable from the device. My software should keep a history of readings and then do some 'smoothing' to make that data more realistic. That could also handle the random jumps, meaning if I am only walking about 3 mph, and then get a random signal to put me a block away, then that reading should be ignored unless substantiated by further readings.

Route

Just before vacation, I was able to get routes to work. So you can get text directions from a starting address to an end address. Extended the schema to support saving off all the waypoint info, so that ultimately I could make it speak by saying turn left or right accordingly. Further, once Speech .NET is on the PPC, then it could read out all of the text that was returned within range of that waypoint. On my way to the airport, I hooked the external antenna to the GPS and stuck it on the roof of my car; then recorded the GPS signals as I drove to the airport. Also before leaving, I saved off a handful of Dallas addresses I knew with routes, to test it out there, and it worked great. The real weakness of it right now is the connection. A 14.4 kbps phone connection can take a minute or two to get a lat/long, route, and a map. The next generation phones with speeds around 56 kbps should improve this. Because of the weak connection I would typically get some maps while my device was cradled, and then go without a connection while walking around, just carrying the PocketPC with the CompactFlash GPS. If the connection was better I would make it auto acquire a new map as I walked off the edge of the world.

route map full demo run
videos of a route map and a longer video of how it is used

Resources

PocketPC GPS NMEA String Parsing

GpsReadPpcLib (my C# CF .NET class library with source)

nmm_outAptFmkt.txt (recorded data for simulation)

Persisted MapPoint .NET [Meta]Data

nmmTds.xml (data)

nmmTds.xsd (schema)

nmm_FreeMarkets_Apartment.gif (map)

CompactFlash GPS (i bought this one because their tech support was helpful)

http://www.pretec.com/index2/product/Mobile_peripherals/CompactGPS.htm

highly recommend getting the external antenna for development and car usage

PocketPC CompactFlash communications (written by Hans Hugli of MS)

GpsForm1.cs  

GpsForm1Notes.txt

Compact .NET + MapPoint .NET

http://www.gotdotnet.com/team/netcf/mappoint/default.aspx (CF .NET web service update)

http://www.brains-N-brawn.com/noMadMap (v1 of the above app)

PHASE 3) SQL NotificationServices + XML WebService + MSN Messenger + ASP .NET WebForm

Lot of stuff happening here. The core is still the PocketPC with GPS device, and now the cell phone is mandatory for a constant connection. With that connection the app will periodically post my location to the SQL Notification Services Web Service as an event, it will also receive notifications as a delayed SOAP response from that request of other Users that are nearby. Another notification that it could receive is through Pocket MSN Messenger, if coming within range of an Ad location. To look at an ad, it would view an ASP.NET Web Form in Pocket IE. It can also connect to MapPoint for lat/long, routes, maps per Phase 2. My devbox hosts the Notification Services Web Service wrapper. It connects to MapPoint .NET to get lat/long for advertisement addresses. It also is the single point of entry for submitting events to the Notification Service, albeit Ad or User events. The Notification Service has a Custom Delivery Channel to notify of advertisements. This channel posts a request to send out an MSN Messenger message using my MSN Messenger Web Service, or posts back to the SQL NS Web Service. For users that come within range of each other, the nearby users are rendered within /noMadMap. If they click on a user they see that user's subscriberId and the MSN address, with an option to start a chat. If they choose to chat, then a message is sent through the Messenger Web Service initiating a conversation between both users

SQL NotificationServices

Kitchen sink ideas are fun for reinforcing existing knowledge ... but that is boring, and learning something new is fun. An MS MVP had tipped me off to the SQL Notification Services beta and I had been checking it out to work on something for him. That technology review is actually what helped spawn my idea, and then figuring out how to solve the problem and actually implementing that idea became all consuming (Not sure how many days I forgot to shave before I had the technical risks to some manageable level). Spent about 4 days reading the docs, couple days figuring out the command line BS, and then I started designing my notification app.

The basics of a notification system are: subscriptions and events come into the system, some rules logic is performed on those 2 inputs, and a notification is sent out, being formatted and delivered to the proper device. Notifications can be sent immediately based on an event or scheduled. For my service, there are 'users' and 'advertisers'. A user is a consumer like myself. An advertiser is some locational-based store with something to sell a consumer. So the basic scenario is that based on a user's location they receive an advertisement and/or info about other users nearby

Subscribers - users and advertisers have a unique id and maybe a password

Subscription - a user subscribes based on their device, latitude, and longitude

Events - an advertiser running a lunch special or something to that effect

Rules - base rule is send an ad to a user if they are close to a store running an ad

Notifications - users with range of others users

Chronicle - to get rid of the duplicate ad notification bug pointed out in a video below

Format - use XSLT to shape raw notification data into HTTP requests

Delivery - ad notifications are sent through a custom delivery channel as MSN Messenger messages with a link

Linkback - the MSN messenger link has a notification ID, this ID is used to render an ASP.NET page in Pocket IE with all the data and a map

XML WebService

Wrote an XML web service to wrap the SQL Notification Services interactions. It provides interfaces for adding subscribers, devices, and subscriptions. A web service is really useful here since many devices could be subscribing for the service. Very thin app layers can be built to support these devices, and all the backend logic will be the same through the Web Service. The web service is also my event provider. When a new ad is posted, the ad is posted to the web service, and then the web service submits it to SQL Notification Services. The same goes for when a user updates their location. Finally, when an advertisement ad is viewed, the ASP.NET web form uses the web service to retrieve the notification data from SQL Notification Services to display the AdName, AdText, and generate a map showing the route from the users current location to the advertisement location.

Custom Delivery Channels

This is real simple for Ads. All it does is take the XSLT formatted SOAP message notification, and does an HTTP POST to my MSN Messenger Web Service. The auto-generated Web Service client shows exactly what the message needs to look like in SOAP format. The MSN Messenger Web Service then sends the notification out at an MSN instant message

message received over noMadMap viewing the instant message
these are some early unformatted notifications on Pocket Messenger

For User notifications, I end up posting those back to the Location WebService. These values get stored in an application cache per user. The next time a user posts their updated location info as an event, the return value is the notification of nearby users from their previous posting. The cache can time out periodically so that aged data is not returned. Basically, it is forcing asynchronous notifications into a delayed synchronous model so that I can get the results back into the scope of the /noMadMap application easily

ASP .NET WebForm

Was supposed to write an ASP.NET Web Form app to let users manage their subscriptions ... but I got lazy and just used the basic Web Service interface directly :) A Web Form is used for rendering the advertisement notification data in Pocket IE from the Pocket MSN Messenger link.

MSN Messenger

Had worked with Messenger in the past, and might have been the 1st person to hook it with .NET, with the help of some friends at EDS. The result of that effort ended up being a WebService interface that allows me to programmatically send out instant messages. In other words ... it is a poor man's .NET Alerts. For the Ad notifications, I use it to immediately send out a notification that a user is within range of an ad. The message has a linkback to pickup the notification data, and render a customized map for that user. For Users notifications, I wanted to do something different because I wanted that scenario to take place entirely within /noMadMap. 1st thing I tried was to grab the imCli code from SellsBrothers.com. Ported that to CF .NET (removed Regex, crypto, and gave a NameValueCollection [] a default size). So it compiled, but I knew the MD5 crypto hash I had removed was going to have to be put back in. Went looking around for some low level implementations of the MD5 hash algorithm. Found some stuff, with the most promising being a VB implementation. Ported that to VB .NET and removed the overflow checking from the project. Unfortunately, its results were not the expected results, so it broke somewhere during the port. Another quick scan and nothing was going to get me running within an hour. The other path I saw was that the PocketPC has an high encryption pack add in that should have an MD5 hash algorithm that I could PInvoke. Grabbed that, but could not find the API to wrap ... so I cheated and added the MD5 code into my own MSN Messenger Web Service. Then made the pocket imCli code call out to my web service to get a hash. With this, I was able to send an MSN instant message programmatically from a Pocket CF .NET app (assuming I am the 1st person to do this). The remaining problem was that this methodology would not allow me to remain logged in to the stand alone Pocket MSN Messenger app. Every time I sent a message from my app, it would log me out of Pocket MSN Messenger, effectively not allowing me to receive a response. Could extend the imCli code to receive responses, at which case I would not need Pocket Messenger, but that was also not on my time schedule. Then I remembered my WebService has a conversation WebMethod exposed, and since I was already calling out to a WebService for the MD5 hash ... this made more sense. So now, to start a User conversation, a request is made to the Messenger WebService with both of us as invited buddies and a default message. On the WebService, the 3rd party MSN buddy 'evil mess' starts a conversation with both of us, sends the message, and then exits the conversation. On the PocketPC, we both receive a message on Pocket MSN Messenger, and then can chat with each other, and neither of us need to be on the others buddy list

Summary

Let me reiterate what it does: The PocketPC app still behaves as normal and renders my position on the map from MapPoint .NET. Also, every N seconds it will send my new lat/long location up to a SQL Notification Web Service. This is received as an event to update my current location. Based on that event, 1 of 2 rules might be triggered. 1) If another user is nearby, then I will receive their info as a response, and then their location will be plotted on the map along with my own location. Then I can click on a user icon to view their subscriberId and MSN Messenger address. From that dialog, I can select to initiate a chat conversation with that user, which will start a conversation between me and that user in Pocket MSN Messenger. 2) If a restaurant has posted an ad, and I am close to that restaurant, then an MSN instant message will be sent to me with the name of the restaurant, some text about their ad, and a link. If I click the link, then the full notification data will be retrieved from SQL Notification Services, and displayed in an ASP.NET Web Form in Pocket IE, along with another MapPoint .NET generated map showing how to get to that location from my current location. Finally, remember that my location change might trigger events to occur for other people that are using the system, or events that the advertiser might ultimately use

updated settings tab receiving an AD notification viewing an AD
videos of an advertisement notification and ad

user notification 1 user notification 2
videos of user notifications and chat

Resources

SQL Notification Services

appADF.xml (application definition)

appConfig.xml (duh)

MsnAdHttpPost.mod.xslt (ad notification formatter)

MsnUserHttpPost.mod.xslt (user notification formatter)

FileNotifications.txt (raw ad/user notifications)

http://www.develop.com/dm/course.asp?id=163 / http://staff.develop.com/bobb (Bob Beauchemin of DevelopMentor answered all my questions)

http://www.wronghands.net:8000/myNotify/LocationService/LocationServ.asmx (my web service)

MSN Messenger and .NET

http://www.devhawk.net/messenger.htm / http://www.sellsbrothers.com/tools/ (Chris Sells imCli class)

http://www.brains-N-brawn.com/messenger (my web service)

MapPoint .NET + Pocket IE/ASP .NET

ViewAd.aspx.txt (view source for tags)

ViewAd.aspx.cs.txt (app-layer code only)

http://www.brains-N-brawn.com/clubMap

PHASE 4) MapPoint 2002 + GoogleAPI + ...

Have implemented very little of this phase

While phase 3 was a 'push' model for notifications, this is a 'pull' model. As you are walking around you get lat/long from the GPS. If you get hungry for pizza, then you just submit a query to my MapPoint 2002 wrapper web service. With that info, it uses MapPoint 2002 to do a reverse geocode to find the nearest address for that lat/long location. That address should provide a zipcode, which it will use against a web service to retrieve phone number area codes for that zipcode. Next, armed with an address and area codes, it will call out to the Google API searching for pizza restaurants in the area. It will then crawl against those search result pages using regular expressions to help weed out bad data, and screen scrape an address/phone#. Those results will be presented to the user to select a restaurant as a validity check. Finally, that address will be used with the users current lat/long to generate a lat/long point to display on the users current map or create a new route map on how to get to the restaurant.

MapPoint 2002

This application provides some features and functionality that you cannot currently access from MapPoint .NET. Because of this, I wanted to hook MapPoint 2002 and expose access to it through a web service interface so that I could fake the currently non-available WebMethods. To allow MapPoint 2002 to run in a non-interactive manner you have to run 'dcomcnfg'. This brings up ComponentServices with a folder called 'DCOM Config' under 'Component Services-Computer-My Computer-DCOM Config'. Selecting that folder will show a list of DCOM apps. In this case, we want 'Microsoft MapPoint' ... ignore the MapPoint Control. Right-click and bring up its properties. Modify all of its security permissions so that 'Everyone' has access. Also, give it an Identity username/password to run as a certain user. Then, modify the web.config of the web service to impersonate that user. Finally, add a reference for Microsoft MapPoint 9.0 to create the Runtime Class Wrapper to expose the MapPoint object model to your .NET code. NOTE since I am doing this on Windows XP Pro, I had to go in and add a password for the user the app is impersonating, instead of just letting that user have access without a password.

Reverse GeoCode

Primary reason for hooking MapPoint 2002 was to do a 'reverse geocode'. i.e. Get the nearest address from a lat/long. NOTE MapPoint .NET will provide this feature in the future. There are links below to articles on that subject

Area Code Web Service

I am assuming there is a web service that would return area codes for a given address / zipcode. If not, it would be relatively simple to create one, although it would suck to have to keep updating it. Also, the regular expressions for doing searches would have to take into account 800/866 numbers

Google API

Have a WinForm app for one of my racier sites, that hits the Google API daily to find data that my targeted web spider cannot. The web service is powerful and would be more then adequate to find restaurants for a particular area. As a friend pointed out, a 'yellow pages' web service would also come in a handy for this scenario. From those search results, the actual web pages would be hit for current data and the appropriate data would be parsed out based on regular expressions for addresses, phone number, etc... NOTE Google recently had a competition for search engine ideas, and an 'area search', like this was the winner. NOTE IBM also has a patent from 1998 for a similar idea (1st search result returned for 'GPS' at www.spi.org). I doubt the patent would hold up in court, but I'm too small to fight 'big blue'.

Semantic Web

After creating my own web spider and search engine site, I have learned that HTML has screwed up the internet by creating tons of unformatted data. Now there are a couple pushes to get the Net to where it is understandable to non-humans, which will make it extremely more useful then it is today. With this 'semantic web' I would not require an ASP .NET front-end site for all restaurants/stores/whatever to publish their address as a 'Point of Interest'. They would only register if they wanted to submit an ad alert based on a sale/special/whatever. As long as they had their own site on the internet (likely), or had their info posted on a proper portal site (likely) ... providing the appropriate semantic web 'cookie' borrowing from the IBM patent noted above :), then I would just write a targeted web spider to periodically crawl over these sites and generate the database on my own. HTML had some little features to support this early on, e.g. the <Address/> tag, although nobody used it. To semantic-ify the web currently, elaborate regular expressions and some AI for spiders has to be implemented to scrape the relevant data from HTML. Partnering this with search results from the Google API to find disconnected patches of data on the web, and alot of data can be harvested and aggregated. This will get easier as HTML is tidied up through XHTML and embedded XML data to be parsed out. RSS is another acronym to note, not to forget WebServices as APIs that provide nothing but semantic data.

Resources

MapPoint 2002 Web Service Wrapper (in work)

http://www.wronghands.net:8000/RevGeoCode/GeocodeService.asmx

Reverse Geocoding (my articles are usually too offensive for mp2kmag)

http://www.mp2kmag.com/articles.asp?ArticleID=50

http://www.mp2kmag.com/articles.asp?ArticleID=47

http://www.mp2kmag.com/articles.asp?ArticleID=45

Google API

http://www.google.com/apis/

http://xmlforasp.net/codeSection.aspx?csID=56

PHASE ...) Missing Technologies

Could continue work on this for a long time. Here is what got left out or will become available in the near future

Timeline

Day by day schedule of my work/play

Future

From the missing technologies list above, it is very likely that I will revisit this a couple times over. To receive updates (once a month) about this article, and/or whatever else I am working on next, sign up on my new email list

Last article, I did not see anything new on the short term horizon ... this time I feel like I'm in a toy store again (which is a sight to see). The WebServDevKit is out for GXA level Web Services, which I have fallen behind in and want to get back up to speed. The Windows Media 9 Corona beta is out the day I plan to release this, and I have a rapidly growing codebase for WindowsMedia and DirectShow. Everett beta with CF .NET beta 2 is on the way, with the possibility of SmartPhone managed classes. Among other things ... Later