]> git.itanic.dy.fi Git - maemo-mapper/blob - src/aprs.c
Conditional compilation for Maemo-only features
[maemo-mapper] / src / aprs.c
1 /*
2  * 
3  * This file is part of Maemo Mapper.
4  *
5  * Maemo Mapper is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Maemo Mapper is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
17  * 
18  * 
19  * Parts of this code have been ported from Xastir by Rob Williams (10 Aug 2008):
20  * 
21  *  * XASTIR, Amateur Station Tracking and Information Reporting
22  * Copyright (C) 1999,2000  Frank Giannandrea
23  * Copyright (C) 2000-2007  The Xastir Group
24  * 
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #    include "config.h"
29 #endif
30
31 #ifdef INCLUDE_APRS
32
33 #define _GNU_SOURCE
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38 #include "data.h"
39
40 #include <pthread.h>
41
42 #include <libgnomevfs/gnome-vfs.h>
43 #include <libgnomevfs/gnome-vfs-inet-connection.h>
44 #include <errno.h>
45 #include "aprs_display.h"
46
47 #ifndef LEGACY
48 #    include <hildon/hildon-note.h>
49 #    include <hildon/hildon-banner.h>
50 #else
51 #    include <hildon-widgets/hildon-note.h>
52 #    include <hildon-widgets/hildon-banner.h>
53 #endif
54
55 #include "types.h"
56 #include "data.h"
57 #include "defines.h"
58
59 #include "display.h"
60 #include "aprs.h"
61 #include "gps.h"
62
63 #ifdef HAVE_LIBGPSBT
64 #    include "gpsbt.h"
65 #endif
66
67 #include "path.h"
68 #include "util.h"
69
70 #include "aprs_decode.h"
71
72 static volatile GThread*        _aprs_inet_thread = NULL;
73 static volatile GThread*    _aprs_tty_thread = NULL;
74
75 static GMutex*                          _aprs_inet_init_mutex = NULL;
76 static GMutex*                          _aprs_tty_init_mutex = NULL;
77
78 static gint                             _aprs_rcvr_retry_count = 0;
79
80 static guint _aprs_inet_beacon_timer;
81 static guint _aprs_tty_beacon_timer;
82
83
84 #define VERSIONFRM      "APRS"
85 extern AprsDataRow*                     n_first;  // pointer to first element in name sorted station list
86
87
88
89 TWriteBuffer _write_buffer[APRS_PORT_COUNT];
90
91 gboolean send_line(gchar* text, gint text_len, TAprsPort port);
92 void port_read() ;
93 void aprs_tty_disconnect();
94
95 static gboolean aprs_handle_error_idle(gchar *error)
96 {
97     printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
98
99     /* Ask for re-try. */
100     if(++_aprs_rcvr_retry_count > 2)
101     {
102         GtkWidget *confirm;
103         gchar buffer[BUFFER_SIZE];
104
105         /* Reset retry count. */
106         _aprs_rcvr_retry_count = 0;
107
108         snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
109         confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
110
111         aprs_server_disconnect();
112
113         if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
114         {
115             aprs_server_connect(); /* Try again. */
116         }
117         else
118         {
119             /* Reset Connect to APRS menu item. */
120             gtk_check_menu_item_set_active(
121                     GTK_CHECK_MENU_ITEM(_menu_enable_aprs_inet_item), FALSE);
122         }
123
124         /* Ask user to re-connect. */
125         gtk_widget_destroy(confirm);
126     }
127     else
128     {
129         aprs_server_disconnect();
130         aprs_server_connect(); /* Try again. */
131     }
132
133     g_free(error);
134
135     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
136     return FALSE;
137 }
138
139
140 /**
141  * Set the connection state.  This function controls all connection-related
142  * banners.
143  */
144 void set_aprs_tty_conn_state(ConnState new_conn_state)
145 {
146     printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
147
148     switch(_aprs_tty_state = new_conn_state)
149     {
150         case RCVR_OFF:
151         case RCVR_FIXED:
152         case RCVR_UP:  
153           if(_connect_banner)
154             {
155                 gtk_widget_destroy(_connect_banner);
156                 _connect_banner = NULL;
157             }
158           
159           
160                 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
161                 
162                 if(_aprs_enable && _aprs_tty_enable 
163                                 && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
164                                 _aprs_tty_beacon_timer = g_timeout_add(_aprs_tty_beacon_interval*1000 , timer_callback_aprs_tty, NULL);
165                 
166                 
167                 _aprs_rcvr_retry_count = 0;
168             break;
169         case RCVR_DOWN:
170             if(!_connect_banner)
171                 _connect_banner = hildon_banner_show_animation(
172                         _window, NULL, _("Attempting to connect to TNC"));
173             
174             if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
175                 
176                 
177             break;
178
179         default: ; /* to quell warning. */
180     }
181
182     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
183 }
184
185 /**
186  * Set the connection state.  This function controls all connection-related
187  * banners.
188  */
189 void set_aprs_inet_conn_state(ConnState new_conn_state)
190 {
191     printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
192
193     switch(_aprs_inet_state = new_conn_state)
194     {
195         case RCVR_OFF:
196         case RCVR_FIXED:
197         case RCVR_UP:  
198           if(_connect_banner)
199             {
200                 gtk_widget_destroy(_connect_banner);
201                 _connect_banner = NULL;
202             }
203             if(_fix_banner)
204             {
205                 gtk_widget_destroy(_fix_banner);
206                 _fix_banner = NULL;
207             }
208             
209             if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
210                 
211             if(_aprs_enable && _aprs_inet_enable 
212                         && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
213                 _aprs_inet_beacon_timer = g_timeout_add(_aprs_inet_beacon_interval*1000 , timer_callback_aprs_inet, NULL);
214                         
215                 
216             break;
217         case RCVR_DOWN:
218             if(_fix_banner)
219             {
220                 gtk_widget_destroy(_fix_banner);
221                 _fix_banner = NULL;
222             }
223             if(!_connect_banner)
224                 _connect_banner = hildon_banner_show_animation(
225                         _window, NULL, _("Attempting to connect to APRS server"));
226             
227             if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
228             break;
229
230         default: ; /* to quell warning. */
231     }
232
233     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
234 }
235
236
237 static gboolean aprs_parse_server_packet(gchar *packet)
238 {
239     decode_ax25_line(packet, APRS_PORT_INET);
240
241     g_free(packet);
242
243     return FALSE;
244 }
245
246
247 void update_aprs_inet_options(gboolean force)
248 {
249         // If auto filter is not or we are not connected then stop
250         if(!_aprs_server_auto_filter_on 
251                         || !_aprs_enable 
252                         || !_aprs_inet_enable 
253                         || _aprs_server_auto_filter_km <= 0) return ;
254         
255
256         // Disconnect
257         aprs_server_disconnect();
258         //Re-connect
259         aprs_server_connect();
260         
261 }
262
263 gchar *create_aprs_inet_options_string()
264 {
265         gint current_lat = (gint)round(_gps.lat);
266         gint current_lon = (gint)round(_gps.lon);
267         gchar *filter = NULL;
268         
269         filter = g_strdup_printf("user %s pass %s vers %s v%s filter r/%d/%d/%d \r\n ",
270                         _aprs_mycall, _aprs_inet_server_validation, PACKAGE, VERSION,
271                         current_lat, current_lon, _aprs_server_auto_filter_km );
272         
273         return filter;
274 }
275
276
277 static void thread_read_server()
278 {
279     gchar buf[APRS_BUFFER_SIZE];
280     gchar *buf_curr = buf;
281     gchar *buf_last = buf + sizeof(buf) - 1;
282     GnomeVFSFileSize bytes_read;
283     GnomeVFSResult vfs_result;
284     GnomeVFSInetConnection *iconn = NULL;
285     GnomeVFSSocket *socket = NULL;
286     GThread *my_thread = g_thread_self();
287     gboolean error = FALSE;
288
289     printf("%s(%s)\n", __PRETTY_FUNCTION__, _aprs_server);
290
291     
292     //fprintf(stderr, "Starting thread...\n");
293     
294     /* Lock/Unlock the mutex to ensure that _aprs_inet_thread is done being set. */
295     g_mutex_lock(_aprs_inet_init_mutex);
296     g_mutex_unlock(_aprs_inet_init_mutex);
297     
298     if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
299     {
300         gint tryno;
301
302         /* Attempt to connect to APRS server. */
303         for(tryno = 0; tryno < 10; tryno++)
304         {
305             /* Create a socket to interact with server. */
306             GTimeVal timeout = { 1000, 0 };
307             gchar *filter = create_aprs_inet_options_string();
308             //fprintf(stderr, filter);              
309
310             if(GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create(
311                             &iconn,
312                             _aprs_server,
313                             _aprs_server_port,
314                             NULL))
315                || NULL == ( socket = gnome_vfs_inet_connection_to_socket(iconn))
316                || GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_set_timeout(
317                            socket, &timeout, NULL))
318                || GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_write( socket,
319                                                 filter, strlen(filter), &bytes_read, NULL))
320               )
321             {
322                 g_free(filter);
323                 sleep(1);
324             }
325             else
326             {
327                 g_free(filter);
328                 break;
329             }
330         }
331
332
333         if(!iconn)
334         {
335             g_printerr("Error connecting to APRS server: (%d) %s\n",
336                     vfs_result, gnome_vfs_result_to_string(vfs_result));
337             g_idle_add((GSourceFunc)aprs_handle_error_idle,
338                     g_strdup_printf("%s",
339                     _("Error connecting to APRS server.")));
340             error = TRUE;
341         }
342     }
343     
344
345     if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
346     {
347         
348         set_aprs_inet_conn_state(RCVR_UP);
349
350         while(my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
351         {
352             gchar *eol;
353             
354                 
355             vfs_result = gnome_vfs_socket_read( 
356                         socket,
357                     buf,
358                     buf_last - buf_curr,
359                     &bytes_read,
360                     NULL);
361             
362   
363             if(vfs_result != GNOME_VFS_OK)
364             {
365                 if(my_thread == _aprs_inet_thread)
366                 {
367                     // Error wasn't user-initiated. 
368                     g_idle_add((GSourceFunc)aprs_handle_error_idle,
369                             g_strdup_printf("%s %u",
370                                 _("Error reading APRS data."), vfs_result));
371
372                 }
373
374                 fprintf(stderr, "Read error: %s\n", gnome_vfs_result_to_string(vfs_result));
375                 error = TRUE;
376                 break;
377             }
378
379             /* Loop through the buffer and read each packet. */
380             buf_curr += bytes_read;
381             *buf_curr = '\0'; /* append a \0 so we can read as string */
382             while(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL 
383                         && (eol = strchr(buf, '\n')))
384             {
385                 /* This is the beginning of a sentence; okay to parse. */
386                 *eol = '\0'; /* overwrite \n with \0 */
387
388                 if(my_thread == _aprs_inet_thread)
389                         //g_idle_add_full(G_PRIORITY_HIGH, (GSourceFunc)aprs_parse_server_packet, g_strdup(buf), NULL );
390                     g_idle_add((GSourceFunc)aprs_parse_server_packet, g_strdup(buf));
391
392                 /* If eol is at or after (buf_curr - 1) */
393                 if(eol >= (buf_curr - 1))
394                 {
395                     /* Last read was a newline - reset read buffer */
396                     buf_curr = buf;
397                     *buf_curr = '\0';
398                 }
399                 else
400                 {
401                     /* Move the next line to the front of the buffer. */
402                     memmove(buf, eol + 1,
403                             buf_curr - eol); /* include terminating 0 */
404                     /* Subtract _curr so that it's pointing at the new \0. */
405                     buf_curr -= (eol - buf + 1);
406                 }
407             }
408             _aprs_rcvr_retry_count = 0;
409    
410             // Send any packets queued
411                         // try to get lock, otherwise try next time
412                         if(g_mutex_trylock (_write_buffer[APRS_PORT_INET].write_lock))
413                         {
414                         // Store the current end pointer as it may change
415                                 
416                 gint quantity = 0;
417                 gchar tmp_write_buffer[MAX_DEVICE_BUFFER];
418                 while (_write_buffer[APRS_PORT_INET].write_in_pos != _write_buffer[APRS_PORT_INET].write_out_pos) {
419
420                         tmp_write_buffer[quantity] = _write_buffer[APRS_PORT_INET].device_write_buffer[_write_buffer[APRS_PORT_INET].write_out_pos];
421
422                         _write_buffer[APRS_PORT_INET].write_out_pos++;
423                     if (_write_buffer[APRS_PORT_INET].write_out_pos >= MAX_DEVICE_BUFFER)
424                         _write_buffer[APRS_PORT_INET].write_out_pos = 0;
425
426                     quantity++;
427                 }
428
429                 if(quantity>0)
430                 {
431                         sleep(2);
432                         
433                         GnomeVFSFileSize bytes_read = 0;                                    
434                                         if(GNOME_VFS_OK == gnome_vfs_socket_write( socket,
435                                                         tmp_write_buffer, quantity, &bytes_read, NULL))
436                                         {
437                                                 // OK
438                                                 //fprintf(stderr, "Send packet success: %s (%u)\n", tmp_write_buffer, quantity);
439                                         }
440                                         else
441                                         {
442                                                 // Failed
443                                                 fprintf(stderr, "Failed to send packet: %s (%u)\n", tmp_write_buffer, quantity);
444                                         }
445                                         
446                         sleep(1);
447                 }
448                                 
449                     g_mutex_unlock(_write_buffer[APRS_PORT_INET].write_lock);
450                         }            
451
452         }
453         
454         //fprintf(stderr, "Exiting thread...\n");
455     }
456
457     /* Error, or we're done reading APRS data. */
458
459     /* Clean up. */
460     if(iconn)
461         gnome_vfs_inet_connection_destroy(iconn, NULL);
462         //gnome_vfs_inet_connection_free(iconn, NULL);
463     
464     iconn = NULL;
465     
466     //g_thread_exit(0);
467     
468     
469     printf("%s(): return\n", __PRETTY_FUNCTION__);
470     
471     return;
472 }
473
474 /**
475  * Disconnect from the receiver.  This method cleans up any and everything
476  * that might be associated with the receiver.
477  */
478 void aprs_server_disconnect()
479 {
480     gboolean exit_now = FALSE;
481
482     printf("%s()\n", __PRETTY_FUNCTION__);
483
484     GThread *my_thread = g_thread_self();
485
486     if(my_thread == _aprs_inet_thread)
487     {
488         exit_now = TRUE;
489     }
490
491     g_mutex_lock(_aprs_inet_init_mutex);
492     _aprs_inet_thread = NULL;
493     g_mutex_unlock(_aprs_inet_init_mutex);
494
495     
496     
497     if(_window)
498         set_aprs_inet_conn_state(RCVR_OFF);
499     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
500
501     if(exit_now) 
502     {
503         fprintf(stderr, "Stopping own thread - APRS server\n");
504         exit(0);
505         fprintf(stderr, "Stop Failed\n");
506         
507     }
508 }
509
510 /**
511  * Connect to the server.
512  * This method assumes that _fd is -1 and _channel is NULL.  If unsure, call
513  * rcvr_disconnect() first.
514  * Since this is an idle function, this function returns whether or not it
515  * should be called again, which is always FALSE.
516  */
517 gboolean aprs_server_connect()
518 {
519     printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_inet_state);
520
521     if(_aprs_inet_enable && _aprs_inet_state == RCVR_OFF)
522     {
523         set_aprs_inet_conn_state(RCVR_DOWN);
524
525         /* Lock/Unlock the mutex to ensure that the thread doesn't
526          * start until _gps_thread is set. */
527         g_mutex_lock(_aprs_inet_init_mutex);
528
529         
530         _aprs_inet_thread = g_thread_create((GThreadFunc)thread_read_server,
531                 NULL, TRUE, NULL); /* Joinable. */
532         
533 //        g_thread_set_priority(_aprs_inet_thread, G_THREAD_PRIORITY_LOW);
534         
535         g_mutex_unlock(_aprs_inet_init_mutex);
536     }
537
538     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
539     return FALSE;
540 }
541
542 void aprs_init()
543 {
544     printf("%s()\n", __PRETTY_FUNCTION__);
545
546     _aprs_inet_init_mutex = g_mutex_new();
547     _aprs_tty_init_mutex  = g_mutex_new();
548     _write_buffer[APRS_PORT_INET].write_lock = g_mutex_new();
549     _write_buffer[APRS_PORT_TTY].write_lock = g_mutex_new();
550
551     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
552 }
553
554 void aprs_destroy(gboolean last)
555 {
556     static GThread* tmp = NULL;
557     printf("%s()\n", __PRETTY_FUNCTION__);
558
559     if(!last)
560     {
561         if(_aprs_inet_thread)
562         {
563             tmp = (GThread*)_aprs_inet_thread;
564             _aprs_inet_thread = NULL;
565         }
566     }
567     else if(tmp)
568         g_thread_join(tmp);
569
570     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
571 }
572
573 gboolean select_aprs(gint unitx, gint unity, gboolean quick)
574 {       
575     gint x, y;
576     gdouble lat1, lon1, lat2, lon2;
577     static GtkWidget *dialog = NULL;
578     static GtkWidget *list = NULL;
579     static GtkWidget *sw = NULL;
580     static GtkTreeViewColumn *column = NULL;
581     static GtkCellRenderer *renderer = NULL;
582     GtkListStore *store = NULL;
583     GtkTreeIter iter;
584     gboolean selected = FALSE;
585     gint num_stations = 0;
586     AprsStationList *first_station = NULL;
587     AprsStationList *last_station = NULL;
588
589
590     printf("%s()\n", __PRETTY_FUNCTION__);
591
592     x = unitx - pixel2unit(3 * _draw_width);
593     y = unity + pixel2unit(3 * _draw_width);
594     unit2latlon(x, y, lat1, lon1);
595
596     x = unitx + pixel2unit(3 * _draw_width);
597     y = unity - pixel2unit(3 * _draw_width);
598     unit2latlon(x, y, lat2, lon2);
599     gdouble lat, lon;
600
601     
602     AprsDataRow *p_station = (AprsDataRow *)n_first;
603
604     // Look for all stations in selected area
605     while ( (p_station) != NULL) 
606     { 
607         lat = convert_lat_l2d(p_station->coord_lat);
608         lon = convert_lon_l2d(p_station->coord_lon);
609
610         if ( ( lat2 >= lat && lat >= lat1 ) && (lon2 >= lon && lon >= lon1) )
611         {
612             // This may have been clicked on
613                 AprsStationList * p_list_item = (AprsStationList *)malloc(sizeof(AprsStationList));
614
615                 p_list_item->station = p_station;
616                 p_list_item->next = NULL;
617                 
618                 if(first_station == NULL)
619                 {
620
621                         first_station = p_list_item;
622                         last_station = p_list_item;
623                 }
624                 else
625                 {
626                         last_station->next = p_list_item;
627                         last_station = p_list_item;
628                 }
629                 
630                 num_stations++;
631         }
632
633         (p_station) = (p_station)->n_next;  // Next element in list
634     } // End of while loop
635
636     selected = FALSE;
637     
638     if(num_stations==0)
639     {
640         // No station found, maybe a POI was selected?
641     }
642     else if(num_stations == 1)
643     {
644         // Only one station was found, so display it's info
645         if(first_station->station != NULL)
646         {
647                 ShowAprsStationPopup(first_station->station);
648         }
649         selected = TRUE;
650     }
651     else
652     {
653         // Multiple possibilities, therefore ask the user which one
654         
655         // Initialize store. 
656         store = gtk_list_store_new(APRSPOI_NUM_COLUMNS,
657                                G_TYPE_BOOLEAN, //Selected 
658                                G_TYPE_STRING // Callsign
659                         );
660
661         AprsStationList * p_list_item = first_station;
662         
663         while(p_list_item != NULL)
664         {
665                 if(p_list_item->station != NULL)
666                 {
667                         gtk_list_store_append(store, &iter);
668         
669                         gtk_list_store_set(store, &iter,
670                             APRSPOI_CALLSIGN, g_strdup(p_list_item->station->call_sign),
671                             -1);
672                 }
673                 p_list_item = p_list_item->next;
674         }
675   
676         
677             if(dialog == NULL)
678             {
679                 dialog = gtk_dialog_new_with_buttons(_("Select APRS Station"),
680                         GTK_WINDOW(_window), GTK_DIALOG_MODAL,
681                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
682                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
683                         NULL);
684         
685                 gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
686         
687                 sw = gtk_scrolled_window_new (NULL, NULL);
688                 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
689                         GTK_SHADOW_ETCHED_IN);
690                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
691                         GTK_POLICY_NEVER,
692                         GTK_POLICY_AUTOMATIC);
693                 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
694                         sw, TRUE, TRUE, 0);
695         
696                 list = gtk_tree_view_new();
697                 gtk_container_add(GTK_CONTAINER(sw), list);
698         
699                 gtk_tree_selection_set_mode(
700                         gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
701                         GTK_SELECTION_SINGLE);
702                 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
703
704                 renderer = gtk_cell_renderer_text_new();
705                 column = gtk_tree_view_column_new_with_attributes(
706                         _("Callsign"), renderer, "text", APRSPOI_CALLSIGN, NULL);
707                 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
708
709             }
710
711             
712             gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
713             g_object_unref(G_OBJECT(store));
714         
715             gtk_widget_show_all(dialog);
716             
717             if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
718             {
719                 if(gtk_tree_selection_get_selected(
720                     gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
721                     NULL, &iter))
722                 {
723                         // Find the callsign
724                         p_list_item = first_station;
725                         while(p_list_item != NULL)
726                         {
727                                 if(p_list_item->station != NULL)
728                                 {       
729                                         gchar * callsign = NULL;
730                                     gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
731                                         APRSPOI_CALLSIGN, &(callsign),
732                                         -1);
733         
734                                     if(strcmp(p_list_item->station->call_sign,callsign) == 0)
735                                         {
736                                         gtk_widget_hide(dialog);
737                                         
738                                                 ShowAprsStationPopup(p_list_item->station);
739                                                 selected = TRUE;
740                                                 break;
741                                                 
742                                         }
743                                 }
744                                 
745                                 p_list_item = p_list_item->next;
746                         }
747
748                 }
749
750             }
751
752         // Ensure it has been closed
753         gtk_widget_hide(dialog);
754     }
755
756
757     // Free the list, but not the stations
758     if(first_station)
759     {
760             AprsStationList * p_list_item = first_station;
761             
762             while(first_station)
763             {
764                 // Store pointer to delete contents after next pointer is stored        
765                 p_list_item = first_station;
766             
767                 // Move pointer to next
768                 first_station = p_list_item->next;
769                 
770                 free(p_list_item);
771             }
772     }
773
774
775     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
776     return selected;
777
778 }
779
780
781
782 //*****************************************************************
783 // distance_from_my_station - compute distance from my station and
784 //       course with a given call
785 //
786 // return distance and course
787 //
788 // Returns 0.0 for distance if station not found in database or the
789 // station hasn't sent out a posit yet.
790 //*****************************************************************
791
792 double distance_from_my_station(char *call_sign, gchar *course_deg, gint course_len) {
793     AprsDataRow *p_station;
794     double distance;
795     float value;
796     double d_lat, d_lon;
797
798     distance = 0.0;
799     p_station = NULL;
800     if (search_station_name(&p_station,call_sign,1)) {
801         // Check whether we have a posit yet for this station
802         if ( (p_station->coord_lat == 0l)
803                 && (p_station->coord_lon == 0l) ) {
804             distance = 0.0;
805         }
806         else {
807                 d_lat = convert_lat_l2d(p_station->coord_lat);
808                 d_lon = convert_lon_l2d(p_station->coord_lon);
809                 
810                 value = (float)calculate_distance(_gps.lat, _gps.lon, d_lat, d_lon);
811                 
812                 snprintf(course_deg,  course_len,
813                                 "%.01f°",
814                                 calculate_bearing(_gps.lat, _gps.lon, d_lat, d_lon));
815                 
816             if(_units == UNITS_KM)
817                 distance = value * 1.852;           // nautical miles to km
818             else if(_units == UNITS_MI)
819                 distance = value * 1.15078;         // nautical miles to miles
820             else if(_units == UNITS_NM)
821                 distance = value; 
822             else
823                 distance = 0.0; // Should be unreachable
824             
825                 
826         }
827     }
828     else {  // Station not found
829         distance = 0.0;
830     }
831
832
833     return(distance);
834 }
835
836
837
838 void pad_callsign(char *callsignout, char *callsignin) {
839     int i,l;
840
841     l=(int)strlen(callsignin);
842     for(i=0; i<9;i++) {
843         if(i<l) {
844             if(isalnum((int)callsignin[i]) || callsignin[i]=='-') {
845                 callsignout[i]=callsignin[i];
846             }
847             else {
848                 callsignout[i] = ' ';
849             }
850         }
851         else {
852             callsignout[i] = ' ';
853         }
854     }
855     callsignout[i] = '\0';
856 }
857 /////////// TX functionality
858
859
860
861 // This routine changes callsign chars to proper uppercase chars or
862 // numerals, fixes the callsign to six bytes, shifts the letters left by
863 // one bit, and puts the SSID number into the proper bits in the seventh
864 // byte.  The callsign as processed is ready for inclusion in an
865 // AX.25 header.
866 //
867 void fix_up_callsign(unsigned char *data, int data_size) {
868     unsigned char new_call[8] = "       ";  // Start with seven spaces
869     int ssid = 0;
870     int i;
871     int j = 0;
872     int digipeated_flag = 0;
873
874
875     // Check whether we've digipeated through this callsign yet.
876     if (strstr((const char *)data,"*") != 0) {
877          digipeated_flag++;
878     }
879
880     // Change callsign to upper-case and pad out to six places with
881     // space characters.
882     for (i = 0; i < (int)strlen((const char *)data); i++) {
883         toupper(data[i]);
884
885         if (data[i] == '-') {   // Stop at '-'
886             break;
887         }
888         else if (data[i] == '*') {
889         }
890         else {
891             new_call[j++] = data[i];
892         }
893     }
894     new_call[7] = '\0';
895
896     //fprintf(stderr,"new_call:(%s)\n",new_call);
897
898     // Handle SSID.  'i' should now be pointing at a dash or at the
899     // terminating zero character.
900     if ( (i < (int)strlen((const char *)data)) && (data[i++] == '-') ) {   // We might have an SSID
901         if (data[i] != '\0')
902             ssid = atoi((const char *)&data[i]);
903 //            ssid = data[i++] - 0x30;    // Convert from ascii to int
904 //        if (data[i] != '\0')
905 //            ssid = (ssid * 10) + (data[i] - 0x30);
906     }
907
908 //fprintf(stderr,"SSID:%d\t",ssid);
909
910     if (ssid >= 0 && ssid <= 15) {
911         new_call[6] = ssid | 0x30;  // Set 2 reserved bits
912     }
913     else {  // Whacko SSID.  Set it to zero
914         new_call[6] = 0x30;     // Set 2 reserved bits
915     }
916
917     if (digipeated_flag) {
918         new_call[6] = new_call[6] | 0x40; // Set the 'H' bit
919     }
920  
921     // Shift each byte one bit to the left
922     for (i = 0; i < 7; i++) {
923         new_call[i] = new_call[i] << 1;
924         new_call[i] = new_call[i] & 0xfe;
925     }
926
927 //fprintf(stderr,"Last:%0x\n",new_call[6]);
928
929     // Write over the top of the input string with the newly
930     // formatted callsign
931     xastir_snprintf((char *)data,
932         data_size,
933         "%s",
934         new_call);
935 }
936
937
938
939
940 // Create an AX25 frame and then turn it into a KISS packet.  Dump
941 // it into the transmit queue.
942 //
943 void send_ax25_frame(TAprsPort port, gchar *source, gchar *destination, gchar *path, gchar *data) {
944     unsigned char temp_source[15];
945     unsigned char temp_dest[15];
946     unsigned char temp[15];
947     unsigned char control[2], pid[2];
948     unsigned char transmit_txt[MAX_LINE_SIZE*2];
949     unsigned char transmit_txt2[MAX_LINE_SIZE*2];
950     unsigned char c;
951     int i, j;
952     int erd;
953     int write_in_pos_hold;
954
955
956 //fprintf(stderr,"KISS String:%s>%s,%s:%s\n",source,destination,path,data);
957
958     // Check whether transmits are disabled globally
959 //    if (transmit_disable) {
960 //        return;
961 //    }    
962
963     // Check whether transmit has been enabled for this interface.
964     // If not, get out while the gettin's good.
965 //    if (devices[port].transmit_data != 1) {
966 //        return;
967 //    }
968
969     transmit_txt[0] = '\0';
970
971     // Format the destination callsign
972     snprintf((char *)temp_dest,
973         sizeof(temp_dest),
974         "%s",
975         destination);
976     fix_up_callsign(temp_dest, sizeof(temp_dest));
977     
978     snprintf((char *)transmit_txt,
979         sizeof(transmit_txt),
980         "%s",
981         temp_dest);
982
983     // Format the source callsign
984     snprintf((char *)temp_source,
985         sizeof(temp_source),
986         "%s",
987         source);
988     fix_up_callsign(temp_source, sizeof(temp_source));
989     
990     strncat((char *)transmit_txt,
991         (char *)temp_source,
992         sizeof(transmit_txt) - strlen((char *)transmit_txt));
993
994     // Break up the path into individual callsigns and send them one
995     // by one to fix_up_callsign().  If we get passed an empty path,
996     // we merely skip this section and no path gets added to
997     // "transmit_txt".
998     j = 0;
999     temp[0] = '\0'; // Start with empty path
1000     if ( (path != NULL) && (strlen(path) != 0) ) {
1001         while (path[j] != '\0') {
1002             i = 0;
1003             while ( (path[j] != ',') && (path[j] != '\0') ) {
1004                 temp[i++] = path[j++];
1005             }
1006             temp[i] = '\0';
1007
1008             if (path[j] == ',') {   // Skip over comma
1009                 j++;
1010             }
1011
1012             fix_up_callsign(temp, sizeof(temp));
1013             strncat((char *)transmit_txt,
1014                 (char *)temp,
1015                 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1016         }
1017     }
1018
1019     // Set the end-of-address bit on the last callsign in the
1020     // address field
1021     transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01;
1022
1023     // Add the Control byte
1024     control[0] = 0x03;
1025     control[1] = '\0';
1026     strncat((char *)transmit_txt,
1027         (char *)control,
1028         sizeof(transmit_txt) - strlen((char *)transmit_txt));
1029
1030     // Add the PID byte
1031     pid[0] = 0xf0;
1032     pid[1] = '\0';
1033     strncat((char *)transmit_txt,
1034         (char *)pid,
1035         sizeof(transmit_txt) - strlen((char *)transmit_txt));
1036
1037     // Append the information chars
1038     strncat((char *)transmit_txt,
1039         data,
1040         sizeof(transmit_txt) - strlen((char *)transmit_txt));
1041
1042     //fprintf(stderr,"%s\n",transmit_txt);
1043
1044     // Add the KISS framing characters and do the proper escapes.
1045     j = 0;
1046     transmit_txt2[j++] = KISS_FEND;
1047
1048     // Note:  This byte is where different interfaces would be
1049     // specified:
1050     transmit_txt2[j++] = 0x00;
1051
1052     for (i = 0; i < (int)strlen((const char *)transmit_txt); i++) {
1053         c = transmit_txt[i];
1054         if (c == KISS_FEND) {
1055             transmit_txt2[j++] = KISS_FESC;
1056             transmit_txt2[j++] = KISS_TFEND;
1057         }
1058         else if (c == KISS_FESC) {
1059             transmit_txt2[j++] = KISS_FESC;
1060             transmit_txt2[j++] = KISS_TFESC;
1061         }
1062         else {
1063             transmit_txt2[j++] = c;
1064         }
1065     }
1066     transmit_txt2[j++] = KISS_FEND;
1067
1068     // Terminate the string, but don't increment the 'j' counter.
1069     // We don't want to send the NULL byte out the KISS interface,
1070     // just make sure the string is terminated in all cases.
1071     //
1072     transmit_txt2[j] = '\0';
1073
1074 //-------------------------------------------------------------------
1075 // Had to snag code from port_write_string() below because our string
1076 // needs to have 0x00 chars inside it.  port_write_string() can't
1077 // handle that case.  It's a good thing the transmit queue stuff
1078 // could handle it.
1079 //-------------------------------------------------------------------
1080
1081     erd = 0;
1082
1083
1084     
1085
1086         port_write_string(
1087                         transmit_txt2,
1088                         j/*length*/,
1089                 APRS_PORT_TTY);
1090
1091         
1092         
1093 /*
1094     g_mutex_lock (_write_buffer[port].write_lock);
1095     {
1096         
1097             write_in_pos_hold = _write_buffer[port].write_in_pos;
1098         
1099             for (i = 0; i < j && !erd; i++) {
1100                 _write_buffer[port].device_write_buffer[_write_buffer[port].write_in_pos++] = transmit_txt2[i];
1101                 if (_write_buffer[port].write_in_pos >= MAX_DEVICE_BUFFER)
1102                         _write_buffer[port].write_in_pos = 0;
1103         
1104                 if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
1105         
1106                     // clear this restore original write_in pos and dump this string 
1107                         _write_buffer[port].write_in_pos = write_in_pos_hold;
1108                         _write_buffer[port].errors++;
1109                     erd = 1;
1110                 }
1111             }
1112             
1113             g_mutex_unlock (_write_buffer[port].write_lock);
1114     }
1115 */
1116 }
1117
1118
1119
1120
1121 // convert latitude from long to string 
1122 // Input is in Xastir coordinate system
1123 //
1124 // CONVERT_LP_NOSP      = DDMM.MMN
1125 // CONVERT_HP_NOSP      = DDMM.MMMN
1126 // CONVERT_VHP_NOSP     = DDMM.MMMMN
1127 // CONVERT_LP_NORMAL    = DD MM.MMN
1128 // CONVERT_HP_NORMAL    = DD MM.MMMN
1129 // CONVERT_UP_TRK       = NDD MM.MMMM
1130 // CONVERT_DEC_DEG      = DD.DDDDDN
1131 // CONVERT_DMS_NORMAL   = DD MM SS.SN
1132 // CONVERT_DMS_NORMAL_FORMATED   = DD'MM'SS.SN
1133 // CONVERT_HP_NORMAL_FORMATED   = DD'MM.MMMMN
1134 //
1135 void convert_lat_l2s(long lat, char *str, int str_len, int type) {
1136     char ns;
1137     float deg, min, sec;
1138     int ideg, imin;
1139     long temp;
1140
1141
1142     str[0] = '\0';
1143     deg = (float)(lat - 32400000l) / 360000.0;
1144  
1145     // Switch to integer arithmetic to avoid floating-point
1146     // rounding errors.
1147     temp = (long)(deg * 100000);
1148
1149     ns = 'S';
1150     if (temp <= 0) {
1151         ns = 'N';
1152         temp = labs(temp);
1153     }   
1154
1155     ideg = (int)temp / 100000;
1156     min = (temp % 100000) * 60.0 / 100000.0;
1157
1158     // Again switch to integer arithmetic to avoid floating-point
1159     // rounding errors.
1160     temp = (long)(min * 1000);
1161     imin = (int)(temp / 1000);
1162     sec = (temp % 1000) * 60.0 / 1000.0;
1163
1164     switch (type) {
1165
1166         case(CONVERT_LP_NOSP): /* do low P w/no space */
1167             xastir_snprintf(str,
1168                 str_len,
1169                 "%02d%05.2f%c",
1170                 ideg,
1171 //                min+0.001, // Correct possible unbiased rounding
1172                 min,
1173                 ns);
1174             break;
1175
1176         case(CONVERT_LP_NORMAL): /* do low P normal */
1177             xastir_snprintf(str,
1178                 str_len,
1179                 "%02d %05.2f%c",
1180                 ideg,
1181 //                min+0.001, // Correct possible unbiased rounding
1182                 min,
1183                 ns);
1184             break;
1185
1186         case(CONVERT_HP_NOSP): /* do HP w/no space */
1187             xastir_snprintf(str,
1188                 str_len,
1189                 "%02d%06.3f%c",
1190                 ideg,
1191 //                min+0.0001, // Correct possible unbiased rounding
1192                 min,
1193                 ns);
1194             break;
1195
1196         case(CONVERT_VHP_NOSP): /* do Very HP w/no space */
1197             xastir_snprintf(str,
1198                 str_len,
1199                 "%02d%07.4f%c",
1200                 ideg,
1201 //                min+0.00001, // Correct possible unbiased rounding
1202                 min,
1203                 ns);
1204             break;
1205
1206         case(CONVERT_UP_TRK): /* for tracklog files */
1207             xastir_snprintf(str,
1208                 str_len,
1209                 "%c%02d %07.4f",
1210                 ns,
1211                 ideg,
1212 //                min+0.00001); // Correct possible unbiased rounding
1213                 min);
1214             break;
1215
1216         case(CONVERT_DEC_DEG):
1217             xastir_snprintf(str,
1218                 str_len,
1219                 "%08.5f%c",
1220 //                (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1221                 ideg+min/60.0,
1222                 ns);
1223             break;
1224
1225         case(CONVERT_DMS_NORMAL):
1226             xastir_snprintf(str,
1227                 str_len,
1228                 "%02d %02d %04.1f%c",
1229                 ideg,
1230                 imin,
1231 //                sec+0.01, // Correct possible unbiased rounding
1232                 sec,
1233                 ns);
1234             break;
1235         
1236         case(CONVERT_DMS_NORMAL_FORMATED):
1237             xastir_snprintf(str,
1238                 str_len,
1239                 "%02d°%02d\'%04.1f%c",
1240                 ideg,
1241                 imin,
1242 //                sec+0.01, // Correct possible unbiased rounding
1243                 sec,
1244                 ns);
1245             break;
1246
1247         case(CONVERT_HP_NORMAL_FORMATED):
1248             xastir_snprintf(str,
1249                 str_len,
1250                 "%02d°%06.3f%c",
1251                 ideg,
1252 //                min+0.0001, // Correct possible unbiased roundin
1253                 min,
1254                 ns);
1255             break;
1256         
1257         case(CONVERT_HP_NORMAL):
1258         default: /* do HP normal */
1259             xastir_snprintf(str,
1260                 str_len,
1261                 "%02d %06.3f%c",
1262                 ideg,
1263 //                min+0.0001, // Correct possible unbiased rounding
1264                 min,
1265                 ns);
1266             break;
1267     }
1268 }
1269
1270
1271
1272
1273
1274 // convert longitude from long to string
1275 // Input is in Xastir coordinate system
1276 //
1277 // CONVERT_LP_NOSP      = DDDMM.MME
1278 // CONVERT_HP_NOSP      = DDDMM.MMME
1279 // CONVERT_VHP_NOSP     = DDDMM.MMMME
1280 // CONVERT_LP_NORMAL    = DDD MM.MME
1281 // CONVERT_HP_NORMAL    = DDD MM.MMME
1282 // CONVERT_UP_TRK       = EDDD MM.MMMM
1283 // CONVERT_DEC_DEG      = DDD.DDDDDE
1284 // CONVERT_DMS_NORMAL   = DDD MM SS.SN
1285 // CONVERT_DMS_NORMAL_FORMATED   = DDD'MM'SS.SN
1286 //
1287 void convert_lon_l2s(long lon, char *str, int str_len, int type) {
1288     char ew;
1289     float deg, min, sec;
1290     int ideg, imin;
1291     long temp;
1292
1293     str[0] = '\0';
1294     deg = (float)(lon - 64800000l) / 360000.0;
1295
1296     // Switch to integer arithmetic to avoid floating-point rounding
1297     // errors.
1298     temp = (long)(deg * 100000);
1299
1300     ew = 'E';
1301     if (temp <= 0) {
1302         ew = 'W';
1303         temp = labs(temp);
1304     }
1305
1306     ideg = (int)temp / 100000;
1307     min = (temp % 100000) * 60.0 / 100000.0;
1308
1309     // Again switch to integer arithmetic to avoid floating-point
1310     // rounding errors.
1311     temp = (long)(min * 1000);
1312     imin = (int)(temp / 1000);
1313     sec = (temp % 1000) * 60.0 / 1000.0;
1314
1315     switch(type) {
1316
1317         case(CONVERT_LP_NOSP): /* do low P w/nospacel */
1318             xastir_snprintf(str,
1319                 str_len,
1320                 "%03d%05.2f%c",
1321                 ideg,
1322 //                min+0.001, // Correct possible unbiased rounding
1323                 min,
1324                 ew);
1325             break;
1326
1327         case(CONVERT_LP_NORMAL): /* do low P normal */
1328             xastir_snprintf(str,
1329                 str_len,
1330                 "%03d %05.2f%c",
1331                 ideg,
1332 //                min+0.001, // Correct possible unbiased rounding
1333                 min,
1334                 ew);
1335             break;
1336
1337         case(CONVERT_HP_NOSP): /* do HP w/nospace */
1338             xastir_snprintf(str,
1339                 str_len,
1340                 "%03d%06.3f%c",
1341                 ideg,
1342 //                min+0.0001, // Correct possible unbiased rounding
1343                 min,
1344                 ew);
1345             break;
1346
1347         case(CONVERT_VHP_NOSP): /* do Very HP w/nospace */
1348             xastir_snprintf(str,
1349                 str_len,
1350                 "%03d%07.4f%c",
1351                 ideg,
1352 //                min+0.00001, // Correct possible unbiased rounding
1353                 min,
1354                 ew);
1355             break;
1356
1357         case(CONVERT_UP_TRK): /* for tracklog files */
1358             xastir_snprintf(str,
1359                 str_len,
1360                 "%c%03d %07.4f",
1361                 ew,
1362                 ideg,
1363 //                min+0.00001); // Correct possible unbiased rounding
1364                 min);
1365             break;
1366
1367         case(CONVERT_DEC_DEG):
1368             xastir_snprintf(str,
1369                 str_len,
1370                 "%09.5f%c",
1371 //                (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1372                 ideg+min/60.0,
1373                 ew);
1374             break;
1375
1376         case(CONVERT_DMS_NORMAL):
1377             xastir_snprintf(str,
1378                 str_len,
1379                 "%03d %02d %04.1f%c",
1380                 ideg,
1381                 imin,
1382 //                sec+0.01, // Correct possible unbiased rounding
1383                 sec,
1384                 ew);
1385             break;
1386
1387         case(CONVERT_DMS_NORMAL_FORMATED):
1388             xastir_snprintf(str,
1389                 str_len,
1390                 "%03d°%02d\'%04.1f%c",
1391                 ideg,
1392                 imin,
1393 //                sec+0.01, // Correct possible unbiased rounding
1394                 sec,
1395                 ew);
1396             break;
1397         
1398         case(CONVERT_HP_NORMAL_FORMATED):
1399             xastir_snprintf(str,
1400                 str_len,
1401                 "%03d°%06.3f%c",
1402                 ideg,
1403 //                min+0.0001, // Correct possible unbiased rounding
1404                 min,
1405                 ew);
1406             break;
1407
1408         case(CONVERT_HP_NORMAL):
1409         default: /* do HP normal */
1410             xastir_snprintf(str,
1411                 str_len,
1412                 "%03d %06.3f%c",
1413                 ideg,
1414 //                min+0.0001, // Correct possible unbiased rounding
1415                 min,
1416                 ew);
1417             break;
1418     }
1419 }
1420
1421
1422
1423
1424
1425
1426 /*************************************************************************/
1427 /* output_lat - format position with position_amb_chars for transmission */
1428 /*************************************************************************/
1429 /*
1430 char *output_lat(char *in_lat, int comp_pos) {
1431     int i,j;
1432     int position_amb_chars = 0;
1433 //fprintf(stderr,"in_lat:%s\n", in_lat);
1434
1435     if (!comp_pos) {
1436         // Don't do this as it results in truncation!
1437         //in_lat[7]=in_lat[8]; // Shift N/S down for transmission
1438     }
1439     else if (position_amb_chars>0) {
1440         in_lat[7]='0';
1441     }
1442
1443     j=0;
1444     if (position_amb_chars>0 && position_amb_chars<5) {
1445         for (i=6;i>(6-position_amb_chars-j);i--) {
1446             if (i==4) {
1447                 i--;
1448                 j=1;
1449             }
1450             if (!comp_pos) {
1451                 in_lat[i]=' ';
1452             } else
1453                 in_lat[i]='0';
1454         }
1455     }
1456
1457     if (!comp_pos) {
1458         in_lat[8] = '\0';
1459     }
1460
1461     return(in_lat);
1462 }
1463 */
1464
1465
1466
1467 /**************************************************************************/
1468 /* output_long - format position with position_amb_chars for transmission */
1469 /**************************************************************************/
1470 /*
1471 char *output_long(char *in_long, int comp_pos) {
1472     int i,j;
1473 int position_amb_chars = 0;
1474 //fprintf(stderr,"in_long:%s\n", in_long);
1475
1476     if (!comp_pos) {
1477         // Don't do this as it results in truncation!
1478         //in_long[8]=in_long[9]; // Shift e/w down for transmission
1479     }
1480     else if (position_amb_chars>0) {
1481         in_long[8]='0';
1482     }
1483
1484     j=0;
1485     if (position_amb_chars>0 && position_amb_chars<5) {
1486         for (i=7;i>(7-position_amb_chars-j);i--) {
1487             if (i==5) {
1488                 i--;
1489                 j=1;
1490             }
1491             if (!comp_pos) {
1492                 in_long[i]=' ';
1493             } else
1494                 in_long[i]='0';
1495         }
1496     }
1497
1498     if (!comp_pos)
1499         in_long[9] = '\0';
1500
1501     return(in_long);
1502 }
1503 */
1504
1505
1506
1507 //***********************************************************
1508 // output_my_aprs_data
1509 // This is the function responsible for sending out my own
1510 // posits.  The next function below this one handles objects,
1511 // messages and the like (output_my_data).
1512 //***********************************************************/
1513
1514 /*
1515 void create_output_lat_long(gchar *my_output_lat, gchar *my_output_long )
1516 {
1517     _aprs_transmit_compressed_posit = FALSE;
1518     gchar *my_lat = g_strdup_printf("%lf", _gps.lat);
1519     gchar *my_long = g_strdup_printf("%lf", _gps.lon);
1520
1521     
1522     // Format latitude string for transmit later
1523     if (_aprs_transmit_compressed_posit) {    // High res version
1524         // TODO - enable compressed beacon
1525         snprintf(my_output_lat,
1526             sizeof(my_output_lat),
1527             "%s",
1528             my_lat);
1529  
1530     }
1531     else {  // Create a low-res version of the latitude string
1532         long my_temp_lat;
1533         char temp_data[20];
1534
1535         // Convert to long
1536         my_temp_lat = convert_lat_s2l(my_lat);
1537
1538         // Convert to low-res string
1539         convert_lat_l2s(my_temp_lat,
1540             temp_data,
1541             sizeof(temp_data),
1542             CONVERT_LP_NORMAL);
1543
1544         snprintf(my_output_lat,
1545             sizeof(my_output_lat),
1546             "%c%c%c%c.%c%c%c",
1547             temp_data[0],
1548             temp_data[1],
1549             temp_data[3],
1550             temp_data[4],
1551             temp_data[6],
1552             temp_data[7],
1553             temp_data[8]);
1554     }
1555
1556     (void)output_lat(my_output_lat, _aprs_transmit_compressed_posit);
1557
1558     // Format longitude string for transmit later
1559     if (_aprs_transmit_compressed_posit) {    // High res version
1560         snprintf(my_output_long,
1561             sizeof(my_output_long),
1562             "%s",
1563             my_long);
1564     }
1565     else {  // Create a low-res version of the longitude string
1566         long my_temp_long;
1567         char temp_data[20];
1568
1569         // Convert to long
1570         my_temp_long = convert_lon_s2l(my_long);
1571
1572         // Convert to low-res string
1573         convert_lon_l2s(my_temp_long,
1574             temp_data,
1575             sizeof(temp_data),
1576             CONVERT_LP_NORMAL);
1577
1578         snprintf(my_output_long,
1579             sizeof(my_output_long),
1580             "%c%c%c%c%c.%c%c%c",
1581             temp_data[0],
1582             temp_data[1],
1583             temp_data[2],
1584             temp_data[4],
1585             temp_data[5],
1586             temp_data[7],
1587             temp_data[8],
1588             temp_data[9]);
1589     }
1590
1591     (void)output_long(my_output_long, _aprs_transmit_compressed_posit);
1592
1593 }
1594
1595
1596 void output_my_aprs_data_tty() {
1597 //TODO
1598         return ;
1599
1600         gchar my_output_lat[MAX_LAT];
1601     gchar my_output_long[MAX_LONG];
1602 //    gchar header_txt[MAX_LINE_SIZE+5];
1603 //    gchar header_txt_save[MAX_LINE_SIZE+5];
1604     gchar path_txt[MAX_LINE_SIZE+5];
1605     gchar data_txt[MAX_LINE_SIZE+5];    
1606     gchar temp[MAX_LINE_SIZE+5];
1607     gchar *unproto_path = "";
1608     gchar data_txt2[5];
1609     struct tm *day_time;
1610     gchar my_pos[256];
1611     gchar output_net[256];
1612     gchar output_phg[10];
1613     gchar output_cs[10];
1614     gchar output_alt[20];
1615     gchar output_brk[3];
1616     int ok;
1617     gchar my_comment_tx[APRS_MAX_COMMENT+1];
1618     int interfaces_ok_for_transmit = 0;
1619     gchar my_phg[10];
1620
1621     time_t sec;
1622     gchar header_txt[MAX_LINE_SIZE+5];
1623     gchar header_txt_save[MAX_LINE_SIZE+5];
1624
1625     gchar data_txt_save[MAX_LINE_SIZE+5];
1626
1627
1628     if (!(port_data.status == DEVICE_UP 
1629                 && _aprs_tty_enable && _aprs_enable && _aprs_enable_tty_tx)) return ;
1630
1631     header_txt_save[0] = '\0';
1632     data_txt_save[0] = '\0';
1633     
1634     sec = sec_now();
1635     
1636     my_phg[0] = '\0';
1637         
1638     create_output_lat_long(my_output_lat, my_output_long);
1639         
1640
1641     // First send any header/path info we might need out the port,
1642     // set up TNC's to the proper mode, etc.
1643     ok = 1;
1644
1645     // clear this for a TNC 
1646     output_net[0] = '\0';
1647
1648     // Set my call sign 
1649     // The leading \r is sent to normal serial TNCs.  The only
1650     // reason for it is that some folks' D700s are getting 
1651     // garbage in the input buffer, and the result is the mycall
1652     // line is rejected.  The \r at the beginning clears out the 
1653     // junk and lets it go through.  But data_out_ax25 tries to 
1654     // parse the MYCALL line, and the presence of a leading \r 
1655     // breaks it.
1656     snprintf(header_txt,
1657         sizeof(header_txt),
1658         "%c%s %s\r",
1659         '\3',
1660         ((port_data.device_type !=DEVICE_AX25_TNC)?
1661                     "\rMYCALL":"MYCALL"),
1662                     _aprs_mycall);
1663
1664     // Send the callsign out to the TNC only if the interface is up and tx is enabled???
1665     // We don't set it this way for KISS TNC interfaces.
1666     if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1667             && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1668             && (port_data.status == DEVICE_UP)
1669             //&& (devices.transmit_data == 1)
1670             //&& !transmit_disable
1671             //&& !posit_tx_disable
1672             ) {
1673         port_write_string(header_txt, APRS_PORT_TTY);
1674 //send_line(gchar* text, gint text_len, TAprsPort port)
1675     }
1676
1677     // Set unproto path:  Get next unproto path in
1678     // sequence.
1679     
1680     snprintf(header_txt,
1681             sizeof(header_txt),
1682             "%c%s %s VIA %s\r",
1683             '\3',
1684             "UNPROTO",
1685             VERSIONFRM,
1686             _aprs_unproto_path);
1687
1688     snprintf(header_txt_save,
1689             sizeof(header_txt_save),
1690             "%s>%s,%s:",
1691             _aprs_mycall,
1692             VERSIONFRM,
1693             _aprs_unproto_path);
1694
1695     snprintf(path_txt,
1696             sizeof(path_txt),
1697             "%s",
1698             _aprs_unproto_path);
1699
1700
1701     // Send the header data to the TNC.  This sets the
1702     // unproto path that'll be used by the next packet.
1703     // We don't set it this way for KISS TNC interfaces.
1704     if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1705             && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1706             && (port_data.status == DEVICE_UP)
1707             //&& (devices.transmit_data == 1)
1708             //&& !transmit_disable
1709             //&& !posit_tx_disable
1710             ) {
1711         port_write_string(header_txt, APRS_PORT_TTY);
1712     }
1713
1714
1715     // Set converse mode.  We don't need to do this for
1716     // KISS TNC interfaces.  One european TNC (tnc2-ui)
1717     // doesn't accept "conv" but does accept the 'k'
1718     // command.  A Kantronics KPC-2 v2.71 TNC accepts
1719     // the "conv" command but not the 'k' command.
1720     // Figures!
1721     // 
1722     snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', APRS_CONVERSE_MODE);
1723  
1724         if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1725                 && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1726                 && (port_data.status == DEVICE_UP)
1727                 //&& (devices.transmit_data == 1)
1728                 //&& !transmit_disable
1729             //&& !posit_tx_disable
1730         ) {
1731         port_write_string(header_txt, APRS_PORT_TTY);
1732     }
1733     // sleep(1);
1734
1735
1736
1737     // Set up some more strings for later transmission
1738
1739     // send station info 
1740     output_cs[0] = '\0';
1741     output_phg[0] = '\0';
1742     output_alt[0] = '\0';
1743     output_brk[0] = '\0';
1744
1745
1746     if (_aprs_transmit_compressed_posit)
1747     {
1748         // TOOD - enable compressed beacon support
1749
1750 //      snprintf(my_pos,
1751 //            sizeof(my_pos),
1752 //            "%s",
1753 //            compress_posit(my_output_lat,
1754 //                my_group,
1755 //                my_output_long,
1756 //                my_symbol,
1757 //                my_last_course,
1758 //                my_last_speed,  // In knots
1759 //                my_phg));
1760
1761     }
1762     else { // standard non compressed mode 
1763         snprintf(my_pos,
1764             sizeof(my_pos),
1765             "%s%c%s%c",
1766             my_output_lat,
1767             _aprs_beacon_group,
1768             my_output_long,
1769             _aprs_beacon_symbol);
1770         // get PHG, if used for output 
1771         if (strlen(my_phg) >= 6)
1772             snprintf(output_phg,
1773                 sizeof(output_phg),
1774                 "%s",
1775                 my_phg);
1776
1777         // get CSE/SPD, Always needed for output even if 0 
1778         snprintf(output_cs,
1779             sizeof(output_cs),
1780             "%03d/%03d/",
1781             _gps.heading,
1782             _gps.speed);    // Speed in knots
1783
1784         // get altitude 
1785 // TODO
1786 //        if (my_last_altitude_time > 0)
1787 //            snprintf(output_alt,
1788 //                sizeof(output_alt),
1789 //                "A=%06ld/",
1790 //                 my_last_altitude);
1791     }
1792
1793
1794     // APRS_MOBILE LOCAL TIME 
1795
1796 // TODO
1797 //    if((strlen(output_cs) < 8) && (my_last_altitude_time > 0)) {
1798 //        xastir_snprintf(output_brk,
1799 //            sizeof(output_brk),
1800 //            "/");
1801 //    }
1802
1803     day_time = localtime(&sec);
1804
1805     snprintf(data_txt_save,
1806         sizeof(data_txt_save),
1807         "@%02d%02d%02d/%s%s%s%s%s",
1808         day_time->tm_mday,
1809         day_time->tm_hour,
1810         day_time->tm_min,
1811         my_pos,
1812         output_cs,
1813         output_brk,
1814         output_alt,
1815         my_comment_tx);
1816
1817 //WE7U2:
1818     // Truncate at max length for this type of APRS
1819     // packet.
1820     if (_aprs_transmit_compressed_posit) {
1821         if (strlen(data_txt_save) > 61) {
1822             data_txt_save[61] = '\0';
1823         }
1824     }
1825     else { // Uncompressed lat/long
1826         if (strlen(data_txt_save) > 70) {
1827             data_txt_save[70] = '\0';
1828         }
1829     }
1830
1831     // Add '\r' onto end.
1832     strncat(data_txt_save, "\r", 1);
1833
1834     snprintf(data_txt,
1835         sizeof(data_txt),
1836         "%s%s",
1837         output_net,
1838         data_txt_save);
1839
1840
1841     if (ok) {
1842         // Here's where the actual transmit of the posit occurs.  The
1843         // transmit string has been set up in "data_txt" by this point.
1844
1845         // If transmit or posits have been turned off, don't transmit posit
1846         if ( (port_data.status == DEVICE_UP)
1847 //                && (devices.transmit_data == 1)
1848 //                    && !transmit_disable
1849 //                    && !posit_tx_disable
1850                 ) {
1851
1852             interfaces_ok_for_transmit++;
1853
1854 // WE7U:  Change so that path is passed as well for KISS TNC
1855 // interfaces:  header_txt_save would probably be the one to pass,
1856 // or create a new string just for KISS TNC's.
1857
1858             if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1859                     || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1860
1861                 // Note:  This one has callsign & destination in the string
1862
1863                 // Transmit the posit out the KISS interface
1864                 send_ax25_frame(APRS_PORT_TTY, 
1865                                                 _aprs_mycall,    // source
1866                                 VERSIONFRM,     // destination
1867                                 path_txt,       // path
1868                                 data_txt);      // data
1869             }
1870             else {  // Not a Serial KISS TNC interface
1871
1872
1873                 port_write_string(data_txt, APRS_PORT_TTY);  // Transmit the posit
1874             }
1875
1876
1877             // Put our transmitted packet into the Incoming Data
1878             // window as well.  This way we can see both sides of a
1879             // conversation.  data_port == -1 for x_spider port,
1880             // normal interface number otherwise.  -99 to get a "**"
1881             // display meaning all ports.
1882             //
1883             // For packets that we're igating we end up with a CR or
1884             // LF on the end of them.  Remove that so the display
1885             // looks nice.
1886             //snprintf(temp,
1887             //    sizeof(temp),
1888             //    "%s>%s,%s:%s",
1889             //    my_callsign,
1890             //    VERSIONFRM,
1891             //    unproto_path,
1892             //    data_txt);
1893             //makePrintable(temp);
1894             //packet_data_add("TX ", temp, port);
1895
1896         }
1897     } // End of posit transmit: "if (ok)"
1898 }
1899 */
1900
1901 void create_output_pos_packet(TAprsPort port, gchar **packet, int *length)
1902 {
1903         
1904 //      gchar encodedPos[MAX_LINE_SIZE];
1905         
1906         if(_aprs_transmit_compressed_posit)
1907         {
1908                 // TODO
1909         }
1910         else
1911         {
1912                 //!5122.09N/00008.42W&APRS4R IGATE RUNNING ON NSLU2
1913                 
1914                 // For now just use a simple packet
1915                 
1916                 gchar slat[10];
1917                 gchar slon[10];
1918                 
1919                 gdouble pos = (_gps.lat > 0 ? _gps.lat : 0-_gps.lat);
1920                 
1921                 gdouble min = (pos - (int)pos)*60.0;
1922                 sprintf(slat, "%02d%02d.%02.0f", (int)pos, (int)min,
1923                                     ((min - (int)min)*100.0) );
1924                             
1925                 pos = (_gps.lon > 0 ? _gps.lon : 0-_gps.lon);
1926                 
1927                 min = (pos - (int)pos)*60.0;
1928                 sprintf(slon, "%03d%02d.%02.0f", (int)pos, (int)min,
1929                                                     ((min - (int)min)*100.0) );
1930                 
1931                 *packet = g_strdup_printf(
1932                         "%c%s%c%c%s%c%c%s%c",
1933                         '=',
1934                         slat, 
1935                         (_gps.lat > 0 ? 'N' : 'S'),
1936                         _aprs_beacon_group,
1937                         slon,
1938                         (_gps.lon > 0 ? 'E' : 'W'),
1939                         _aprs_beacon_symbol,
1940                         (port == APRS_PORT_INET ? _aprs_inet_beacon_comment : _aprs_beacon_comment),
1941                         (char)0
1942                         );
1943         }
1944         
1945         *length = strlen(*packet);
1946 }
1947
1948
1949 void send_packet(TAprsPort port, gchar* to_call, gchar* path, gchar* packet, gint packet_length)
1950 {
1951         if(port == APRS_PORT_INET 
1952                         || !(port_data.device_type == DEVICE_SERIAL_KISS_TNC
1953                 || port_data.device_type == DEVICE_SERIAL_MKISS_TNC) )
1954         {
1955                 gchar *packet_header
1956                         =  g_strdup_printf(
1957                 "%s>%s,%s:",
1958                 _aprs_mycall,
1959                 to_call,
1960                 path);
1961                 
1962                 gchar *full_packet = g_strdup_printf("%s%s\r\n", packet_header, packet);
1963                 
1964                 
1965                 send_line(full_packet, strlen(packet_header)+packet_length+2,  port);
1966         }
1967         else
1968         {
1969                 send_ax25_frame(port, _aprs_mycall, to_call, path, packet);
1970         }
1971         
1972 }
1973
1974 void output_my_aprs_data(TAprsPort port) {
1975         
1976
1977         gchar *packet;
1978         int length = 0;
1979         
1980         
1981     //create_output_lat_long(my_output_lat, my_output_long);
1982         create_output_pos_packet(port, &packet, &length);
1983
1984         
1985         send_packet(port, VERSIONFRM, _aprs_unproto_path, packet, length);
1986         
1987         if(packet != NULL) g_free(packet);
1988 }
1989
1990 /////////// TTY functionality
1991
1992 int serial_init();
1993 int _aprs_tnc_retry_count = 0;
1994
1995 static gboolean aprs_tnc_handle_error_idle (gchar *error)
1996 {
1997         printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
1998         
1999         /* Ask for re-try. */
2000     if(++_aprs_tnc_retry_count > 2)
2001     {
2002         GtkWidget *confirm;
2003         gchar buffer[BUFFER_SIZE];
2004
2005         /* Reset retry count. */
2006         _aprs_tnc_retry_count = 0;
2007
2008         snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
2009         confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
2010
2011         aprs_tty_disconnect();
2012
2013         if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2014             aprs_tty_connect(); /* Try again. */
2015         else
2016         {
2017             /* Disable GPS. */
2018             gtk_check_menu_item_set_active(
2019                     GTK_CHECK_MENU_ITEM(_menu_enable_aprs_tty_item), FALSE);
2020         }
2021
2022         /* Ask user to re-connect. */
2023         gtk_widget_destroy(confirm);
2024     }
2025     else
2026     {
2027         aprs_tty_disconnect();
2028         aprs_tty_connect(); /* Try again. */
2029     }
2030
2031     g_free(error);
2032
2033     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2034     return FALSE;
2035
2036 }
2037
2038 void close_tnc_port();
2039
2040 static void thread_read_tty()
2041 {
2042 //      gint max_retries = 5;
2043         GThread *my_thread = g_thread_self();
2044         
2045         //fprintf(stderr, "in thread_read_tty\n");
2046         
2047         if(/*max_retries>0 &&*/ _aprs_tty_thread == my_thread )
2048         {
2049                 if( serial_init() >= 0 )
2050                 {
2051                         // Success
2052                         //fprintf(stderr, "TTY port open \n");
2053                         port_read();
2054                         
2055                         if(_aprs_tty_thread == my_thread)
2056                         {
2057                     g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2058                             g_strdup_printf("%s",
2059                             _("Error reading data from TNC Port.")));
2060
2061                         }
2062                 }
2063                 else
2064                 {
2065                         // Failed
2066                         fprintf(stderr, "Failed to init serial port\n");
2067                         
2068             g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2069                     g_strdup_printf("%s",
2070                     _("Error connecting to TNC Port.")));
2071
2072                 }
2073
2074                 close_tnc_port();
2075 //              max_retries--;
2076 //              sleep(50);
2077         }
2078         
2079 //      if(max_retries==0)
2080 //      {
2081                 // Failed
2082 //              set_aprs_tty_conn_state(RCVR_OFF);
2083 //              MACRO_BANNER_SHOW_INFO(_window, _("Failed to connect to TNC!")); \
2084 //      }
2085
2086 }
2087
2088 gboolean aprs_tty_connect()
2089 {
2090     printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_tty_state);
2091
2092     if(_aprs_tty_enable && _aprs_tty_state == RCVR_OFF)
2093     {
2094         set_aprs_tty_conn_state(RCVR_DOWN);
2095
2096         // Lock/Unlock the mutex to ensure that the thread doesn't
2097         // start until _gps_thread is set. 
2098         g_mutex_lock(_aprs_tty_init_mutex);
2099
2100         _aprs_tty_thread = g_thread_create((GThreadFunc)thread_read_tty,
2101                 NULL, TRUE, NULL); // Joinable. 
2102
2103         g_mutex_unlock(_aprs_tty_init_mutex);
2104     }
2105
2106     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2107     return FALSE;
2108
2109 }
2110
2111 void aprs_tty_disconnect()
2112 {
2113     gboolean exit_now = FALSE;
2114
2115     printf("%s()\n", __PRETTY_FUNCTION__);
2116
2117     GThread *my_thread = g_thread_self();
2118
2119     if(my_thread == _aprs_tty_thread)
2120     {
2121         exit_now = TRUE;
2122         close_tnc_port();
2123     }
2124
2125     _aprs_tty_thread = NULL;
2126
2127     if(_window)
2128         set_aprs_tty_conn_state(RCVR_OFF);
2129     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2130
2131     if(exit_now) exit(0);
2132
2133 }
2134
2135
2136 //***********************************************************
2137 // port_write_string()
2138 //
2139 // port is port# used
2140 // data is the string to write
2141 //***********************************************************
2142
2143 void port_write_string(gchar *data, gint len, TAprsPort port) {
2144 //    int i,erd, 
2145     int retval;
2146 //    int write_in_pos_hold;
2147
2148     if (data == NULL)
2149         return;
2150
2151     if (data[0] == '\0')
2152         return;
2153     
2154     
2155     
2156     if(port == APRS_PORT_TTY)
2157     {
2158     
2159         if(g_mutex_trylock (_write_buffer[port].write_lock))
2160         {
2161                 //fprintf(stderr, "TTY Write... ");
2162                     retval = (int)write(port_data.channel,
2163                         data,
2164                         len);
2165                     //fprintf(stderr, "done... ");
2166                     g_mutex_unlock (_write_buffer[port].write_lock);
2167                     //fprintf(stderr, "Unlocked\n");
2168         }
2169         else
2170                 fprintf(stderr, "Failed to get lock\n");
2171     }
2172     else
2173     {
2174         send_line(data, len, port);
2175     }
2176 }
2177
2178
2179 gboolean send_line(gchar* text, gint text_len, TAprsPort port)
2180 {
2181         if(APRS_PORT_INET == port && !_aprs_enable_inet_tx) return FALSE;
2182         else if (APRS_PORT_TTY == port && !_aprs_enable_tty_tx) return FALSE;
2183         
2184         if(APRS_PORT_TTY == port)
2185         {
2186         
2187         }
2188         gboolean error = FALSE;
2189         gint i;
2190     gint write_in_pos_hold = _write_buffer[port].write_in_pos;
2191     
2192     // Lock the mutex 
2193     g_mutex_lock(_write_buffer[port].write_lock);
2194     
2195     for (i = 0; i < text_len && !error; i++) {
2196         _write_buffer[port].device_write_buffer[_write_buffer[port].write_in_pos++] 
2197                                                 = text[i];
2198         
2199         if (_write_buffer[port].write_in_pos >= MAX_DEVICE_BUFFER)
2200                 _write_buffer[port].write_in_pos = 0;
2201
2202         if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
2203             fprintf(stderr,"Port %d Buffer overrun\n",port);
2204
2205             /* clear this restore original write_in pos and dump this string */
2206             _write_buffer[port].write_in_pos = write_in_pos_hold;
2207             _write_buffer[port].errors++;
2208             error = TRUE;
2209         }
2210     }
2211         
2212     g_mutex_unlock(_write_buffer[port].write_lock);
2213     
2214     return error;
2215 }
2216
2217
2218 //***********************************************************
2219 // port_read()
2220 //
2221 //
2222 // This function becomes the long-running thread that snags
2223 // characters from an interface and passes them off to the
2224 // decoding routines.  One copy of this is run for each read
2225 // thread for each interface.
2226 //***********************************************************
2227 gboolean read_port_data();
2228
2229 void port_read() {
2230 //    unsigned char cin, last;
2231 //    gint i;
2232     struct timeval tmv;
2233     fd_set rd;
2234
2235 //    cin = (unsigned char)0;
2236 //    last = (unsigned char)0;
2237     gboolean success = TRUE;
2238     GThread *my_thread = g_thread_self();
2239
2240     fprintf(stderr, "Enter port_read\n");
2241     
2242     // We stay in this read loop until the port is shut down
2243     while(port_data.active == DEVICE_IN_USE && _aprs_tty_thread == my_thread
2244                 && RCVR_UP == _aprs_tty_state && success == TRUE){
2245
2246         if (port_data.status == DEVICE_UP){
2247
2248             port_data.read_in_pos = 0;
2249             port_data.scan = 1;
2250             
2251             
2252             while (port_data.scan >= 0
2253                         && success == TRUE
2254                         //&& RCVR_UP == _aprs_tty_state
2255                     && (port_data.read_in_pos < (MAX_DEVICE_BUFFER - 1) )
2256                     && (port_data.status == DEVICE_UP)
2257                     && (_aprs_tty_thread == my_thread) 
2258                 ) 
2259             {
2260     
2261                 success = read_port_data();
2262             }
2263             
2264         }
2265         if (port_data.active == DEVICE_IN_USE)  {
2266
2267             
2268                 
2269                 // We need to delay here so that the thread doesn't use
2270             // high amounts of CPU doing nothing.
2271
2272 // This select that waits on data and a timeout, so that if data
2273 // doesn't come in within a certain period of time, we wake up to
2274 // check whether the socket has gone down.  Else, we go back into
2275 // the select to wait for more data or a timeout.  FreeBSD has a
2276 // problem if this is less than 1ms.  Linux works ok down to 100us.
2277 // We don't need it anywhere near that short though.  We just need
2278 // to check whether the main thread has requested the interface be
2279 // closed, and so need to have this short enough to have reasonable
2280 // response time to the user.
2281
2282 //sched_yield();  // Yield to other threads
2283
2284             // Set up the select to block until data ready or 100ms
2285             // timeout, whichever occurs first.
2286             FD_ZERO(&rd);
2287             FD_SET(port_data.channel, &rd);
2288             tmv.tv_sec = 0;
2289             tmv.tv_usec = 100000;    // 100 ms
2290             (void)select(0,&rd,NULL,NULL,&tmv);
2291         }
2292     }
2293
2294     fprintf(stderr, "End of port_read\n");
2295 }
2296
2297
2298 gboolean aprs_send_beacon_inet()
2299 {
2300
2301         aprs_send_beacon(APRS_PORT_INET);
2302
2303         return TRUE;
2304 }
2305
2306 gboolean aprs_send_beacon(TAprsPort port)
2307 {
2308         if(_aprs_enable)
2309         {
2310                 output_my_aprs_data(port);
2311                 
2312                 //fprintf(stderr, "Beacon sent\n" );
2313         }
2314         
2315         return TRUE;
2316 }
2317
2318
2319 gboolean timer_callback_aprs_inet (gpointer data) {
2320
2321         if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
2322         {
2323                 aprs_send_beacon(APRS_PORT_INET);
2324                 return TRUE; // Continue timer
2325         }
2326         
2327         return FALSE; // Stop timer
2328 }
2329
2330
2331
2332 gboolean timer_callback_aprs_tty (gpointer data) {
2333
2334         if(_aprs_tty_enable && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
2335         {
2336                 fprintf(stderr, "Sending beacon for TNC...\n");
2337                 aprs_send_beacon(APRS_PORT_TTY);
2338                 return TRUE; // Continue timer
2339         }
2340         
2341         return FALSE; // Stop timer
2342 }
2343
2344
2345 void aprs_timer_init()
2346 {
2347         // disable timer if exists
2348         if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
2349         if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
2350         
2351         if(_aprs_enable)
2352         {
2353                 if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
2354                         _aprs_inet_beacon_timer = g_timeout_add(_aprs_inet_beacon_interval*1000 , timer_callback_aprs_inet, NULL);
2355                 
2356                 if(_aprs_tty_enable && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
2357                         _aprs_tty_beacon_timer = g_timeout_add(_aprs_tty_beacon_interval*1000 , timer_callback_aprs_tty, NULL);
2358         }
2359 }
2360
2361 #endif //INCLUDE_APRS