123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- #include "gpsd_config.h"
- #include <arpa/inet.h>
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <sys/select.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <termios.h>
- #include <time.h>
- #include <unistd.h>
- #include "gpsd.h"
- #include "gpsdclient.h"
- #include "revision.h"
- #include "strfuncs.h"
- #include "timespec.h"
- #define MAX_TIME_LEN 80
- #define MAX_GPSD_RETRY 10
- static struct gps_data_t gpsdata;
- #define MAX_UDP_DEST 5
- static struct sockaddr_in remote[MAX_UDP_DEST];
- static int sock[MAX_UDP_DEST];
- static int udpchannel;
- static struct fixsource_t gpsd_source;
- static unsigned int flags;
- static int debug = 0;
- static bool aisonly = false;
- static char* time2string(void)
- {
- static char buffer[MAX_TIME_LEN];
- time_t curtime;
- struct tm *loctime;
-
- curtime = time (NULL);
-
- loctime = localtime (&curtime);
-
- (void)strftime (buffer, sizeof(buffer), "%H:%M:%S", loctime);
- return (buffer);
- }
- static int send_udp (char *nmeastring, size_t ind)
- {
- char message [255];
- char *buffer;
- int channel;
-
- if (ind == 0) {
-
- for (ind=0; nmeastring [ind] != '\0'; ind ++) {
- if (ind >= sizeof(message) - 3) {
- (void)fprintf(stderr, "gps2udp: too big [%s] \n", nmeastring);
- return -1;
- }
- message[ind] = nmeastring[ind];
- }
- buffer = message;
- } else {
-
- buffer = nmeastring;
- ind = ind-1;
- }
-
- buffer[ind] = '\r'; ind++;
- buffer[ind] = '\n'; ind++;
- buffer[ind] = '\0';
- if ((flags & WATCH_JSON)==0 && buffer[0] == '{') {
-
- return 0;
- }
-
- for (channel=0; channel < udpchannel; channel ++) {
- ssize_t status = sendto(sock[channel],
- buffer,
- ind,
- 0,
- (const struct sockaddr *)&remote[channel],
- (int)sizeof(remote));
- if (status < (ssize_t)ind) {
- (void)fprintf(stderr, "gps2udp: failed to send [%s] \n", nmeastring);
- return -1;
- }
- }
- return 0;
- }
- static int open_udp(char **hostport)
- {
- int channel;
- for (channel=0; channel <udpchannel; channel ++)
- {
- char *hostname = NULL;
- char *portname = NULL;
- char *endptr = NULL;
- int portnum;
- struct hostent *hp;
-
- hostname = strsep(&hostport[channel], ":");
- portname = strsep(&hostport[channel], ":");
- if ((hostname == NULL) || (portname == NULL)) {
- (void)fprintf(stderr, "gps2udp: syntax is [-u hostname:port]\n");
- return (-1);
- }
- errno = 0;
- portnum = (int)strtol(portname, &endptr, 10);
- if (1 > portnum || 65535 < portnum || '\0' != *endptr || 0 != errno) {
- (void)fprintf(stderr, "gps2udp: syntax is [-u hostname:port] [%s] is not a valid port number\n",portname);
- return (-1);
- }
- sock[channel]= socket(AF_INET, SOCK_DGRAM, 0);
- if (sock[channel] < 0) {
- (void)fprintf(stderr, "gps2udp: error creating UDP socket\n");
- return (-1);
- }
- remote[channel].sin_family = (sa_family_t)AF_INET;
- hp = gethostbyname(hostname);
- if (hp==NULL) {
- (void)fprintf(stderr,
- "gps2udp: syntax is [-u hostname:port] [%s]"
- " is not a valid hostname\n",
- hostname);
- return (-1);
- }
- memcpy( &remote[channel].sin_addr, hp->h_addr_list[0], hp->h_length);
- remote[channel].sin_port = htons((in_port_t)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/JSON feed to host:port [multiple -u host:port accepted]\n"
- "-n Feed NMEA.\n"
- "-j Feed JSON.\n"
- "-a Select AIS 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 display ignored packets.\n"
- "-v Print version and exit.\n\n"
- "example: gps2udp -a -n -c 2 -d 1 -u data.aishub.net:2222 fridu.net\n"
- );
- }
- static void connect2gpsd(bool restart)
- {
- unsigned int delay;
- if (restart) {
- (void)gps_close(&gpsdata);
- if (debug > 0)
- (void)fprintf(stdout,
- "gps2udp [%s] reset gpsd connection\n",
- time2string());
- }
-
- for (delay = 10; ; delay = delay*2) {
- int status = gps_open(gpsd_source.server, gpsd_source.port, &gpsdata);
- if (status != 0) {
- (void)fprintf(stderr,
- "gps2udp [%s] connection failed at %s:%s\n",
- time2string(), gpsd_source.server, gpsd_source.port);
- (void)sleep(delay);
- } else {
- if (debug > 0)
- (void)fprintf(stdout, "gps2udp [%s] connect to gpsd %s:%s\n",
- time2string(), gpsd_source.server, gpsd_source.port);
- break;
- }
- }
-
- (void)gps_stream(&gpsdata, flags, gpsd_source.device);
- }
- static ssize_t read_gpsd(char *message, size_t len)
- {
- int ind;
- char c;
- int retry=0;
-
- len--;
-
- for (ind = 0; ind < (int)len;) {
-
- int result = nanowait(gpsdata.gps_fd, 10 % NS_IN_SEC);
- switch (result)
- {
- case 1:
- result = (int)read(gpsdata.gps_fd, &c, 1);
-
- if (result != 1) {
- connect2gpsd (true);
- }
- if ((c == '\n') || (c == '\r')){
- message[ind]='\0';
- if (ind > 0) {
- if (retry > 0) {
- if (debug ==1)
- (void)fprintf (stdout,"\r");
- if (debug > 1)
- (void)fprintf(stdout,
- " [%s] No Data for: %ds\n",
- time2string(), retry*10);
- }
- if (aisonly && message[0] != '!') {
- if (debug >1)
- (void)fprintf(stdout,
- ".... [%s %d] %s\n", time2string(),
- ind, message);
- return(0);
- }
- }
- return ((ssize_t)ind+1);
- } else {
- message[ind]= c;
- ind++;
- }
- break;
- case 0:
- retry++;
-
- if (retry > MAX_GPSD_RETRY)
- {
- connect2gpsd(true);
- retry = 0;
- }
- if (debug > 0)
- ignore_return(write (1, ".", 1));
- break;
- default:
- connect2gpsd(true);
- break;
- }
- }
- message[ind] = '\0';
- (void)fprintf (stderr,"\n gps2udp: message too big [%s]\n", message);
- return(-1);
- }
- static unsigned char AISto6bit(unsigned char c)
- {
- unsigned char cp = c;
- if(c < (unsigned char)0x30)
- return (unsigned char)-1;
- if(c > (unsigned char)0x77)
- return (unsigned char)-1;
- if(((unsigned char)0x57 < c) && (c < (unsigned char)0x60))
- return (unsigned char)-1;
- cp += (unsigned char)0x28;
- if(cp > (unsigned char)0x80)
- cp += (unsigned char)0x20;
- else
- cp += (unsigned char)0x28;
- return (unsigned char)(cp & (unsigned char)0x3f);
- }
- static unsigned int AISGetInt(unsigned char *bitbytes, unsigned int sp, unsigned int len)
- {
- unsigned int acc = 0;
- unsigned int s0p = sp-1;
- unsigned int i;
- for(i=0 ; i<len ; i++)
- {
- unsigned int cp, cx, c0;
- acc = acc << 1;
- cp = (s0p + i) / 6;
- cx = (unsigned int)bitbytes[cp];
- 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;
- char *udphostport[MAX_UDP_DEST];
- flags = WATCH_ENABLE;
- while ((option = getopt(argc, argv, "?habnjvc:l:u:d:")) != -1)
- {
- switch (option) {
- case 'd':
- debug = atoi(optarg);
- if ((debug <1) || (debug > 2)) {
- usage();
- exit(1);
- }
- break;
- case 'n':
- if (debug >0)
- (void)fprintf(stdout, "NMEA selected\n");
- flags |= WATCH_NMEA;
- break;
- case 'j':
- if (debug >0)
- (void)fprintf(stdout, "JSON selected\n");
- flags |= WATCH_JSON;
- break;
- case 'a':
- aisonly = true;
- break;
- case 'c':
- count = atol(optarg);
- break;
- case 'b':
- daemonize = true;
- break;
- case 'u':
- if (udpchannel >= MAX_UDP_DEST) {
- (void)fprintf(stderr,
- "gps2udp: too many UDP destinations (max=%d)\n",
- MAX_UDP_DEST);
- } else {
- udphostport[udpchannel++] = optarg;
- }
- break;
- case 'v':
- (void)fprintf(stderr, "%s: %s (revision %s)\n",
- argv[0], VERSION, REVISION);
- exit(0);
- case '?':
- case 'h':
- default:
- usage();
- exit(1);
- }
- }
-
- 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;
-
- connect2gpsd(false);
-
- if (udpchannel > 0) {
- int status = open_udp(udphostport);
- if (status !=0) exit (1);
- }
-
- if (daemonize) {
- if (os_daemon(0, 0) != 0) {
- (void)fprintf(stderr,
- "gps2udp: daemonization failed: %s\n",
- strerror(errno));
- }
- }
-
- for (;;)
- {
- char buffer[512];
- ssize_t len;
- len = read_gpsd(buffer, sizeof(buffer));
-
- if (len > 3)
- {
- if (debug > 0)
- {
- (void)fprintf (stdout,"---> [%s] -- %s",time2string(),buffer);
-
- if (str_starts_with(buffer, "!AIVDM"))
- {
- #define MAX_INFO 6
- int i,j;
- unsigned char packet[512];
- unsigned char *adrpkt = packet;
- unsigned char *info[MAX_INFO];
- unsigned int mmsi;
- unsigned char bitstrings [255];
-
- (void)strlcpy((char *)packet, buffer, sizeof(packet));
- for (j=0; j<MAX_INFO; j++) {
- info[j] = (unsigned char *)strsep((char **)&adrpkt, ",");
- }
- for(i=0 ; i < (int)strlen((char *)info[5]); i++) {
- if (i > (int) sizeof (bitstrings)) break;
- bitstrings[i] = AISto6bit(info[5][i]);
- }
- mmsi = AISGetInt(bitstrings, 9, 30);
- (void)fprintf(stdout," MMSI=%9u", mmsi);
- }
- (void)fprintf(stdout,"\n");
- }
-
- if (udpchannel > 0)
- (void)send_udp(buffer, (size_t)len);
-
- if (count >= 0) {
- if (count-- == 0) {
-
- (void)fprintf(stderr,
- "gpsd2udp: normal exit after counted packets\n");
- exit (0);
- }
- }
- }
- }
-
- (void)fprintf (stderr, "gpsd2udp ERROR abnormal exit\n");
- exit (-1);
- }
|