Blog der Heimetli Software AG

Auf dem Raspberry PI GPS-Daten auslesen und per UDP ins Netz schicken

Die iPad-App iNAVX kann UDP-Pakete mit NMEA-Daten aus dem Netzwerk empfangen und auswerten. Das nachfolgend beschriebene Programm liest die NMEA-Daten von einem GPS an der seriellen Schnittstelle eines Raspberry PI und schickt die empfangenen Zeilen per Broadcast ins Netz.

Bedienungsanleitung

Das Programm heisst BroadcastGPS und wird auf der Shell gestartet. Um es einigermassen universell zu halten, verlangt es den Namen des Device-Files und eine IP-Adresse:

pi@raspberrypi ~ $ ./BroadcastGPS /dev/ttyUSB0 192.168.1.255

Die IP-Adresse kann wie in diesem Beispiel eine Broadcast-Adresse sein.

Vor dem Start von BroadcastGPS muss die Schnittstelle per stty richtig konfiguriert werden. Das Programm verstellt keine Parameter der Schnittstelle und erwartet deshalb, dass sie korrekt konfiguriert ist.

Das Programm

/******************************************************************************/
/*                                                                            */
/*                                                     FILE: BroadcastGPS.cpp */
/*                                                                            */
/*  Reads GPS data from a given device file and broadcasts the lines          */
/*  ================================================================          */
/*                                                                            */
/*  V1.00   09-APR-2014   Te                                                  */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/******************/
 int CreateSocket()
/******************/

{
    // Create a socket
    int sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;

    if( sock == -1 )
    {
       printf( "CreateSocket: socket failed" ) ;
       return -1 ;
    }

    int on = 1 ;
    if( setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)) != 0 )
       printf( "setsockopt failed" ) ;

    // Bind it to the local address
    struct sockaddr_in address ;

    memset( &address, 0, sizeof(address) ) ;

    address.sin_family      = AF_INET ;
    address.sin_addr.s_addr = htonl( INADDR_ANY ) ;
    address.sin_port        = htons( 0 ) ;

    if( bind(sock,(struct sockaddr *)&address,sizeof(address)) == -1 )
    {
       printf( "CreateSocket: bind failed" ) ;
       close( sock ) ;
       return -1 ;
    }

    return sock ;
}

/**********************************/
 int main( int argc, char *argv[] )
/**********************************/

{
   printf( "BroadcastGPS V1.00\n" ) ;

   if( argc != 3 )
   {
      printf( "usage: %s devicename ipaddress", argv[0] ) ;
      return 1 ;
   }

   int fd = open( argv[1], O_RDONLY ) ;

   if( fd == -1 )
   {
      printf( "Error: can't open %s\n", argv[1] ) ;
      return 2 ;
   }

   struct sockaddr_in address ;

   memset( &address, 0, sizeof(address) ) ;

   address.sin_family      = AF_INET ;
   address.sin_addr.s_addr = inet_addr( argv[2] ) ;
   address.sin_port        = htons( 10110 ) ;
  
   if( address.sin_addr.s_addr == INADDR_NONE )
   {
      printf( "Error: invalid ip %s\n", argv[2] ) ;

      close( fd ) ;
      return 3 ;
   }

   int socket = CreateSocket() ;

   if( socket == -1 )
   {
      close( fd ) ;
      return 4 ;
   }

   char buffer[1024] ;
   char line[256] ;
   int  index = 0 ;
   int  count ;

   for( ;; )
   {
       count = read( fd, buffer, sizeof(buffer) ) ;

       if( count < 1 )
          break ;

       for( int i = 0; i < count; i++ )
       {
           if( buffer[i] != '\n' )
           {
              if( index < (int)sizeof(line) - 2 )
                 line[index++] = buffer[i] ;
           }
           else
           {
              line[index++] = buffer[i] ;

              sendto( socket, line, index, 0, (const sockaddr *)&address, sizeof(address) ) ;

              index = 0 ;
           }
       }
   }

   close( fd ) ;
   close( socket ) ;

   return 0 ;
}

Die Installation

BroadcastGPS.cpp mit diesem Link herunterladen, mit
g++ -Wall -o BroadcastGPS BroadcastGPS.cpp

compilieren und schon ist das Programm bereit.

Nachtrag: mein Setup

Beim Neu-Aufbau des Systems gab es unerklärliche Probleme mit dem USB-Seriell Adapter. Beim einen fehlten immer wieder Zeichen, während der andere wunderbar funktionierte.

Damit ich nicht nochmals so lange suchen muss:

* Den blauen Adapter nehmen * Schnittstelle einstellen mit stty -F /dev/ttyUSB0 4800 raw

Die gesendeten Daten wieder empfangen

Auf speziellen Wunsch habe ich ein Gegenstück zu diesem Programm geschrieben das die Daten wieder empfängt und auf die serielle Schnittstelle ausgibt. Mit diesem Link kommen Sie zum Empfänger für die gesendeten Daten.