From 57e9bdeae2f00664616ee1d9a936a5cfe27bfd30 Mon Sep 17 00:00:00 2001 From: "Fulup.ArFoll" Date: Tue, 30 Apr 2013 23:24:47 +0200 Subject: Added gps2udp a gpsdclient to dispatch AIS to AISHUB, MarineTraffic, ... Signed-off-by: Eric S. Raymond --- gps2udp.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 gps2udp.c (limited to 'gps2udp.c') diff --git a/gps2udp.c b/gps2udp.c new file mode 100644 index 00000000..271ee2ac --- /dev/null +++ b/gps2udp.c @@ -0,0 +1,448 @@ +/* + * gps2udp + * + * Dump NMEA to UDP socket for AIShub + * gps2udp -u data.aishub.net:1234 + * + * Author Fulup Ar Foll (directly inspired from gpspipe.c from gpsd official distrib) + * Date 01-march-2013 + * + * This file is Copyright (c) 2010 by the GPSD project + * BSD terms apply: see the file COPYING in the distribution root for details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef S_SPLINT_S +#include +#endif /* S_SPLINT_S */ + +#include "gpsd.h" +#include "gpsdclient.h" +#include "revision.h" + +#include +#include +#include +#include + + +static struct gps_data_t gpsdata; + +/* UDP socket variables */ +#define MAX_UDP_DEST 5 +static struct sockaddr_in remote[MAX_UDP_DEST]; +static int sock[MAX_UDP_DEST]; +static int udpchanel; + +/* gpsclient source */ +#define MAX_GPSD_RETRY 10 +static struct fixsource_t gpsd_source; +static int flags; +static int debug=0; +static int aisonly=0; + +// return local time hh:mm:ss +static char* time2string (void) { + #define MAX_TIME_LEN 80 + static char buffer[MAX_TIME_LEN]; + time_t curtime; + struct tm *loctime; + + /* Get the current time. */ + curtime = time (NULL); + + /* Convert it to local time representation. */ + loctime = localtime (&curtime); + + + /* Print it out in a nice format. */ + strftime (buffer, MAX_TIME_LEN, "%H:%M:%S", loctime); + +return (buffer); +} + +static int send_udp (char *nmeastring, int ind) { + char message [255]; + char *buffer; + int status, chanel; + + /* if string lenght is unknow make a copy and compute it */ + if (ind == 0) { + /* compute message size and add 0x0a 0x0d */ + for (ind=0; nmeastring [ind] != '\0'; ind ++) { + if (ind > (int)sizeof (message)) { + fprintf(stderr, "gps2udp: too big [%s] \n", nmeastring); + return -1; + } + message[ind] = nmeastring[ind]; + } + buffer = message; + } else { + /* use directly nmeastring but change terminition */ + buffer = nmeastring; + ind=ind-1; + } + /* Add termination to NMEA feed for AISHUB */ + buffer[ind]='\n'; ind ++; + buffer[ind]='\r'; ind ++; + buffer[ind]='\0'; + + /* send message on udp chanel */ + for (chanel=0; chanel < udpchanel; chanel ++) { + status=sendto(sock[chanel],buffer,ind,0,&remote[chanel],sizeof(remote)); + if (status < ind) { + fprintf(stderr, "gps2udp: fail to send [%s] \n", nmeastring); + return -1; + } + } +return 0; +} + + +static int open_udp(char **hostport) +/* Open and bind udp socket to host */ +{ + struct hostent *hp; + char *hostname = NULL; + char *portname = NULL; + int portnum, chanel; + + for (chanel=0; chanel h_addr, (char *)&remote[chanel].sin_addr, hp->h_length); + remote[chanel].sin_port = htons(portnum); + } +return (0); +} + +static void usage(void) +{ + (void)fprintf(stderr, + "Usage: gps2udp [OPTIONS] [server[:port[:device]]]\n\n" + "-h Show this help.\n" + "-u Send UDP NMEA/JASON feed to host:port [multiple -u host:port accepted\n" + "-n Feed NMEA.\n" + "-j Feed Jason.\n" + "-a Select !AISDM message only.\n" + "-c [count] exit after count packets.\n" + "-b Run in background as a daemon.\n" + "-d [0-2] 1 display sent packets, 2 ignored packets.\n" + "-v Print version and exit.\n\n" + "You must specify one, or more, of -r, -R, or -w\n" + ); +} + +/* loop until we connect with GPSd */ +static void connect2gpsd (int restart) { + int delay,status; + + if (restart) { + gps_close (&gpsdata); + if (debug > 0) fprintf(stdout, "gps2udp [%s] reset gpsd connection\n", time2string()); + + } + + /* loop until we reach GPSd */ + for (delay=10;;delay=delay*2) { + status = gps_open(gpsd_source.server, gpsd_source.port, &gpsdata); + if (status != 0) { + fprintf(stderr, "gps2udp [%s] connection failed at %s:%s\n", + time2string(), gpsd_source.server, gpsd_source.port); + sleep (delay); + } else { + if (debug > 0) fprintf(stdout, "gps2udp [%s] connect to gpsd %s:%s\n", + time2string(), gpsd_source.server, gpsd_source.port); + break; + } + } + /* select the right set of gps data */ + gps_stream(&gpsdata, flags, gpsd_source.device); + +} + +/* get date from gpsd */ +static int read_gpsd (char *message, int len) { + + struct timeval tv; + fd_set fds,master; + int result,ind; + char c; + int retry=0; + + // prepare select structure */ + FD_ZERO(&master); + FD_SET(gpsdata.gps_fd, &master); + + + /* loop until we get some data or an error */ + for (ind=0; ind 0) { + if (retry > 0) { + if (debug ==1) fprintf (stdout,"\r"); + if (debug > 1) fprintf (stdout," [%s] No Data for: %ds\n",time2string(), retry*10); + } + + if (aisonly && message[0] != '!') { + if (debug >1) fprintf (stdout,".... [%s %d] %s\n", time2string(), ind, message); + return (0); + } + } + + return (ind+1); + } else { + message[ind]= c; + ind ++; + } + break; + + case 0: /* no data fail in timeout */ + retry ++; + /* if too many empty packet are received reset gpsd connection */ + if (retry > MAX_GPSD_RETRY) { + connect2gpsd (true); + retry=0; + } + if (debug > 0) (void)write (1,".",1); + + break; + + default:/* we lost connection with gpsd */ + connect2gpsd (true); + break; + } + } + message [ind]='\0'; + fprintf (stderr,"\n gps2udp: message to big [%s]\n", message); + return (-1); +} + +// 6 bits decoding of AIS payload +static unsigned char AISto6bit(char c) { + if(c < 0x30) + return (unsigned char)-1; + if(c > 0x77) + return (unsigned char)-1; + if((0x57 < c) && (c < 0x60)) + return (unsigned char)-1; + + unsigned char cp = c; + cp += 0x28; + + if(cp > 0x80) + cp += 0x20; + else + cp += 0x28; + return (unsigned char)(cp & 0x3f); +} + +// get mmsi from ais bit string +static int AISGetInt(unsigned char* bitbytes, int sp, int len) { + int acc = 0; + int s0p = sp-1; // to zero base + int cp, cx, c0, i, cs; + + for(i=0 ; i= byte_length? + cs = 5 - ((s0p + i) % 6); + c0 = (cx >> (5 - ((s0p + i) % 6))) & 1; + acc |= c0; + } + + return acc; + +} + + +int main(int argc, char **argv) { + bool daemonize = false; + long count = -1; + int option, status; + char *udphostport[MAX_UDP_DEST]; + + flags = WATCH_ENABLE; + while ((option = getopt(argc, argv, "?habnjcvl:u:d:")) != -1) { + + switch (option) { + case 'd': + debug= strtol(optarg, 0, 0); + break; + case 'n': + if (debug >0) fprintf (stdout, "NMEA selected\n"); + flags |= WATCH_NMEA; + break; + case 'j': + if (debug >0) fprintf (stdout, "JASON selected\n"); + flags |= WATCH_JSON; + break; + case 'a': + aisonly=1; + break; + case 'c': + count = strtol(optarg, 0, 0); + break; + case 'b': + daemonize = true; + break; + case 'u': + if (udpchanel > MAX_UDP_DEST) { + fprintf (stderr, "gps2udp: to many UDP destination (max=%d)\n",MAX_UDP_DEST); + } else { + udphostport [udpchanel]= optarg; + udpchanel ++; + } + break; + case 'v': + (void)fprintf(stderr, "%s: %s (revision %s)\n", + argv[0], VERSION, REVISION); + exit(0); + case '?': + case 'h': + default: + usage(); + exit(1); + } + } + + /* Grok the server, port, and device. */ + if (optind < argc) gpsd_source_spec(argv[optind], &gpsd_source); + else gpsd_source_spec(NULL, &gpsd_source); + if (gpsd_source.device != NULL) flags |= WATCH_DEVICE; + + /* check before going background if we can connect to gpsd */ + connect2gpsd (false); + + /* Open UDP port */ + if (udpchanel > 0) { + status = open_udp(udphostport); + if (status !=0) exit (1); + } + + /* Daemonize if the user requested it. */ + if (daemonize) { + if (daemon(0, 0) != 0) { + fprintf(stderr, "gps2udp: demonization failed: %s\n", strerror(errno)); + } + } + + /* Infinit loop to get date from GPSd and push them to AIShub */ + for (;;) { + + char buffer [512]; + int len; + + len = read_gpsd (buffer, sizeof (buffer)); + + /* ignore empty message */ + if (len > 3) { + if (debug > 0) { + fprintf (stdout,"---> [%s] -- %s",time2string(),buffer); + + // Try to extract MMSI from AIS payload + if (strncmp (buffer,"!AIVDM",6) == 0) { + #define MAX_INFO 6 + char packet [512]; + char *adrpkt=packet; + char *info [MAX_INFO]; + int i,j; + unsigned int mmsi; + unsigned char bitstrings [255]; + + // strtok break original string + strncpy (packet,buffer,sizeof(packet)); + for (j=0; j (int) sizeof (bitstrings)) break; + bitstrings[i] = AISto6bit(info[5][i]); + } + + mmsi=AISGetInt (bitstrings, 9, 30); + fprintf (stdout," MMSI=%9d", mmsi); + + } + fprintf (stdout,"\n"); + + } + + // send to all UDP destination + if (udpchanel > 0) send_udp (buffer, len); + + // if we count messages check it now + if (count >= 0) { + if (count-- == 0) { + /* completed count */ + fprintf (stderr, "gpsd2udp normal exit after [%d] packets\n",(int)count); + exit (0); + } + } // end count + } // end len > 3 + } // end for (;;) + +// This is an infinite loop, should never be here +fprintf (stderr, "gpsd2udp ERROR abnormal exit\n"); +exit (-1); +} -- cgit v1.2.1