Using libgps instead of libQgpsmm within a Qt application


I was in need of creating a Qt application using current Debian stable (Stretch) and gpsd. I could have used libQgpsmm which creates a QTcpSocket for stablishing the connection to the gpsd daemon. But then I hit an issue: libQgpsmm was switched to Qt 5 after the Strech release, namely in gpsd 3.17-4. And I'm using Qt 5.

So the next thing to do is to use libgps itself, which is written in C. In this case one needs to call [gps_open()]{style="font-family: \"Courier New\", Courier, monospace;"} to open a connection, [gps_stream()]{style="font-family: \"Courier New\", Courier, monospace;"} to ask for the needed stream... and use [gps_waiting()]{style="font-family: \"Courier New\", Courier, monospace;"} to poll the socket for data.
[
]{style="font-family: \"Courier New\", Courier, monospace;"}[gps_waiting()]{style="font-family: \"Courier New\", Courier, monospace;"} checks for data for a maximum of time specified in it's parameters. That means I would need to create a QTimer and poll it to get the data. Poll it fast enough for the application to be responsive, but not too excessively to avoid useless CPU cycles.

I did not like this idea, so I started digging gpsd's code until I found that it exposes the socket it uses in it's base struct, [struct gps_data_t]{style="font-family: \"Courier New\", Courier, monospace;"}'s [gps_fd]{style="font-family: \"Courier New\", Courier, monospace;"}. So the next step was to set up a QSocketNotifier around it, and use it's [activated()]{style="font-family: \"Courier New\", Courier, monospace;"} signal.

So (very) basically:

[// Class private:]{style="font-family: \"Courier New\", Courier, monospace;"}
[struct gps_data_t mGpsData; ]{style="font-family: \"Courier New\", Courier, monospace;"}
[QSocketNotifier * mNotifier;]{style="font-family: \"Courier New\", Courier, monospace;"}
[
]{style="font-family: \"Courier New\", Courier, monospace;"}[// In the implementation:]{style="font-family: \"Courier New\", Courier, monospace;"}
[result = gps_open("localhost", DEFAULT_GPSD_PORT, &mGpsData);]{style="font-family: \"Courier New\", Courier, monospace;"}
[// [...check result status...]]{style="font-family: \"Courier New\", Courier, monospace;"}

[result = gps_stream(&mGPSData,WATCH_ENABLE|WATCH_JSON, NULL);]{style="font-family: \"Courier New\", Courier, monospace;"}
[// [...check result status...]]{style="font-family: \"Courier New\", Courier, monospace;"}

[//  Set up the QSocketNotifier instance.]{style="font-family: \"Courier New\", Courier, monospace;"}
[mNotifier = new QSocketNotifier(mGpsData.gps_fd, QSocketNotifier::Read, this); ]{style="font-family: \"Courier New\", Courier, monospace;"}

[connect(mNotifier, &QSocketNotifier::activated, this, &MyGps::readData);]{style="font-family: \"Courier New\", Courier, monospace;"}

And of course, calling [gps_read(&mGpsData)]{style="font-family: \"Courier New\", Courier, monospace;"} in [MyGps::readData()]{style="font-family: \"Courier New\", Courier, monospace;"}. With this every time there is activity on the socket readData() will be called, an no need to set up a timer anymore.

Comments


There are no comments yet.

Add a Comment

You can use the Markdown syntax to format your comment.

Comment Atom Feed