3 * This file is part of Maemo Mapper.
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.
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.
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/>.
19 * Parts of this code have been ported from Xastir by Rob Williams (10 Aug 2008):
21 * * XASTIR, Amateur Station Tracking and Information Reporting
22 * Copyright (C) 1999,2000 Frank Giannandrea
23 * Copyright (C) 2000-2007 The Xastir Group
42 #include <libgnomevfs/gnome-vfs.h>
43 #include <libgnomevfs/gnome-vfs-inet-connection.h>
45 #include "aprs_display.h"
48 # include <hildon/hildon-note.h>
49 # include <hildon/hildon-banner.h>
51 # include <hildon-widgets/hildon-note.h>
52 # include <hildon-widgets/hildon-banner.h>
66 #include "aprs_decode.h"
68 static volatile GThread* _aprs_inet_thread = NULL;
69 static volatile GThread* _aprs_tty_thread = NULL;
71 static GMutex* _aprs_inet_init_mutex = NULL;
72 static GMutex* _aprs_tty_init_mutex = NULL;
74 static gint _aprs_rcvr_retry_count = 0;
76 static guint _aprs_inet_beacon_timer;
77 static guint _aprs_tty_beacon_timer;
80 #define VERSIONFRM "APRS"
81 extern AprsDataRow* n_first; // pointer to first element in name sorted station list
85 TWriteBuffer _write_buffer[APRS_PORT_COUNT];
87 gboolean send_line(gchar* text, gint text_len, TAprsPort port);
89 void aprs_tty_disconnect();
91 static gboolean aprs_handle_error_idle(gchar *error)
93 printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
96 if(++_aprs_rcvr_retry_count > 2)
99 gchar buffer[BUFFER_SIZE];
101 /* Reset retry count. */
102 _aprs_rcvr_retry_count = 0;
104 snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
105 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
107 aprs_server_disconnect();
109 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
111 aprs_server_connect(); /* Try again. */
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);
120 /* Ask user to re-connect. */
121 gtk_widget_destroy(confirm);
125 aprs_server_disconnect();
126 aprs_server_connect(); /* Try again. */
131 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
137 * Set the connection state. This function controls all connection-related
140 void set_aprs_tty_conn_state(ConnState new_conn_state)
142 printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
144 switch(_aprs_tty_state = new_conn_state)
151 gtk_widget_destroy(_connect_banner);
152 _connect_banner = NULL;
156 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
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);
163 _aprs_rcvr_retry_count = 0;
167 _connect_banner = hildon_banner_show_animation(
168 _window, NULL, _("Attempting to connect to TNC"));
170 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
175 default: ; /* to quell warning. */
178 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
182 * Set the connection state. This function controls all connection-related
185 void set_aprs_inet_conn_state(ConnState new_conn_state)
187 printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
189 switch(_aprs_inet_state = new_conn_state)
196 gtk_widget_destroy(_connect_banner);
197 _connect_banner = NULL;
201 gtk_widget_destroy(_fix_banner);
205 if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
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);
216 gtk_widget_destroy(_fix_banner);
220 _connect_banner = hildon_banner_show_animation(
221 _window, NULL, _("Attempting to connect to APRS server"));
223 if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
226 default: ; /* to quell warning. */
229 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
233 static gboolean aprs_parse_server_packet(gchar *packet)
235 decode_ax25_line(packet, APRS_PORT_INET);
243 void update_aprs_inet_options(gboolean force)
245 // If auto filter is not or we are not connected then stop
246 if(!_aprs_server_auto_filter_on
248 || !_aprs_inet_enable
249 || _aprs_server_auto_filter_km <= 0) return ;
253 aprs_server_disconnect();
255 aprs_server_connect();
259 gchar *create_aprs_inet_options_string()
261 gint current_lat = (gint)round(_gps.lat);
262 gint current_lon = (gint)round(_gps.lon);
263 gchar *filter = NULL;
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 );
273 static void thread_read_server()
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;
285 printf("%s(%s)\n", __PRETTY_FUNCTION__, _aprs_server);
288 //fprintf(stderr, "Starting thread...\n");
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);
294 if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
298 /* Attempt to connect to APRS server. */
299 for(tryno = 0; tryno < 10; tryno++)
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);
306 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create(
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))
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.")));
341 if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
344 set_aprs_inet_conn_state(RCVR_UP);
346 while(my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
351 vfs_result = gnome_vfs_socket_read(
359 if(vfs_result != GNOME_VFS_OK)
361 if(my_thread == _aprs_inet_thread)
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));
370 fprintf(stderr, "Read error: %s\n", gnome_vfs_result_to_string(vfs_result));
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')))
381 /* This is the beginning of a sentence; okay to parse. */
382 *eol = '\0'; /* overwrite \n with \0 */
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));
388 /* If eol is at or after (buf_curr - 1) */
389 if(eol >= (buf_curr - 1))
391 /* Last read was a newline - reset read buffer */
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);
404 _aprs_rcvr_retry_count = 0;
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))
410 // Store the current end pointer as it may change
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) {
416 tmp_write_buffer[quantity] = _write_buffer[APRS_PORT_INET].device_write_buffer[_write_buffer[APRS_PORT_INET].write_out_pos];
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;
429 GnomeVFSFileSize bytes_read = 0;
430 if(GNOME_VFS_OK == gnome_vfs_socket_write( socket,
431 tmp_write_buffer, quantity, &bytes_read, NULL))
434 //fprintf(stderr, "Send packet success: %s (%u)\n", tmp_write_buffer, quantity);
439 fprintf(stderr, "Failed to send packet: %s (%u)\n", tmp_write_buffer, quantity);
445 g_mutex_unlock(_write_buffer[APRS_PORT_INET].write_lock);
450 //fprintf(stderr, "Exiting thread...\n");
453 /* Error, or we're done reading APRS data. */
457 gnome_vfs_inet_connection_destroy(iconn, NULL);
458 //gnome_vfs_inet_connection_free(iconn, NULL);
465 printf("%s(): return\n", __PRETTY_FUNCTION__);
471 * Disconnect from the receiver. This method cleans up any and everything
472 * that might be associated with the receiver.
474 void aprs_server_disconnect()
476 gboolean exit_now = FALSE;
478 printf("%s()\n", __PRETTY_FUNCTION__);
480 GThread *my_thread = g_thread_self();
482 if(my_thread == _aprs_inet_thread)
487 g_mutex_lock(_aprs_inet_init_mutex);
488 _aprs_inet_thread = NULL;
489 g_mutex_unlock(_aprs_inet_init_mutex);
494 set_aprs_inet_conn_state(RCVR_OFF);
495 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
499 fprintf(stderr, "Stopping own thread - APRS server\n");
501 fprintf(stderr, "Stop Failed\n");
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.
513 gboolean aprs_server_connect()
515 printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_inet_state);
517 if(_aprs_inet_enable && _aprs_inet_state == RCVR_OFF)
519 set_aprs_inet_conn_state(RCVR_DOWN);
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);
526 _aprs_inet_thread = g_thread_create((GThreadFunc)thread_read_server,
527 NULL, TRUE, NULL); /* Joinable. */
529 // g_thread_set_priority(_aprs_inet_thread, G_THREAD_PRIORITY_LOW);
531 g_mutex_unlock(_aprs_inet_init_mutex);
534 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
540 printf("%s()\n", __PRETTY_FUNCTION__);
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();
547 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
550 void aprs_destroy(gboolean last)
552 static GThread* tmp = NULL;
553 printf("%s()\n", __PRETTY_FUNCTION__);
557 if(_aprs_inet_thread)
559 tmp = (GThread*)_aprs_inet_thread;
560 _aprs_inet_thread = NULL;
566 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
569 gboolean select_aprs(gint unitx, gint unity, gboolean quick)
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;
580 gboolean selected = FALSE;
581 gint num_stations = 0;
582 AprsStationList *first_station = NULL;
583 AprsStationList *last_station = NULL;
586 printf("%s()\n", __PRETTY_FUNCTION__);
588 x = unitx - pixel2unit(3 * _draw_width);
589 y = unity + pixel2unit(3 * _draw_width);
590 unit2latlon(x, y, lat1, lon1);
592 x = unitx + pixel2unit(3 * _draw_width);
593 y = unity - pixel2unit(3 * _draw_width);
594 unit2latlon(x, y, lat2, lon2);
598 AprsDataRow *p_station = (AprsDataRow *)n_first;
600 // Look for all stations in selected area
601 while ( (p_station) != NULL)
603 lat = convert_lat_l2d(p_station->coord_lat);
604 lon = convert_lon_l2d(p_station->coord_lon);
606 if ( ( lat2 >= lat && lat >= lat1 ) && (lon2 >= lon && lon >= lon1) )
608 // This may have been clicked on
609 AprsStationList * p_list_item = (AprsStationList *)malloc(sizeof(AprsStationList));
611 p_list_item->station = p_station;
612 p_list_item->next = NULL;
614 if(first_station == NULL)
617 first_station = p_list_item;
618 last_station = p_list_item;
622 last_station->next = p_list_item;
623 last_station = p_list_item;
629 (p_station) = (p_station)->n_next; // Next element in list
630 } // End of while loop
636 // No station found, maybe a POI was selected?
638 else if(num_stations == 1)
640 // Only one station was found, so display it's info
641 if(first_station->station != NULL)
643 ShowAprsStationPopup(first_station->station);
649 // Multiple possibilities, therefore ask the user which one
652 store = gtk_list_store_new(APRSPOI_NUM_COLUMNS,
653 G_TYPE_BOOLEAN, //Selected
654 G_TYPE_STRING // Callsign
657 AprsStationList * p_list_item = first_station;
659 while(p_list_item != NULL)
661 if(p_list_item->station != NULL)
663 gtk_list_store_append(store, &iter);
665 gtk_list_store_set(store, &iter,
666 APRSPOI_CALLSIGN, g_strdup(p_list_item->station->call_sign),
669 p_list_item = p_list_item->next;
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,
681 gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
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),
688 GTK_POLICY_AUTOMATIC);
689 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
692 list = gtk_tree_view_new();
693 gtk_container_add(GTK_CONTAINER(sw), list);
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);
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);
708 gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
709 g_object_unref(G_OBJECT(store));
711 gtk_widget_show_all(dialog);
713 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
715 if(gtk_tree_selection_get_selected(
716 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
720 p_list_item = first_station;
721 while(p_list_item != NULL)
723 if(p_list_item->station != NULL)
725 gchar * callsign = NULL;
726 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
727 APRSPOI_CALLSIGN, &(callsign),
730 if(strcmp(p_list_item->station->call_sign,callsign) == 0)
732 gtk_widget_hide(dialog);
734 ShowAprsStationPopup(p_list_item->station);
741 p_list_item = p_list_item->next;
748 // Ensure it has been closed
749 gtk_widget_hide(dialog);
753 // Free the list, but not the stations
756 AprsStationList * p_list_item = first_station;
760 // Store pointer to delete contents after next pointer is stored
761 p_list_item = first_station;
763 // Move pointer to next
764 first_station = p_list_item->next;
771 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
778 //*****************************************************************
779 // distance_from_my_station - compute distance from my station and
780 // course with a given call
782 // return distance and course
784 // Returns 0.0 for distance if station not found in database or the
785 // station hasn't sent out a posit yet.
786 //*****************************************************************
788 double distance_from_my_station(char *call_sign, gchar *course_deg, gint course_len) {
789 AprsDataRow *p_station;
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) ) {
803 d_lat = convert_lat_l2d(p_station->coord_lat);
804 d_lon = convert_lon_l2d(p_station->coord_lon);
806 value = (float)calculate_distance(_gps.lat, _gps.lon, d_lat, d_lon);
808 snprintf(course_deg, course_len,
810 calculate_bearing(_gps.lat, _gps.lon, d_lat, d_lon));
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)
819 distance = 0.0; // Should be unreachable
824 else { // Station not found
834 void pad_callsign(char *callsignout, char *callsignin) {
837 l=(int)strlen(callsignin);
840 if(isalnum((int)callsignin[i]) || callsignin[i]=='-') {
841 callsignout[i]=callsignin[i];
844 callsignout[i] = ' ';
848 callsignout[i] = ' ';
851 callsignout[i] = '\0';
853 /////////// TX functionality
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
863 void fix_up_callsign(unsigned char *data, int data_size) {
864 unsigned char new_call[8] = " "; // Start with seven spaces
868 int digipeated_flag = 0;
871 // Check whether we've digipeated through this callsign yet.
872 if (strstr((const char *)data,"*") != 0) {
876 // Change callsign to upper-case and pad out to six places with
878 for (i = 0; i < (int)strlen((const char *)data); i++) {
881 if (data[i] == '-') { // Stop at '-'
884 else if (data[i] == '*') {
887 new_call[j++] = data[i];
892 //fprintf(stderr,"new_call:(%s)\n",new_call);
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
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);
904 //fprintf(stderr,"SSID:%d\t",ssid);
906 if (ssid >= 0 && ssid <= 15) {
907 new_call[6] = ssid | 0x30; // Set 2 reserved bits
909 else { // Whacko SSID. Set it to zero
910 new_call[6] = 0x30; // Set 2 reserved bits
913 if (digipeated_flag) {
914 new_call[6] = new_call[6] | 0x40; // Set the 'H' bit
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;
923 //fprintf(stderr,"Last:%0x\n",new_call[6]);
925 // Write over the top of the input string with the newly
926 // formatted callsign
927 xastir_snprintf((char *)data,
936 // Create an AX25 frame and then turn it into a KISS packet. Dump
937 // it into the transmit queue.
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];
949 int write_in_pos_hold;
952 //fprintf(stderr,"KISS String:%s>%s,%s:%s\n",source,destination,path,data);
954 // Check whether transmits are disabled globally
955 // if (transmit_disable) {
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) {
965 transmit_txt[0] = '\0';
967 // Format the destination callsign
968 snprintf((char *)temp_dest,
972 fix_up_callsign(temp_dest, sizeof(temp_dest));
974 snprintf((char *)transmit_txt,
975 sizeof(transmit_txt),
979 // Format the source callsign
980 snprintf((char *)temp_source,
984 fix_up_callsign(temp_source, sizeof(temp_source));
986 strncat((char *)transmit_txt,
988 sizeof(transmit_txt) - strlen((char *)transmit_txt));
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
995 temp[0] = '\0'; // Start with empty path
996 if ( (path != NULL) && (strlen(path) != 0) ) {
997 while (path[j] != '\0') {
999 while ( (path[j] != ',') && (path[j] != '\0') ) {
1000 temp[i++] = path[j++];
1004 if (path[j] == ',') { // Skip over comma
1008 fix_up_callsign(temp, sizeof(temp));
1009 strncat((char *)transmit_txt,
1011 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1015 // Set the end-of-address bit on the last callsign in the
1017 transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01;
1019 // Add the Control byte
1022 strncat((char *)transmit_txt,
1024 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1029 strncat((char *)transmit_txt,
1031 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1033 // Append the information chars
1034 strncat((char *)transmit_txt,
1036 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1038 //fprintf(stderr,"%s\n",transmit_txt);
1040 // Add the KISS framing characters and do the proper escapes.
1042 transmit_txt2[j++] = KISS_FEND;
1044 // Note: This byte is where different interfaces would be
1046 transmit_txt2[j++] = 0x00;
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;
1054 else if (c == KISS_FESC) {
1055 transmit_txt2[j++] = KISS_FESC;
1056 transmit_txt2[j++] = KISS_TFESC;
1059 transmit_txt2[j++] = c;
1062 transmit_txt2[j++] = KISS_FEND;
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.
1068 transmit_txt2[j] = '\0';
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
1075 //-------------------------------------------------------------------
1090 g_mutex_lock (_write_buffer[port].write_lock);
1093 write_in_pos_hold = _write_buffer[port].write_in_pos;
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;
1100 if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
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++;
1109 g_mutex_unlock (_write_buffer[port].write_lock);
1117 // convert latitude from long to string
1118 // Input is in Xastir coordinate system
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
1131 void convert_lat_l2s(long lat, char *str, int str_len, int type) {
1133 float deg, min, sec;
1139 deg = (float)(lat - 32400000l) / 360000.0;
1141 // Switch to integer arithmetic to avoid floating-point
1143 temp = (long)(deg * 100000);
1151 ideg = (int)temp / 100000;
1152 min = (temp % 100000) * 60.0 / 100000.0;
1154 // Again switch to integer arithmetic to avoid floating-point
1156 temp = (long)(min * 1000);
1157 imin = (int)(temp / 1000);
1158 sec = (temp % 1000) * 60.0 / 1000.0;
1162 case(CONVERT_LP_NOSP): /* do low P w/no space */
1163 xastir_snprintf(str,
1167 // min+0.001, // Correct possible unbiased rounding
1172 case(CONVERT_LP_NORMAL): /* do low P normal */
1173 xastir_snprintf(str,
1177 // min+0.001, // Correct possible unbiased rounding
1182 case(CONVERT_HP_NOSP): /* do HP w/no space */
1183 xastir_snprintf(str,
1187 // min+0.0001, // Correct possible unbiased rounding
1192 case(CONVERT_VHP_NOSP): /* do Very HP w/no space */
1193 xastir_snprintf(str,
1197 // min+0.00001, // Correct possible unbiased rounding
1202 case(CONVERT_UP_TRK): /* for tracklog files */
1203 xastir_snprintf(str,
1208 // min+0.00001); // Correct possible unbiased rounding
1212 case(CONVERT_DEC_DEG):
1213 xastir_snprintf(str,
1216 // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1221 case(CONVERT_DMS_NORMAL):
1222 xastir_snprintf(str,
1224 "%02d %02d %04.1f%c",
1227 // sec+0.01, // Correct possible unbiased rounding
1232 case(CONVERT_DMS_NORMAL_FORMATED):
1233 xastir_snprintf(str,
1235 "%02d°%02d\'%04.1f%c",
1238 // sec+0.01, // Correct possible unbiased rounding
1243 case(CONVERT_HP_NORMAL_FORMATED):
1244 xastir_snprintf(str,
1248 // min+0.0001, // Correct possible unbiased roundin
1253 case(CONVERT_HP_NORMAL):
1254 default: /* do HP normal */
1255 xastir_snprintf(str,
1259 // min+0.0001, // Correct possible unbiased rounding
1270 // convert longitude from long to string
1271 // Input is in Xastir coordinate system
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
1283 void convert_lon_l2s(long lon, char *str, int str_len, int type) {
1285 float deg, min, sec;
1290 deg = (float)(lon - 64800000l) / 360000.0;
1292 // Switch to integer arithmetic to avoid floating-point rounding
1294 temp = (long)(deg * 100000);
1302 ideg = (int)temp / 100000;
1303 min = (temp % 100000) * 60.0 / 100000.0;
1305 // Again switch to integer arithmetic to avoid floating-point
1307 temp = (long)(min * 1000);
1308 imin = (int)(temp / 1000);
1309 sec = (temp % 1000) * 60.0 / 1000.0;
1313 case(CONVERT_LP_NOSP): /* do low P w/nospacel */
1314 xastir_snprintf(str,
1318 // min+0.001, // Correct possible unbiased rounding
1323 case(CONVERT_LP_NORMAL): /* do low P normal */
1324 xastir_snprintf(str,
1328 // min+0.001, // Correct possible unbiased rounding
1333 case(CONVERT_HP_NOSP): /* do HP w/nospace */
1334 xastir_snprintf(str,
1338 // min+0.0001, // Correct possible unbiased rounding
1343 case(CONVERT_VHP_NOSP): /* do Very HP w/nospace */
1344 xastir_snprintf(str,
1348 // min+0.00001, // Correct possible unbiased rounding
1353 case(CONVERT_UP_TRK): /* for tracklog files */
1354 xastir_snprintf(str,
1359 // min+0.00001); // Correct possible unbiased rounding
1363 case(CONVERT_DEC_DEG):
1364 xastir_snprintf(str,
1367 // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1372 case(CONVERT_DMS_NORMAL):
1373 xastir_snprintf(str,
1375 "%03d %02d %04.1f%c",
1378 // sec+0.01, // Correct possible unbiased rounding
1383 case(CONVERT_DMS_NORMAL_FORMATED):
1384 xastir_snprintf(str,
1386 "%03d°%02d\'%04.1f%c",
1389 // sec+0.01, // Correct possible unbiased rounding
1394 case(CONVERT_HP_NORMAL_FORMATED):
1395 xastir_snprintf(str,
1399 // min+0.0001, // Correct possible unbiased rounding
1404 case(CONVERT_HP_NORMAL):
1405 default: /* do HP normal */
1406 xastir_snprintf(str,
1410 // min+0.0001, // Correct possible unbiased rounding
1422 /*************************************************************************/
1423 /* output_lat - format position with position_amb_chars for transmission */
1424 /*************************************************************************/
1426 char *output_lat(char *in_lat, int comp_pos) {
1428 int position_amb_chars = 0;
1429 //fprintf(stderr,"in_lat:%s\n", in_lat);
1432 // Don't do this as it results in truncation!
1433 //in_lat[7]=in_lat[8]; // Shift N/S down for transmission
1435 else if (position_amb_chars>0) {
1440 if (position_amb_chars>0 && position_amb_chars<5) {
1441 for (i=6;i>(6-position_amb_chars-j);i--) {
1463 /**************************************************************************/
1464 /* output_long - format position with position_amb_chars for transmission */
1465 /**************************************************************************/
1467 char *output_long(char *in_long, int comp_pos) {
1469 int position_amb_chars = 0;
1470 //fprintf(stderr,"in_long:%s\n", in_long);
1473 // Don't do this as it results in truncation!
1474 //in_long[8]=in_long[9]; // Shift e/w down for transmission
1476 else if (position_amb_chars>0) {
1481 if (position_amb_chars>0 && position_amb_chars<5) {
1482 for (i=7;i>(7-position_amb_chars-j);i--) {
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 //***********************************************************/
1511 void create_output_lat_long(gchar *my_output_lat, gchar *my_output_long )
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);
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),
1527 else { // Create a low-res version of the latitude string
1532 my_temp_lat = convert_lat_s2l(my_lat);
1534 // Convert to low-res string
1535 convert_lat_l2s(my_temp_lat,
1540 snprintf(my_output_lat,
1541 sizeof(my_output_lat),
1552 (void)output_lat(my_output_lat, _aprs_transmit_compressed_posit);
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),
1561 else { // Create a low-res version of the longitude string
1566 my_temp_long = convert_lon_s2l(my_long);
1568 // Convert to low-res string
1569 convert_lon_l2s(my_temp_long,
1574 snprintf(my_output_long,
1575 sizeof(my_output_long),
1576 "%c%c%c%c%c.%c%c%c",
1587 (void)output_long(my_output_long, _aprs_transmit_compressed_posit);
1592 void output_my_aprs_data_tty() {
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 = "";
1605 struct tm *day_time;
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];
1613 gchar my_comment_tx[APRS_MAX_COMMENT+1];
1614 int interfaces_ok_for_transmit = 0;
1618 gchar header_txt[MAX_LINE_SIZE+5];
1619 gchar header_txt_save[MAX_LINE_SIZE+5];
1621 gchar data_txt_save[MAX_LINE_SIZE+5];
1624 if (!(port_data.status == DEVICE_UP
1625 && _aprs_tty_enable && _aprs_enable && _aprs_enable_tty_tx)) return ;
1627 header_txt_save[0] = '\0';
1628 data_txt_save[0] = '\0';
1634 create_output_lat_long(my_output_lat, my_output_long);
1637 // First send any header/path info we might need out the port,
1638 // set up TNC's to the proper mode, etc.
1641 // clear this for a TNC
1642 output_net[0] = '\0';
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
1652 snprintf(header_txt,
1656 ((port_data.device_type !=DEVICE_AX25_TNC)?
1657 "\rMYCALL":"MYCALL"),
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
1669 port_write_string(header_txt, APRS_PORT_TTY);
1670 //send_line(gchar* text, gint text_len, TAprsPort port)
1673 // Set unproto path: Get next unproto path in
1676 snprintf(header_txt,
1682 _aprs_unproto_path);
1684 snprintf(header_txt_save,
1685 sizeof(header_txt_save),
1689 _aprs_unproto_path);
1694 _aprs_unproto_path);
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
1707 port_write_string(header_txt, APRS_PORT_TTY);
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.
1718 snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', APRS_CONVERSE_MODE);
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
1727 port_write_string(header_txt, APRS_PORT_TTY);
1733 // Set up some more strings for later transmission
1735 // send station info
1736 output_cs[0] = '\0';
1737 output_phg[0] = '\0';
1738 output_alt[0] = '\0';
1739 output_brk[0] = '\0';
1742 if (_aprs_transmit_compressed_posit)
1744 // TOOD - enable compressed beacon support
1749 // compress_posit(my_output_lat,
1754 // my_last_speed, // In knots
1758 else { // standard non compressed mode
1765 _aprs_beacon_symbol);
1766 // get PHG, if used for output
1767 if (strlen(my_phg) >= 6)
1768 snprintf(output_phg,
1773 // get CSE/SPD, Always needed for output even if 0
1778 _gps.speed); // Speed in knots
1782 // if (my_last_altitude_time > 0)
1783 // snprintf(output_alt,
1784 // sizeof(output_alt),
1786 // my_last_altitude);
1790 // APRS_MOBILE LOCAL TIME
1793 // if((strlen(output_cs) < 8) && (my_last_altitude_time > 0)) {
1794 // xastir_snprintf(output_brk,
1795 // sizeof(output_brk),
1799 day_time = localtime(&sec);
1801 snprintf(data_txt_save,
1802 sizeof(data_txt_save),
1803 "@%02d%02d%02d/%s%s%s%s%s",
1814 // Truncate at max length for this type of APRS
1816 if (_aprs_transmit_compressed_posit) {
1817 if (strlen(data_txt_save) > 61) {
1818 data_txt_save[61] = '\0';
1821 else { // Uncompressed lat/long
1822 if (strlen(data_txt_save) > 70) {
1823 data_txt_save[70] = '\0';
1827 // Add '\r' onto end.
1828 strncat(data_txt_save, "\r", 1);
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.
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
1848 interfaces_ok_for_transmit++;
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.
1854 if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1855 || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1857 // Note: This one has callsign & destination in the string
1859 // Transmit the posit out the KISS interface
1860 send_ax25_frame(APRS_PORT_TTY,
1861 _aprs_mycall, // source
1862 VERSIONFRM, // destination
1866 else { // Not a Serial KISS TNC interface
1869 port_write_string(data_txt, APRS_PORT_TTY); // Transmit the posit
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.
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
1889 //makePrintable(temp);
1890 //packet_data_add("TX ", temp, port);
1893 } // End of posit transmit: "if (ok)"
1897 void create_output_pos_packet(TAprsPort port, gchar **packet, int *length)
1900 // gchar encodedPos[MAX_LINE_SIZE];
1902 if(_aprs_transmit_compressed_posit)
1908 //!5122.09N/00008.42W&APRS4R IGATE RUNNING ON NSLU2
1910 // For now just use a simple packet
1915 gdouble pos = (_gps.lat > 0 ? _gps.lat : 0-_gps.lat);
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) );
1921 pos = (_gps.lon > 0 ? _gps.lon : 0-_gps.lon);
1923 min = (pos - (int)pos)*60.0;
1924 sprintf(slon, "%03d%02d.%02.0f", (int)pos, (int)min,
1925 ((min - (int)min)*100.0) );
1927 *packet = g_strdup_printf(
1928 "%c%s%c%c%s%c%c%s%c",
1931 (_gps.lat > 0 ? 'N' : 'S'),
1934 (_gps.lon > 0 ? 'E' : 'W'),
1935 _aprs_beacon_symbol,
1936 (port == APRS_PORT_INET ? _aprs_inet_beacon_comment : _aprs_beacon_comment),
1941 *length = strlen(*packet);
1945 void send_packet(TAprsPort port, gchar* to_call, gchar* path, gchar* packet, gint packet_length)
1947 if(port == APRS_PORT_INET
1948 || !(port_data.device_type == DEVICE_SERIAL_KISS_TNC
1949 || port_data.device_type == DEVICE_SERIAL_MKISS_TNC) )
1951 gchar *packet_header
1958 gchar *full_packet = g_strdup_printf("%s%s\r\n", packet_header, packet);
1961 send_line(full_packet, strlen(packet_header)+packet_length+2, port);
1965 send_ax25_frame(port, _aprs_mycall, to_call, path, packet);
1970 void output_my_aprs_data(TAprsPort port) {
1977 //create_output_lat_long(my_output_lat, my_output_long);
1978 create_output_pos_packet(port, &packet, &length);
1981 send_packet(port, VERSIONFRM, _aprs_unproto_path, packet, length);
1983 if(packet != NULL) g_free(packet);
1986 /////////// TTY functionality
1989 int _aprs_tnc_retry_count = 0;
1991 static gboolean aprs_tnc_handle_error_idle (gchar *error)
1993 printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
1995 /* Ask for re-try. */
1996 if(++_aprs_tnc_retry_count > 2)
1999 gchar buffer[BUFFER_SIZE];
2001 /* Reset retry count. */
2002 _aprs_tnc_retry_count = 0;
2004 snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
2005 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
2007 aprs_tty_disconnect();
2009 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2010 aprs_tty_connect(); /* Try again. */
2014 gtk_check_menu_item_set_active(
2015 GTK_CHECK_MENU_ITEM(_menu_enable_aprs_tty_item), FALSE);
2018 /* Ask user to re-connect. */
2019 gtk_widget_destroy(confirm);
2023 aprs_tty_disconnect();
2024 aprs_tty_connect(); /* Try again. */
2029 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2034 void close_tnc_port();
2036 static void thread_read_tty()
2038 // gint max_retries = 5;
2039 GThread *my_thread = g_thread_self();
2041 //fprintf(stderr, "in thread_read_tty\n");
2043 if(/*max_retries>0 &&*/ _aprs_tty_thread == my_thread )
2045 if( serial_init() >= 0 )
2048 //fprintf(stderr, "TTY port open \n");
2051 if(_aprs_tty_thread == my_thread)
2053 g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2054 g_strdup_printf("%s",
2055 _("Error reading data from TNC Port.")));
2062 fprintf(stderr, "Failed to init serial port\n");
2064 g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2065 g_strdup_printf("%s",
2066 _("Error connecting to TNC Port.")));
2075 // if(max_retries==0)
2078 // set_aprs_tty_conn_state(RCVR_OFF);
2079 // MACRO_BANNER_SHOW_INFO(_window, _("Failed to connect to TNC!")); \
2084 gboolean aprs_tty_connect()
2086 printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_tty_state);
2088 if(_aprs_tty_enable && _aprs_tty_state == RCVR_OFF)
2090 set_aprs_tty_conn_state(RCVR_DOWN);
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);
2096 _aprs_tty_thread = g_thread_create((GThreadFunc)thread_read_tty,
2097 NULL, TRUE, NULL); // Joinable.
2099 g_mutex_unlock(_aprs_tty_init_mutex);
2102 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2107 void aprs_tty_disconnect()
2109 gboolean exit_now = FALSE;
2111 printf("%s()\n", __PRETTY_FUNCTION__);
2113 GThread *my_thread = g_thread_self();
2115 if(my_thread == _aprs_tty_thread)
2121 _aprs_tty_thread = NULL;
2124 set_aprs_tty_conn_state(RCVR_OFF);
2125 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2127 if(exit_now) exit(0);
2132 //***********************************************************
2133 // port_write_string()
2135 // port is port# used
2136 // data is the string to write
2137 //***********************************************************
2139 void port_write_string(gchar *data, gint len, TAprsPort port) {
2142 // int write_in_pos_hold;
2147 if (data[0] == '\0')
2152 if(port == APRS_PORT_TTY)
2155 if(g_mutex_trylock (_write_buffer[port].write_lock))
2157 //fprintf(stderr, "TTY Write... ");
2158 retval = (int)write(port_data.channel,
2161 //fprintf(stderr, "done... ");
2162 g_mutex_unlock (_write_buffer[port].write_lock);
2163 //fprintf(stderr, "Unlocked\n");
2166 fprintf(stderr, "Failed to get lock\n");
2170 send_line(data, len, port);
2175 gboolean send_line(gchar* text, gint text_len, TAprsPort port)
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;
2180 if(APRS_PORT_TTY == port)
2184 gboolean error = FALSE;
2186 gint write_in_pos_hold = _write_buffer[port].write_in_pos;
2189 g_mutex_lock(_write_buffer[port].write_lock);
2191 for (i = 0; i < text_len && !error; i++) {
2192 _write_buffer[port].device_write_buffer[_write_buffer[port].write_in_pos++]
2195 if (_write_buffer[port].write_in_pos >= MAX_DEVICE_BUFFER)
2196 _write_buffer[port].write_in_pos = 0;
2198 if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
2199 fprintf(stderr,"Port %d Buffer overrun\n",port);
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++;
2208 g_mutex_unlock(_write_buffer[port].write_lock);
2214 //***********************************************************
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();
2226 // unsigned char cin, last;
2231 // cin = (unsigned char)0;
2232 // last = (unsigned char)0;
2233 gboolean success = TRUE;
2234 GThread *my_thread = g_thread_self();
2236 fprintf(stderr, "Enter port_read\n");
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){
2242 if (port_data.status == DEVICE_UP){
2244 port_data.read_in_pos = 0;
2248 while (port_data.scan >= 0
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)
2257 success = read_port_data();
2261 if (port_data.active == DEVICE_IN_USE) {
2265 // We need to delay here so that the thread doesn't use
2266 // high amounts of CPU doing nothing.
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.
2278 //sched_yield(); // Yield to other threads
2280 // Set up the select to block until data ready or 100ms
2281 // timeout, whichever occurs first.
2283 FD_SET(port_data.channel, &rd);
2285 tmv.tv_usec = 100000; // 100 ms
2286 (void)select(0,&rd,NULL,NULL,&tmv);
2290 fprintf(stderr, "End of port_read\n");
2294 gboolean aprs_send_beacon_inet()
2297 aprs_send_beacon(APRS_PORT_INET);
2302 gboolean aprs_send_beacon(TAprsPort port)
2306 output_my_aprs_data(port);
2308 //fprintf(stderr, "Beacon sent\n" );
2315 gboolean timer_callback_aprs_inet (gpointer data) {
2317 if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
2319 aprs_send_beacon(APRS_PORT_INET);
2320 return TRUE; // Continue timer
2323 return FALSE; // Stop timer
2328 gboolean timer_callback_aprs_tty (gpointer data) {
2330 if(_aprs_tty_enable && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
2332 fprintf(stderr, "Sending beacon for TNC...\n");
2333 aprs_send_beacon(APRS_PORT_TTY);
2334 return TRUE; // Continue timer
2337 return FALSE; // Stop timer
2341 void aprs_timer_init()
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);
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);
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);
2357 #endif //INCLUDE_APRS