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>
70 #include "aprs_decode.h"
72 static volatile GThread* _aprs_inet_thread = NULL;
73 static volatile GThread* _aprs_tty_thread = NULL;
75 static GMutex* _aprs_inet_init_mutex = NULL;
76 static GMutex* _aprs_tty_init_mutex = NULL;
78 static gint _aprs_rcvr_retry_count = 0;
80 static guint _aprs_inet_beacon_timer;
81 static guint _aprs_tty_beacon_timer;
84 #define VERSIONFRM "APRS"
85 extern AprsDataRow* n_first; // pointer to first element in name sorted station list
89 TWriteBuffer _write_buffer[APRS_PORT_COUNT];
91 gboolean send_line(gchar* text, gint text_len, TAprsPort port);
93 void aprs_tty_disconnect();
95 static gboolean aprs_handle_error_idle(gchar *error)
97 printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
100 if(++_aprs_rcvr_retry_count > 2)
103 gchar buffer[BUFFER_SIZE];
105 /* Reset retry count. */
106 _aprs_rcvr_retry_count = 0;
108 snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
109 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
111 aprs_server_disconnect();
113 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
115 aprs_server_connect(); /* Try again. */
119 /* Reset Connect to APRS menu item. */
120 gtk_check_menu_item_set_active(
121 GTK_CHECK_MENU_ITEM(_menu_enable_aprs_inet_item), FALSE);
124 /* Ask user to re-connect. */
125 gtk_widget_destroy(confirm);
129 aprs_server_disconnect();
130 aprs_server_connect(); /* Try again. */
135 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
141 * Set the connection state. This function controls all connection-related
144 void set_aprs_tty_conn_state(ConnState new_conn_state)
146 printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
148 switch(_aprs_tty_state = new_conn_state)
155 gtk_widget_destroy(_connect_banner);
156 _connect_banner = NULL;
160 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
162 if(_aprs_enable && _aprs_tty_enable
163 && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
164 _aprs_tty_beacon_timer = g_timeout_add(_aprs_tty_beacon_interval*1000 , timer_callback_aprs_tty, NULL);
167 _aprs_rcvr_retry_count = 0;
171 _connect_banner = hildon_banner_show_animation(
172 _window, NULL, _("Attempting to connect to TNC"));
174 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
179 default: ; /* to quell warning. */
182 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
186 * Set the connection state. This function controls all connection-related
189 void set_aprs_inet_conn_state(ConnState new_conn_state)
191 printf("%s(%d)\n", __PRETTY_FUNCTION__, new_conn_state);
193 switch(_aprs_inet_state = new_conn_state)
200 gtk_widget_destroy(_connect_banner);
201 _connect_banner = NULL;
205 gtk_widget_destroy(_fix_banner);
209 if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
211 if(_aprs_enable && _aprs_inet_enable
212 && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
213 _aprs_inet_beacon_timer = g_timeout_add(_aprs_inet_beacon_interval*1000 , timer_callback_aprs_inet, NULL);
220 gtk_widget_destroy(_fix_banner);
224 _connect_banner = hildon_banner_show_animation(
225 _window, NULL, _("Attempting to connect to APRS server"));
227 if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
230 default: ; /* to quell warning. */
233 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
237 static gboolean aprs_parse_server_packet(gchar *packet)
239 decode_ax25_line(packet, APRS_PORT_INET);
247 void update_aprs_inet_options(gboolean force)
249 // If auto filter is not or we are not connected then stop
250 if(!_aprs_server_auto_filter_on
252 || !_aprs_inet_enable
253 || _aprs_server_auto_filter_km <= 0) return ;
257 aprs_server_disconnect();
259 aprs_server_connect();
263 gchar *create_aprs_inet_options_string()
265 gint current_lat = (gint)round(_gps.lat);
266 gint current_lon = (gint)round(_gps.lon);
267 gchar *filter = NULL;
269 filter = g_strdup_printf("user %s pass %s vers %s v%s filter r/%d/%d/%d \r\n ",
270 _aprs_mycall, _aprs_inet_server_validation, PACKAGE, VERSION,
271 current_lat, current_lon, _aprs_server_auto_filter_km );
277 static void thread_read_server()
279 gchar buf[APRS_BUFFER_SIZE];
280 gchar *buf_curr = buf;
281 gchar *buf_last = buf + sizeof(buf) - 1;
282 GnomeVFSFileSize bytes_read;
283 GnomeVFSResult vfs_result;
284 GnomeVFSInetConnection *iconn = NULL;
285 GnomeVFSSocket *socket = NULL;
286 GThread *my_thread = g_thread_self();
287 gboolean error = FALSE;
289 printf("%s(%s)\n", __PRETTY_FUNCTION__, _aprs_server);
292 //fprintf(stderr, "Starting thread...\n");
294 /* Lock/Unlock the mutex to ensure that _aprs_inet_thread is done being set. */
295 g_mutex_lock(_aprs_inet_init_mutex);
296 g_mutex_unlock(_aprs_inet_init_mutex);
298 if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
302 /* Attempt to connect to APRS server. */
303 for(tryno = 0; tryno < 10; tryno++)
305 /* Create a socket to interact with server. */
306 GTimeVal timeout = { 1000, 0 };
307 gchar *filter = create_aprs_inet_options_string();
308 //fprintf(stderr, filter);
310 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_inet_connection_create(
315 || NULL == ( socket = gnome_vfs_inet_connection_to_socket(iconn))
316 || GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_set_timeout(
317 socket, &timeout, NULL))
318 || GNOME_VFS_OK != (vfs_result = gnome_vfs_socket_write( socket,
319 filter, strlen(filter), &bytes_read, NULL))
335 g_printerr("Error connecting to APRS server: (%d) %s\n",
336 vfs_result, gnome_vfs_result_to_string(vfs_result));
337 g_idle_add((GSourceFunc)aprs_handle_error_idle,
338 g_strdup_printf("%s",
339 _("Error connecting to APRS server.")));
345 if(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
348 set_aprs_inet_conn_state(RCVR_UP);
350 while(my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL)
355 vfs_result = gnome_vfs_socket_read(
363 if(vfs_result != GNOME_VFS_OK)
365 if(my_thread == _aprs_inet_thread)
367 // Error wasn't user-initiated.
368 g_idle_add((GSourceFunc)aprs_handle_error_idle,
369 g_strdup_printf("%s %u",
370 _("Error reading APRS data."), vfs_result));
374 fprintf(stderr, "Read error: %s\n", gnome_vfs_result_to_string(vfs_result));
379 /* Loop through the buffer and read each packet. */
380 buf_curr += bytes_read;
381 *buf_curr = '\0'; /* append a \0 so we can read as string */
382 while(!error && my_thread == _aprs_inet_thread && _aprs_inet_thread != NULL
383 && (eol = strchr(buf, '\n')))
385 /* This is the beginning of a sentence; okay to parse. */
386 *eol = '\0'; /* overwrite \n with \0 */
388 if(my_thread == _aprs_inet_thread)
389 //g_idle_add_full(G_PRIORITY_HIGH, (GSourceFunc)aprs_parse_server_packet, g_strdup(buf), NULL );
390 g_idle_add((GSourceFunc)aprs_parse_server_packet, g_strdup(buf));
392 /* If eol is at or after (buf_curr - 1) */
393 if(eol >= (buf_curr - 1))
395 /* Last read was a newline - reset read buffer */
401 /* Move the next line to the front of the buffer. */
402 memmove(buf, eol + 1,
403 buf_curr - eol); /* include terminating 0 */
404 /* Subtract _curr so that it's pointing at the new \0. */
405 buf_curr -= (eol - buf + 1);
408 _aprs_rcvr_retry_count = 0;
410 // Send any packets queued
411 // try to get lock, otherwise try next time
412 if(g_mutex_trylock (_write_buffer[APRS_PORT_INET].write_lock))
414 // Store the current end pointer as it may change
417 gchar tmp_write_buffer[MAX_DEVICE_BUFFER];
418 while (_write_buffer[APRS_PORT_INET].write_in_pos != _write_buffer[APRS_PORT_INET].write_out_pos) {
420 tmp_write_buffer[quantity] = _write_buffer[APRS_PORT_INET].device_write_buffer[_write_buffer[APRS_PORT_INET].write_out_pos];
422 _write_buffer[APRS_PORT_INET].write_out_pos++;
423 if (_write_buffer[APRS_PORT_INET].write_out_pos >= MAX_DEVICE_BUFFER)
424 _write_buffer[APRS_PORT_INET].write_out_pos = 0;
433 GnomeVFSFileSize bytes_read = 0;
434 if(GNOME_VFS_OK == gnome_vfs_socket_write( socket,
435 tmp_write_buffer, quantity, &bytes_read, NULL))
438 //fprintf(stderr, "Send packet success: %s (%u)\n", tmp_write_buffer, quantity);
443 fprintf(stderr, "Failed to send packet: %s (%u)\n", tmp_write_buffer, quantity);
449 g_mutex_unlock(_write_buffer[APRS_PORT_INET].write_lock);
454 //fprintf(stderr, "Exiting thread...\n");
457 /* Error, or we're done reading APRS data. */
461 gnome_vfs_inet_connection_destroy(iconn, NULL);
462 //gnome_vfs_inet_connection_free(iconn, NULL);
469 printf("%s(): return\n", __PRETTY_FUNCTION__);
475 * Disconnect from the receiver. This method cleans up any and everything
476 * that might be associated with the receiver.
478 void aprs_server_disconnect()
480 gboolean exit_now = FALSE;
482 printf("%s()\n", __PRETTY_FUNCTION__);
484 GThread *my_thread = g_thread_self();
486 if(my_thread == _aprs_inet_thread)
491 g_mutex_lock(_aprs_inet_init_mutex);
492 _aprs_inet_thread = NULL;
493 g_mutex_unlock(_aprs_inet_init_mutex);
498 set_aprs_inet_conn_state(RCVR_OFF);
499 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
503 fprintf(stderr, "Stopping own thread - APRS server\n");
505 fprintf(stderr, "Stop Failed\n");
511 * Connect to the server.
512 * This method assumes that _fd is -1 and _channel is NULL. If unsure, call
513 * rcvr_disconnect() first.
514 * Since this is an idle function, this function returns whether or not it
515 * should be called again, which is always FALSE.
517 gboolean aprs_server_connect()
519 printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_inet_state);
521 if(_aprs_inet_enable && _aprs_inet_state == RCVR_OFF)
523 set_aprs_inet_conn_state(RCVR_DOWN);
525 /* Lock/Unlock the mutex to ensure that the thread doesn't
526 * start until _gps_thread is set. */
527 g_mutex_lock(_aprs_inet_init_mutex);
530 _aprs_inet_thread = g_thread_create((GThreadFunc)thread_read_server,
531 NULL, TRUE, NULL); /* Joinable. */
533 // g_thread_set_priority(_aprs_inet_thread, G_THREAD_PRIORITY_LOW);
535 g_mutex_unlock(_aprs_inet_init_mutex);
538 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
544 printf("%s()\n", __PRETTY_FUNCTION__);
546 _aprs_inet_init_mutex = g_mutex_new();
547 _aprs_tty_init_mutex = g_mutex_new();
548 _write_buffer[APRS_PORT_INET].write_lock = g_mutex_new();
549 _write_buffer[APRS_PORT_TTY].write_lock = g_mutex_new();
551 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
554 void aprs_destroy(gboolean last)
556 static GThread* tmp = NULL;
557 printf("%s()\n", __PRETTY_FUNCTION__);
561 if(_aprs_inet_thread)
563 tmp = (GThread*)_aprs_inet_thread;
564 _aprs_inet_thread = NULL;
570 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
573 gboolean select_aprs(gint unitx, gint unity, gboolean quick)
576 gdouble lat1, lon1, lat2, lon2;
577 static GtkWidget *dialog = NULL;
578 static GtkWidget *list = NULL;
579 static GtkWidget *sw = NULL;
580 static GtkTreeViewColumn *column = NULL;
581 static GtkCellRenderer *renderer = NULL;
582 GtkListStore *store = NULL;
584 gboolean selected = FALSE;
585 gint num_stations = 0;
586 AprsStationList *first_station = NULL;
587 AprsStationList *last_station = NULL;
590 printf("%s()\n", __PRETTY_FUNCTION__);
592 x = unitx - pixel2unit(3 * _draw_width);
593 y = unity + pixel2unit(3 * _draw_width);
594 unit2latlon(x, y, lat1, lon1);
596 x = unitx + pixel2unit(3 * _draw_width);
597 y = unity - pixel2unit(3 * _draw_width);
598 unit2latlon(x, y, lat2, lon2);
602 AprsDataRow *p_station = (AprsDataRow *)n_first;
604 // Look for all stations in selected area
605 while ( (p_station) != NULL)
607 lat = convert_lat_l2d(p_station->coord_lat);
608 lon = convert_lon_l2d(p_station->coord_lon);
610 if ( ( lat2 >= lat && lat >= lat1 ) && (lon2 >= lon && lon >= lon1) )
612 // This may have been clicked on
613 AprsStationList * p_list_item = (AprsStationList *)malloc(sizeof(AprsStationList));
615 p_list_item->station = p_station;
616 p_list_item->next = NULL;
618 if(first_station == NULL)
621 first_station = p_list_item;
622 last_station = p_list_item;
626 last_station->next = p_list_item;
627 last_station = p_list_item;
633 (p_station) = (p_station)->n_next; // Next element in list
634 } // End of while loop
640 // No station found, maybe a POI was selected?
642 else if(num_stations == 1)
644 // Only one station was found, so display it's info
645 if(first_station->station != NULL)
647 ShowAprsStationPopup(first_station->station);
653 // Multiple possibilities, therefore ask the user which one
656 store = gtk_list_store_new(APRSPOI_NUM_COLUMNS,
657 G_TYPE_BOOLEAN, //Selected
658 G_TYPE_STRING // Callsign
661 AprsStationList * p_list_item = first_station;
663 while(p_list_item != NULL)
665 if(p_list_item->station != NULL)
667 gtk_list_store_append(store, &iter);
669 gtk_list_store_set(store, &iter,
670 APRSPOI_CALLSIGN, g_strdup(p_list_item->station->call_sign),
673 p_list_item = p_list_item->next;
679 dialog = gtk_dialog_new_with_buttons(_("Select APRS Station"),
680 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
681 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
682 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
685 gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
687 sw = gtk_scrolled_window_new (NULL, NULL);
688 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
689 GTK_SHADOW_ETCHED_IN);
690 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
692 GTK_POLICY_AUTOMATIC);
693 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
696 list = gtk_tree_view_new();
697 gtk_container_add(GTK_CONTAINER(sw), list);
699 gtk_tree_selection_set_mode(
700 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
701 GTK_SELECTION_SINGLE);
702 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
704 renderer = gtk_cell_renderer_text_new();
705 column = gtk_tree_view_column_new_with_attributes(
706 _("Callsign"), renderer, "text", APRSPOI_CALLSIGN, NULL);
707 gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
712 gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
713 g_object_unref(G_OBJECT(store));
715 gtk_widget_show_all(dialog);
717 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
719 if(gtk_tree_selection_get_selected(
720 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
724 p_list_item = first_station;
725 while(p_list_item != NULL)
727 if(p_list_item->station != NULL)
729 gchar * callsign = NULL;
730 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
731 APRSPOI_CALLSIGN, &(callsign),
734 if(strcmp(p_list_item->station->call_sign,callsign) == 0)
736 gtk_widget_hide(dialog);
738 ShowAprsStationPopup(p_list_item->station);
745 p_list_item = p_list_item->next;
752 // Ensure it has been closed
753 gtk_widget_hide(dialog);
757 // Free the list, but not the stations
760 AprsStationList * p_list_item = first_station;
764 // Store pointer to delete contents after next pointer is stored
765 p_list_item = first_station;
767 // Move pointer to next
768 first_station = p_list_item->next;
775 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
782 //*****************************************************************
783 // distance_from_my_station - compute distance from my station and
784 // course with a given call
786 // return distance and course
788 // Returns 0.0 for distance if station not found in database or the
789 // station hasn't sent out a posit yet.
790 //*****************************************************************
792 double distance_from_my_station(char *call_sign, gchar *course_deg, gint course_len) {
793 AprsDataRow *p_station;
800 if (search_station_name(&p_station,call_sign,1)) {
801 // Check whether we have a posit yet for this station
802 if ( (p_station->coord_lat == 0l)
803 && (p_station->coord_lon == 0l) ) {
807 d_lat = convert_lat_l2d(p_station->coord_lat);
808 d_lon = convert_lon_l2d(p_station->coord_lon);
810 value = (float)calculate_distance(_gps.lat, _gps.lon, d_lat, d_lon);
812 snprintf(course_deg, course_len,
814 calculate_bearing(_gps.lat, _gps.lon, d_lat, d_lon));
816 if(_units == UNITS_KM)
817 distance = value * 1.852; // nautical miles to km
818 else if(_units == UNITS_MI)
819 distance = value * 1.15078; // nautical miles to miles
820 else if(_units == UNITS_NM)
823 distance = 0.0; // Should be unreachable
828 else { // Station not found
838 void pad_callsign(char *callsignout, char *callsignin) {
841 l=(int)strlen(callsignin);
844 if(isalnum((int)callsignin[i]) || callsignin[i]=='-') {
845 callsignout[i]=callsignin[i];
848 callsignout[i] = ' ';
852 callsignout[i] = ' ';
855 callsignout[i] = '\0';
857 /////////// TX functionality
861 // This routine changes callsign chars to proper uppercase chars or
862 // numerals, fixes the callsign to six bytes, shifts the letters left by
863 // one bit, and puts the SSID number into the proper bits in the seventh
864 // byte. The callsign as processed is ready for inclusion in an
867 void fix_up_callsign(unsigned char *data, int data_size) {
868 unsigned char new_call[8] = " "; // Start with seven spaces
872 int digipeated_flag = 0;
875 // Check whether we've digipeated through this callsign yet.
876 if (strstr((const char *)data,"*") != 0) {
880 // Change callsign to upper-case and pad out to six places with
882 for (i = 0; i < (int)strlen((const char *)data); i++) {
885 if (data[i] == '-') { // Stop at '-'
888 else if (data[i] == '*') {
891 new_call[j++] = data[i];
896 //fprintf(stderr,"new_call:(%s)\n",new_call);
898 // Handle SSID. 'i' should now be pointing at a dash or at the
899 // terminating zero character.
900 if ( (i < (int)strlen((const char *)data)) && (data[i++] == '-') ) { // We might have an SSID
902 ssid = atoi((const char *)&data[i]);
903 // ssid = data[i++] - 0x30; // Convert from ascii to int
904 // if (data[i] != '\0')
905 // ssid = (ssid * 10) + (data[i] - 0x30);
908 //fprintf(stderr,"SSID:%d\t",ssid);
910 if (ssid >= 0 && ssid <= 15) {
911 new_call[6] = ssid | 0x30; // Set 2 reserved bits
913 else { // Whacko SSID. Set it to zero
914 new_call[6] = 0x30; // Set 2 reserved bits
917 if (digipeated_flag) {
918 new_call[6] = new_call[6] | 0x40; // Set the 'H' bit
921 // Shift each byte one bit to the left
922 for (i = 0; i < 7; i++) {
923 new_call[i] = new_call[i] << 1;
924 new_call[i] = new_call[i] & 0xfe;
927 //fprintf(stderr,"Last:%0x\n",new_call[6]);
929 // Write over the top of the input string with the newly
930 // formatted callsign
931 xastir_snprintf((char *)data,
940 // Create an AX25 frame and then turn it into a KISS packet. Dump
941 // it into the transmit queue.
943 void send_ax25_frame(TAprsPort port, gchar *source, gchar *destination, gchar *path, gchar *data) {
944 unsigned char temp_source[15];
945 unsigned char temp_dest[15];
946 unsigned char temp[15];
947 unsigned char control[2], pid[2];
948 unsigned char transmit_txt[MAX_LINE_SIZE*2];
949 unsigned char transmit_txt2[MAX_LINE_SIZE*2];
953 int write_in_pos_hold;
956 //fprintf(stderr,"KISS String:%s>%s,%s:%s\n",source,destination,path,data);
958 // Check whether transmits are disabled globally
959 // if (transmit_disable) {
963 // Check whether transmit has been enabled for this interface.
964 // If not, get out while the gettin's good.
965 // if (devices[port].transmit_data != 1) {
969 transmit_txt[0] = '\0';
971 // Format the destination callsign
972 snprintf((char *)temp_dest,
976 fix_up_callsign(temp_dest, sizeof(temp_dest));
978 snprintf((char *)transmit_txt,
979 sizeof(transmit_txt),
983 // Format the source callsign
984 snprintf((char *)temp_source,
988 fix_up_callsign(temp_source, sizeof(temp_source));
990 strncat((char *)transmit_txt,
992 sizeof(transmit_txt) - strlen((char *)transmit_txt));
994 // Break up the path into individual callsigns and send them one
995 // by one to fix_up_callsign(). If we get passed an empty path,
996 // we merely skip this section and no path gets added to
999 temp[0] = '\0'; // Start with empty path
1000 if ( (path != NULL) && (strlen(path) != 0) ) {
1001 while (path[j] != '\0') {
1003 while ( (path[j] != ',') && (path[j] != '\0') ) {
1004 temp[i++] = path[j++];
1008 if (path[j] == ',') { // Skip over comma
1012 fix_up_callsign(temp, sizeof(temp));
1013 strncat((char *)transmit_txt,
1015 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1019 // Set the end-of-address bit on the last callsign in the
1021 transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01;
1023 // Add the Control byte
1026 strncat((char *)transmit_txt,
1028 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1033 strncat((char *)transmit_txt,
1035 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1037 // Append the information chars
1038 strncat((char *)transmit_txt,
1040 sizeof(transmit_txt) - strlen((char *)transmit_txt));
1042 //fprintf(stderr,"%s\n",transmit_txt);
1044 // Add the KISS framing characters and do the proper escapes.
1046 transmit_txt2[j++] = KISS_FEND;
1048 // Note: This byte is where different interfaces would be
1050 transmit_txt2[j++] = 0x00;
1052 for (i = 0; i < (int)strlen((const char *)transmit_txt); i++) {
1053 c = transmit_txt[i];
1054 if (c == KISS_FEND) {
1055 transmit_txt2[j++] = KISS_FESC;
1056 transmit_txt2[j++] = KISS_TFEND;
1058 else if (c == KISS_FESC) {
1059 transmit_txt2[j++] = KISS_FESC;
1060 transmit_txt2[j++] = KISS_TFESC;
1063 transmit_txt2[j++] = c;
1066 transmit_txt2[j++] = KISS_FEND;
1068 // Terminate the string, but don't increment the 'j' counter.
1069 // We don't want to send the NULL byte out the KISS interface,
1070 // just make sure the string is terminated in all cases.
1072 transmit_txt2[j] = '\0';
1074 //-------------------------------------------------------------------
1075 // Had to snag code from port_write_string() below because our string
1076 // needs to have 0x00 chars inside it. port_write_string() can't
1077 // handle that case. It's a good thing the transmit queue stuff
1079 //-------------------------------------------------------------------
1094 g_mutex_lock (_write_buffer[port].write_lock);
1097 write_in_pos_hold = _write_buffer[port].write_in_pos;
1099 for (i = 0; i < j && !erd; i++) {
1100 _write_buffer[port].device_write_buffer[_write_buffer[port].write_in_pos++] = transmit_txt2[i];
1101 if (_write_buffer[port].write_in_pos >= MAX_DEVICE_BUFFER)
1102 _write_buffer[port].write_in_pos = 0;
1104 if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
1106 // clear this restore original write_in pos and dump this string
1107 _write_buffer[port].write_in_pos = write_in_pos_hold;
1108 _write_buffer[port].errors++;
1113 g_mutex_unlock (_write_buffer[port].write_lock);
1121 // convert latitude from long to string
1122 // Input is in Xastir coordinate system
1124 // CONVERT_LP_NOSP = DDMM.MMN
1125 // CONVERT_HP_NOSP = DDMM.MMMN
1126 // CONVERT_VHP_NOSP = DDMM.MMMMN
1127 // CONVERT_LP_NORMAL = DD MM.MMN
1128 // CONVERT_HP_NORMAL = DD MM.MMMN
1129 // CONVERT_UP_TRK = NDD MM.MMMM
1130 // CONVERT_DEC_DEG = DD.DDDDDN
1131 // CONVERT_DMS_NORMAL = DD MM SS.SN
1132 // CONVERT_DMS_NORMAL_FORMATED = DD'MM'SS.SN
1133 // CONVERT_HP_NORMAL_FORMATED = DD'MM.MMMMN
1135 void convert_lat_l2s(long lat, char *str, int str_len, int type) {
1137 float deg, min, sec;
1143 deg = (float)(lat - 32400000l) / 360000.0;
1145 // Switch to integer arithmetic to avoid floating-point
1147 temp = (long)(deg * 100000);
1155 ideg = (int)temp / 100000;
1156 min = (temp % 100000) * 60.0 / 100000.0;
1158 // Again switch to integer arithmetic to avoid floating-point
1160 temp = (long)(min * 1000);
1161 imin = (int)(temp / 1000);
1162 sec = (temp % 1000) * 60.0 / 1000.0;
1166 case(CONVERT_LP_NOSP): /* do low P w/no space */
1167 xastir_snprintf(str,
1171 // min+0.001, // Correct possible unbiased rounding
1176 case(CONVERT_LP_NORMAL): /* do low P normal */
1177 xastir_snprintf(str,
1181 // min+0.001, // Correct possible unbiased rounding
1186 case(CONVERT_HP_NOSP): /* do HP w/no space */
1187 xastir_snprintf(str,
1191 // min+0.0001, // Correct possible unbiased rounding
1196 case(CONVERT_VHP_NOSP): /* do Very HP w/no space */
1197 xastir_snprintf(str,
1201 // min+0.00001, // Correct possible unbiased rounding
1206 case(CONVERT_UP_TRK): /* for tracklog files */
1207 xastir_snprintf(str,
1212 // min+0.00001); // Correct possible unbiased rounding
1216 case(CONVERT_DEC_DEG):
1217 xastir_snprintf(str,
1220 // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1225 case(CONVERT_DMS_NORMAL):
1226 xastir_snprintf(str,
1228 "%02d %02d %04.1f%c",
1231 // sec+0.01, // Correct possible unbiased rounding
1236 case(CONVERT_DMS_NORMAL_FORMATED):
1237 xastir_snprintf(str,
1239 "%02d°%02d\'%04.1f%c",
1242 // sec+0.01, // Correct possible unbiased rounding
1247 case(CONVERT_HP_NORMAL_FORMATED):
1248 xastir_snprintf(str,
1252 // min+0.0001, // Correct possible unbiased roundin
1257 case(CONVERT_HP_NORMAL):
1258 default: /* do HP normal */
1259 xastir_snprintf(str,
1263 // min+0.0001, // Correct possible unbiased rounding
1274 // convert longitude from long to string
1275 // Input is in Xastir coordinate system
1277 // CONVERT_LP_NOSP = DDDMM.MME
1278 // CONVERT_HP_NOSP = DDDMM.MMME
1279 // CONVERT_VHP_NOSP = DDDMM.MMMME
1280 // CONVERT_LP_NORMAL = DDD MM.MME
1281 // CONVERT_HP_NORMAL = DDD MM.MMME
1282 // CONVERT_UP_TRK = EDDD MM.MMMM
1283 // CONVERT_DEC_DEG = DDD.DDDDDE
1284 // CONVERT_DMS_NORMAL = DDD MM SS.SN
1285 // CONVERT_DMS_NORMAL_FORMATED = DDD'MM'SS.SN
1287 void convert_lon_l2s(long lon, char *str, int str_len, int type) {
1289 float deg, min, sec;
1294 deg = (float)(lon - 64800000l) / 360000.0;
1296 // Switch to integer arithmetic to avoid floating-point rounding
1298 temp = (long)(deg * 100000);
1306 ideg = (int)temp / 100000;
1307 min = (temp % 100000) * 60.0 / 100000.0;
1309 // Again switch to integer arithmetic to avoid floating-point
1311 temp = (long)(min * 1000);
1312 imin = (int)(temp / 1000);
1313 sec = (temp % 1000) * 60.0 / 1000.0;
1317 case(CONVERT_LP_NOSP): /* do low P w/nospacel */
1318 xastir_snprintf(str,
1322 // min+0.001, // Correct possible unbiased rounding
1327 case(CONVERT_LP_NORMAL): /* do low P normal */
1328 xastir_snprintf(str,
1332 // min+0.001, // Correct possible unbiased rounding
1337 case(CONVERT_HP_NOSP): /* do HP w/nospace */
1338 xastir_snprintf(str,
1342 // min+0.0001, // Correct possible unbiased rounding
1347 case(CONVERT_VHP_NOSP): /* do Very HP w/nospace */
1348 xastir_snprintf(str,
1352 // min+0.00001, // Correct possible unbiased rounding
1357 case(CONVERT_UP_TRK): /* for tracklog files */
1358 xastir_snprintf(str,
1363 // min+0.00001); // Correct possible unbiased rounding
1367 case(CONVERT_DEC_DEG):
1368 xastir_snprintf(str,
1371 // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding
1376 case(CONVERT_DMS_NORMAL):
1377 xastir_snprintf(str,
1379 "%03d %02d %04.1f%c",
1382 // sec+0.01, // Correct possible unbiased rounding
1387 case(CONVERT_DMS_NORMAL_FORMATED):
1388 xastir_snprintf(str,
1390 "%03d°%02d\'%04.1f%c",
1393 // sec+0.01, // Correct possible unbiased rounding
1398 case(CONVERT_HP_NORMAL_FORMATED):
1399 xastir_snprintf(str,
1403 // min+0.0001, // Correct possible unbiased rounding
1408 case(CONVERT_HP_NORMAL):
1409 default: /* do HP normal */
1410 xastir_snprintf(str,
1414 // min+0.0001, // Correct possible unbiased rounding
1426 /*************************************************************************/
1427 /* output_lat - format position with position_amb_chars for transmission */
1428 /*************************************************************************/
1430 char *output_lat(char *in_lat, int comp_pos) {
1432 int position_amb_chars = 0;
1433 //fprintf(stderr,"in_lat:%s\n", in_lat);
1436 // Don't do this as it results in truncation!
1437 //in_lat[7]=in_lat[8]; // Shift N/S down for transmission
1439 else if (position_amb_chars>0) {
1444 if (position_amb_chars>0 && position_amb_chars<5) {
1445 for (i=6;i>(6-position_amb_chars-j);i--) {
1467 /**************************************************************************/
1468 /* output_long - format position with position_amb_chars for transmission */
1469 /**************************************************************************/
1471 char *output_long(char *in_long, int comp_pos) {
1473 int position_amb_chars = 0;
1474 //fprintf(stderr,"in_long:%s\n", in_long);
1477 // Don't do this as it results in truncation!
1478 //in_long[8]=in_long[9]; // Shift e/w down for transmission
1480 else if (position_amb_chars>0) {
1485 if (position_amb_chars>0 && position_amb_chars<5) {
1486 for (i=7;i>(7-position_amb_chars-j);i--) {
1507 //***********************************************************
1508 // output_my_aprs_data
1509 // This is the function responsible for sending out my own
1510 // posits. The next function below this one handles objects,
1511 // messages and the like (output_my_data).
1512 //***********************************************************/
1515 void create_output_lat_long(gchar *my_output_lat, gchar *my_output_long )
1517 _aprs_transmit_compressed_posit = FALSE;
1518 gchar *my_lat = g_strdup_printf("%lf", _gps.lat);
1519 gchar *my_long = g_strdup_printf("%lf", _gps.lon);
1522 // Format latitude string for transmit later
1523 if (_aprs_transmit_compressed_posit) { // High res version
1524 // TODO - enable compressed beacon
1525 snprintf(my_output_lat,
1526 sizeof(my_output_lat),
1531 else { // Create a low-res version of the latitude string
1536 my_temp_lat = convert_lat_s2l(my_lat);
1538 // Convert to low-res string
1539 convert_lat_l2s(my_temp_lat,
1544 snprintf(my_output_lat,
1545 sizeof(my_output_lat),
1556 (void)output_lat(my_output_lat, _aprs_transmit_compressed_posit);
1558 // Format longitude string for transmit later
1559 if (_aprs_transmit_compressed_posit) { // High res version
1560 snprintf(my_output_long,
1561 sizeof(my_output_long),
1565 else { // Create a low-res version of the longitude string
1570 my_temp_long = convert_lon_s2l(my_long);
1572 // Convert to low-res string
1573 convert_lon_l2s(my_temp_long,
1578 snprintf(my_output_long,
1579 sizeof(my_output_long),
1580 "%c%c%c%c%c.%c%c%c",
1591 (void)output_long(my_output_long, _aprs_transmit_compressed_posit);
1596 void output_my_aprs_data_tty() {
1600 gchar my_output_lat[MAX_LAT];
1601 gchar my_output_long[MAX_LONG];
1602 // gchar header_txt[MAX_LINE_SIZE+5];
1603 // gchar header_txt_save[MAX_LINE_SIZE+5];
1604 gchar path_txt[MAX_LINE_SIZE+5];
1605 gchar data_txt[MAX_LINE_SIZE+5];
1606 gchar temp[MAX_LINE_SIZE+5];
1607 gchar *unproto_path = "";
1609 struct tm *day_time;
1611 gchar output_net[256];
1612 gchar output_phg[10];
1613 gchar output_cs[10];
1614 gchar output_alt[20];
1615 gchar output_brk[3];
1617 gchar my_comment_tx[APRS_MAX_COMMENT+1];
1618 int interfaces_ok_for_transmit = 0;
1622 gchar header_txt[MAX_LINE_SIZE+5];
1623 gchar header_txt_save[MAX_LINE_SIZE+5];
1625 gchar data_txt_save[MAX_LINE_SIZE+5];
1628 if (!(port_data.status == DEVICE_UP
1629 && _aprs_tty_enable && _aprs_enable && _aprs_enable_tty_tx)) return ;
1631 header_txt_save[0] = '\0';
1632 data_txt_save[0] = '\0';
1638 create_output_lat_long(my_output_lat, my_output_long);
1641 // First send any header/path info we might need out the port,
1642 // set up TNC's to the proper mode, etc.
1645 // clear this for a TNC
1646 output_net[0] = '\0';
1649 // The leading \r is sent to normal serial TNCs. The only
1650 // reason for it is that some folks' D700s are getting
1651 // garbage in the input buffer, and the result is the mycall
1652 // line is rejected. The \r at the beginning clears out the
1653 // junk and lets it go through. But data_out_ax25 tries to
1654 // parse the MYCALL line, and the presence of a leading \r
1656 snprintf(header_txt,
1660 ((port_data.device_type !=DEVICE_AX25_TNC)?
1661 "\rMYCALL":"MYCALL"),
1664 // Send the callsign out to the TNC only if the interface is up and tx is enabled???
1665 // We don't set it this way for KISS TNC interfaces.
1666 if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1667 && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1668 && (port_data.status == DEVICE_UP)
1669 //&& (devices.transmit_data == 1)
1670 //&& !transmit_disable
1671 //&& !posit_tx_disable
1673 port_write_string(header_txt, APRS_PORT_TTY);
1674 //send_line(gchar* text, gint text_len, TAprsPort port)
1677 // Set unproto path: Get next unproto path in
1680 snprintf(header_txt,
1686 _aprs_unproto_path);
1688 snprintf(header_txt_save,
1689 sizeof(header_txt_save),
1693 _aprs_unproto_path);
1698 _aprs_unproto_path);
1701 // Send the header data to the TNC. This sets the
1702 // unproto path that'll be used by the next packet.
1703 // We don't set it this way for KISS TNC interfaces.
1704 if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1705 && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1706 && (port_data.status == DEVICE_UP)
1707 //&& (devices.transmit_data == 1)
1708 //&& !transmit_disable
1709 //&& !posit_tx_disable
1711 port_write_string(header_txt, APRS_PORT_TTY);
1715 // Set converse mode. We don't need to do this for
1716 // KISS TNC interfaces. One european TNC (tnc2-ui)
1717 // doesn't accept "conv" but does accept the 'k'
1718 // command. A Kantronics KPC-2 v2.71 TNC accepts
1719 // the "conv" command but not the 'k' command.
1722 snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', APRS_CONVERSE_MODE);
1724 if ( (port_data.device_type != DEVICE_SERIAL_KISS_TNC)
1725 && (port_data.device_type != DEVICE_SERIAL_MKISS_TNC)
1726 && (port_data.status == DEVICE_UP)
1727 //&& (devices.transmit_data == 1)
1728 //&& !transmit_disable
1729 //&& !posit_tx_disable
1731 port_write_string(header_txt, APRS_PORT_TTY);
1737 // Set up some more strings for later transmission
1739 // send station info
1740 output_cs[0] = '\0';
1741 output_phg[0] = '\0';
1742 output_alt[0] = '\0';
1743 output_brk[0] = '\0';
1746 if (_aprs_transmit_compressed_posit)
1748 // TOOD - enable compressed beacon support
1753 // compress_posit(my_output_lat,
1758 // my_last_speed, // In knots
1762 else { // standard non compressed mode
1769 _aprs_beacon_symbol);
1770 // get PHG, if used for output
1771 if (strlen(my_phg) >= 6)
1772 snprintf(output_phg,
1777 // get CSE/SPD, Always needed for output even if 0
1782 _gps.speed); // Speed in knots
1786 // if (my_last_altitude_time > 0)
1787 // snprintf(output_alt,
1788 // sizeof(output_alt),
1790 // my_last_altitude);
1794 // APRS_MOBILE LOCAL TIME
1797 // if((strlen(output_cs) < 8) && (my_last_altitude_time > 0)) {
1798 // xastir_snprintf(output_brk,
1799 // sizeof(output_brk),
1803 day_time = localtime(&sec);
1805 snprintf(data_txt_save,
1806 sizeof(data_txt_save),
1807 "@%02d%02d%02d/%s%s%s%s%s",
1818 // Truncate at max length for this type of APRS
1820 if (_aprs_transmit_compressed_posit) {
1821 if (strlen(data_txt_save) > 61) {
1822 data_txt_save[61] = '\0';
1825 else { // Uncompressed lat/long
1826 if (strlen(data_txt_save) > 70) {
1827 data_txt_save[70] = '\0';
1831 // Add '\r' onto end.
1832 strncat(data_txt_save, "\r", 1);
1842 // Here's where the actual transmit of the posit occurs. The
1843 // transmit string has been set up in "data_txt" by this point.
1845 // If transmit or posits have been turned off, don't transmit posit
1846 if ( (port_data.status == DEVICE_UP)
1847 // && (devices.transmit_data == 1)
1848 // && !transmit_disable
1849 // && !posit_tx_disable
1852 interfaces_ok_for_transmit++;
1854 // WE7U: Change so that path is passed as well for KISS TNC
1855 // interfaces: header_txt_save would probably be the one to pass,
1856 // or create a new string just for KISS TNC's.
1858 if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1859 || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1861 // Note: This one has callsign & destination in the string
1863 // Transmit the posit out the KISS interface
1864 send_ax25_frame(APRS_PORT_TTY,
1865 _aprs_mycall, // source
1866 VERSIONFRM, // destination
1870 else { // Not a Serial KISS TNC interface
1873 port_write_string(data_txt, APRS_PORT_TTY); // Transmit the posit
1877 // Put our transmitted packet into the Incoming Data
1878 // window as well. This way we can see both sides of a
1879 // conversation. data_port == -1 for x_spider port,
1880 // normal interface number otherwise. -99 to get a "**"
1881 // display meaning all ports.
1883 // For packets that we're igating we end up with a CR or
1884 // LF on the end of them. Remove that so the display
1893 //makePrintable(temp);
1894 //packet_data_add("TX ", temp, port);
1897 } // End of posit transmit: "if (ok)"
1901 void create_output_pos_packet(TAprsPort port, gchar **packet, int *length)
1904 // gchar encodedPos[MAX_LINE_SIZE];
1906 if(_aprs_transmit_compressed_posit)
1912 //!5122.09N/00008.42W&APRS4R IGATE RUNNING ON NSLU2
1914 // For now just use a simple packet
1919 gdouble pos = (_gps.lat > 0 ? _gps.lat : 0-_gps.lat);
1921 gdouble min = (pos - (int)pos)*60.0;
1922 sprintf(slat, "%02d%02d.%02.0f", (int)pos, (int)min,
1923 ((min - (int)min)*100.0) );
1925 pos = (_gps.lon > 0 ? _gps.lon : 0-_gps.lon);
1927 min = (pos - (int)pos)*60.0;
1928 sprintf(slon, "%03d%02d.%02.0f", (int)pos, (int)min,
1929 ((min - (int)min)*100.0) );
1931 *packet = g_strdup_printf(
1932 "%c%s%c%c%s%c%c%s%c",
1935 (_gps.lat > 0 ? 'N' : 'S'),
1938 (_gps.lon > 0 ? 'E' : 'W'),
1939 _aprs_beacon_symbol,
1940 (port == APRS_PORT_INET ? _aprs_inet_beacon_comment : _aprs_beacon_comment),
1945 *length = strlen(*packet);
1949 void send_packet(TAprsPort port, gchar* to_call, gchar* path, gchar* packet, gint packet_length)
1951 if(port == APRS_PORT_INET
1952 || !(port_data.device_type == DEVICE_SERIAL_KISS_TNC
1953 || port_data.device_type == DEVICE_SERIAL_MKISS_TNC) )
1955 gchar *packet_header
1962 gchar *full_packet = g_strdup_printf("%s%s\r\n", packet_header, packet);
1965 send_line(full_packet, strlen(packet_header)+packet_length+2, port);
1969 send_ax25_frame(port, _aprs_mycall, to_call, path, packet);
1974 void output_my_aprs_data(TAprsPort port) {
1981 //create_output_lat_long(my_output_lat, my_output_long);
1982 create_output_pos_packet(port, &packet, &length);
1985 send_packet(port, VERSIONFRM, _aprs_unproto_path, packet, length);
1987 if(packet != NULL) g_free(packet);
1990 /////////// TTY functionality
1993 int _aprs_tnc_retry_count = 0;
1995 static gboolean aprs_tnc_handle_error_idle (gchar *error)
1997 printf("%s(%s)\n", __PRETTY_FUNCTION__, error);
1999 /* Ask for re-try. */
2000 if(++_aprs_tnc_retry_count > 2)
2003 gchar buffer[BUFFER_SIZE];
2005 /* Reset retry count. */
2006 _aprs_tnc_retry_count = 0;
2008 snprintf(buffer, sizeof(buffer), "%s\nRetry?", error);
2009 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
2011 aprs_tty_disconnect();
2013 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2014 aprs_tty_connect(); /* Try again. */
2018 gtk_check_menu_item_set_active(
2019 GTK_CHECK_MENU_ITEM(_menu_enable_aprs_tty_item), FALSE);
2022 /* Ask user to re-connect. */
2023 gtk_widget_destroy(confirm);
2027 aprs_tty_disconnect();
2028 aprs_tty_connect(); /* Try again. */
2033 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2038 void close_tnc_port();
2040 static void thread_read_tty()
2042 // gint max_retries = 5;
2043 GThread *my_thread = g_thread_self();
2045 //fprintf(stderr, "in thread_read_tty\n");
2047 if(/*max_retries>0 &&*/ _aprs_tty_thread == my_thread )
2049 if( serial_init() >= 0 )
2052 //fprintf(stderr, "TTY port open \n");
2055 if(_aprs_tty_thread == my_thread)
2057 g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2058 g_strdup_printf("%s",
2059 _("Error reading data from TNC Port.")));
2066 fprintf(stderr, "Failed to init serial port\n");
2068 g_idle_add((GSourceFunc)aprs_tnc_handle_error_idle,
2069 g_strdup_printf("%s",
2070 _("Error connecting to TNC Port.")));
2079 // if(max_retries==0)
2082 // set_aprs_tty_conn_state(RCVR_OFF);
2083 // MACRO_BANNER_SHOW_INFO(_window, _("Failed to connect to TNC!")); \
2088 gboolean aprs_tty_connect()
2090 printf("%s(%d)\n", __PRETTY_FUNCTION__, _aprs_tty_state);
2092 if(_aprs_tty_enable && _aprs_tty_state == RCVR_OFF)
2094 set_aprs_tty_conn_state(RCVR_DOWN);
2096 // Lock/Unlock the mutex to ensure that the thread doesn't
2097 // start until _gps_thread is set.
2098 g_mutex_lock(_aprs_tty_init_mutex);
2100 _aprs_tty_thread = g_thread_create((GThreadFunc)thread_read_tty,
2101 NULL, TRUE, NULL); // Joinable.
2103 g_mutex_unlock(_aprs_tty_init_mutex);
2106 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2111 void aprs_tty_disconnect()
2113 gboolean exit_now = FALSE;
2115 printf("%s()\n", __PRETTY_FUNCTION__);
2117 GThread *my_thread = g_thread_self();
2119 if(my_thread == _aprs_tty_thread)
2125 _aprs_tty_thread = NULL;
2128 set_aprs_tty_conn_state(RCVR_OFF);
2129 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2131 if(exit_now) exit(0);
2136 //***********************************************************
2137 // port_write_string()
2139 // port is port# used
2140 // data is the string to write
2141 //***********************************************************
2143 void port_write_string(gchar *data, gint len, TAprsPort port) {
2146 // int write_in_pos_hold;
2151 if (data[0] == '\0')
2156 if(port == APRS_PORT_TTY)
2159 if(g_mutex_trylock (_write_buffer[port].write_lock))
2161 //fprintf(stderr, "TTY Write... ");
2162 retval = (int)write(port_data.channel,
2165 //fprintf(stderr, "done... ");
2166 g_mutex_unlock (_write_buffer[port].write_lock);
2167 //fprintf(stderr, "Unlocked\n");
2170 fprintf(stderr, "Failed to get lock\n");
2174 send_line(data, len, port);
2179 gboolean send_line(gchar* text, gint text_len, TAprsPort port)
2181 if(APRS_PORT_INET == port && !_aprs_enable_inet_tx) return FALSE;
2182 else if (APRS_PORT_TTY == port && !_aprs_enable_tty_tx) return FALSE;
2184 if(APRS_PORT_TTY == port)
2188 gboolean error = FALSE;
2190 gint write_in_pos_hold = _write_buffer[port].write_in_pos;
2193 g_mutex_lock(_write_buffer[port].write_lock);
2195 for (i = 0; i < text_len && !error; i++) {
2196 _write_buffer[port].device_write_buffer[_write_buffer[port].write_in_pos++]
2199 if (_write_buffer[port].write_in_pos >= MAX_DEVICE_BUFFER)
2200 _write_buffer[port].write_in_pos = 0;
2202 if (_write_buffer[port].write_in_pos == _write_buffer[port].write_out_pos) {
2203 fprintf(stderr,"Port %d Buffer overrun\n",port);
2205 /* clear this restore original write_in pos and dump this string */
2206 _write_buffer[port].write_in_pos = write_in_pos_hold;
2207 _write_buffer[port].errors++;
2212 g_mutex_unlock(_write_buffer[port].write_lock);
2218 //***********************************************************
2222 // This function becomes the long-running thread that snags
2223 // characters from an interface and passes them off to the
2224 // decoding routines. One copy of this is run for each read
2225 // thread for each interface.
2226 //***********************************************************
2227 gboolean read_port_data();
2230 // unsigned char cin, last;
2235 // cin = (unsigned char)0;
2236 // last = (unsigned char)0;
2237 gboolean success = TRUE;
2238 GThread *my_thread = g_thread_self();
2240 fprintf(stderr, "Enter port_read\n");
2242 // We stay in this read loop until the port is shut down
2243 while(port_data.active == DEVICE_IN_USE && _aprs_tty_thread == my_thread
2244 && RCVR_UP == _aprs_tty_state && success == TRUE){
2246 if (port_data.status == DEVICE_UP){
2248 port_data.read_in_pos = 0;
2252 while (port_data.scan >= 0
2254 //&& RCVR_UP == _aprs_tty_state
2255 && (port_data.read_in_pos < (MAX_DEVICE_BUFFER - 1) )
2256 && (port_data.status == DEVICE_UP)
2257 && (_aprs_tty_thread == my_thread)
2261 success = read_port_data();
2265 if (port_data.active == DEVICE_IN_USE) {
2269 // We need to delay here so that the thread doesn't use
2270 // high amounts of CPU doing nothing.
2272 // This select that waits on data and a timeout, so that if data
2273 // doesn't come in within a certain period of time, we wake up to
2274 // check whether the socket has gone down. Else, we go back into
2275 // the select to wait for more data or a timeout. FreeBSD has a
2276 // problem if this is less than 1ms. Linux works ok down to 100us.
2277 // We don't need it anywhere near that short though. We just need
2278 // to check whether the main thread has requested the interface be
2279 // closed, and so need to have this short enough to have reasonable
2280 // response time to the user.
2282 //sched_yield(); // Yield to other threads
2284 // Set up the select to block until data ready or 100ms
2285 // timeout, whichever occurs first.
2287 FD_SET(port_data.channel, &rd);
2289 tmv.tv_usec = 100000; // 100 ms
2290 (void)select(0,&rd,NULL,NULL,&tmv);
2294 fprintf(stderr, "End of port_read\n");
2298 gboolean aprs_send_beacon_inet()
2301 aprs_send_beacon(APRS_PORT_INET);
2306 gboolean aprs_send_beacon(TAprsPort port)
2310 output_my_aprs_data(port);
2312 //fprintf(stderr, "Beacon sent\n" );
2319 gboolean timer_callback_aprs_inet (gpointer data) {
2321 if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
2323 aprs_send_beacon(APRS_PORT_INET);
2324 return TRUE; // Continue timer
2327 return FALSE; // Stop timer
2332 gboolean timer_callback_aprs_tty (gpointer data) {
2334 if(_aprs_tty_enable && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
2336 fprintf(stderr, "Sending beacon for TNC...\n");
2337 aprs_send_beacon(APRS_PORT_TTY);
2338 return TRUE; // Continue timer
2341 return FALSE; // Stop timer
2345 void aprs_timer_init()
2347 // disable timer if exists
2348 if(_aprs_inet_beacon_timer>0) g_source_remove(_aprs_inet_beacon_timer);
2349 if(_aprs_tty_beacon_timer>0) g_source_remove(_aprs_tty_beacon_timer);
2353 if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval>0)
2354 _aprs_inet_beacon_timer = g_timeout_add(_aprs_inet_beacon_interval*1000 , timer_callback_aprs_inet, NULL);
2356 if(_aprs_tty_enable && _aprs_enable_tty_tx && _aprs_tty_beacon_interval>0)
2357 _aprs_tty_beacon_timer = g_timeout_add(_aprs_tty_beacon_interval*1000 , timer_callback_aprs_tty, NULL);
2361 #endif //INCLUDE_APRS