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