dimanche 12 juillet 2009

OpenStreetMap - Gosmore



It is possible to run gosmore to use an OpenStreetMap on a CarTrek 600 (< 100.00€ - Benelux - june 2009)

Get a new SD card (1 or 2 MB, no High-Capacity).

Get the files for Windows CE from http://nroets.openhost.dk/.

Make a /MobileNavigator directory on the card using a standard cardreader, unzip gosm_arm.zip (and a map.zip in that directory. Rename the file gosm_arm.exe into MobileNavigator.exe (this is because the CarTrek will execute /MobileNavigator/MobileNavigator.exe on the SD card).

The gosmore (15sep2008) is a little bit spartian, but it works.



Use the 'o' button to run through the options and '+'/'-' to modify the options. After setting 'QuickOption' to '1', you get a menu when you click 'o'. Another interesting option is 'ShowCoordinates'. But you won't get your location by GPS until you set 'CommPort' to '7' and 'BaudRate' to '57600'. After this, you have to 'Exit', come back to gosmore ans select the option 'FollowGPSr' and maybe 'OrientNorthwards' if you are not moving. (Ofcourse, you also set 'ButtonSize' to '1').

You can also 'Search' a town using a virtual keyboard (the searh field is not autofocused). If you select a 'StartRoute' and an 'EndRoute', gosmore computes an itineraire.



When displaying the map, '+' and '-' zooms/dezooms and you can drag the map.
----
*http://www.cartrekgps.com
*HardwareManual-UK.pdf
*CarTrek600(UK).pdf (original software - CosmicNavigation)

Programming the CarTrek600



It is possible to write programs for the Cartrek 600 on an Ubuntu platform using CeGCC.

First, get the software. The .rpm did not work so I used the .tgz from http://sourceforge.net/projects/cegcc/files/
(I don't know exactly which ones I really needed)

$ sudo bash
...
# cd /
# tar xvfz ~/mandriva-cegcc-cegcc-0.55.tar.gz
...
# tar xvfz ~/mandriva-cegcc-mingw32ce-0.55.tar.gz
...
# tar xvfz ~/mandriva-gdb-mingw32ce-arm-0.55.tar.gz
...
# exit
$ export PATH=$PATH:/opt/cegcc/bin:/opt/mingw32ce/bin
$ arm-cegcc-g++ -static -static-libgcc hello.c -o hello.exe

and put the hello.exe on the SD card under the name /MobileNavigator/MobileNavigator.exe (where the CarTrek 600 thinks the application is).

The first program is the trivial example :

#include <windows.h>
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
MessageBox(0, L"Hello!", L"CeGCC says...", MB_OK);
}


Now, the problem is to find documentation about Windows CE and its API. (Maybe read the gosmore sources, it is not that long).

A little bit further...

#include
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
wchar_t argv0[80];

GetModuleFileName (NULL, argv0, sizeof (argv0) / sizeof (argv0[0]));
MessageBox(0, argv0, L"CeGCC says...", MB_OK);
}

gives the full name of the program :
' \SDMMC\MobileNavigator\MobileNavigator.exe'

----
Gosmore

# apt-get install libxml2-dev

$ svn co http://svn.openstreetmap.org/applications/rendering/gosmore/
$ cd gosmore
$ make
$ make gosm_arm.exe

(I had to correct 'ARCH=arm-mingw32ce' in the Makefile (it was 'ARCH=arm-wince-mingw32ce')
And I have a gosm_arm.exe compiled on my computer (Hardy Heron - Ubuntu 8.04) working on the CarTrek 600. (see another entry in this blog on how to install the software)

The self-compiled version doesn't seem to show the map (abut the binary does).

NMEA logging


A little bit experimental...


#include <stdio.h>
#include <windows.h>
/*
** CarTrek 600 NMEA logger (code inspired by gosmore)
** still a little bit experimental...
*/
#define prog_name TEXT("nmealog")
void msg(char *str1, char *str2)
{
static char txtbuf[512];
static wchar_t wtxtbuf[512];

sprintf(txtbuf, "%s %s (GetLastError()=%ld)", str1, str2, GetLastError());
mbstowcs(&wtxtbuf[0], &txtbuf[0], strlen(txtbuf)+1);
MessageBox(0, &wtxtbuf[0], prog_name, MB_OK);
}
/*
** NMEA module
** NMEA_init()
** NMEA_close()
** n = NMEA_read(buf, size)
*/
HANDLE NMEA_handle;
#define port_name TEXT("COM7:")
#define port_rate CBR_57600
int NMEA_init()
{
COMMTIMEOUTS commTiming;
DCB portState;

if ((NMEA_handle = CreateFile (port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
{
MessageBox(0, TEXT("Can't open port COMx:"), prog_name, MB_OK);
return(0);
}
if (!GetCommTimeouts(NMEA_handle, &commTiming))
{
MessageBox(0, TEXT("Can't GetCommTimeouts"), prog_name, MB_OK);
CloseHandle(NMEA_handle);
return(0);
}
commTiming.ReadIntervalTimeout = 20;
commTiming.ReadTotalTimeoutMultiplier = 0;
commTiming.ReadTotalTimeoutConstant = 200; /* Bailout when nothing on the port */
commTiming.WriteTotalTimeoutMultiplier=5; /* No writing */
commTiming.WriteTotalTimeoutConstant=5;
if (!SetCommTimeouts(NMEA_handle, &commTiming))
{
MessageBox(0, TEXT("Can't SetCommTimeouts"), prog_name, MB_OK);
CloseHandle(NMEA_handle);
return(0);
}
if(!GetCommState(NMEA_handle, &portState))
{
MessageBox(0, TEXT("Can't GetCommState"), prog_name, MB_OK);
CloseHandle(NMEA_handle);
return(0);
}
portState.BaudRate = port_rate;
if(!SetCommState(NMEA_handle, &portState))
{
MessageBox(0, TEXT("Can't GetCommState"), prog_name, MB_OK);
CloseHandle(NMEA_handle);
return(0);
}
PurgeComm(NMEA_handle, PURGE_RXCLEAR); /* Baud rate wouldn't change without this ! (?) */
return(1);
}
int NMEA_close()
{
return(CloseHandle(NMEA_handle));
}
int NMEA_read(char *buf, int n)
{
DWORD nr;
char stuff[80];

if (!ReadFile(NMEA_handle, buf, n, &nr, NULL))
{
MessageBox(0, TEXT("Can't ReadFile"), prog_name, MB_OK);
return(-1);
}
else {
n = nr;
return(n);
}
}
/*===================================================================*/
/* LOG module
**
*/
char *LOG_fname="\\SDMMC\\NMEAlog.txt";
FILE *LOG_stream;
int LOG_init()
{
if ((LOG_stream=fopen(LOG_fname, "a+")) == NULL)
{
msg("Can't fopen()", LOG_fname);
return(0);
}
fprintf(LOG_stream, "===== New log =====\n");
return(1);
}
int LOG_close()
{
return(fclose(LOG_stream));
}
int LOG_write(char *buf, int len)
{
if (fwrite(buf, 1, len, LOG_stream) != len)
msg("Can't write LOG_stream", LOG_fname);
return(len);
}
/*===================================================================*/
#define MAXLOG (100)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
wchar_t argv0[80];
char buf[512];
int n, count;

GetModuleFileName (NULL, argv0, sizeof (argv0) / sizeof (argv0[0]));
MessageBox(0, argv0, L"CeGCC says...", MB_OK);

NMEA_init();
if (LOG_init())
{
for (count = 0; count < MAXLOG; )
{
if ((n = NMEA_read(&buf[0], sizeof(buf))) < 0)
{
msg("Can't read NMEA", "");
break;
}
if (n > 0)
{
if (LOG_write(&buf[0], n) != n)
{
msg("Can't write LOG", "");
break;
}
count++;
}
}
}
LOG_close();
NMEA_close();
}

I get stuff like :

$GPRMC,110034.02,V,0000.0000,N,00000.0000,E,,,010103,,W,N*17^M
$GPGSA,A,1,,,,,,,,,,,,,60.000,60.000,60.000*06^M
$GPGSV,5,1,20,1,5,322,,5,15,296,,6,5,,,7,5,,*45^M
$GPGSV,5,2,20,8,5,,,9,41,12,,10,16,156,,11,5,,*4F^M
$GPGSV,5,3,20,14,23,316,,15,71,187,,16,10,282,,18,5,,*73^M
$GPGSV,5,4,20,21,5,,,22,1,273,,24,34,172,,25,5,,*4C^M
$GPGSV,5,5,20,26,5,,,28,5,,,30,23,4,,31,41,14,*41^M
$GPGGA,110039.02,0000.0000,N,00000.0000,E,,,60.000,,M,,M,,*53^M
$GPRMC,110039.02,V,0000.0000,N,00000.0000,E,,,010103,,W,N*1A^M

which is encouraging.
See
* Wikipedia->NMEA 0183
** NMEA reference Manual1.pdf SiRF Technology inc.
* Wikipedia->Dilution of precision
----
Three GPS, same location, same time. xy in meters (-75 is CarTrek (green); -64,-89 are Connex (red & blue))

xy plot

time (06:42-)/latitudes (meters)

time (06:42-)/longitudes (meters)

Rem : lines are interrupted due to an artifact sexagesimal/decimal
(06 42 59 + 1 = 06 43 00)

What's in the beast?

A (simplified) du(1) utility (recursive walk of the directory structure)

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <windows.h>
/*
** CarTrek 600 a kind of du(1) utility (disk usage)
** what's in the beast...
*/
#define prog_name TEXT("du")
void msg(char *str1, char *str2)
{
static char txtbuf[512];
static wchar_t wtxtbuf[512];

sprintf(txtbuf, "%s %s (GetLastError()=%ld)", str1, str2, GetLastError());
mbstowcs(&wtxtbuf[0], &txtbuf[0], strlen(txtbuf)+1);
MessageBox(0, &wtxtbuf[0], prog_name, MB_OK);
}
/*===================================================================*/
/* LOG module
**
*/
char *LOG_fname="\\SDMMC\\du.txt";
FILE *LOG_stream;
int LOG_init()
{
if ((LOG_stream=fopen(LOG_fname, "a+")) == NULL)
{
msg("Can't fopen()", LOG_fname);
return(0);
}
fprintf(LOG_stream, "===== New log =====\n");
return(1);
}
int LOG_close()
{
return(fclose(LOG_stream));
}
int LOG_write(char *buf, int len)
{
if (fwrite(buf, 1, len, LOG_stream) != len)
msg("Can't write LOG_stream", LOG_fname);
return(len);
}
/*===================================================================*/
#define BUF_SIZE 512
int list_dir(FILE *fp, char *dir_name)
{
DIR *dirp;
struct dirent *direntp;
char buf[BUF_SIZE];
int len0;

fprintf(fp, "%s\n", dir_name);
if ((dirp = opendir(dir_name)) == NULL)
{
// fprintf(fp, "Can't opendir %s\n", dir_name);
return(0);
}
len0 = strlen(dir_name);
while ((direntp = readdir(dirp)) != NULL)
{
direntp->d_name[direntp->d_namlen] = '\0'; /* to be sure */
// fprintf(fp, "%s/%s\n", dir_name, direntp->d_name);
if (strcmp(direntp->d_name, "..") && strcmp(direntp->d_name, "."))
{
if ((len0 + strlen(direntp->d_name)) < (BUF_SIZE-2))
{
if (dir_name[0] == '/' && dir_name[1] == '\0')
sprintf(buf, "/%s", direntp->d_name); /* no double-slash */
else sprintf(buf, "%s/%s", dir_name, direntp->d_name);
list_dir(fp, buf);
}
else {
fprintf(fp, "OVERFLOW %s/%s", dir_name, direntp->d_name);
return(0);
}
}
}
closedir(dirp);
return(1);
}
/*===================================================================*/
#define MAXLOG (100)
volatile int running;
DWORD stop_box_threadId;
DWORD WINAPI stop_box(LPVOID lParam)
{
msg("Stop?", "");
running = 0;
return(0);
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
wchar_t argv0[80];
char buf[512];
int n, count;

GetModuleFileName (NULL, argv0, sizeof (argv0) / sizeof (argv0[0]));
MessageBox(0, argv0, L"CeGCC says...", MB_OK);

running = 1;
CreateThread (NULL, 0, stop_box, NULL, 0, &stop_box_threadId);
if (LOG_init())
{
list_dir(LOG_stream, "/");
}
LOG_close();
}

Gives something like (310 'files'):

/Network/.
/Network/..
/ResidentFlash/.
/ResidentFlash/..
/ResidentFlash/gpspara0.bin
/ResidentFlash/gpspara1.bin
/ResidentFlash/gpspara2.bin
...
/SDMMC/.
/SDMMC/..
/SDMMC/gosm_arm.exe
...
/SDMMC/gosmore.pak
/SDMMC/MobileNavigator
/SDMMC/MobileNavigator/.
/SDMMC/MobileNavigator/..
...
/Windows/Desktop
/Windows/Desktop/.
/Windows/Desktop/..
/Windows/Desktop/desktop.ini
/Windows/TempI2C.dll
/Windows/PwrButton.dll
/Windows/wavedev.dll
/Windows/usbotg.dll
/Windows/SerialUSBFn.dll
/Windows/gps.dll
...

If I just look at /Windows/*.exe :

/Windows/ceplayer.exe
/Windows/connmc.exe
/Windows/control.exe
/Windows/CPITGuider.exe
/Windows/ctlpnl.exe
/Windows/device.exe
/Windows/eventrst.exe
/Windows/explorer.exe
/Windows/filesys.exe
/Windows/GpsMC.exe
/Windows/gwes.exe
/Windows/iexplore.exe
/Windows/IrDARmtCtrl_Daemon.exe
/Windows/launch.exe
/Windows/nk.exe
/Windows/OVL_Manager.exe
/Windows/rapisrv.exe
/Windows/repllog.exe
/Windows/rnaapp.exe
/Windows/shell.exe
/Windows/udp2tcp.exe
/Windows/unload.exe
/Windows/wceload.exe

But, of course, .dll are may be more importants... There are 123 of them.

exec() - CreateProcess() test

Here is a simple code that launches an application on the SD card.

#include <stdio.h>
#include <windows.h>
/*
** CarTrek 600
** CreateProcess() test
*/
#define prog_name TEXT("exec")
void msg(char *str1, char *str2)
{
static char txtbuf[512];
static wchar_t wtxtbuf[512];

sprintf(txtbuf, "%s %s (GetLastError()=%ld)", str1, str2, GetLastError());
mbstowcs(&wtxtbuf[0], &txtbuf[0], strlen(txtbuf)+1);
MessageBox(0, &wtxtbuf[0], prog_name, MB_OK);
}
/*===================================================================*/
PROCESS_INFORMATION ProcessInformation;
char *progname = "\\SDMMC\\gosm_arm_good.exe";

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
wchar_t argv0[80];
wchar_t wtxtbuf[128];

GetModuleFileName (NULL, argv0, sizeof (argv0) / sizeof (argv0[0]));
MessageBox(0, argv0, L"CeGCC says...", MB_OK);

mbstowcs(&wtxtbuf[0], progname, strlen(progname)+1);
if (!CreateProcess(&wtxtbuf[0], &wtxtbuf[0], NULL, NULL, FALSE, 0, NULL, NULL, NULL, &ProcessInformation))
msg(progname, "failed");
else msg(progname, "started");
}

NB: I was not able to launch '\Windows\explore.exe' by this method (and I don't know why nor what it should give).

Runit


It may be interesting to run any program on a GPS device...

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <windows.h>

#define prog_name TEXT("runit")
/*
** debug boxes
*/
void msg(char *str1, char *str2)
{
static char txtbuf[512];
static wchar_t wtxtbuf[512];

sprintf(txtbuf, "%s %s (GetLastError()=%ld)", str1, str2, GetLastError());
mbstowcs(&wtxtbuf[0], &txtbuf[0], strlen(txtbuf)+1);
MessageBox(0, &wtxtbuf[0], prog_name, MB_OK);
}
/*
** transform ASCII string into 'wide char string' and bufferize
*/
wchar_t *mylstr(char *cp)
{
int len;
wchar_t *wcp;
char *cp1, *cp2;
char buf[256];

for (cp1 = buf, cp2 = cp;((*cp1 = *cp2) != '\0') && ((cp1 - &buf[0]) < sizeof(buf)); cp1++, cp2++)
{
if (*cp1 == '/')
*cp1 = '\\';
}
len = strlen(cp)+1;
if ((wcp = (wchar_t*)malloc(len * sizeof(wchar_t))) == NULL)
{
msg("mylstr():Can't malloc()", "");
exit(0);
}
mbstowcs(wcp, buf, len);
return(wcp);
}

/*===================================================================*/
/* Debug module
** to write debug text into flash
*/
char *DBG_fname="\\SDMMC\\debug.txt";
FILE *DBG_stream;
int DBG_init()
{
if ((DBG_stream=fopen(DBG_fname, "a+")) == NULL)
{
msg("Can't fopen()", DBG_fname);
return(0);
}
fprintf(DBG_stream, "===== New log =====\n");
return(1);
}
int DBG_close()
{
return(fclose(DBG_stream));
}
int DBG_write(char *buf, int len)
{
if (fwrite(buf, 1, len, DBG_stream) != len)
msg("Can't write DBG_stream", DBG_fname);
return(len);
}
/*===================================================================*/
#define BUF_SIZE 512
/*
** run down the file tree and insert .exe files into the listbox
*/
int find_exe(FILE *fp, HWND hlistp, char *dir_name)
{
DIR *dirp;
struct dirent *direntp;
char buf[BUF_SIZE];
int len0;

len0 = strlen(dir_name);
if ((dirp = opendir(dir_name)) == NULL)
{ // probably a simple file...
if ((len0 > 4) && (strcmp(&dir_name[len0-4], ".exe") == 0))
{
SendMessage(hlistp, LB_ADDSTRING, 0, (LPARAM)mylstr(dir_name));
}
return(0);
}
while ((direntp = readdir(dirp)) != NULL)
{
direntp->d_name[direntp->d_namlen] = '\0'; /* to be sure */
if (strcmp(direntp->d_name, "..") && strcmp(direntp->d_name, "."))
{
if ((len0 + strlen(direntp->d_name)) < (BUF_SIZE-2))
{
if (dir_name[0] == '/' && dir_name[1] == '\0')
sprintf(buf, "/%s", direntp->d_name); /* no double-slash */
else sprintf(buf, "%s/%s", dir_name, direntp->d_name);
find_exe(fp, hlistp, buf);
}
else {
fprintf(fp, "OVERFLOW %s/%s", dir_name, direntp->d_name);
return(0);
}
}
}
closedir(dirp);
return(1);
}
/*===================================================================*/
// from http://www.siteduzero.com/tutoriel-3-8778-apprentissage-de-l-api-windows.html?all=1#ss_part_8698
HINSTANCE instance;

#define ID_LIST_FILES 110
#define ID_BUTTON_EXEC 111

HWND hList1;

VOID MainWin_init(HWND hMainWin)
{ // http://msdn.microsoft.com/en-us/library/ms960010.aspx
// http://www.xs4all.nl/~rjg70/vbapi/ref/msgc.html#listboxes
hList1=CreateWindow(
L"LISTBOX",
L"",
WS_CHILD|WS_VISIBLE|WS_VSCROLL,
10,10,
160,80,
hMainWin,
(HMENU)ID_LIST_FILES,
instance,
NULL);

CreateWindow(
L"BUTTON",
L"Execute",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
10,100,
70,20,
hMainWin,
(HMENU)ID_BUTTON_EXEC,
instance,
NULL);
}
PROCESS_INFORMATION ProcessInformation;

VOID Doit(HWND hMainWin,UINT message,WPARAM wParam, LPARAM lParam)
{
WCHAR lpText[256];
LRESULT lRes;
UINT iId = LOWORD(wParam);
UINT iCode = HIWORD(wParam);
HWND hCtl = (HWND)lParam;

switch (iId)
{
case ID_LIST_FILES:
break;

case ID_BUTTON_EXEC:
if ((lRes = SendMessage(hList1, LB_GETCURSEL, 0, 0)) == LB_ERR)
{
MessageBox(hMainWin, L"Nothing selected", L"Abort!", MB_OK);
return;
}
SendMessage(hList1, LB_GETTEXT, (WPARAM)lRes, (LPARAM)lpText);
if (!CreateProcess(lpText, lpText, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &ProcessInformation))
MessageBox(hMainWin, lpText, L"Failed", MB_OK);
else MessageBox(hMainWin, lpText, L"Success", MB_OK);

break;

default:
break;
}
}
LRESULT CALLBACK MainWin_do(HWND hMainWin, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
MainWin_init(hMainWin);
return(0);
break;

case WM_COMMAND:
Doit(hMainWin, msg, wParam, lParam);
return(0);
break;

case WM_DESTROY:
PostQuitMessage(0);
return(0);
break;

default:
return(DefWindowProc(hMainWin, msg, wParam, lParam));
break;
}
}

int WinMain (HINSTANCE thisInst, HINSTANCE prevInst,
LPWSTR cmdLine, int displayMode)
{
HWND hMainWin;
MSG msg;
WNDCLASS windowClass;

DBG_init();
instance = thisInst;

windowClass.style = CS_DBLCLKS;// to catch double-clics
windowClass.lpfnWndProc = MainWin_do;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = NULL;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = L"Wclass";

if(!RegisterClass(&windowClass))
return FALSE;

hMainWin=CreateWindow(
L"Wclass",
L"Run It",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
240,200,
NULL,
NULL,
thisInst,
NULL);

if (!hMainWin)
return FALSE;

ShowWindow(hMainWin, displayMode);
UpdateWindow(hMainWin);

find_exe(DBG_stream, hList1, "/");
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DBG_close();
return msg.wParam;
}


On the connex, we can now use the Windows explorer to launch gosm_arm.exe :

Connex GPC35Js NMEA

The first messages are

GloNav Ltd (c) 2007. GN_GPS_Nav_Lib: 2.05.5-080304-301-0EF5 Mar 4 2008 14:25:57
GloNav Ltd (c) 2007. WinCE_5: 2.05.5-080304-301-0000 Mar 4 2008 14:28:35

And then, every second, we can read curiously redondant NMEA informations

$GPGGA,064151.000,5038.736180,N,00534.110749,E,1,3,2.49,94.083,M,47.536,M,,*6F
$GPGLL,5038.736180,N,00534.110749,E,064151.000,A,A*53
$GPGSA,A,2,08,10,25,,,,,,,,,,2.69,2.49,1.00*0E
$GPGST,064151.000,1.5,31,30,19,31,30,62*68
$GPGSV,2,1,06,08,71,176,38,10,61,289,39,25,36,056,42,15,09,273,*7A
$GPGSV,2,2,06,07,,,39,13,,,37*74
$GPRMC,064151.000,A,5038.736180,N,00534.110749,E,0.013,0,120809,,,A*7A
$GPVTG,0,T,,M,0.013,N,0.024,K,A*17
$GPZDA,064151.000,12,08,2009,,*51

hms 064151.000 (06:41:51) appears 5 times
date 2009/08/12 appears twice
latitude 5038.736180 (50° 38.736180') appears 3 times
longitude 00534.110749 (5° 34.110749') appears 3 times

See NMEA Reference Manual1.pdf for the signification.

* GPGGA[2] = latitude (dddmm.mmmmm)
* GPGGA[4] = longitude (dddmm.mmmmm)
* GPGGA[7] = #satellites used 0..12
* GPGGA[8] = HDOP (Horizontal Dilution Of Precision
* GPGGA[9] = altitude (meters)

* GPGLL - latitude - longitude -time

* GPGSA[3..15] = SatId[channel]
* GPGSA[16..18] = PDOP - HDOP - VDOP

* GPGST ?

* GPGSV[4..7] = SatId, elevation, azimut, SNR

* GPRMC[7] = speed over ground (knots)
* GPRMC[8] = course over ground (degrees)

* GPVTG[1] = course (degrees)
* GPVTG[7] = speed over ground (km/h)

* GPZDA - time - hms dmy