16 static void vehicle_file_disable_watch(struct vehicle_priv *priv);
17 static void vehicle_file_enable_watch(struct vehicle_priv *priv);
20 file_type_pipe = 1, file_type_device, file_type_file
23 static int buffer_size = 256;
27 enum file_type file_type;
28 struct callback_list *cbl;
45 vehicle_file_open(struct vehicle_priv *priv)
51 name = priv->source + 5;
52 if (!strncmp(priv->source, "file:", 5)) {
53 priv->fd = open(name, O_RDONLY | O_NDELAY);
57 if (S_ISREG(st.st_mode)) {
58 priv->file_type = file_type_file;
60 tcgetattr(priv->fd, &tio);
62 cfsetispeed(&tio, B4800);
63 cfsetospeed(&tio, B4800);
66 tcsetattr(priv->fd, TCSANOW, &tio);
67 priv->file_type = file_type_device;
70 priv->file = popen(name, "r");
73 priv->fd = fileno(priv->file);
74 priv->file_type = file_type_pipe;
76 priv->iochan = g_io_channel_unix_new(priv->fd);
81 vehicle_file_close(struct vehicle_priv *priv)
85 g_io_channel_shutdown(priv->iochan, 0, &error);
90 else if (priv->fd >= 0)
97 vehicle_file_enable_watch_timer(gpointer t)
99 struct vehicle_priv *priv = t;
100 vehicle_file_enable_watch(priv);
108 vehicle_file_parse(struct vehicle_priv *priv, char *buffer)
113 int len = strlen(buffer);
114 unsigned char csum = 0;
116 dbg(1, "buffer='%s'\n", buffer);
119 dbg(0, "too short\n");
122 if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')
123 buffer[--len] = '\0';
127 if (buffer[0] != '$') {
128 dbg(0, "no leading $\n");
131 if (buffer[len - 3] != '*') {
135 for (i = 1; i < len - 3; i++) {
136 csum ^= (unsigned char) (buffer[i]);
138 if (!sscanf(buffer + len - 2, "%x", &bcsum)) {
139 dbg(0, "no checksum\n");
143 dbg(0, "wrong checksum\n");
151 while (*p && *p != ',')
158 if (!strncmp(buffer, "$GPGGA", 6)) {
160 0 1 2 3 4 5 6 7 8 9 0 1234
161 $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
162 UTC of Fix[1],Latitude[2],N/S[3],Longitude[4],E/W[5],Quality(0=inv,1=gps,2=dgps)[6],Satelites used[7],
163 HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
165 sscanf(item[2], "%lf", &lat);
166 priv->geo.lat = floor(lat / 100);
167 lat -= priv->geo.lat * 100;
168 priv->geo.lat += lat / 60;
170 sscanf(item[4], "%lf", &lng);
171 priv->geo.lng = floor(lng / 100);
172 lng -= priv->geo.lng * 100;
173 priv->geo.lng += lng / 60;
175 sscanf(item[6], "%d", &priv->status);
176 sscanf(item[7], "%d", &priv->sats_used);
177 sscanf(item[9], "%lf", &priv->height);
179 callback_list_call_0(priv->cbl);
180 if (priv->file_type == file_type_file) {
181 vehicle_file_disable_watch(priv);
183 vehicle_file_enable_watch_timer,
187 if (!strncmp(buffer, "$GPVTG", 6)) {
189 $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
190 Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
191 Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
193 sscanf(item[1], "%lf", &priv->direction);
194 sscanf(item[7], "%lf", &priv->speed);
196 if (!strncmp(buffer, "$GPRMC", 6)) {
198 0 1 2 3 4 5 6 7 8 9 0 1
199 $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
200 Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
201 magnetic variation[10],magnetic variation direction[11]
203 sscanf(item[8], "%lf", &priv->direction);
204 sscanf(item[7], "%lf", &priv->speed);
205 priv->speed *= 1.852;
210 vehicle_file_io(GIOChannel * iochan, GIOCondition condition, gpointer t)
212 struct vehicle_priv *priv = t;
216 dbg(1, "enter condition=%d\n", condition);
217 if (condition == G_IO_IN) {
219 read(g_io_channel_unix_get_fd(iochan),
220 priv->buffer + priv->buffer_pos,
221 buffer_size - priv->buffer_pos - 1);
223 vehicle_file_close(priv);
224 vehicle_file_open(priv);
227 priv->buffer_pos += size;
228 priv->buffer[priv->buffer_pos] = '\0';
229 dbg(1, "size=%d pos=%d buffer='%s'\n", size,
230 priv->buffer_pos, priv->buffer);
232 while ((tok = index(str, '\n'))) {
234 dbg(1, "line='%s'\n", str);
235 vehicle_file_parse(priv, str);
238 if (str != priv->buffer) {
239 size = priv->buffer + priv->buffer_pos - str;
240 memmove(priv->buffer, str, size + 1);
241 priv->buffer_pos = size;
242 dbg(1, "now pos=%d buffer='%s'\n",
243 priv->buffer_pos, priv->buffer);
244 } else if (priv->buffer_pos == buffer_size - 1) {
246 "Overflow. Most likely wrong baud rate or no nmea protocol\n");
247 priv->buffer_pos = 0;
255 vehicle_file_enable_watch(struct vehicle_priv *priv)
258 g_io_add_watch(priv->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP,
259 vehicle_file_io, priv);
263 vehicle_file_disable_watch(struct vehicle_priv *priv)
266 g_source_remove(priv->watch);
272 vehicle_file_destroy(struct vehicle_priv *priv)
274 vehicle_file_close(priv);
276 g_free(priv->source);
278 g_free(priv->buffer);
283 vehicle_file_position_attr_get(struct vehicle_priv *priv,
284 enum attr_type type, struct attr *attr)
287 case attr_position_height:
288 attr->u.numd = &priv->height;
290 case attr_position_speed:
291 attr->u.numd = &priv->speed;
293 case attr_position_direction:
294 attr->u.numd = &priv->direction;
296 case attr_position_sats_used:
297 attr->u.num = priv->sats_used;
299 case attr_position_coord_geo:
300 attr->u.coord_geo = &priv->geo;
309 struct vehicle_methods vehicle_file_methods = {
310 vehicle_file_destroy,
311 vehicle_file_position_attr_get,
314 static struct vehicle_priv *
315 vehicle_file_new_file(struct vehicle_methods
316 *meth, struct callback_list
317 *cbl, struct attr **attrs)
319 struct vehicle_priv *ret;
323 source = attr_search(attrs, NULL, attr_source);
324 ret = g_new0(struct vehicle_priv, 1);
327 ret->source = g_strdup(source->u.str);
328 ret->buffer = g_malloc(buffer_size);
329 *meth = vehicle_file_methods;
330 if (vehicle_file_open(ret)) {
331 vehicle_file_enable_watch(ret);
334 dbg(0, "Failed to open '%s'\n", ret->source);
335 vehicle_file_destroy(ret);
343 plugin_register_vehicle_type("file", vehicle_file_new_file);
344 plugin_register_vehicle_type("pipe", vehicle_file_new_file);