Leer Gps

Salvador
Posts: 142
Joined: Sun Dec 18, 2005 3:18 pm
Location: España

Leer Gps

Post by Salvador »

Hola a todos,

Les dejo esta sencilla clase que permite conectar con un gps y obtener algunos de los parámetros de navegación que estos dispositivos proporcionan.
Espero que sea de interés y podamos mejorarla entre todos.
Utiliza unas funciones de comunicación que se pueden encontrar en:
http://fivetechsoft.com/forums/viewtopic.php?t=8361

Saludos.
Salvador Gallardo

Code: Select all

#include "fwce.ch"
Function Main( cCom ) // especifica el puerto como parámetro
     LOCAL oWnd, oGps, nCom, oTimer
     DEFAULT cCom := "8" // puerto Com:8
     nCom := VAL(cCom)


    DEFINE WINDOW oWnd TITLE "GPS TEST"


    oGps   := Tgps():New( oWnd )
    oTimer := Ttimer():New( 1000, { || UpdateControls( oWnd, oTimer ) }, oWnd )

    @ 5,    5 SAY "Fecha"    SIZE 53, 20 RIGHT PIXEL
    @ 5,   60 GET oGps:cDate SIZE 80, 20 WHEN .f. PIXEL OF oWnd
    @ 5,  145 GET oGps:cTime SIZE 60, 20 WHEN .f. PIXEL OF oWnd

    @ 27,   5 SAY "Lat."    SIZE 53,20 RIGHT PIXEL
    @ 27,  60 GET oGps:cLat SIZE 80,20 WHEN .f. PIXEL OF oWnd
    @ 27, 145 GET oGps:cNS  SIZE 20,20 WHEN .f. PIXEL  OF oWnd

    @ 50,   5 SAY "Long."    SIZE 53,20 RIGHT PIXEL
    @ 50,  60 GET oGps:cLong SIZE 80,20 WHEN .f. PIXEL OF oWnd
    @ 50, 145 GET oGps:cEW   SIZE 20,20 WHEN .f. PIXEL OF oWnd

    @ 72,  5 SAY "Lat dec."  SIZE 50,20 RIGHT PIXEL
    @ 72, 60 GET oGps:nLat   SIZE 80,20 PICTURE "999.999999" RIGHT;
    WHEN .f. PIXEL OF oWnd

    @ 94,  5 SAY "Lon dec."  SIZE 50,20 RIGHT PIXEL
    @ 94, 60 GET oGps:nLong  SIZE 80,20 PICTURE "999.999999" RIGHT;
    WHEN .f. PIXEL OF oWnd

    @ 118,  5 SAY "Fix"     SIZE 50,20 RIGHT PIXEL
    @ 116, 60 GET oGps:cFix SIZE 30,20 WHEN .f. PIXEL OF oWnd

    @ 140,  5 SAY "Sats"     SIZE 50,20 RIGHT PIXEL
    @ 138, 60 GET oGps:cSats SIZE 30,20 WHEN .f. PIXEL OF oWnd

    @ 162,  5 SAY "Alt."    SIZE 50,20 RIGHT PIXEL
    @ 160, 60 GET oGps:cAlt SIZE 60,20 WHEN .f. PIXEL OF oWnd

    @ 184,  5 SAY "Veloc."    SIZE 50,20 RIGHT PIXEL
    @ 182, 60 GET oGps:cSpeed SIZE 60,20 WHEN .f. PIXEL OF oWnd

    @ 204, 5  GET oGps:cNMEA SIZE 232,40 WHEN .f. MULTILINE;
     NO VSCROLL PIXEL OF oWnd

    @ 258, 5 BUTTON "CONECTAR" SIZE 95, 25 PIXEL;
    ACTION ( oGps:Conecta( nCom ), oTimer:Activate());

     @ 258, 110 BUTTON "DESCONECTAR" SIZE 95, 25 PIXEL;
    ACTION ( oTimer:Deactivate(), oGps:Desconecta() )

    ACTIVATE WINDOW oWnd;
    VALID ( oTimer:End(), oGps:end(), .t.)


RETURN .t.


///////////////////////////////////////////////////////
// Mini Clase TGps
//
// Lectura de sentencias NMEA GPGGA y GPRMC de un GPS
// son las necesarias para conocer fecha, hora, posición, velocidad
// Probado con GPS bluetooth en Com:8 e IPAQ HP2210
//
// Autor: Salvador Gallardo 2007
//
///////////////////////////////////////////////////////

#define LENNMEA      1024     // longitud cadena leida 3 sentencias minimo
#define READINTERVAL 1500     // intervalo de lectura del puerto en ms.
#define NRETRY       10       // reintentos de lectura del puerto
#define BAUDS        4800     // velocidad de recepcion


CLASS TGps

DATA lGps                  // hay conexion con el gps
DATA oTimer                // intervalo de tiempo para leer el puerto
DATA oWnd                  // ventana asociada los timers estan asociados a una window
DATA aNMEA                 // array con las sentencias nmea leidas
DATA cNMEA                 // ultima sentencia interpretada
DATA cTime                 // hora
DATA cDate                 // fecha
DATA cLat, cLong           // latitud y longitud en formato //dddmm.mmmm,ddddmm.mmmm
DATA cNS, cEW              // indicadores de N/S E/O
DATA nLat, nLong           // latitud y longitud en formato decimal dd.mmmmmmmm
DATA cFix                  // fix del gps 0= invalido 1= valido
DATA cSats                 // satelites usados
DATA cAlt                  // altitud
DATA cSpeed                // velocidad
DATA CMsgErr               // guarda estado conexion con gps
DATA nHdlCom               // handle del puerto de comunicaciones
DATA nRetry                // reintentos sin recibir datos del GPS
DATA lLog                  // hace log de los datos en una dbf

METHOD New( oWnd ) CONSTRUCTOR
METHOD Conecta( nCom )
METHOD Desconecta( )
METHOD LeeNMEA()          // lee datos del gps
METHOD GPGGA( cCad )     // procesa sentencia GPGGA
METHOD GPRMC( cCad )     // procesa sentencia GPRMC
METHOD End()

ENDCLASS

METHOD New( oWnd ) CLASS TGps

::aNMEA     := Array(3) // se leen 3 sentencias cada vez
::lGps      := .f.
::cMsgErr   := "INIT"
::oWnd      := oWnd
::nRetry    := 0
::oTimer    := TTimer():New( READINTERVAL, { || ::LeeNMEA()}, ::oWnd )
::lLog      := .f.
::nLat      := 0
::nLong     := 0
RETURN self


////////////////////////////////////////////////////////////////
METHOD Conecta( nCom ) CLASS TGps

::nHdlCom := OpenCom( nCom, BAUDS )

 IF ::nHdlCom < 0
    ::lGps    := .f.
    ::cMsgErr :=  "FALLO AL ABRIR EL COM:"+ Str( nCom,2 )
 ENDIF
 ::cMsgErr :=  "PUERTO ABIERTO"
 ::oTimer:Activate()
RETURN nil

/////////////////////////////////////////////////////////////////
METHOD DesConecta() CLASS TGps

::oTimer:Deactivate()
ComClose( ::nHdlCom )
::lGps    := .f.
::cMsgErr :=  "DESCONECTADO DEL GPS"

RETURN nil

//////////////////////////////////////////////////////////////////
//
// LeeNMEA()
// Lee el puerto y si hay datos los interpreta
///////////////////////////////////////////////////////////////////
METHOD LeeNMEA()  CLASS TGps
LOCAL  c, cBuffer

::oTimer:Deactivate()
cBuffer := ComRead( ::nHdlCom, LENNMEA )

IF Len( cBuffer ) <= 0
  ::nRetry ++
  IF::nRetry > NRETRY
     ::lGps    := .f.
     ::cMsgErr := "PERDIDA CONEXION"
  ENDIF
  ELSE
    ::nRetry := 0
    FOR c := 1 TO LEN( ::aNMEA )
      ::aNMEA[c] := StrToken( cBuffer, c, "$" ) 
    NEXT

    FOR c :=  LEN( ::aNMEA ) TO 1 STEP -1  // leemos ultimas sentencias

      DO CASE
        CASE AT( "GPGGA", ::aNMEA[c] ) ==1
          IF ChkSum( ::aNMEA[c] )
              ::cNMEA   := ::aNMEA[c]
              ::GPGGA( ::aNMEA[c] )
          ENDIF
          EXIT
        CASE AT( "GPRMC", ::aNMEA[c] ) ==1
          IF ChkSum( ::aNMEA[c] )
              ::cNMEA   := ::aNMEA[c]
              ::GPRMC( ::aNMEA[c] )
          ENDIF
          EXIT
      ENDCASE

    NEXT

ENDIF

::oTimer:Activate()

RETURN nil


//////////////////////////////////////////////////////////////
//
// GPGGA( cCad )
// Extrae los datos de una sentencia GPGGA
////////////////////////////////////////////////////////////
METHOD GPGGA( cCad )  CLASS TGps
LOCAL cHora, nLat, nLon, nGrados, nMinutos

SET DECIMALS TO 6

cHora     := StrToken( cCad, 2, "," )
::cTime   := Substr( cHora,1,2)+":"+Substr( cHora,3,2)+":"+Substr( cHora,5,2)
::cLat    := StrToken( cCad, 3, "," )
::cNS     := StrToken( cCad, 4, "," )
::cLong   := StrToken( cCad, 5, "," )
::cEW     := StrToken( cCad, 6, "," )
::cFix    := StrToken( cCad, 7, "," )
::cSats   := StrToken( cCad, 8, "," )
::cAlt    := StrToken( cCad, 10, "," )

// calculamos latitud y longitud en decimal
// es la que utiliza Google Maps
nGrados  := Val(SubStr( ::cLat, 1, 2) )
nMinutos := Val(SubStr( ::cLat, 3, 7) ) /60
::nLat   := nGrados+ nMinutos* IIF( ::cNS ="S", -1, 1 )

// longitud
nGrados   := Val(SubStr( ::cLong, 1, 3 ) )
nMinutos  := Val(SubStr( ::cLong, 4, 7 ) ) /60
::nLong   := nGrados+ nMinutos* IIF( ::cNS ="W", -1, 1 )
::lGps    := .t.
::cMsgErr := "OK"


// log de los datos leidos
// hay que mejorar la gestion de la dbf
// añadir fecha y hora
IF  ::lLog .AND. VAL( ::cFix ) != 0
  use (CURDIR()+"\gps.dbf" ) VIA "DBFCDX"
  append blank
  replace lon with ::nLong
  replace lat WITH ::nlat
  replace fix WITH VAL(::cFix)
  replace sats WITH val(::cSats)
  replace clong WITH ::cLong
  replace cLat  WITH ::cLat
  USE
endif

RETURN nil

////////////////////////////////////////////////////////////
//
// GPRMC( cCad )
// Extrae los datos de una sentencia GPRMC
////////////////////////////////////////////////////////////

METHOD GPRMC( cCad )  CLASS TGps
Local cFecha

cFecha    := StrToken( cCad, 10, "," )
::cDate   := Substr( cFecha, 1, 2 ) + "/"+ Substr( cFecha, 3, 2) + "/"+ Substr(cFecha, 5, 2 )
::cSpeed  := StrToken( cCad, 8, "," )
::lGps    := .t.
::cMsgErr := "OK"

RETURN nil


/////////////////////////////////////////////////////////
METHOD End() CLASS TGps
::OTimer:Deactivate()
::oTimer:End()
ComClose( ::nHdlCom )
RETURN nil


//////////////////////////////////////////////////////////////////////
// ChkSum( cCad )
//
// Calcula el checksum de la sentencia NMEA
////////////////////////////////////////////////////////////////////7
STATIC Function ChkSum( cCad )
LOCAL c, nLen, nSum1, nSum2

nLen  := AT( "*", cCad )
nSum1 := HexToDec( Substr( cCad, nLen +1, 2 ) ) // el checksum esta apartir de "*"
nSum2 := Asc( Substr( cCad, 1, 1 ) ) // cogemos el primer caracter a sumar

FOR c := 2 TO nLen -1
   nSum2 := nXor( nSum2, Asc( Substr( cCad, c, 1 ) ) )
NEXT

RETURN IIF( nSum1 == nSum2, .t., .f. )



//////////////////////////////////////////
//
// Actualiza los datos de la ventana
//////////////////////////////////////////

Function UpdateControls( oWnd, oTimer )
LOCAL c
oTimer:Deactivate()
For c = 1 to Len(oWnd:aControls)
oWnd:aControls[c]:Refresh()
next

oTimer:Activate()
return .t.


#pragma BEGINDUMP

#include <windows.h>
#include <math.h>
#include <hbapi.h>

// funcion de FW adaptada a FWPPC
HB_FUNC (HEXTODEC) 
{
   LPBYTE pString = ( LPBYTE ) hb_parc( 1 );
   WORD  w = 0, wLen = hb_parclen( 1 );
   BYTE  bChar;
   LONG  nHex = 0;

   while( w < wLen )
   {
      bChar = pString[ w ] ;
      if ( bChar >= 97 ) bChar -= 39;  // lowercase
      if ( bChar >= 65 ) bChar -= 7 ;  // uppercase
      bChar -= 48;
      nHex += bChar * pow( 16, wLen - w - 1 );
      w++;
   }

   hb_retnl( nHex );
}

#pragma ENDDUMP

User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Salvador,

Muchas gracias! :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Biel EA6DD
Posts: 680
Joined: Tue Feb 14, 2006 9:48 am
Location: Mallorca
Contact:

Post by Biel EA6DD »

Gracias Salvador, buen aporte.
Justo antes de irme de vacaciones, estaba con el tema GPS y mirando las sentencias NMEA. Tenia en mente desarrollar una clase para conexion y lectura de datos del GPS. Y mira por donde que tu tambien estabas en lo mismo.
Muchas gracias por compartir la clase, la probare y ya te comentare que tal me ha funcionado.
Saludos desde Mallorca
Biel Maimó
http://bielsys.blogspot.com/
User avatar
Biel EA6DD
Posts: 680
Joined: Tue Feb 14, 2006 9:48 am
Location: Mallorca
Contact:

Post by Biel EA6DD »

Hola Salvador, he probado la clase con un GPS bluetooth y una PDA Symbol MC90, y funciona perfectamente.
He cambiado el metodo conecta, creo que lo correcto es un else para el caso en que no consigue abrir el puerto.

Ademas le he añadido un retorno de valor logico a conecta, si bien ese dato se podria conseguir del data lGps, o nHdlCom.

Code: Select all

////////////////////////////////////////////////////////////////
METHOD Conecta( nCom ) CLASS TGps 

   ::nHdlCom := OpenCom( nCom, BAUDS )

   IF ::nHdlCom < 0
      ::lGps    := .f.
      ::cMsgErr :=  "FALLO AL ABRIR EL COM:"+ Str( nCom,2 )
   ELSE
      ::cMsgErr :=  "PUERTO ABIERTO"
      ::lGps    := .T.
      ::oTimer:Activate()
   ENDIF
RETURN ::lGps
Saludos desde Mallorca
Biel Maimó
http://bielsys.blogspot.com/
Salvador
Posts: 142
Joined: Sun Dec 18, 2005 3:18 pm
Location: España

Post by Salvador »

Gracias Biel.

Tienes razón en la modificación.
Con esta clase y las funciones de conexión GPRS, y el API de Google Maps tenemos el camino abierto para incluir en las aplicaciones móviles la posibilidad de localizar geográficamente cualquier persona o vehículo en un mapa.

Una aportación de José Luis Capel que puede darnos ideas:
http://www.capelblog.com/?p=83

Saludos desde El Baix Empordà

Salvador Gallardo
User avatar
Biel EA6DD
Posts: 680
Joined: Tue Feb 14, 2006 9:48 am
Location: Mallorca
Contact:

Post by Biel EA6DD »

Hola Salvador y demas lectores de este foro.

He variado, y creo que mejorado un poco la gestion de log a DBF. He cambiado el punto donde comprobar si se debe registrar en el log, lo he incluido en el metodo LeeNMEA()

Code: Select all

METHOD LeeNMEA()  CLASS TGps
   LOCAL  c, cBuffer

   ::oTimer:Deactivate()
   cBuffer := ComRead( ::nHdlCom, LENNMEA )

   IF Len( cBuffer ) <= 0
      ::nRetry ++
      IF::nRetry > NRETRY
        ::lGps    := .f.
        ::cMsgErr := "PERDIDA CONEXION"
      ENDIF
   ELSE
      ::nRetry := 0
      FOR c := 1 TO LEN( ::aNMEA )
         ::aNMEA[c] := StrToken( cBuffer, c, "$" )
      NEXT
      FOR c :=  LEN( ::aNMEA ) TO 1 STEP -1  // leemos ultimas sentencias
         DO CASE
         CASE AT( "GPGGA", ::aNMEA[c] ) ==1
            IF ChkSum( ::aNMEA[c] )
               ::cNMEA   := ::aNMEA[c]
               ::GPGGA( ::aNMEA[c] )
            ENDIF
            EXIT
         CASE AT( "GPRMC", ::aNMEA[c] ) ==1
           IF ChkSum( ::aNMEA[c] )
              ::cNMEA   := ::aNMEA[c]
              ::GPRMC( ::aNMEA[c] )
           ENDIF
           EXIT
        ENDCASE
     NEXT
     //Comprobar si hay que registrar el log.
     IF ::lLog .AND. Val(::cFix)!=0 //Log datos leidos
         LogDbf( SELF )                      
      ENDIF
   ENDIF
   ::oTimer:Activate()
RETURN nil
Y el log lo proceso por medio de una funciona estatica interna (en principio no le he visto necesidad de que fuera metodo, ni que fuera accesible desde el exterior)

Code: Select all


///////////////////////////////////////////////////////////////////////7
//
// LogDbf()
// Graba log de los datos leidos del GPS.
///////////////////////////////////////////////////////////////////////
STATIC FUNCTION  LogDbf( SELF )
   IF !File(CurDir()+"\gps.dbf")
      DBCreate(CurDir()+"\gps.dbf",{;
                                     { "FECHA"  , "D",     8,    0 },;
                                     { "HORA"   , "C",     8,    0 },;
                                     { "LAT"    , "N",    10,    6 },;
                                     { "LON"    , "N",    10,    6 },;
                                     { "SAT"    , "N",     1,    0 },;
                                     { "ALT"    , "N",     5,    0 },;
                                     { "VEL"    , "N",     6,    2 } ;
                                   })

   ENDIF
   IF Select('gps')==0
      DBUseArea(.T.,'DBFCDX',CurDir()+'\GPS',,.F.)
   ENDIF
   Gps->(DBAppend())
   Gps->Fecha := CToD(::cDate)
   Gps->Hora  := ::cTime
   Gps->Lon   := ::nLong
   Gps->Lat   := ::nLat
   Gps->Sat   := Val(::cSats)
   Gps->Alt   := Val(::cAlt)
   Gps->Vel   := Val(::cSpeed)
RETURN NIL
Está función crea el DBF si no existe, y abre la tabla si no lo está. Deja la tabala abierta, luego debiera cerrarse en el meotodo end.

No he colgado toda la clase, para no aburrir con lineas y lineas de codigo que no cambian. De todas formas si a alguine le interesa, solo tiene que pedirla.
Saludos desde Mallorca
Biel Maimó
http://bielsys.blogspot.com/
User avatar
Silvio
Posts: 3107
Joined: Fri Oct 07, 2005 6:28 pm
Location: Teramo,Italy

Post by Silvio »

this class run on bluetooth gps
But if I have a gps into palm How I can see if it run ok ?
Best Regards, Saludos

Falconi Silvio
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Silvio,

Tu palm tiene Windows Mobile ?
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Silvio
Posts: 3107
Joined: Fri Oct 07, 2005 6:28 pm
Location: Teramo,Italy

Post by Silvio »

yes HTC TNT I and HTC TNT II ( with gps)
Best Regards, Saludos

Falconi Silvio
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Silvio,

Windows Mobile 2003 or 2005 ?
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Silvio
Posts: 3107
Joined: Fri Oct 07, 2005 6:28 pm
Location: Teramo,Italy

Post by Silvio »

on HTC TNT I I have installed WINDOWs MOBILE 5.0 ( s.o. 5.1.465) con Feature Pack ( AKU)

on HTCTNT II there is Windows Mobile 6 Professional


I downloading wm6 because I want installed on HTC TNT I because wm5 have many problems when there is a wifi connections


the first is a samsung processor 400 MHz the second is a Qualcomm MSM 7200, 400MHz

All have Bluetooth 2.0, IRDA, Wi-Fi IEEE 802.11 b/g and only the HTC TNT II have a gps antenna connector internal

THE FIRST have a 2.0 MB Pixel camera the second ( HTC TNT II) have two cameras with 3.0 MB pixel



I trying all sample on each Machine : not have problems!!!!

HTC IS GOOD Pocket PC!!!
Best Regards, Saludos

Falconi Silvio
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Re: Leer Gps

Post by Ugo »

Hi all,
during the compilation return this errors:

Code: Select all

Progetto: GPS, Ambiente: FWPPC:
[1]:Link.Exe @GPS.vcl /nologo /SUBSYSTEM:WINDOWSCE,4.20 /MACHINE:ARM
   Creating library C:\Work\Src-CE\GPS\GPS.lib and object C:\Work\Src-CE\GPS\GPS.exp
Gps_1.Obj : error LNK2001: unresolved external symbol HB_FUN_COMREAD
Gps_1.Obj : error LNK2001: unresolved external symbol HB_FUN_COMCLOSE
Gps_1.Obj : error LNK2001: unresolved external symbol HB_FUN_OPENCOM
C:\Work\Src-CE\GPS\GPS.Exe : fatal error LNK1120: 3 unresolved externals
I don't found library for comm connection in my Harbour_ce and FwPPC directory.
How can resolve?
Ciao, best regards,
Ugo
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Antonio,
thanks

Merry Christmas at all Fw's :D
Ciao, best regards,
Ugo
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply