21 static void vehicle_file_disable_watch(struct vehicle_priv *priv);
22 static void vehicle_file_enable_watch(struct vehicle_priv *priv);
23 static void vehicle_file_parse(struct vehicle_priv *priv, char *buffer);
24 static int vehicle_file_open(struct vehicle_priv *priv);
25 static void vehicle_file_close(struct vehicle_priv *priv);
29 file_type_pipe = 1, file_type_device, file_type_file
32 static int buffer_size = 256;
36 enum file_type file_type;
37 struct callback_list *cbl;
61 static int vehicle_win32_serial_track(struct vehicle_priv *priv)
64 static char buffer[2048] = {0,};
65 static int current_index = 0;
66 const int chunk_size = 1024;
68 if ( priv->no_data_count > 5 )
70 vehicle_file_close( priv );
71 priv->no_data_count = 0;
76 vehicle_file_open( priv );
79 if ( current_index >= ( sizeof( buffer ) - chunk_size ) )
83 memset( buffer, 0 , sizeof( buffer ) );
86 int dwBytes = serial_io_read( priv->fd, &buffer[ current_index ], chunk_size );
89 current_index += dwBytes;
91 char* return_pos = NULL;
92 while ( ( return_pos = strchr( buffer, '\n' ) ) != NULL )
94 char return_buffer[1024];
95 int bytes_to_copy = return_pos - buffer + 1;
96 memcpy( return_buffer, buffer, bytes_to_copy );
97 return_buffer[ bytes_to_copy + 1 ] = '\0';
99 // printf( "received %d : '%s' bytes to copy\n", bytes_to_copy, return_buffer );
100 vehicle_file_parse( priv, return_buffer );
102 current_index -= bytes_to_copy;
103 memmove( buffer, &buffer[ bytes_to_copy ] , sizeof( buffer ) - bytes_to_copy );
109 priv->no_data_count++;
116 vehicle_file_open(struct vehicle_priv *priv)
119 dbg(1, "enter vehicle_file_open, priv->source='%s'\n", priv->source);
123 char* raw_setting_str = g_strdup( priv->source );
125 char* strport = strchr(raw_setting_str, ':' );
126 char* strsettings = strchr(raw_setting_str, ' ' );
128 if ( strport && strsettings )
134 dbg(1, "calling serial_io_init('%s', '%s')\n", strport, strsettings );
135 priv->fd=serial_io_init( strport, strsettings );
137 g_free( raw_setting_str );
144 name = priv->source + 5;
145 if (!strncmp(priv->source, "file:", 5)) {
146 priv->fd = open(name, O_RDONLY | O_NDELAY);
150 if (S_ISREG(st.st_mode)) {
151 priv->file_type = file_type_file;
153 tcgetattr(priv->fd, &tio);
155 cfsetispeed(&tio, B4800);
156 cfsetospeed(&tio, B4800);
159 tcsetattr(priv->fd, TCSANOW, &tio);
160 priv->file_type = file_type_device;
163 priv->file = popen(name, "r");
166 priv->fd = fileno(priv->file);
167 priv->file_type = file_type_pipe;
169 priv->iochan = g_io_channel_unix_new(priv->fd);
175 vehicle_file_close(struct vehicle_priv *priv)
178 serial_io_shutdown( priv->fd );
180 GError *error = NULL;
182 g_io_channel_shutdown(priv->iochan, 0, &error);
187 else if (priv->fd >= 0)
195 vehicle_file_enable_watch_timer(gpointer t)
197 struct vehicle_priv *priv = t;
198 vehicle_file_enable_watch(priv);
206 vehicle_file_parse(struct vehicle_priv *priv, char *buffer)
208 char *nmea_data_buf, *p, *item[16];
211 int len = strlen(buffer);
212 unsigned char csum = 0;
214 dbg(1, "buffer='%s'\n", buffer);
217 dbg(0, "'%s' too short\n", buffer);
220 if (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')
221 buffer[--len] = '\0';
225 if (buffer[0] != '$') {
226 dbg(0, "no leading $ in '%s'\n", buffer);
229 if (buffer[len - 3] != '*') {
230 dbg(0, "no *XX in '%s'\n", buffer);
233 for (i = 1; i < len - 3; i++) {
234 csum ^= (unsigned char) (buffer[i]);
236 if (!sscanf(buffer + len - 2, "%x", &bcsum)) {
237 dbg(0, "no checksum in '%s'\n", buffer);
241 dbg(0, "wrong checksum in '%s'\n", buffer);
245 if (!priv->nmea_data_buf || strlen(priv->nmea_data_buf) < 65536) {
246 nmea_data_buf=g_strconcat(priv->nmea_data_buf ? priv->nmea_data_buf : "", buffer, "\n", NULL);
247 g_free(priv->nmea_data_buf);
248 priv->nmea_data_buf=nmea_data_buf;
250 dbg(0, "nmea buffer overflow, discarding '%s'\n", buffer);
256 while (*p && *p != ',')
263 if (!strncmp(buffer, "$GPGGA", 6)) {
265 0 1 2 3 4 5 6 7 8 9 0 1234
266 $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C
267 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],
268 HDOP[8],Altitude[9],"M"[10],height of geoid[11], "M"[12], time since dgps update[13], dgps ref station [14]
270 lat = g_ascii_strtod(item[2], NULL);
271 priv->geo.lat = floor(lat / 100);
272 lat -= priv->geo.lat * 100;
273 priv->geo.lat += lat / 60;
275 if (!strcasecmp(item[3],"S"))
276 priv->geo.lat=-priv->geo.lat;
278 lng = g_ascii_strtod(item[4], NULL);
279 priv->geo.lng = floor(lng / 100);
280 lng -= priv->geo.lng * 100;
281 priv->geo.lng += lng / 60;
283 if (!strcasecmp(item[5],"W"))
284 priv->geo.lng=-priv->geo.lng;
286 sscanf(item[6], "%d", &priv->status);
287 sscanf(item[7], "%d", &priv->sats_used);
288 priv->height = g_ascii_strtod(item[9], NULL);
289 g_free(priv->nmea_data);
290 priv->nmea_data=priv->nmea_data_buf;
291 priv->nmea_data_buf=NULL;
293 callback_list_call_0(priv->cbl);
296 if (priv->file_type == file_type_file) {
297 vehicle_file_disable_watch(priv);
298 g_timeout_add(priv->time,
299 vehicle_file_enable_watch_timer,
304 if (!strncmp(buffer, "$GPVTG", 6)) {
306 $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A
307 Course Over Ground Degrees True[1],"T"[2],Course Over Ground Degrees Magnetic[3],"M"[4],
308 Speed in Knots[5],"N"[6],"Speed in KM/H"[7],"K"[8]
310 priv->direction = g_ascii_strtod( item[1], NULL );
311 priv->speed = g_ascii_strtod( item[7], NULL );
313 if (!strncmp(buffer, "$GPRMC", 6)) {
315 0 1 2 3 4 5 6 7 8 9 0 1
316 $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
317 Time[1],Active/Void[2],lat[3],N/S[4],long[5],W/E[6],speed in knots[7],track angle[8],date[9],
318 magnetic variation[10],magnetic variation direction[11]
320 priv->direction = g_ascii_strtod( item[8], NULL );
321 priv->speed = g_ascii_strtod( item[7], NULL );
322 priv->speed *= 1.852;
328 vehicle_file_io(GIOChannel * iochan, GIOCondition condition, gpointer t)
330 struct vehicle_priv *priv = t;
334 dbg(1, "enter condition=%d\n", condition);
335 if (condition == G_IO_IN) {
337 read(g_io_channel_unix_get_fd(iochan),
338 priv->buffer + priv->buffer_pos,
339 buffer_size - priv->buffer_pos - 1);
341 switch (priv->on_eof) {
343 vehicle_file_close(priv);
344 vehicle_file_open(priv);
354 priv->buffer_pos += size;
355 priv->buffer[priv->buffer_pos] = '\0';
356 dbg(1, "size=%d pos=%d buffer='%s'\n", size,
357 priv->buffer_pos, priv->buffer);
359 while ((tok = index(str, '\n'))) {
361 dbg(1, "line='%s'\n", str);
362 vehicle_file_parse(priv, str);
365 if (str != priv->buffer) {
366 size = priv->buffer + priv->buffer_pos - str;
367 memmove(priv->buffer, str, size + 1);
368 priv->buffer_pos = size;
369 dbg(1, "now pos=%d buffer='%s'\n",
370 priv->buffer_pos, priv->buffer);
371 } else if (priv->buffer_pos == buffer_size - 1) {
373 "Overflow. Most likely wrong baud rate or no nmea protocol\n");
374 priv->buffer_pos = 0;
383 vehicle_file_enable_watch(struct vehicle_priv *priv)
386 g_timeout_add(500, vehicle_win32_serial_track, priv);
389 g_io_add_watch(priv->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP,
390 vehicle_file_io, priv);
395 vehicle_file_disable_watch(struct vehicle_priv *priv)
399 g_source_remove(priv->watch);
406 vehicle_file_destroy(struct vehicle_priv *priv)
408 vehicle_file_close(priv);
410 g_free(priv->source);
412 g_free(priv->buffer);
417 vehicle_file_position_attr_get(struct vehicle_priv *priv,
418 enum attr_type type, struct attr *attr)
421 case attr_position_height:
422 attr->u.numd = &priv->height;
424 case attr_position_speed:
425 attr->u.numd = &priv->speed;
427 case attr_position_direction:
428 attr->u.numd = &priv->direction;
430 case attr_position_sats_used:
431 attr->u.num = priv->sats_used;
433 case attr_position_coord_geo:
434 attr->u.coord_geo = &priv->geo;
436 case attr_position_nmea:
437 attr->u.str=priv->nmea_data;
448 struct vehicle_methods vehicle_file_methods = {
449 vehicle_file_destroy,
450 vehicle_file_position_attr_get,
453 static struct vehicle_priv *
454 vehicle_file_new_file(struct vehicle_methods
455 *meth, struct callback_list
456 *cbl, struct attr **attrs)
458 struct vehicle_priv *ret;
464 source = attr_search(attrs, NULL, attr_source);
465 ret = g_new0(struct vehicle_priv, 1);
468 ret->source = g_strdup(source->u.str);
469 ret->buffer = g_malloc(buffer_size);
471 time = attr_search(attrs, NULL, attr_time);
473 ret->time=time->u.num;
474 on_eof = attr_search(attrs, NULL, attr_on_eof);
475 if (on_eof && !strcasecmp(on_eof->u.str, "stop"))
477 if (on_eof && !strcasecmp(on_eof->u.str, "exit"))
479 dbg(0,"on_eof=%d\n", ret->on_eof);
480 *meth = vehicle_file_methods;
481 if (vehicle_file_open(ret)) {
482 vehicle_file_enable_watch(ret);
487 ret->no_data_count = 0;
489 dbg(0, "Failed to open '%s'\n", ret->source);
490 vehicle_file_destroy(ret);
498 plugin_register_vehicle_type("file", vehicle_file_new_file);
499 plugin_register_vehicle_type("pipe", vehicle_file_new_file);