# `libgpsd_core.c`

Functions:- | Direct access to GPSes on serial or USB devices.
--- | ---
Notes based mostly on code as of Mon Apr 5 21:38:06 2010 -040.

`void gpsd_log(const struct errout_t, int errlevel, const char *fmt, ... )`

This code is used for error reporting, but is dependant on SQUELCH_DISABLE so that embedded systems (for example) are not burdened with unnecessary noise. The first thing to check is if the error level offered is high enough to be of interest (controlled by the debug level we are running at).

If we are interested, the first step is to protect the code with a mutex if we are using the 1PPS input.

Now we build a message buffer which has a fixed header (gpsd: ) and the incoming data. The output buffer is prepared (load the start with a NULL) and then the input buffer is scanned, byte-by-byte, up to its terminating NULL. The scanned data is transferred on the fly to the output buffer subject to the following tests:-

If the character is printable, it passes through unchanged.

If it is a space and either of the next two bytes is NULL it will also pass through unchanged.

In any other case, it is copied across as a hexadecimal string like x09.

The completed output buffer is then either sent to the system logger if we are in background mode (daemon) or to the stderr file if we are in foreground mode.

`int gpsd_switch_driver(struct gps_device_t *session, char* typename)`

Test if the function is called with the same name as the active driver.

If it is, test if the driver has a configurator function and is able to be reconfigured. A good result here will call the driver event hook with type 'driver_switch', and return a 0.

For an entry with a different driver name, scan all available drivers to see if the wanted one is there. An unmatched name exits, returning 0.

If we got a match, get the baudrate for the device with `gpsd_assert_sync()`, probe for the subtype if we have one.

If the device has a configurator and is reconfigurable, trigger the configurator.

Return a 1 to indicate a device switch.

`void gpsd_init(struct gps_device_t *session, struct gps_context_t *context, const char *device)` | Copy the device name to the session data structure, initialise important data fields and call `gpsd_tty_init()`, `gpsd_zero_satellites()` and `packet_reset()`.
`void gpsd_deactivate(struct gps_device_t *session)` | All actions below, except the last one are conditional on the `ntpd` interface being compiled in. Release the `ntpd` resources, including the 1PPS resources if they are active. If the device has a revert function, trigger it. If it has an NMEA mode switcher, invoke it. If it has a wrapup routine, invoke it. Finally, close the device.

`static void *gpsd_ppsmonitor(void *arg)`

An `ioctl()` call is made which returns either 0 if the status of the port changed, or an error.

If we got a change, we read the modem control bits and extract the 1PPS information.

We check the returned value and see if it has changed recently. A counter of 10 unchanged events will disable further testing.

If we are still hanging in there, we now see if we already have had more than 4 good fixes, otherwise we can't trust the 1PPS.

We then finally test the pulse duration. If it is either a genuine 1PPS or a 2Hz square wave, we call `ntpshm_pps()`.

Short or long PPS pulses are dropped with an error report.

`int gpsd_activate(struct gps_device_t *session, bool reconfigurable)`

If the devicename matches an NTRIP or DGNSS URI, hand off to special code for opening a socket to that source over the network.

Try and open the device, returning -1 if we fail.

Probe all possible drivers to see if one recognises the device.

Set some fundamental data to a clean value.

Handle the initialisation of NTP and 1PPS functions if needed.

If we did succeed in probing some device type, try and get the subtype.

If we need to do so, we now configure the device.

Finally, signal success by returning the file descriptor given by the device open call.

`void gpsd_error_model(struct gps_device_t *session, struct gps_fix_t *fix, struct gps_fix_t *oldfix)`

Check we have a 2D fix (or better) and if the gps didn't provide an eph value, use the HDOP to calculate one or fail to NAN.

Do the same with epv/VDOP if we have a 3D or better fix.

Do the same with epe/PDOP.

Consider speed error; check if we have two fixes with differing timestamps and use their times and eph values to calculate the speed.

If we have two valid 3D fixes, we can calculate the climb/sink rate.

Finally, just before exiting, save this fix as the old fix for the next comparison round.

`gps_mask_t gpsd_poll(struct gps_device_t *session)`

Make a call to `gps_clear_fix()` to prepare the newdata structure to receive data from an incoming packet.

Check if we know the device type. If we do, stash the count of of characters we are able to get from it.

If the read has given a full packet, we can call the subtype probing method, if the device supports it.

If we don't know the device type, try and figure out what it is, exiting if we can't.

Make some checks if the device is offline or the packet is incomplete, using the stashed count of characters and the full packet indicator.

If a full packet is available, we try to get the fix data and update the main data structure. We also compute the DOPs so we can fill them in if they are not included in the gps device output.

Mopst of the possible driver events are called from somewhere in here.

`void gpsd_wrap(struct gps_device_t *session)` | Simple call to `gpsd_deactivate(session)`.
`void gpsd_zero_satellites(struct gps_data_t *out)` | Zero the status data for all satellites.