13 static struct vehicle_priv {
16 struct callback_list *cbl;
20 struct gps_data_t *gps;
33 #define DEFAULT_RETRY_INTERVAL 10 // seconds
34 #define MIN_RETRY_INTERVAL 1 // seconds
36 static gboolean vehicle_gpsd_io(GIOChannel * iochan,
37 GIOCondition condition, gpointer t);
42 vehicle_gpsd_callback(struct gps_data_t *data, char *buf, size_t len,
45 char *pos,*nmea_data_buf;
46 struct vehicle_priv *priv = vehicle_last;
47 if (buf[0] == '$' && len > 0) {
50 memcpy(buffer, buf, len);
51 pos=strchr(buffer,'\n');
54 if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
55 nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, NULL);
56 g_free(priv->nmea_data_buf);
57 priv->nmea_data_buf=nmea_data_buf;
59 dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
63 dbg(1,"data->set=0x%x\n", data->set);
64 // If data->fix.speed is NAN, then the drawing gets jumpy.
65 if (isnan(data->fix.speed)) {
69 if (data->set & SPEED_SET) {
70 priv->speed = data->fix.speed * 3.6;
71 data->set &= ~SPEED_SET;
73 if (data->set & TRACK_SET) {
74 priv->direction = data->fix.track;
75 data->set &= ~TRACK_SET;
77 if (data->set & ALTITUDE_SET) {
78 priv->height = data->fix.altitude;
79 data->set &= ~ALTITUDE_SET;
81 if (data->set & SATELLITE_SET) {
82 priv->sats_used = data->satellites_used;
83 priv->sats = data->satellites;
84 data->set &= ~SATELLITE_SET;
86 if (data->set & STATUS_SET) {
87 priv->status = data->status;
88 data->set &= ~STATUS_SET;
90 if (data->set & PDOP_SET) {
91 dbg(0, "pdop : %g\n", data->pdop);
92 data->set &= ~PDOP_SET;
94 if (data->set & LATLON_SET) {
95 priv->geo.lat = data->fix.latitude;
96 priv->geo.lng = data->fix.longitude;
97 dbg(1,"lat=%f lng=%f\n", priv->geo.lat, priv->geo.lng);
98 g_free(priv->nmea_data);
99 priv->nmea_data=priv->nmea_data_buf;
100 priv->nmea_data_buf=NULL;
101 callback_list_call_0(priv->cbl);
102 data->set &= ~LATLON_SET;
107 * Attempt to open the gps device.
108 * Return FALSE if retry not required
109 * Return TRUE to try again
112 vehicle_gpsd_try_open(gpointer *data)
114 struct vehicle_priv *priv = (struct vehicle_priv *)data;
115 char *source = g_strdup(priv->source);
116 char *colon = index(source + 7, ':');
119 priv->gps = gps_open(source + 7, colon + 1);
121 priv->gps = gps_open(source + 7, NULL);
125 g_warning("gps_open failed for '%s'. Retrying in %d seconds. Have you started gpsd?\n", priv->source, priv->retry_interval);
128 gps_query(priv->gps, priv->gpsd_query);
129 gps_set_raw_hook(priv->gps, vehicle_gpsd_callback);
130 priv->iochan = g_io_channel_unix_new(priv->gps->gps_fd);
132 g_io_add_watch(priv->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP,
133 vehicle_gpsd_io, priv);
134 dbg(0,"Connected to gpsd fd=%d iochan=%p watch=%p\n", priv->gps->gps_fd, priv->iochan, priv->watch);
139 * Open a connection to gpsd. Will re-try the connection if it fails
142 vehicle_gpsd_open(struct vehicle_priv *priv)
145 if (vehicle_gpsd_try_open((gpointer *)priv)) {
146 priv->retry_timer = g_timeout_add(priv->retry_interval*1000, (GSourceFunc)vehicle_gpsd_try_open, (gpointer *)priv);
151 vehicle_gpsd_close(struct vehicle_priv *priv)
153 GError *error = NULL;
156 g_source_remove(priv->watch);
159 if (priv->retry_timer) {
160 g_source_remove(priv->retry_timer);
164 g_io_channel_shutdown(priv->iochan, 0, &error);
168 gps_close(priv->gps);
174 vehicle_gpsd_io(GIOChannel * iochan, GIOCondition condition, gpointer t)
176 struct vehicle_priv *priv = t;
178 dbg(1, "enter condition=%d\n", condition);
179 if (condition == G_IO_IN) {
182 if (gps_poll(priv->gps)) {
183 g_warning("gps_poll failed\n");
184 vehicle_gpsd_close(priv);
185 vehicle_gpsd_open(priv);
194 vehicle_gpsd_destroy(struct vehicle_priv *priv)
196 vehicle_gpsd_close(priv);
198 g_free(priv->source);
199 if (priv->gpsd_query)
200 g_free(priv->gpsd_query);
205 vehicle_gpsd_position_attr_get(struct vehicle_priv *priv,
206 enum attr_type type, struct attr *attr)
209 case attr_position_height:
210 attr->u.numd = &priv->height;
212 case attr_position_speed:
213 attr->u.numd = &priv->speed;
215 case attr_position_direction:
216 attr->u.numd = &priv->direction;
218 case attr_position_sats:
219 attr->u.num = priv->sats;
221 case attr_position_sats_used:
222 attr->u.num = priv->sats_used;
224 case attr_position_coord_geo:
225 attr->u.coord_geo = &priv->geo;
227 case attr_position_nmea:
228 attr->u.str=priv->nmea_data;
239 struct vehicle_methods vehicle_gpsd_methods = {
240 vehicle_gpsd_destroy,
241 vehicle_gpsd_position_attr_get,
244 static struct vehicle_priv *
245 vehicle_gpsd_new_gpsd(struct vehicle_methods
246 *meth, struct callback_list
247 *cbl, struct attr **attrs)
249 struct vehicle_priv *ret;
250 struct attr *source, *query, *retry_int;
253 source = attr_search(attrs, NULL, attr_source);
254 ret = g_new0(struct vehicle_priv, 1);
255 ret->source = g_strdup(source->u.str);
256 query = attr_search(attrs, NULL, attr_gpsd_query);
258 ret->gpsd_query = g_strconcat(query->u.str, "\n", NULL);
260 ret->gpsd_query = g_strdup("w+x\n");
262 dbg(1,"Format string for gpsd_query: %s\n",ret->gpsd_query);
263 retry_int = attr_search(attrs, NULL, attr_retry_interval);
265 ret->retry_interval = retry_int->u.num;
266 if (ret->retry_interval < MIN_RETRY_INTERVAL) {
267 dbg(0, "Retry interval %d too small, setting to %d\n", ret->retry_interval, MIN_RETRY_INTERVAL);
268 ret->retry_interval = MIN_RETRY_INTERVAL;
271 dbg(0, "Retry interval not defined, setting to %d\n", DEFAULT_RETRY_INTERVAL);
272 ret->retry_interval = DEFAULT_RETRY_INTERVAL;
275 *meth = vehicle_gpsd_methods;
276 vehicle_gpsd_open(ret);
284 plugin_register_vehicle_type("gpsd", vehicle_gpsd_new_gpsd);