/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (C)2013 Semtech-Cycleo Description: Minimum test program for the loragw_gps 'library' License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Michael Coracin */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ /* fix an issue between POSIX and C99 */ #if __STDC_VERSION__ >= 199901L #define _XOPEN_SOURCE 600 #else #define _XOPEN_SOURCE 500 #endif #include /* C99 types */ #include /* bool type */ #include /* printf */ #include /* memset */ #include /* sigaction */ #include /* exit */ #include /* read */ #include #include #include "loragw_hal.h" #include "loragw_gps.h" #include "loragw_aux.h" /* -------------------------------------------------------------------------- */ /* --- PRIVATE VARIABLES ---------------------------------------------------- */ 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; /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ static void sig_handler(int sigio); static void gps_process_sync(void); static void gps_process_coords(void); /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ static void sig_handler(int sigio) { if (sigio == SIGQUIT) { quit_sig = 1;; } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { exit_sig = 1; } } static void gps_process_sync(void) { /* variables for PPM pulse GPS synchronization */ uint32_t ppm_tstamp; struct timespec ppm_gps; struct timespec ppm_utc; /* variables for timestamp <-> GPS time conversions */ uint32_t x, z; struct timespec y; /* get GPS time for synchronization */ int i = lgw_gps_get(&ppm_utc, &ppm_gps, NULL, NULL); if (i != LGW_GPS_SUCCESS) { printf(" No valid reference GPS time available, synchronization impossible.\n"); return; } /* get timestamp for synchronization */ i = lgw_get_trigcnt(&ppm_tstamp); if (i != LGW_HAL_SUCCESS) { printf(" Failed to read timestamp, synchronization impossible.\n"); return; } /* try to update synchronize time reference with the new GPS & timestamp */ i = lgw_gps_sync(&ppm_ref, ppm_tstamp, ppm_utc, ppm_gps); if (i != LGW_GPS_SUCCESS) { printf(" Synchronization error.\n"); return; } /* display result */ printf(" * Synchronization successful *\n"); printf(" UTC reference time: %lld.%09ld\n", (long long)ppm_ref.utc.tv_sec, ppm_ref.utc.tv_nsec); printf(" GPS reference time: %lld.%09ld\n", (long long)ppm_ref.gps.tv_sec, ppm_ref.gps.tv_nsec); printf(" Internal counter reference value: %u\n", ppm_ref.count_us); printf(" Clock error: %.9f\n", ppm_ref.xtal_err); x = ppm_tstamp + 500000; printf(" * Test of timestamp counter <-> GPS value conversion *\n"); printf(" Test value: %u\n", x); lgw_cnt2gps(ppm_ref, x, &y); printf(" Conversion to GPS: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec); lgw_gps2cnt(ppm_ref, y, &z); printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x)); printf(" * Test of timestamp counter <-> UTC value conversion *\n"); printf(" Test value: %u\n", x); lgw_cnt2utc(ppm_ref, x, &y); printf(" Conversion to UTC: %lld.%09ld\n", (long long)y.tv_sec, y.tv_nsec); lgw_utc2cnt(ppm_ref, y, &z); printf(" Converted back: %u ==> %dµs\n", z, (int32_t)(z-x)); } 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); /* update gateway coordinates */ if (i == LGW_GPS_SUCCESS) { printf("# GPS coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", coord.lat, coord.lon, coord.alt); printf("# GPS err: latitude %.5f, longitude %.5f, altitude %i m\n", gpserr.lat, gpserr.lon, gpserr.alt); } } /* -------------------------------------------------------------------------- */ /* --- MAIN FUNCTION -------------------------------------------------------- */ int main() { struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ int i; /* concentrator variables */ struct lgw_conf_board_s boardconf; struct lgw_conf_rxrf_s rfconf; /* serial variables */ char serial_buff[128]; /* buffer to receive GPS data */ size_t wr_idx = 0; /* pointer to end of chars in buffer */ int gps_tty_dev; /* file descriptor to the serial port of the GNSS module */ /* NMEA/UBX variables */ enum gps_msg latest_msg = UNKNOWN; /* 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; sigact.sa_handler = sig_handler; sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); /* Intro message and library information */ printf("Beginning of test for loragw_gps.c\n"); printf("*** Library version information ***\n%s\n***\n", lgw_version_info()); /* Open and configure GPS */ i = lgw_gps_enable("/dev/ttyS0", "ubx7", 0, &gps_tty_dev, 1); if (i != LGW_GPS_SUCCESS) { printf("ERROR: Failed to enable GPS\n"); exit(EXIT_FAILURE); } /* start concentrator (default conf for IoT SK) */ /* board config */ memset(&boardconf, 0, sizeof(boardconf)); boardconf.lorawan_public = true; boardconf.clksrc = 1; lgw_board_setconf(boardconf); /* RF config */ memset(&rfconf, 0, sizeof(rfconf)); rfconf.enable = true; rfconf.freq_hz = 868000000; rfconf.rssi_offset = 0.0; rfconf.type = LGW_RADIO_TYPE_SX1257; rfconf.tx_enable = true; lgw_rxrf_setconf(0, rfconf); lgw_start(); /* initialize some variables before loop */ memset(serial_buff, 0, sizeof serial_buff); memset(&ppm_ref, 0, sizeof ppm_ref); /* loop until user action */ while ((quit_sig != 1) && (exit_sig != 1)) { 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; /* 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; 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); } 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(); } } } } } } else { if (r == -1) { if (errno == EAGAIN) continue; else { printf(stderr, "gpspipe: read error %s(%d)\n", strerror(errno), errno); exit(EXIT_FAILURE); } } else { exit(EXIT_SUCCESS); } } } /* clean up before leaving */ if (exit_sig == 1) { lgw_gps_disable(gps_tty_dev); lgw_stop(); } printf("\nEnd of test for loragw_gps.c\n"); exit(EXIT_SUCCESS); } /* --- EOF ------------------------------------------------------------------ */