Skip to content

Instantly share code, notes, and snippets.

@ncoder-1
Last active July 1, 2022 09:07
Show Gist options
  • Save ncoder-1/8313815ac387e6757f751dc8960f03d7 to your computer and use it in GitHub Desktop.
Save ncoder-1/8313815ac387e6757f751dc8960f03d7 to your computer and use it in GitHub Desktop.
example C++17 gpsd program using libgpsmm
// Example C++17 gpsd program using libgpsmm
// Has no actual purpose other than output some of libgpsmm struct variables of your choosing.
// reference declarations: https://fossies.org/dox/gpsd-3.22/index.html
//
// compiles without warning as follows:
// g++ -std=c++17 -Wall -pedantic -pthread $(pkg-config --cflags --libs libgps) gpsd-example.cpp -o gpsd-example
// clang++ -std=c++17 -Wall -pedantic -pthread $(pkg-config --cflags --libs libgps) gpsd-example.cpp -o gpsd-example
// Free for the taking.
// Version 1.84
#include <libgpsmm.h>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
enum TimeFormat { LOCALTIME, UTC, UNIX, ISO_8601 };
auto TimespecToTimeStr(const timespec& gpsd_time, TimeFormat time_format = LOCALTIME) {
// example showing different ways of formating GPSD's timespec, depending on requirement
std::ostringstream oss;
switch (time_format) {
case LOCALTIME: {
// convert timespec_t into localtime (dd-mm-YY HH:MM:SS)
const auto tm = *std::localtime(&gpsd_time.tv_sec);
oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S");
break;
}
case UTC: {
// convert timespec_t into UTC (dd-mm-YY HH:MM:SS)
const auto tm = *std::gmtime(&gpsd_time.tv_sec);
oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S");
break;
}
case UNIX:
// returns seconds since the Epoch
oss << gpsd_time.tv_sec;
break;
case ISO_8601: {
// convert timespec_t into ISO8601 UTC time (yyyy-MM-dd'T'HH:mm:ss'Z')
constexpr size_t kScrSize{128};
std::array<char, kScrSize> scr{};
timespec_to_iso8601(gpsd_time, scr.data(), kScrSize);
oss << scr.data();
break;
}
}
return oss.str();
}
auto main() -> int {
gpsmm gps_rec("localhost", DEFAULT_GPSD_PORT);
if (gps_rec.stream(WATCH_ENABLE | WATCH_JSON) == nullptr) {
std::cerr << "No GPSD running.\n";
return 1;
}
constexpr auto kWaitingTime{1000000}; // 1000000 is 1 second
for (;;) {
if (!gps_rec.waiting(kWaitingTime)) {
continue;
}
struct gps_data_t* gpsd_data;
if ((gps_rec.read()) == nullptr) {
std::cerr << "GPSD read error.\n";
return 1;
}
while (((gpsd_data = gps_rec.read()) == nullptr) || (gpsd_data->fix.mode < MODE_2D)) {
// Do nothing until fix, block execution for 1 second (busy wait mitigation)
std::this_thread::sleep_for(std::chrono::seconds(1));
}
const auto latitude{gpsd_data->fix.latitude};
const auto longitude{gpsd_data->fix.longitude};
const auto hdop{gpsd_data->dop.hdop};
const auto vdop{gpsd_data->dop.vdop};
const auto pdop{gpsd_data->dop.pdop};
const auto s_vis{gpsd_data->satellites_visible};
const auto s_used{gpsd_data->satellites_used};
const auto time_str{TimespecToTimeStr(gpsd_data->fix.time, ISO_8601)}; // you can change the 2nd argument to LOCALTIME, UTC, UNIX or ISO8601
std::cout << std::setprecision(8) << std::fixed; // set output to fixed floating point, 8 decimal precision
std::cout << time_str << "," << latitude << "," << longitude << "," << hdop << "," << vdop << "," << pdop << "," << s_vis << "," << s_used << '\n';
}
}
@garyv100
Copy link

garyv100 commented Mar 29, 2020

Hi @ncoder-1, in addition to monitoring lat and long I also calculate the distance between the initial location and the current one - easier to see the drift.

@ncoder-1
Copy link
Author

ncoder-1 commented Mar 29, 2020

@garyv100, just want to make sure though, the drift is getting further and further away from the real location or is it closing in on the real location over time? Currently here looking at it, after 15 minutes from a USB GPS (and a cold boot), it started around 50 meters off until it had about 8 or so satellites and now it's been dead on the right location and no drift.

@garyv100
Copy link

garyv100 commented Mar 29, 2020

@ncoder-1, the way I measure the drift is I take initial good gps location (usually 10 satellites or more and that is fast) and save it into variable and then monitor and calculate the distance between the initial location and all subsequent once as time goes by while keeping the receiver stationary, Within 15min I can see sometimes over 20 meter drift.

@ncoder-1
Copy link
Author

ncoder-1 commented Mar 29, 2020

@garyv100, I've had a USB unit (u-blox driver) running for about 40 minutes and a raw UART (nmea driver) running for about 20 minutes and both aren't showing the drift (other than the normal cold boot drift which is quickly corrected as satellites are received). I suggest you post an issue here: https://gitlab.com/gpsd/gpsd/issues and the main gpsd dev (also named Gary) can maybe help if it's a driver issue with your hardware or within the gpsd code itself. I suggest you link this gist so he can get some context as well. Wish I could be of more help.

edit: are you seeing the same behavior with gpsd's cgps tool?

@garyv100
Copy link

garyv100 commented Mar 29, 2020

@ncoder-1, I am using VK-162 GPS Receiver Dongle Navigation Module USB Interface G-mouse Antenna DEN. I think this is the problem. Not the Linux drivers or software. Can you recommend a different receiver for Linux?
Thank you for your help.
Gary

@ncoder-1
Copy link
Author

@garyv100, I use a GR-8013 USB GPS (one of the rare USB ones that also have PPS) and also the ND-100S which both work well with gpsd.

@garyv100
Copy link

garyv100 commented Mar 29, 2020

@ncoder-1, I tried to lookup GR-8013 USB GPS, but I am coming up w/ all kind of stuff. If you could send me the link - it would be great.
Thanks,
Gary

@ncoder-1
Copy link
Author

@garyv100, they are quite rare now, but this is the one I have: https://www.globalsources.com/gsol/I/PC-PDA/p/sm/1147069913.htm#1147069913

@garyv100
Copy link

garyv100 commented Mar 29, 2020

@ncoder-1, Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment