From 5089c2fdb3d140d7e0e54448e23a7a5bc87ac7a6 Mon Sep 17 00:00:00 2001
From: Harsh Sharma <harsh.sharma@multitech.com>
Date: Wed, 26 Sep 2018 15:57:59 -0500
Subject: Added GPSD integration to the lora packet forwarder and gateway

---
 .../lora/lora-gateway/lora-gateway-gpsd.patch      | 471 +++++++++++++++++++++
 recipes-connectivity/lora/lora-gateway_5.0.1.bb    |   1 +
 .../lora-packet-forwarder-gpsd.patch               | 293 +++++++++++++
 .../lora/lora-packet-forwarder_4.0.1.bb            |   1 +
 4 files changed, 766 insertions(+)
 create mode 100644 recipes-connectivity/lora/lora-gateway/lora-gateway-gpsd.patch
 create mode 100644 recipes-connectivity/lora/lora-packet-forwarder/lora-packet-forwarder-gpsd.patch

(limited to 'recipes-connectivity/lora')

diff --git a/recipes-connectivity/lora/lora-gateway/lora-gateway-gpsd.patch b/recipes-connectivity/lora/lora-gateway/lora-gateway-gpsd.patch
new file mode 100644
index 0000000..471cd82
--- /dev/null
+++ b/recipes-connectivity/lora/lora-gateway/lora-gateway-gpsd.patch
@@ -0,0 +1,471 @@
+diff --git a/libloragw/Makefile b/libloragw/Makefile
+index 53c33d9..4575bdc 100644
+--- a/libloragw/Makefile
++++ b/libloragw/Makefile
+@@ -10,14 +10,14 @@ CROSS_COMPILE ?=
+ CC := $(CROSS_COMPILE)gcc
+ AR := $(CROSS_COMPILE)ar
+ 
+-CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I.
++CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I. -isystem =/usr/include/gps
+ 
+ OBJDIR = obj
+ INCLUDES = $(wildcard inc/*.h)
+ 
+ ### linking options
+ 
+-LIBS := -lloragw -lrt -lm
++LIBS := -lloragw -lrt -lm -lgps
+ 
+ ### general build targets
+ 
+diff --git a/libloragw/inc/loragw_gps.h b/libloragw/inc/loragw_gps.h
+index 6dbd30b..59b2d37 100644
+--- a/libloragw/inc/loragw_gps.h
++++ b/libloragw/inc/loragw_gps.h
+@@ -27,9 +27,11 @@ Maintainer: Michael Coracin
+ #include <time.h>       /* time library */
+ #include <termios.h>    /* speed_t */
+ #include <unistd.h>     /* ssize_t */
++#include <gpsd.h>
++#include <gpsdclient.h>
++#include <errno.h>      /* error messages */
+ 
+ #include "config.h"     /* library configuration options (dynamically generated) */
+-
+ /* -------------------------------------------------------------------------- */
+ /* --- PUBLIC TYPES --------------------------------------------------------- */
+ 
+@@ -83,6 +85,7 @@ enum gps_msg {
+     UBX_NAV_TIMEUTC  /*!> UTC Time Solution */
+ };
+ 
++// struct gps_data_t gpsdata;
+ /* -------------------------------------------------------------------------- */
+ /* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+ 
+@@ -99,21 +102,19 @@ enum gps_msg {
+ /**
+ @brief Configure a GPS module
+ 
+-@param tty_path path to the TTY connected to the GPS
+-@param gps_familly parameter (eg. ubx6 for uBlox gen.6)
+-@param target_brate target baudrate for communication (0 keeps default target baudrate)
+-@param fd_ptr pointer to a variable to receive file descriptor on GPS tty
+-@return success if the function was able to connect and configure a GPS module
++@param gpsdata handler for gpsd data
++@param source source for setup of gpsd
++@return success if the function was able to connect and configure a GPSD stream
+ */
+-int lgw_gps_enable(char* tty_path, char* gps_familly, speed_t target_brate, int* fd_ptr);
++int lgw_gps_enable(struct gps_data_t *gpsdata, struct fixsource_t *source);
+ 
+ /**
+ @brief Restore GPS serial configuration and close serial device
+ 
+-@param fd file descriptor on GPS tty
++@param gpsdata handler for gpsd data
+ @return success if the function was able to complete
+ */
+-int lgw_gps_disable(int fd);
++int lgw_gps_disable(struct gps_data_t *gpsdata);
+ 
+ /**
+ @brief Parse messages coming from the GPS system (or other GNSS)
+diff --git a/libloragw/src/loragw_gps.c b/libloragw/src/loragw_gps.c
+index c0e0ded..d3d1ca1 100644
+--- a/libloragw/src/loragw_gps.c
++++ b/libloragw/src/loragw_gps.c
+@@ -251,109 +251,22 @@ int str_chop(char *s, int buff_size, char separator, int *idx_ary, int max_idx)
+ /* -------------------------------------------------------------------------- */
+ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+ 
+-int lgw_gps_enable(char *tty_path, char *gps_family, speed_t target_brate, int *fd_ptr) {
+-    int i;
+-    struct termios ttyopt; /* serial port options */
+-    int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */
+-    uint8_t ubx_cmd_timegps[UBX_MSG_NAVTIMEGPS_LEN] = {
+-                    0xB5, 0x62, /* UBX Sync Chars */
+-                    0x06, 0x01, /* CFG-MSG Class/ID */
+-                    0x08, 0x00, /* Payload length */
+-                    0x01, 0x20, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, /* Enable NAV-TIMEGPS output on serial */
+-                    0x32, 0x94 }; /* Checksum */
+-    ssize_t num_written;
+-
+-    /* check input parameters */
+-    CHECK_NULL(tty_path);
+-    CHECK_NULL(fd_ptr);
+-
+-    /* open TTY device */
+-    gps_tty_dev = open(tty_path, O_RDWR | O_NOCTTY);
+-    if (gps_tty_dev <= 0) {
+-        DEBUG_MSG("ERROR: TTY PORT FAIL TO OPEN, CHECK PATH AND ACCESS RIGHTS\n");
+-        return LGW_GPS_ERROR;
+-    }
+-    *fd_ptr = gps_tty_dev;
+-
+-    /* manage the different GPS modules families */
+-    if (gps_family == NULL) {
+-        DEBUG_MSG("WARNING: this version of GPS module may not be supported\n");
+-    } else if (strncmp(gps_family, "ubx7", 4) != 0) {
+-        /* The current implementation relies on proprietary messages from U-Blox */
+-        /* GPS modules (UBX, NAV-TIMEGPS...) and has only be tested with a u-blox 7. */
+-        /* Those messages allow to get NATIVE GPS time (no leap seconds) required */
+-        /* for class-B handling and GPS synchronization */
+-        /* see lgw_parse_ubx() function for details */
+-        DEBUG_MSG("WARNING: this version of GPS module may not be supported\n");
+-    }
+-
+-    /* manage the target bitrate */
+-    if (target_brate != 0) {
+-        DEBUG_MSG("WARNING: target_brate parameter ignored for now\n"); // TODO
+-    }
+-
+-    /* get actual serial port configuration */
+-    i = tcgetattr(gps_tty_dev, &ttyopt);
+-    if (i != 0) {
+-        DEBUG_MSG("ERROR: IMPOSSIBLE TO GET TTY PORT CONFIGURATION\n");
+-        return LGW_GPS_ERROR;
+-    }
+-
+-    /* Save current serial port configuration for restoring later */
+-    memcpy(&ttyopt_restore, &ttyopt, sizeof ttyopt);
+-
+-    /* update baudrates */
+-    cfsetispeed(&ttyopt, DEFAULT_BAUDRATE);
+-    cfsetospeed(&ttyopt, DEFAULT_BAUDRATE);
+-
+-    /* update terminal parameters */
+-    /* The following configuration should allow to:
+-            - Get ASCII NMEA messages
+-            - Get UBX binary messages
+-            - Send UBX binary commands
+-        Note: as binary data have to be read/written, we need to disable
+-              various character processing to avoid loosing data */
+-    /* Control Modes */
+-    ttyopt.c_cflag |= CLOCAL;  /* local connection, no modem control */
+-    ttyopt.c_cflag |= CREAD;   /* enable receiving characters */
+-    ttyopt.c_cflag |= CS8;     /* 8 bit frames */
+-    ttyopt.c_cflag &= ~PARENB; /* no parity */
+-    ttyopt.c_cflag &= ~CSTOPB; /* one stop bit */
+-    /* Input Modes */
+-    ttyopt.c_iflag |= IGNPAR;  /* ignore bytes with parity errors */
+-    ttyopt.c_iflag &= ~ICRNL;  /* do not map CR to NL on input*/
+-    ttyopt.c_iflag &= ~IGNCR;  /* do not ignore carriage return on input */
+-    ttyopt.c_iflag &= ~IXON;   /* disable Start/Stop output control */
+-    ttyopt.c_iflag &= ~IXOFF;  /* do not send Start/Stop characters */
+-    /* Output Modes */
+-    ttyopt.c_oflag = 0;        /* disable everything on output as we only write binary */
+-    /* Local Modes */
+-    ttyopt.c_lflag &= ~ICANON; /* disable canonical input - cannot use with binary input */
+-    ttyopt.c_lflag &= ~ISIG;   /* disable check for INTR, QUIT, SUSP special characters */
+-    ttyopt.c_lflag &= ~IEXTEN; /* disable any special control character */
+-    ttyopt.c_lflag &= ~ECHO;   /* do not echo back every character typed */
+-    ttyopt.c_lflag &= ~ECHOE;  /* does not erase the last character in current line */
+-    ttyopt.c_lflag &= ~ECHOK;  /* do not echo NL after KILL character */
+-
+-    /* settings for non-canonical mode
+-       read will block for until the lesser of VMIN or requested chars have been received */
+-    ttyopt.c_cc[VMIN]  = LGW_GPS_MIN_MSG_SIZE;
+-    ttyopt.c_cc[VTIME] = 0;
+-
+-    /* set new serial ports parameters */
+-    i = tcsetattr(gps_tty_dev, TCSANOW, &ttyopt);
+-    if (i != 0){
+-        DEBUG_MSG("ERROR: IMPOSSIBLE TO UPDATE TTY PORT CONFIGURATION\n");
++int lgw_gps_enable(struct gps_data_t *gpsdata, struct fixsource_t *source) {
++
++    unsigned int flags;
++    fd_set fds;
++    flags = WATCH_ENABLE;
++    flags |= WATCH_RAW;
++    flags |= WATCH_NMEA;
++    gpsd_source_spec(NULL, source);
++
++    if (gps_open(source->server, source->port, gpsdata) != 0) {
++        DEBUG_MSG("gpspipe: could not connect to gpsd %s:%s, %s(%d)\n",
++              source->server, source->port, gps_errstr(errno), errno);
+         return LGW_GPS_ERROR;
+     }
+-    tcflush(gps_tty_dev, TCIOFLUSH);
+ 
+-    /* Send UBX CFG NAV-TIMEGPS message to tell GPS module to output native GPS time */
+-    /* This is a binary message, serial port has to be properly configured to handle this */
+-    num_written = write (gps_tty_dev, ubx_cmd_timegps, UBX_MSG_NAVTIMEGPS_LEN);
+-    if (num_written != UBX_MSG_NAVTIMEGPS_LEN) {
+-        DEBUG_MSG("ERROR: Failed to write on serial port (written=%d)\n", (int) num_written);
+-    }
++    (void)gps_stream(gpsdata, flags, source->device);
+ 
+     /* get timezone info */
+     tzset();
+@@ -368,20 +281,13 @@ int lgw_gps_enable(char *tty_path, char *gps_family, speed_t target_brate, int *
+ 
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+ 
+-int lgw_gps_disable(int fd) {
++int lgw_gps_disable(struct gps_data_t *gpsdata) {
+     int i;
+ 
+-    /* restore serial ports parameters */
+-    i = tcsetattr(fd, TCSANOW, &ttyopt_restore);
+-    if (i != 0){
+-        DEBUG_MSG("ERROR: IMPOSSIBLE TO RESTORE TTY PORT CONFIGURATION\n");
+-        return LGW_GPS_ERROR;
+-    }
+-    tcflush(fd, TCIOFLUSH);
+-
+-    i = close(fd);
+-    if (i <= 0) {
+-        DEBUG_MSG("ERROR: TTY PORT FAIL TO CLOSE\n");
++    /* ends the session */
++    i = gps_close(gpsdata);
++    if (i != 0) {
++        DEBUG_MSG("ERROR: GPSD FAILED TO CLOSE\n");
+         return LGW_GPS_ERROR;
+     }
+ 
+@@ -526,7 +432,7 @@ enum gps_msg lgw_parse_nmea(const char *serial_buff, int buff_size) {
+     } else if (!validate_nmea_checksum(serial_buff, buff_size)) {
+         DEBUG_MSG("Warning: invalid NMEA sentence (bad checksum)\n");
+         return INVALID;
+-    } else if (match_label(serial_buff, "$G?RMC", 6, '?')) {
++    } else if (match_label(serial_buff, "G?RMC", 5, '?')) {
+         /*
+         NMEA sentence format: $xxRMC,time,status,lat,NS,long,EW,spd,cog,date,mv,mvEW,posMode*cs<CR><LF>
+         Valid fix: $GPRMC,083559.34,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A*00
+@@ -535,19 +441,19 @@ enum gps_msg lgw_parse_nmea(const char *serial_buff, int buff_size) {
+         memcpy(parser_buf, serial_buff, buff_size);
+         parser_buf[buff_size] = '\0';
+         nb_fields = str_chop(parser_buf, buff_size, ',', str_index, ARRAY_SIZE(str_index));
+-        if (nb_fields != 13) {
++        if (nb_fields != 12) {
+             DEBUG_MSG("Warning: invalid RMC sentence (number of fields)\n");
+             return IGNORED;
+         }
+         /* parse GPS status */
+-        gps_mod = *(parser_buf + str_index[12]); /* get first character, no need to bother with sscanf */
++        gps_mod = *(parser_buf + str_index[2]); /* get first character, no need to bother with sscanf */
+         if ((gps_mod != 'N') && (gps_mod != 'A') && (gps_mod != 'D')) {
+             gps_mod = 'N';
+         }
+         /* parse complete time */
+         i = sscanf(parser_buf + str_index[1], "%2hd%2hd%2hd%4f", &gps_hou, &gps_min, &gps_sec, &gps_fra);
+         j = sscanf(parser_buf + str_index[9], "%2hd%2hd%2hd", &gps_day, &gps_mon, &gps_yea);
+-        if ((i == 4) && (j == 3)) {
++        if ((i == 3) && (j == 3)) {
+             if ((gps_mod == 'A') || (gps_mod == 'D')) {
+                 gps_time_ok = true;
+                 DEBUG_MSG("Note: Valid RMC sentence, GPS locked, date: 20%02d-%02d-%02dT%02d:%02d:%06.3fZ\n", gps_yea, gps_mon, gps_day, gps_hou, gps_min, gps_fra + (float)gps_sec);
+@@ -561,7 +467,7 @@ enum gps_msg lgw_parse_nmea(const char *serial_buff, int buff_size) {
+             DEBUG_MSG("Note: Valid RMC sentence, mode %c, no date\n", gps_mod);
+         }
+         return NMEA_RMC;
+-    } else if (match_label(serial_buff, "$G?GGA", 6, '?')) {
++    } else if (match_label(serial_buff, "G?GGA", 5, '?')) {
+         /*
+         NMEA sentence format: $xxGGA,time,lat,NS,long,EW,quality,numSV,HDOP,alt,M,sep,M,diffAge,diffStation*cs<CR><LF>
+         Valid fix: $GPGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*5B
+diff --git a/libloragw/tst/test_loragw_gps.c b/libloragw/tst/test_loragw_gps.c
+index a4164a3..e4b1546 100644
+--- a/libloragw/tst/test_loragw_gps.c
++++ b/libloragw/tst/test_loragw_gps.c
+@@ -31,6 +31,8 @@ Maintainer: Michael Coracin
+ #include <signal.h>     /* sigaction */
+ #include <stdlib.h>     /* exit */
+ #include <unistd.h>     /* read */
++#include <gps.h>
++#include <gpsd.h>
+ 
+ #include "loragw_hal.h"
+ #include "loragw_gps.h"
+@@ -41,7 +43,8 @@ Maintainer: Michael Coracin
+ 
+ static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
+ static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
+-
++static struct gps_data_t gpsdata;
++static struct fixsource_t source;
+ struct tref ppm_ref;
+ 
+ /* -------------------------------------------------------------------------- */
+@@ -149,6 +152,10 @@ int main()
+     /* NMEA/UBX variables */
+     enum gps_msg latest_msg; /* keep track of latest NMEA/UBX message parsed */
+ 
++    fd_set fds;
++    char delim[4] = "$";
++    char *token[254];
++
+     /* configure signal handling */
+     sigemptyset(&sigact.sa_mask);
+     sigact.sa_flags = 0;
+@@ -162,7 +169,7 @@ int main()
+     printf("*** Library version information ***\n%s\n***\n", lgw_version_info());
+ 
+     /* Open and configure GPS */
+-    i = lgw_gps_enable("/dev/ttyAMA0", "ubx7", 0, &gps_tty_dev);
++    i = lgw_gps_enable(&gpsdata, &source); 
+     if (i != LGW_GPS_SUCCESS) {
+         printf("ERROR: IMPOSSIBLE TO ENABLE GPS\n");
+         exit(EXIT_FAILURE);
+@@ -192,92 +199,87 @@ int main()
+ 
+     /* loop until user action */
+     while ((quit_sig != 1) && (exit_sig != 1)) {
+-        size_t rd_idx = 0;
+-        size_t frame_end_idx = 0;
+-
+-        /* blocking non-canonical read on serial port */
+-        ssize_t nb_char = read(gps_tty_dev, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE);
+-        if (nb_char <= 0) {
+-            printf("WARNING: [gps] read() returned value %d\n", nb_char);
++        int r = 0;
++        struct timeval tv;
++        tv.tv_sec = 0;
++        tv.tv_usec = 100000;
++        FD_ZERO(&fds);
++        FD_SET(gpsdata.gps_fd, &fds);
++        errno = 0;
++        r = select(gpsdata.gps_fd+1, &fds, NULL, NULL, &tv);
++        if (r == -1 && errno != EINTR) {
++            printf("gpspipe: select error %s(%d)\n", strerror(errno), errno);
++            exit(EXIT_FAILURE);
++        } else if (r == 0)
+             continue;
+-        }
+-        wr_idx += (size_t)nb_char;
+ 
+-        /*******************************************
+-         * Scan buffer for UBX/NMEA sync chars and *
+-         * attempt to decode frame if one is found *
+-         *******************************************/
+-        while (rd_idx < wr_idx) {
++        /* reading directly from the socket avoids decode overhead */
++        errno = 0;
++        r = (int)read(gpsdata.gps_fd, serial_buff, sizeof(serial_buff));
++        if (r > 0) {
++            int i = 0;
+             size_t frame_size = 0;
+-
+-            /* Scan buffer for UBX sync char */
+-            if (serial_buff[rd_idx] == LGW_GPS_UBX_SYNC_CHAR) {
+-
+-                /***********************
+-                 * Found UBX sync char *
+-                 ***********************/
+-                latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size);
+-
+-                if (frame_size > 0) {
+-                    if (latest_msg == INCOMPLETE) {
+-                        /* UBX header found but frame appears to be missing bytes */
+-                        frame_size = 0;
+-                    } else if (latest_msg == INVALID) {
+-                        /* message header received but message appears to be corrupted */
+-                        printf("WARNING: [gps] could not get a valid message from GPS (no time)\n");
+-                        frame_size = 0;
+-                    } else if (latest_msg == UBX_NAV_TIMEGPS) {
+-                        printf("\n~~ UBX NAV-TIMEGPS sentence, triggering synchronization attempt ~~\n");
+-                        gps_process_sync();
++            for (i = 0; i < r; i++) {
++                if (serial_buff[i] == (char)LGW_GPS_UBX_SYNC_CHAR) {
++                    /***********************
++                     * Found UBX sync char *
++                     ***********************/
++                    size_t ubx_size = (uint8_t)serial_buff[i+4];
++                    ubx_size |= (uint8_t)serial_buff[i+5] << 8;
++                    ubx_size += 8;
++                    if (ubx_size < 27){
++                        latest_msg = lgw_parse_ubx(&serial_buff[i], ubx_size , &frame_size);
+                     }
+-                }
+-            } else if(serial_buff[rd_idx] == LGW_GPS_NMEA_SYNC_CHAR) {
+-                /************************
+-                 * Found NMEA sync char *
+-                 ************************/
+-                /* scan for NMEA end marker (LF = 0x0a) */
+-                char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx));
+-
+-                if (nmea_end_ptr) {
+-                    /* found end marker */
+-                    frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1;
+-                    latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size);
+-
+-                    if(latest_msg == INVALID || latest_msg == UNKNOWN) {
+-                        /* checksum failed */
+-                        frame_size = 0;
+-                    } else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */
+-                        gps_process_coords();
++                    if (frame_size > 0) {
++                        if(latest_msg == INVALID || latest_msg == UNKNOWN) {
++                            /* checksum failed */
++                            frame_size = 0;
++                        } else if (latest_msg == UBX_NAV_TIMEGPS) {
++                            gps_process_sync();
++                        }
++                    }
++                } else if((serial_buff[i] == LGW_GPS_NMEA_SYNC_CHAR) && (serial_buff[i+1] == 0x47) && (serial_buff[i+2] == 0x50)){
++                    /************************
++                     * Found NMEA sync char *
++                     ************************/
++                    int k, l= 0;
++                    token[0] = strtok(serial_buff, delim);
++
++                    while (token[l] != NULL) {
++                        l++;
++                        token[l] = strtok(NULL, delim); 
+                     }
++                    for (k=0; k<=l-1; k++) {
++                        if ((strlen(token[k]) > 66) && (strlen(token[k]) < 74)){
++                            lgw_parse_nmea(token[k], strlen(token[k]));
++                            if(latest_msg == INVALID || latest_msg == UNKNOWN) {
++                                /* checksum failed */
++                                frame_size = 0;
++                            } else if (latest_msg == NMEA_RMC) { 
++                                /* Get location from RMC frames */
++                                gps_process_coords();
++                            }
++                        }
++                    }               
+                 }
+             }
+-
+-            if (frame_size > 0) {
+-                /* At this point message is a checksum verified frame
+-                   we're processed or ignored. Remove frame from buffer */
+-                rd_idx += frame_size;
+-                frame_end_idx = rd_idx;
++        } else {
++            if (r == -1) {
++                if (errno == EAGAIN)
++                    continue;
++                else {
++                    printf(stderr, "gpspipe: read error %s(%d)\n", strerror(errno), errno);
++                    exit(EXIT_FAILURE);
++                }
+             } else {
+-                rd_idx++;
++                exit(EXIT_SUCCESS);
+             }
+-        } /* ...for(rd_idx = 0... */
+-
+-        if (frame_end_idx) {
+-          /* Frames have been processed. Remove bytes to end of last processed frame */
+-          memcpy(serial_buff,&serial_buff[frame_end_idx],wr_idx - frame_end_idx);
+-          wr_idx -= frame_end_idx;
+-        } /* ...for(rd_idx = 0... */
+-
+-        /* Prevent buffer overflow */
+-        if ((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) {
+-            memcpy(serial_buff,&serial_buff[LGW_GPS_MIN_MSG_SIZE],wr_idx - LGW_GPS_MIN_MSG_SIZE);
+-            wr_idx -= LGW_GPS_MIN_MSG_SIZE;
+         }
+     }
+ 
+     /* clean up before leaving */
+     if (exit_sig == 1) {
+-        lgw_gps_disable(gps_tty_dev);
++        lgw_gps_disable(&gpsdata);
+         lgw_stop();
+     }
+ 
diff --git a/recipes-connectivity/lora/lora-gateway_5.0.1.bb b/recipes-connectivity/lora/lora-gateway_5.0.1.bb
index b899126..c8f1ffc 100644
--- a/recipes-connectivity/lora/lora-gateway_5.0.1.bb
+++ b/recipes-connectivity/lora/lora-gateway_5.0.1.bb
@@ -17,6 +17,7 @@ SRC_URI = "git://github.com/Lora-net/lora_gateway.git;protocol=git \
            file://lora-gateway-change-util-tx-continuous-clksrc.patch \
            file://lora-gateway-v28-skip-IQ-invert.patch \
            file://lora-gateway-spectral-scan-skip-fpga-reset.patch \
+           file://lora-gateway-gpsd.patch \
           "
 
 SRC_URI[md5sum] = "9e06a3733a9fea39a3d61f77b412badf"
diff --git a/recipes-connectivity/lora/lora-packet-forwarder/lora-packet-forwarder-gpsd.patch b/recipes-connectivity/lora/lora-packet-forwarder/lora-packet-forwarder-gpsd.patch
new file mode 100644
index 0000000..be9b059
--- /dev/null
+++ b/recipes-connectivity/lora/lora-packet-forwarder/lora-packet-forwarder-gpsd.patch
@@ -0,0 +1,293 @@
+diff --git a/lora_pkt_fwd/Makefile b/lora_pkt_fwd/Makefile
+index 1330d62..dda589e 100644
+--- a/lora_pkt_fwd/Makefile
++++ b/lora_pkt_fwd/Makefile
+@@ -22,7 +22,7 @@ RELEASE_VERSION := `cat ../VERSION`
+ CC := $(CROSS_COMPILE)gcc
+ AR := $(CROSS_COMPILE)ar
+ 
+-CFLAGS := -O2 -Wall -Wextra -std=c99 -Iinc -I.
++MORECFLAGS := -Wall -Wextra -std=c99 -Iinc -I. -isystem =/usr/include/gps
+ VFLAG := -D VERSION_STRING="\"$(RELEASE_VERSION)\""
+ 
+ ### Constants for Lora concentrator HAL library
+@@ -38,7 +38,7 @@ LGW_INC += $(LGW_PATH)/inc/loragw_gps.h
+ 
+ ### Linking options
+ 
+-LIBS := -lloragw -lrt -lpthread -lm
++LIBS := -lloragw -lrt -lpthread -lm -lgps
+ 
+ ### General build targets
+ 
+@@ -54,12 +54,14 @@ $(OBJDIR):
+ 	mkdir -p $(OBJDIR)
+ 
+ $(OBJDIR)/%.o: src/%.c $(INCLUDES) | $(OBJDIR)
+-	$(CC) -c $(CFLAGS) -I$(LGW_PATH)/inc $< -o $@
++	@echo compile $@
++	$(CC) -c $(CFLAGS) $(MORECFLAGS) -I$(LGW_PATH)/inc $< -o $@
+ 
+ ### Main program compilation and assembly
+ 
+ $(OBJDIR)/$(APP_NAME).o: src/$(APP_NAME).c $(LGW_INC) $(INCLUDES) | $(OBJDIR)
+-	$(CC) -c $(CFLAGS) $(VFLAG) -I$(LGW_PATH)/inc $< -o $@
++	@echo compile $@
++	$(CC) -c $(CFLAGS) $(MORECFLAGS) $(VFLAG) -I$(LGW_PATH)/inc $< -o $@
+ 
+ $(APP_NAME): $(OBJDIR)/$(APP_NAME).o $(LGW_PATH)/libloragw.a $(OBJDIR)/parson.o $(OBJDIR)/base64.o $(OBJDIR)/jitqueue.o $(OBJDIR)/timersync.o
+ 	$(CC) -L$(LGW_PATH) $< $(OBJDIR)/parson.o $(OBJDIR)/base64.o $(OBJDIR)/jitqueue.o $(OBJDIR)/timersync.o -o $@ $(LIBS)
+diff --git a/lora_pkt_fwd/src/lora_pkt_fwd.c b/lora_pkt_fwd/src/lora_pkt_fwd.c
+index 801f28d..6bca482 100644
+--- a/lora_pkt_fwd/src/lora_pkt_fwd.c
++++ b/lora_pkt_fwd/src/lora_pkt_fwd.c
+@@ -156,10 +156,10 @@ static bool xtal_correct_ok = false; /* set true when XTAL correction is stable
+ static double xtal_correct = 1.0;
+ 
+ /* GPS configuration and synchronization */
+-static char gps_tty_path[64] = "\0"; /* path of the TTY port GPS is connected on */
+-static int gps_tty_fd = -1; /* file descriptor of the GPS TTY port */
++static bool use_gps = false; /* Use the GPSD stream */
+ static bool gps_enabled = false; /* is GPS enabled on that gateway ? */
+-
++static struct gps_data_t gpsdata;
++static struct fixsource_t source;
+ /* GPS time reference */
+ static pthread_mutex_t mx_timeref = PTHREAD_MUTEX_INITIALIZER; /* control access to GPS time reference */
+ static bool gps_ref_valid; /* is GPS reference acceptable (ie. not too old) */
+@@ -747,13 +747,6 @@ static int parse_gateway_configuration(const char * conf_file) {
+     }
+     MSG("INFO: packets received with no CRC will%s be forwarded\n", (fwd_nocrc_pkt ? "" : " NOT"));
+ 
+-    /* GPS module TTY path (optional) */
+-    str = json_object_get_string(conf_obj, "gps_tty_path");
+-    if (str != NULL) {
+-        strncpy(gps_tty_path, str, sizeof gps_tty_path);
+-        MSG("INFO: GPS serial port path is configured to \"%s\"\n", gps_tty_path);
+-    }
+-
+     /* get reference coordinates */
+     val = json_object_get_value(conf_obj, "ref_latitude");
+     if (val != NULL) {
+@@ -772,6 +765,17 @@ static int parse_gateway_configuration(const char * conf_file) {
+     }
+ 
+     /* Gateway GPS coordinates hardcoding (aka. faking) option */
++    val = json_object_get_value(conf_obj, "gps");
++    if (json_value_get_type(val) == JSONBoolean) {
++        use_gps = (bool)json_value_get_boolean(val);
++        if (use_gps == true) {
++            MSG("INFO: GPS is enabled\n");
++        } else {
++            MSG("INFO: GPS is disabled\n");
++        }
++    }
++
++    /* Gateway GPS coordinates hardcoding (aka. faking) option */
+     val = json_object_get_value(conf_obj, "fake_gps");
+     if (json_value_get_type(val) == JSONBoolean) {
+         gps_fake_enable = (bool)json_value_get_boolean(val);
+@@ -1098,14 +1102,14 @@ int main(void)
+     }
+ 
+     /* Start GPS a.s.a.p., to allow it to lock */
+-    if (gps_tty_path[0] != '\0') { /* do not try to open GPS device if no path set */
+-        i = lgw_gps_enable(gps_tty_path, "ubx7", 0, &gps_tty_fd); /* HAL only supports u-blox 7 for now */
++    if (use_gps == true) {
++        int i = lgw_gps_enable(&gpsdata, &source); 
+         if (i != LGW_GPS_SUCCESS) {
+-            printf("WARNING: [main] impossible to open %s for GPS sync (check permissions)\n", gps_tty_path);
++            printf("WARNING: [main] impossible to open for GPS sync (Check GPSD)\n");
+             gps_enabled = false;
+             gps_ref_valid = false;
+         } else {
+-            printf("INFO: [main] TTY port %s open for GPS synchronization\n", gps_tty_path);
++            printf("INFO: [main] GPSD polling open for GPS synchronization\n");
+             gps_enabled = true;
+             gps_ref_valid = false;
+         }
+@@ -1413,7 +1417,7 @@ int main(void)
+         pthread_cancel(thrid_gps); /* don't wait for GPS thread */
+         pthread_cancel(thrid_valid); /* don't wait for validation thread */
+ 
+-        i = lgw_gps_disable(gps_tty_fd);
++        i = lgw_gps_disable(&gpsdata);
+         if (i == LGW_HAL_SUCCESS) {
+             MSG("INFO: GPS closed successfully\n");
+         } else {
+@@ -2691,7 +2695,7 @@ static void gps_process_coords(void) {
+     /* position variable */
+     struct coord_s coord;
+     struct coord_s gpserr;
+-    int    i = lgw_gps_get(NULL, NULL, &coord, &gpserr);
++    int i = lgw_gps_get(NULL, NULL, &coord, &gpserr);
+ 
+     /* update gateway coordinates */
+     pthread_mutex_lock(&mx_meas_gps);
+@@ -2707,96 +2711,88 @@ static void gps_process_coords(void) {
+ }
+ 
+ void thread_gps(void) {
+-    /* serial variables */
+     char serial_buff[128]; /* buffer to receive GPS data */
+-    size_t wr_idx = 0;     /* pointer to end of chars in buffer */
+-
+-    /* variables for PPM pulse GPS synchronization */
+     enum gps_msg latest_msg; /* keep track of latest NMEA message parsed */
+-
+-    /* initialize some variables before loop */
+-    memset(serial_buff, 0, sizeof serial_buff);
+-
++    memset(serial_buff, 0, sizeof serial_buff); /* initialize some variables before loop */
++    fd_set fds;
++    char delim[4] = "$";
++    char *token[254];
+     while (!exit_sig && !quit_sig) {
+-        size_t rd_idx = 0;
+-        size_t frame_end_idx = 0;
+-
+-        /* blocking non-canonical read on serial port */
+-        ssize_t nb_char = read(gps_tty_fd, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE);
+-        if (nb_char <= 0) {
+-            MSG("WARNING: [gps] read() returned value %d\n", nb_char);
++        int r = 0;
++        struct timeval tv;
++        tv.tv_sec = 0;
++        tv.tv_usec = 100000;
++        FD_ZERO(&fds);
++        FD_SET(gpsdata.gps_fd, &fds);
++        errno = 0;
++        r = select(gpsdata.gps_fd+1, &fds, NULL, NULL, &tv);
++        if (r == -1 && errno != EINTR) {
++            MSG("gpspipe: select error %s(%d)\n", strerror(errno), errno);
++            exit(EXIT_FAILURE);
++        } else if (r == 0)
+             continue;
+-        }
+-        wr_idx += (size_t)nb_char;
+ 
+-        /*******************************************
+-         * Scan buffer for UBX/NMEA sync chars and *
+-         * attempt to decode frame if one is found *
+-         *******************************************/
+-        while(rd_idx < wr_idx) {
++        /* reading directly from the socket avoids decode overhead */
++        errno = 0;
++        r = (int)read(gpsdata.gps_fd, serial_buff, sizeof(serial_buff));
++        if (r > 0) {
++            int i = 0;
+             size_t frame_size = 0;
+-
+-            /* Scan buffer for UBX sync char */
+-            if(serial_buff[rd_idx] == (char)LGW_GPS_UBX_SYNC_CHAR) {
+-
+-                /***********************
+-                 * Found UBX sync char *
+-                 ***********************/
+-                latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size);
+-
+-                if (frame_size > 0) {
+-                    if (latest_msg == INCOMPLETE) {
+-                        /* UBX header found but frame appears to be missing bytes */
+-                        frame_size = 0;
+-                    } else if (latest_msg == INVALID) {
+-                        /* message header received but message appears to be corrupted */
+-                        MSG("WARNING: [gps] could not get a valid message from GPS (no time)\n");
+-                        frame_size = 0;
+-                    } else if (latest_msg == UBX_NAV_TIMEGPS) {
+-                        gps_process_sync();
++            for (i = 0; i < r; i++) {
++                if (serial_buff[i] == (char)LGW_GPS_UBX_SYNC_CHAR) {
++                    /***********************
++                     * Found UBX sync char *
++                     ***********************/
++                    size_t ubx_size = (uint8_t)serial_buff[i+4];
++                    ubx_size |= (uint8_t)serial_buff[i+5] << 8;
++                    ubx_size += 8;
++                    if (ubx_size < 27){
++                        latest_msg = lgw_parse_ubx(&serial_buff[i], ubx_size , &frame_size);
+                     }
+-                }
+-            } else if(serial_buff[rd_idx] == LGW_GPS_NMEA_SYNC_CHAR) {
+-                /************************
+-                 * Found NMEA sync char *
+-                 ************************/
+-                /* scan for NMEA end marker (LF = 0x0a) */
+-                char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx));
+-
+-                if(nmea_end_ptr) {
+-                    /* found end marker */
+-                    frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1;
+-                    latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size);
+-
+-                    if(latest_msg == INVALID || latest_msg == UNKNOWN) {
+-                        /* checksum failed */
+-                        frame_size = 0;
+-                    } else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */
+-                        gps_process_coords();
++                    if (frame_size > 0) {
++                        if(latest_msg == INVALID || latest_msg == UNKNOWN) {
++                            /* checksum failed */
++                            frame_size = 0;
++                        } else if (latest_msg == UBX_NAV_TIMEGPS) {
++                            gps_process_sync();
++                        }
++                    }
++                } else if((serial_buff[i] == LGW_GPS_NMEA_SYNC_CHAR) && (serial_buff[i+1] == 0x47) && (serial_buff[i+2] == 0x50)){
++                    /************************
++                     * Found NMEA sync char *
++                     ************************/
++                    int k, l= 0;
++                    token[0] = strtok(serial_buff, delim);
++
++                    while (token[l] != NULL) {
++                        l++;
++                        token[l] = strtok(NULL, delim); 
++                    }
++                    for (k=0; k<=l-1; k++) {
++                        if ((strlen(token[k]) > 66) && (strlen(token[k]) < 74)){
++                            lgw_parse_nmea(token[k], strlen(token[k]));
++                            if(latest_msg == INVALID || latest_msg == UNKNOWN) {
++                                /* checksum failed */
++                                frame_size = 0;
++                            } else if (latest_msg == NMEA_RMC) {
++                                /* Get location from RMC frames */
++                                gps_process_coords();
++                            }
++                        }
+                     }
+                 }
+             }
+-
+-            if(frame_size > 0) {
+-                /* At this point message is a checksum verified frame
+-                   we're processed or ignored. Remove frame from buffer */
+-                rd_idx += frame_size;
+-                frame_end_idx = rd_idx;
++        } else {
++            if (r == -1) {
++                if (errno == EAGAIN)
++                    continue;
++                else {
++                    MSG(stderr, "gpspipe: read error %s(%d)\n", strerror(errno), errno);
++                    exit(EXIT_FAILURE);
++                }
+             } else {
+-                rd_idx++;
++                exit(EXIT_SUCCESS);
+             }
+-        } /* ...for(rd_idx = 0... */
+-
+-        if(frame_end_idx) {
+-          /* Frames have been processed. Remove bytes to end of last processed frame */
+-          memcpy(serial_buff, &serial_buff[frame_end_idx], wr_idx - frame_end_idx);
+-          wr_idx -= frame_end_idx;
+-        } /* ...for(rd_idx = 0... */
+-
+-        /* Prevent buffer overflow */
+-        if((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) {
+-            memcpy(serial_buff, &serial_buff[LGW_GPS_MIN_MSG_SIZE], wr_idx - LGW_GPS_MIN_MSG_SIZE);
+-            wr_idx -= LGW_GPS_MIN_MSG_SIZE;
+         }
+     }
+     MSG("\nINFO: End of GPS thread\n");
diff --git a/recipes-connectivity/lora/lora-packet-forwarder_4.0.1.bb b/recipes-connectivity/lora/lora-packet-forwarder_4.0.1.bb
index f7dbbdf..7fe7f95 100644
--- a/recipes-connectivity/lora/lora-packet-forwarder_4.0.1.bb
+++ b/recipes-connectivity/lora/lora-packet-forwarder_4.0.1.bb
@@ -35,6 +35,7 @@ SRC_URI = "git://github.com/Lora-net/packet_forwarder.git;protocol=git \
            file://local_conf.json \
            file://lora-packet-forwarder-add-spi-dev-path.patch \
            file://lora-packet-forwarder-remove-jit-power-check.patch \
+           file://lora-packet-forwarder-gpsd.patch \
 "
 
 
-- 
cgit v1.2.3