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() to poll the socket for data.
[
]{style="font-family: \"Courier New\", Courier, monospace;"}gps_waiting() 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() signal.

So (very) basically:

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

result = gps_stream(&mGPSData,WATCH_ENABLE|WATCH_JSON, NULL);
// [...check result status...]

//  Set up the QSocketNotifier instance.
mNotifier = new QSocketNotifier(mGpsData.gps_fd, QSocketNotifier::Read, this); 

connect(mNotifier, &QSocketNotifier::activated, this, &MyGps::readData);

And of course, calling gps_read(&mGpsData)]{style="font-family: \"Courier New\", Courier, monospace;"} in [MyGps::readData(). 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