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, mitg++ -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.