Decoding GPS with C#

I have a fairly old GPS receiver that communicates with my desktop through COM1.

I found some code on the internet to decode the strings i get from the receiver which look something like:

$GPGSA,A,1,,,,,,,,,,,,,1.27,0.75,1.03*04
$GPRMC,215606,V,3511.1990,N,12904.2725,W,0.000,0.0,151208,15.0,E*45
$PRWIZCH,29,6,12,0,12,0,31,0,24,6,31,0,16,0,31,0,31,0,31,0,31,0,12,0*44
$GPGGA,,,,,,0,00,,,,,,,*66
$GPGSA,A,1,,,,,,,,,,,,,1.27,0.75,1.03*04
$GPGSV,3,1,12,29,70,024,34,24,70,006,39,30,50,190,,21,48,264,*79
$GPGSV,3,2,12,10,34,052,,05,28,173,,18,21,194,,12,20,163,*73
$GPGSV,3,3,12,16,11,321,,31,11,268,,15,09,124,,26,07,108,*73
$GPRMC,215607,V,3511.1990,N,12904.2725,W,0.000,0.0,151208,15.0,E*44
$PRWIZCH,29,6,12,0,12,0,31,0,24,6,31,0,16,0,31,0,31,0,31,0,31,0,12,0*44
$GPGGA,,,,,,0,00,,,,,,,*66

The code if found here.
Using a resource I found on the internet i can tell that the GPS is working and giving me a fairly accurate location (once i get a fix).
However, this is over a terminal application called Tera Term and my GPS requires me to broadcast the command “ASTRAL” before any useful data is sent. The problem is, the code from the link above has no command to submit the command “ASTRAL”. I tried:

private void button3_Click(object sender, EventArgs e)
        {
            if (comport.IsOpen)
            {
                //byte astral;
                //astral = Convert.ToByte("ASTRAL");
                comport.Write("ASTRAL");
                comport.WriteLine("ASTRAL");
            }
            else
            {
            }
        }

But that didn’t work. Any suggestions?

Your code to write to the serial port should work, though I recommend you pick Write or WriteLine, and not try to use both. There’s a large number of reasons why this might not be working for you, though. If you don’t have the communication parameters set correctly, you can end up receiving but sending gibberish to the GPS, or not sending anything at all. You also might not be sending the appropriate end of line characters in the appropriate sequence. Common options are “\x0A” (new line), “\x0D” (carriage return)(Ding!), “\x0D\x0A”, and rarely “\x0A\x0D”. Your GPS might use more exotic characters, however.

If you have it working over Tera Term, make sure you have ALL of the communication parameters the same, and then find out what end of line characters it’s using. Once you make sure you’re doing everything the same as Tera Term, it should work for you.

You could always try good ol’ "
" and/or “\r”. I’m not quite certain of the setup you have, but you might be able to use a system() command to pass the word “ASTRAL” through the echo command.

If nothing else works, there’s always the down-and-dirty last-resort method of sending raw data to the serial port through “outb”. This is a Linux C command, and I’m not sure if it works in any other OS’s/C derivatives, but there’s probably something similar. Note that this function only passes one byte on at a time, so you’d have to find something else that can pass whole strings at the correct baud rate.

It was only sending “ASTRAL”
However, I just tried "ASTRAL
", “ASTRAL\r”, “ASTRAL
\r”, "ASTRAL
", “ASTRAL\x0A”, “ASTRAL\x0D”, “ASTRAL\x0A\x0D”, and “ASTRAL\x0D\x0A”.
None worked.

You might try looking at the open source project, GPSd http://gpsd.berlios.de/. It runs on Linux and Macs. I haven’t tried it under Windows, but I would guess it’ll compile under cygwin and run fine. GPSd has support for reading gps data in a bunch of different formats, and then translates the data into a common, easier to use, format which is accessible either through a TCP (telnet) connection to the server running gpsd, or through the gpsd client (available for a number of different languages, including C, C++ and perl).

A thought came to mind… I believe the .NET framework works in Unicode by default, which means it’s probably sending double-wide characters, and most serial devices expect single-wide (ASCII) characters. You’ll need to use the the Encoding class to convert between them. There’s plenty of examples on MSDN, I’ve also included one below:

using System;
using System.Text;

class ASCIIEncodingExample {
public static void Main() {
// The encoding.
ASCIIEncoding ascii = new ASCIIEncoding();

    // A Unicode string
    String unicodeString = "ASTRAL

";

    // Encode string.
    Byte] encodedBytes = ascii.GetBytes(unicodeString);
    
    foreach (Byte b in encodedBytes)
    {
        Console.Write((char)b);
    }

    Console.ReadLine();
}

}

C# defaults to standard ASCII encoding for serial ports and suchlike. There’s no need for re-encoding the string or anything like that. If you really think it’s necessary, however, it’s much much easier to do this in the port setting area before comport.Open():

comport.Encoding = Encoding.ASCII;

Also, thanks to a bit of googling to identify your odd GPS, I ran across your somewhat more informative post on XKCD. The nice webpage you link from there about your Delorme Tripmate actually tells you straight out that the string you should be attempting to send is "ASTRAL
". So it’s nice to have that confirmed, and you can stick with that as the string to send.

I assume that you’ve actually linked your button click function to your button’s onClick event, but just for grins, you could try forcing your program to send "ASTRAL
" as soon as it opens the comport. To wit:

                // Open the port
                comport.Open();
                button1.Text = "Close Port";
                comport.Write("ASTRAL
");

That should guarantee that your string is getting sent at some point, since it has to call Write after successfully opening the port.