Blog der Heimetli Software AG

UDP-Meldungen empfangen und seriell ausgeben

Vor einer ganzen Weile habe ich ein Programm für den Raspberry geschrieben welches NMEA-Daten von einem GPS-Empfänger per UDP im Netzwerk verteilt: Broadcast von GPS-Daten.

Jezt kam der Wunsch auf, diese Daten wieder zu empfangen und auf ein serielles Port auszugeben. Um das Programm etwas allgemeiner zu machen, lasse ich es auf ein beliebiges File schreiben:

./ReceiveGPS /dev/ttyUSB0

Damit das auf der seriellen Schnittstelle richtig funktioniert, muss diese vorgängig mit stty -F /dev/ttyUSB0 ... konfiguriert werden.

Das Programm ist für den Raspberry gedacht, aber es sollte auch auf jedem anderen Linux-System laufen

Die Source des Programms

/******************************************************************************/
/*                                                                            */
/*                                                       FILE: ReceiveGPS.cpp */
/*                                                                            */
/*  Reads GPS data from a UDP socket and sends it to a serial port            */
/*  ==============================================================            */
/*                                                                            */
/*  V1.00   13-MAR-2017   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( int port )
/****************************/

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

    if( sock == -1 )
    {
       fprintf( stderr, "CreateSocket: socket failed\n" ) ;
       return -1 ;
    }

    // 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( port ) ;

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

    return sock ;
}

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

{
   fprintf( stderr, "ReceiveGPS V1.00\n" ) ;

   if( argc != 2 )
   {
      fprintf( stderr, "usage: %s devicename\n", argv[0] ) ;
      return 1 ;
   }

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

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

   int socket = CreateSocket( 10110 ) ;

   if( socket == -1 )
   {
      fprintf( stderr, "error: can't create socket\n" ) ;
      close( fd ) ;
      return 3 ;
   }

   struct sockaddr_in address ;
   char   line[256] ;
   int    count ;
   int    size ;
   int    c ;

   for( ;; )
   {
       socklen_t length = sizeof( address ) ;
       size = recvfrom( socket, line, sizeof(line), 0, (struct sockaddr *)&address, &length ) ;

       if( size < 1 )
       {
          fprintf( stderr, "error: recvfrom failed\n" ) ;
          break ;
       }

       for( count = 0; count < size; count += c )
       {
          c = write( fd, line + count, size - count ) ;

          if( c < 1 )
          {
             fprintf( stderr, "error: write failed\n" ) ;
          }
       }
   }

   close( fd ) ;
   close( socket ) ;

   return 0 ;
}

Compilieren und starten

Compilieren geht mit einer einzigen Zeile:

g++ -Wall -o ReceiveGPS ReceiveGPS.cpp

Das Port ist hartcodiert, so dass es sicher zum Sendeprogramm passt. Darum verlangt es einzig einen Filenamen als Argument. Dieses File wird in den meisten Fällen der Pfad zum seriellen Device sein:

./ReceiveGPS /dev/ttyUSB0

Download der Source

Damit Sie den Code nicht von der Webseite kratzen müssen, gibt es ihn hier zum Download: Source von ReceiveGPS.cpp