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
34 #include "aprs_kiss.h"
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
57 #include <sys/socket.h>
60 #include <netinet/in.h> // Moved ahead of inet.h as reports of some *BSD's not
61 // including this as they should.
71 #include <sys/types.h>
77 #define DBUS_API_SUBJECT_TO_CHANGE
78 #include <dbus/dbus-glib.h>
81 #define DISABLE_SETUID_PRIVILEGE do { \
85 #define ENABLE_SETUID_PRIVILEGE do { \
93 #define MAX_INPUT_QUEUE 1000
94 gint decode_ax25_line(gchar *line, TAprsPort port);
102 xastir_mutex connect_lock; // Protects port_data[].thread_status and port_data[].connect_status
104 // Read/write pointers for the circular input queue
106 static int incoming_read_ptr = 0;
107 static int incoming_write_ptr = 0;
108 static int queue_depth = 0;
109 static int push_count = 0;
110 static int pop_count = 0;
117 iface port_data; // shared port data
121 // We feed a raw 7-byte string into this routine. It decodes the
122 // callsign-SSID and tells us whether there are more callsigns after
123 // this. If the "asterisk" input parameter is nonzero it'll add an
124 // asterisk to the callsign if it has been digipeated. This
125 // function is called by the decode_ax25_header() function.
127 // Inputs: string Raw input string
128 // asterisk 1 = add "digipeated" asterisk
130 // Outputs: callsign Processed string
131 // returned int 1=more callsigns follow, 0=end of address field
133 gint decode_ax25_address(gchar *string, gchar *callsign, gint asterisk) {
140 // Shift each of the six callsign characters right one bit to
141 // convert to ASCII. We also get rid of the extra spaces here.
143 for (i = 0; i < 6; i++) {
144 t = ((unsigned char)string[i] >> 1) & 0x7f;
150 // Snag out the SSID byte to play with. We need more than just
151 // the 4 SSID bits out of it.
152 ssid = (unsigned char)string[6];
154 // Check the digipeat bit
155 if ( (ssid & 0x80) && asterisk)
156 digipeated++; // Has been digipeated
158 // Check whether it is the end of the address field
159 if ( !(ssid & 0x01) )
160 more++; // More callsigns to come after this one
162 // Snag the four SSID bits
163 ssid = (ssid >> 1) & 0x0f;
165 // Construct the SSID number and add it to the end of the
166 // callsign if non-zero. If it's zero we don't add it.
173 callsign[j++] = '0' + ssid;
176 // Add an asterisk if the packet has been digipeated through
181 // Terminate the string
188 // Function which receives raw AX.25 packets from a KISS interface and
189 // converts them to a printable TAPR-2 (more or less) style string.
190 // We receive the packet with a KISS Frame End character at the
191 // beginning and a "\0" character at the end. We can end up with
192 // multiple asterisks, one for each callsign that the packet was
193 // digipeated through. A few other TNC's put out this same sort of
196 // Note about KISS & CRC's: The TNC checks the CRC. If bad, it
197 // drops the packet. If good, it sends it to the computer WITHOUT
198 // the CRC bytes. There's no way at the computer end to check
199 // whether the packet was corrupted over the serial channel between
200 // the TNC and the computer. Upon sending a KISS packet to the TNC,
201 // the TNC itself adds the CRC bytes back on before sending it over
202 // the air. In Xastir we can just assume that we're getting
203 // error-free packets from the TNC, ignoring possible corruption
204 // over the serial line.
206 // Some versions of KISS can encode the radio channel (for
207 // multi-port TNC's) in the command byte. How do we know we're
208 // running those versions of KISS though? Here are the KISS
209 // variants that I've been able to discover to date:
211 // KISS No CRC, one radio port
213 // SMACK 16-bit CRC, multiport TNC's
219 // KISS Multi-drop (Kantronics) 8-bit XOR Checksum, multiport TNC's (AGWPE compatible)
220 // BPQKISS (Multi-drop) 8-bit XOR Checksum, multiport TNC's
221 // XKISS (Kantronics) 8-bit XOR Checksum, multiport TNC's
223 // JKISS (AGWPE and BPQ32 compatible)
225 // MKISS Linux driver which supports KISS/BPQ and
226 // hardware handshaking? Also Paccomm command to
227 // immediately enter KISS mode.
230 // FlexCRC -|-- These are all the same!
235 // It appears that none of the above protocols implement any form of
236 // hardware flow control.
239 // Compare this function with interface.c:process_ax25_packet() to
240 // see if we're missing anything important.
243 // Inputs: data_string Raw string (must be MAX_LINE_SIZE or bigger)
244 // length Length of raw string (may get changed here)
246 // Outputs: int 0 if it is a bad packet,
248 // data_string Processed string
250 gint decode_ax25_header(
251 unsigned char *data_string,
254 gchar result[MAX_LINE_SIZE+100];
262 // Do we have a string at all?
263 if (data_string == NULL)
266 // Drop the packet if it is too long. Note that for KISS packets
267 // we can't use strlen() as there can be 0x00 bytes in the
269 if (*length > 1024) {
270 data_string[0] = '\0';
275 // Start with an empty string for the result
280 // Process the destination address
281 for (i = 0; i < 7; i++)
282 temp[i] = data_string[ptr++];
284 more = decode_ax25_address(temp, callsign, 0); // No asterisk
285 snprintf(dest,sizeof(dest),"%s",callsign);
287 // Process the source address
288 for (i = 0; i < 7; i++)
289 temp[i] = data_string[ptr++];
291 more = decode_ax25_address(temp, callsign, 0); // No asterisk
293 // Store the two callsigns we have into "result" in the correct
295 snprintf(result,sizeof(result),"%s>%s",callsign,dest);
297 // Process the digipeater addresses (if any)
299 while (more && num_digis < 8) {
300 for (i = 0; i < 7; i++)
301 temp[i] = data_string[ptr++];
304 more = decode_ax25_address(temp, callsign, 1); // Add asterisk
307 sizeof(result) - strlen(result));
311 sizeof(result) - strlen(result));
317 sizeof(result) - strlen(result));
320 // Check the Control and PID bytes and toss packets that are
321 // AX.25 connect/disconnect or information packets. We only
322 // want to process UI packets in Xastir.
325 // Control byte should be 0x03 (UI Frame). Strip the poll-bit
326 // from the PID byte before doing the comparison.
327 if ( (data_string[ptr++] & (~0x10)) != 0x03) {
332 // PID byte should be 0xf0 (normal AX.25 text)
333 if (data_string[ptr++] != 0xf0)
337 // WE7U: We get multiple concatenated KISS packets sometimes. Look
338 // for that here and flag when it happens (so we know about it and
339 // can fix it someplace earlier in the process). Correct the
340 // current packet so we don't get the extra garbage tacked onto the
342 for (i = ptr; i < *length; i++) {
343 if (data_string[i] == KISS_FEND) {
344 fprintf(stderr,"***Found concatenated KISS packets:***\n");
345 data_string[i] = '\0'; // Truncate the string
350 // Add the Info field to the decoded header info
352 (char *)(&data_string[ptr]),
353 sizeof(result) - strlen(result));
355 // Copy the result onto the top of the input data. Note that
356 // the length can sometimes be longer than the input string, so
357 // we can't just use the "length" variable here or we'll
358 // truncate our string. Make sure the data_string variable is
359 // MAX_LINE_SIZE or bigger.
361 snprintf((char *)data_string,
366 // Write out the new length
367 *length = strlen(result);
369 //fprintf(stderr,"%s\n",data_string);
390 // Added by KB6MER for KAM XL(SERIAL_TNC_AUX_GPS) support
391 // buf is a null terminated string
392 // returns buf as a null terminated string after cleaning.
394 // removes leading 'cmd:' prompts from TNC if needed
395 // Can be used to add any additional data cleaning functions desired.
396 // Currently only called for SERIAL_TNC_AUX_GPS, but could be added
397 // to other device routines to improve packet decode on other devices.
399 // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER,
400 // which is currently set to 4096.
402 void tnc_data_clean(gchar *buf) {
404 while (!strncmp(buf,"cmd:",4)) {
407 // We're _shortening_ the string here, so we don't need to
408 // know the length of the buffer unless it has no '\0'
409 // terminator to begin with! In that one case we could run
410 // off the end of the string and get a segfault or cause
412 for (ii = 0; ; ii++) {
422 static gboolean aprs_parse_tty_packet(gchar *packet)
424 decode_ax25_line(packet, APRS_PORT_TTY);
432 static gboolean kiss_parse_packet(unsigned char *data_string, gint data_length)
436 //fprintf(stderr, "Parse: %s\n", data_string);
438 gint devicetype = port_data.device_type;
443 case DEVICE_SERIAL_KISS_TNC:
444 case DEVICE_SERIAL_MKISS_TNC:
445 if ( !decode_ax25_header( data_string,
447 // Had a problem decoding it. Drop
452 // Good decode. Drop through to the
453 // next block to log and decode the
457 case DEVICE_SERIAL_TNC:
458 tnc_data_clean((char *)data_string);
460 case DEVICE_AX25_TNC:
465 //fprintf(stderr, "Decoded kiss: %s\n", data_string);
466 g_idle_add((GSourceFunc)aprs_parse_tty_packet, data_string);
467 // decode_ax25_line(data_string, "T", 0);
479 // Add one record to the circular queue. Returns 1 if queue is
480 // full, 0 if successful.
483 int push_incoming_data(unsigned char *data_string, int length) {
485 int next_write_ptr = (incoming_write_ptr + 1) % MAX_INPUT_QUEUE;
487 // Check whether queue is full
488 if (incoming_read_ptr == next_write_ptr) {
493 // Advance the write pointer
494 incoming_write_ptr = next_write_ptr;
496 incoming_data_queue[incoming_write_ptr].length = length;
498 // incoming_data_queue[incoming_write_ptr].port = port;
500 snprintf((char *)incoming_data_queue[incoming_write_ptr].data,
501 (length < MAX_LINE_SIZE) ? length : MAX_LINE_SIZE,
520 //***********************************************************
523 // Takes data read in from a port and adds it to the
524 // incoming_data_queue. If queue is full, waits for queue to have
525 // space before continuing.
528 // string is the string of data
529 // length is the length of the string. If 0 then use strlen()
530 // on the string itself to determine the length.
532 // Note that decode_ax25_header() and perhaps other routines may
533 // increase the length of the string while processing. We need to
534 // send a COPY of our input string off to the decoding routines for
535 // this reason, and the size of the buffer must be MAX_LINE_SIZE
536 // for this reason also.
537 //***********************************************************
538 void channel_data(unsigned char *string, int length) {
540 // struct timeval tmv;
541 // Some messiness necessary because we're using xastir_mutex's
542 // instead of pthread_mutex_t's.
546 //fprintf(stderr,"channel_data: %x %d\n",string[0],length);
556 if (string[0] == '\0')
562 // Compute length of string including terminator
563 length = strlen((const char *)string) + 1;
566 // Check for excessively long packets. These might be TCP/IP
567 // packets or concatenated APRS packets. In any case it's some
568 // kind of garbage that we don't want to try to parse.
570 // Note that for binary data (WX stations and KISS packets), the
571 // strlen() function may not work correctly.
572 if (length > MAX_LINE_SIZE) { // Too long!
573 // fprintf(stderr, "Too long");
574 string[0] = '\0'; // Truncate it to zero length
579 // This protects channel_data from being run by more than one
580 // thread at the same time.
585 // Install the cleanup routine for the case where this
586 // thread gets killed while the mutex is locked. The
587 // cleanup routine initiates an unlock before the thread
588 // dies. We must be in deferred cancellation mode for the
589 // thread to have this work properly. We must first get the
590 // pthread_mutex_t address.
594 // If it's any of three types of GPS ports and is a GPRMC or
595 // GPGGA string, just stick it in one of two global
596 // variables for holding such strings. UpdateTime() can
597 // come along and process/clear-out those strings at the
598 // gps_time interval.
602 // Remove the cleanup routine for the case where this thread
603 // gets killed while the mutex is locked. The cleanup
604 // routine initiates an unlock before the thread dies. We
605 // must be in deferred cancellation mode for the thread to
606 // have this work properly.
607 // pthread_cleanup_pop(0);
610 //fprintf(stderr,"Channel data on Port [%s]\n",(char *)string);
614 // Wait for empty space in queue
615 //fprintf(stderr,"\n== %s", string);
619 while (push_incoming_data(string, length) && max < 5400) {
620 sched_yield(); // Yield to other threads
622 tmv.tv_usec = 2; // 2 usec
623 (void)select(0,NULL,NULL,NULL,&tmv);
628 kiss_parse_packet(g_strdup(string), length);
629 //g_idle_add((GSourceFunc)kiss_parse_packet, g_strdup(string));
635 // fprintf(stderr,"Channel data on Port [%s]\n",(char *)string);
644 //****************************************************************
645 // get device name only (the portion at the end of the full path)
646 // device_name current full name of device
647 //****************************************************************
649 char *get_device_name_only(char *device_name) {
652 if (device_name == NULL)
656 len = (int)strlen(device_name);
657 for(i = len; i > 0 && !done; i--){
658 if(device_name[i] == '/'){
659 device_name += (i+1);
667 int filethere(char *fn) {
683 * Close the serial port
685 gint serial_detach() {
690 if (port_data.active == DEVICE_IN_USE && port_data.status == DEVICE_UP)
693 (void)tcsetattr(port_data.channel, TCSANOW, &port_data.t_old);
694 if (close(port_data.channel) == 0)
696 port_data.status = DEVICE_DOWN;
698 port_data.active = DEVICE_NOT_IN_USE;
704 fprintf(stderr,"Could not close port %s\n",port_data.device_name);
706 port_data.status = DEVICE_DOWN;
708 port_data.active = DEVICE_NOT_IN_USE;
712 //update_interface_list();
715 snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data.device_name));
717 ENABLE_SETUID_PRIVILEGE;
719 DISABLE_SETUID_PRIVILEGE;
728 char *adapter; /* do not free this, it is freed somewhere else */
729 char *bonding; /* allocated from heap, you must free this */
732 gboolean open_bluetooth_tty_connection(gchar *bda, gchar **aprs_bt_port)
734 gint i, st, num_bondings = 0, num_rfcomms = 0, num_posdev = 0;
735 //gint j, k, num_classes = 0, bonding_cnt = 0,
736 GError *error = NULL;
737 DBusGConnection *bus = NULL;
738 DBusGProxy *proxy = NULL;
739 //char **str_iter = NULL;
740 //char **tmp_bondings = 0, **tmp_classes = 0;
741 //char **adapters = 0;
743 bonding_t *bondings = 0; /* points to array of bonding_t */
744 bonding_t *posdev = 0; /* bondings with positioning bit on */
747 const gchar const *spp="SPP";
750 // gchar *gpsd_ctrl_sock;
752 /* Use the dbus interface to get the BT information */
755 #if (__GNUC__ > 2) && ((__GNUC__ > 3) || (__GNUC_MINOR__ > 2))
756 #define ERRSTR(fmt, args...) \
757 if (error_buf && error_buf_max_len>0) { \
758 set_error_msg(error_buf, error_buf_max_len, fmt, args); \
763 #define ERRSTR(fmt, args...) \
764 if (error_buf && error_buf_max_len>0) { \
765 set_error_msg(error_buf, error_buf_max_len, fmt, ##args); \
767 PDEBUG(fmt, ##args); \
773 bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
778 errno = ECONNREFUSED; /* close enough :) */
779 //ERRSTR("%s", error->message);
780 //PDEBUG("Cannot get reply message [%s]\n", error->message);
784 /* We need BT information only if the caller does not specify
785 * the BT address. If address is defined, it is assumed that
786 * it is already bonded and we just create RFCOMM connection
791 // May want to support auto detect for serial ports?
792 } else { /* if (!bda) */
793 /* Caller supplied BT address so use it */
795 posdev = calloc(1, sizeof(bonding_t *));
802 posdev[0].bonding = strdup(bda);
804 /* Adapter information is not needed */
805 posdev[0].adapter = "<not avail>";
808 /* For each bondend BT GPS device, try to create rfcomm */
809 for (i=0; i<num_posdev; i++)
811 /* Note that bluez does not provide this interface (its defined but not
812 * yet implemented) so we use btcond for creating rfcomm device(s)
815 proxy = dbus_g_proxy_new_for_name(bus,
816 BTCOND_DBUS, BTCOND_PATH, BTCOND_INTERFACE);
820 if(!dbus_g_proxy_call(proxy, BTCOND_CONNECT, &error,
821 G_TYPE_STRING, posdev[i].bonding,
823 G_TYPE_BOOLEAN, TRUE,
827 || error || !tmp || !*tmp)
829 /*PDEBUG("dbus_g_proxy_call returned an error: (error=(%d,%s), tmp=%s\n",
830 error ? error->code : -1,
831 error ? error->message : "<null>",
832 tmp ? tmp : "<null>");
834 /* No error if already connected */
835 if (error && !strstr(error->message,
836 "com.nokia.btcond.error.connected"))
839 fprintf(stderr, "Cannot send msg (service=%s, object=%s, interface=%s, "
845 error->message ? error->message : "<no error msg>");
846 /* ERRSTR("Cannot send msg (service=%s, object=%s, interface=%s, "
852 error->message ? error->message : "<no error msg>");
856 else if(!tmp || !*tmp)
858 /* hack: rfcommX device name is at the end of error message */
859 char *last_space = strstr(error->message, " rfcomm");
866 tmp = g_strdup_printf("/dev/%s", last_space+1);
869 g_object_unref(proxy);
873 rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
881 rfcomms[num_rfcomms] = tmp;
884 fprintf(stderr, "BT addr=%s, RFCOMM %s now exists (adapter=%s)\n",
885 posdev[i].bonding, tmp, posdev[i].adapter);
897 /* serial device creation failed */
898 fprintf(stderr, "No rfcomm created\n");
905 /* Add null at the end */
906 rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
915 rfcomms[num_rfcomms] = NULL;
917 /* Just start the beast (to be done if everything is ok) */
920 *aprs_bt_port = g_strdup_printf("%s",rfcomms[0]);
928 g_strfreev(adapters);
933 for (i=0; i<num_posdev; i++)
935 if (posdev[i].bonding)
937 free(posdev[i].bonding);
938 memset(&posdev[i], 0, sizeof(bonding_t)); /* just in case */
947 for (i=0; i<num_bondings; i++)
949 if (bondings[i].bonding)
951 free(bondings[i].bonding);
952 memset(&bondings[i], 0, sizeof(bonding_t)); /* just in case */
961 for (i=0; i<num_rfcomms; i++)
975 dbus_g_connection_unref(bus);
987 //***********************************************************
989 //***********************************************************
997 // struct passwd *user_info;
1009 // clear port_channel
1010 port_data.channel = -1;
1012 // clear port active
1013 port_data.active = DEVICE_NOT_IN_USE;
1015 // clear port status
1016 port_data.status = DEVICE_DOWN;
1018 // Show the latest status in the interface control dialog
1019 // update_interface_list();
1024 if(_aprs_tnc_method == TNC_CONNECTION_BT)
1026 // Bluetooth connection
1027 gchar * aprs_bt_port = NULL;
1029 if(!open_bluetooth_tty_connection(_aprs_tnc_bt_mac, &aprs_bt_port))
1031 fprintf(stderr, "Failed to connect to BT device\n");
1032 // Failed to connect
1037 snprintf(port_data.device_name, MAX_DEVICE_NAME, aprs_bt_port);
1038 g_free(aprs_bt_port);
1040 fprintf(stderr, "BT Port: %s\n", port_data.device_name);
1044 snprintf(port_data.device_name, MAX_DEVICE_NAME, _aprs_tty_port);
1048 port_data.device_type = DEVICE_SERIAL_KISS_TNC;
1049 port_data.sp = B9600;
1052 // check for lock file
1054 // Try to open the serial port now
1055 ENABLE_SETUID_PRIVILEGE;
1056 port_data.channel = open(port_data.device_name, O_RDWR|O_NOCTTY);
1057 DISABLE_SETUID_PRIVILEGE;
1058 if (port_data.channel == -1){
1060 fprintf(stderr,"Could not open channel on port!\n");
1065 // Attempt to create the lock file
1066 /* snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data.device_name));
1068 ENABLE_SETUID_PRIVILEGE;
1069 lock = fopen(fn,"w");
1070 DISABLE_SETUID_PRIVILEGE;
1072 // get my process id for lock file
1077 user_info = getpwuid(user_id);
1081 user_info->pw_name);
1083 fprintf(lock,"%9d %s %s",(int)mypid,"xastir",temp);
1085 // We've successfully created our own lock file
1089 fprintf(stderr,"Warning: Failed opening LCK file! Continuing on...\n");
1094 // get port attributes for new and old
1095 if (tcgetattr(port_data.channel, &port_data.t) != 0) {
1096 fprintf(stderr,"Could not get t port attributes for port!\n");
1098 // Here we should close the port and remove the lock.
1104 if (tcgetattr(port_data.channel, &port_data.t_old) != 0) {
1106 fprintf(stderr,"Could not get t_old port attributes for port!\n");
1108 // Here we should close the port and remove the lock.
1115 port_data.t.c_cc[VMIN] = (cc_t)1;
1116 port_data.t.c_cc[VTIME] = (cc_t)2;
1119 port_data.t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
1120 port_data.t.c_iflag = (tcflag_t)(IGNBRK | IGNPAR);
1122 port_data.t.c_oflag = (0);
1123 port_data.t.c_lflag = (0);
1126 speed = (int)(port_data.t.c_cflag & CBAUD);
1131 port_data.t.c_cflag = (tcflag_t)(HUPCL|CLOCAL|CREAD);
1132 port_data.t.c_cflag &= ~PARENB;
1133 switch (port_data.style){
1136 port_data.t.c_cflag &= ~CSTOPB;
1137 port_data.t.c_cflag &= ~CSIZE;
1138 port_data.t.c_cflag |= CS8;
1142 // Even parity (7E1)
1143 port_data.t.c_cflag &= ~PARODD;
1144 port_data.t.c_cflag &= ~CSTOPB;
1145 port_data.t.c_cflag &= ~CSIZE;
1146 port_data.t.c_cflag |= CS7;
1150 // Odd parity (7O1):
1151 port_data.t.c_cflag |= PARODD;
1152 port_data.t.c_cflag &= ~CSTOPB;
1153 port_data.t.c_cflag &= ~CSIZE;
1154 port_data.t.c_cflag |= CS7;
1161 port_data.t.c_cflag |= speed;
1162 // set input and out put speed
1163 if (cfsetispeed(&port_data.t, port_data.sp) == -1)
1165 fprintf(stderr,"Could not set port input speed for port!\n");
1167 // Here we should close the port and remove the lock.
1173 if (cfsetospeed(&port_data.t, port_data.sp) == -1) {
1175 fprintf(stderr,"Could not set port output speed for port!\n");
1177 // Here we should close the port and remove the lock.
1183 if (tcflush(port_data.channel, TCIFLUSH) == -1) {
1185 fprintf(stderr,"Could not flush data for port!\n");
1187 // Here we should close the port and remove the lock.
1193 if (tcsetattr(port_data.channel,TCSANOW, &port_data.t) == -1)
1195 fprintf(stderr,"Could not set port attributes for port!\n");
1197 // Here we should close the port and remove the lock.
1203 // clear port active
1204 port_data.active = DEVICE_IN_USE;
1206 // clear port status
1207 port_data.status = DEVICE_UP;
1209 // Show the latest status in the interface control dialog
1210 // update_interface_list();
1212 // Ensure we are in KISS mode
1213 if(port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1215 // Send KISS init string
1216 gchar * cmd = g_strdup("\nINT KISS\nRESTART\n");
1217 port_write_string(cmd, strlen(cmd), APRS_PORT_TTY);
1220 // return good condition
1225 //***********************************************************
1229 // This function becomes the long-running thread that snags
1230 // characters from an interface and passes them off to the
1231 // decoding routines. One copy of this is run for each read
1232 // thread for each interface.
1233 //***********************************************************
1236 unsigned char cin, last;
1237 // unsigned char buffer[MAX_DEVICE_BUFFER]; // Only used for AX.25 packets
1244 * Some local variables used for checking AX.25 data - PE1DNN
1246 * "from" is used to look up where the data comes from
1247 * "from_len" is used to keep the size of sockaddr structure
1248 * "dev" is used to keep the name of the interface that
1249 * belongs to our port/device_name
1251 // struct sockaddr from;
1252 // socklen_t from_len;
1255 // max = MAX_DEVICE_BUFFER - 1;
1256 cin = (unsigned char)0;
1257 last = (unsigned char)0;
1261 // We stay in this read loop until the port is shut down
1262 while(port_data.active == DEVICE_IN_USE){
1264 if (port_data.status == DEVICE_UP){
1266 port_data.read_in_pos = 0;
1269 while (port_data.scan
1270 && (port_data.read_in_pos < (MAX_DEVICE_BUFFER - 1) )
1271 && (port_data.status == DEVICE_UP) ) {
1275 // pthread_testcancel(); // Check for thread termination request
1277 // Handle all EXCEPT AX25_TNC interfaces here
1278 // Get one character
1279 port_data.scan = (int)read(port_data.channel,&cin,1);
1280 //fprintf(stderr,"tty in:%02x ",cin);
1283 // Below is code for ALL types of interfaces
1284 if (port_data.scan > 0 && port_data.status == DEVICE_UP ) {
1286 if (port_data.device_type != DEVICE_AX25_TNC)
1287 port_data.bytes_input += port_data.scan; // Add character to read buffer
1291 // Handle all EXCEPT AX25_TNC interfaces here
1292 if (port_data.device_type != DEVICE_AX25_TNC){
1295 // Do special KISS packet processing here.
1296 // We save the last character in
1297 // port_data.channel2, as it is
1298 // otherwise only used for AX.25 ports.
1300 if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1301 || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1304 if (port_data.channel2 == KISS_FESC) { // Frame Escape char
1305 if (cin == KISS_TFEND) { // Transposed Frame End char
1307 // Save this char for next time
1309 port_data.channel2 = cin;
1313 else if (cin == KISS_TFESC) { // Transposed Frame Escape char
1315 // Save this char for next time
1317 port_data.channel2 = cin;
1322 port_data.channel2 = cin;
1325 else if (port_data.channel2 == KISS_FEND) { // Frame End char
1326 // Frame start or frame end. Drop
1327 // the next character which should
1328 // either be another frame end or a
1331 // Note this "type" byte is where it specifies which KISS interface
1332 // the packet came from. We may want to use this later for
1333 // multi-drop KISS or other types of KISS protocols.
1335 // Save this char for next time
1337 port_data.channel2 = cin;
1341 else if (cin == KISS_FESC) { // Frame Escape char
1342 port_data.channel2 = cin;
1346 port_data.channel2 = cin;
1348 } // End of first special KISS processing
1351 // We shouldn't see any AX.25 flag
1352 // characters on a KISS interface because
1353 // they are stripped out by the KISS code.
1354 // What we should see though are KISS_FEND
1355 // characters at the beginning of each
1356 // packet. These characters are where we
1357 // should break the data apart in order to
1358 // send strings to the decode routines. It
1359 // may be just fine to still break it on \r
1360 // or \n chars, as the KISS_FEND should
1361 // appear immediately afterwards in
1362 // properly formed packets.
1366 && (cin == (unsigned char)'\r'
1367 || cin == (unsigned char)'\n'
1368 || port_data.read_in_pos >= (MAX_DEVICE_BUFFER - 1)
1369 || ( (cin == KISS_FEND) && (port_data.device_type == DEVICE_SERIAL_KISS_TNC) )
1370 || ( (cin == KISS_FEND) && (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) )
1371 && port_data.data_type == 0) { // If end-of-line
1373 // End serial/net type data send it to the decoder Put a terminating
1374 // zero at the end of the read-in data
1376 port_data.device_read_buffer[port_data.read_in_pos] = (char)0;
1378 if (port_data.status == DEVICE_UP && port_data.read_in_pos > 0) {
1381 // Compute length of string in
1384 //fprintf(stderr,"%d\t%d\n",port_data.read_in_pos,port_data.read_out_pos);
1386 // KISS TNC sends binary data
1387 if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1388 || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1390 length = port_data.read_in_pos - port_data.read_out_pos;
1392 length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER;
1396 else { // ASCII data
1401 (unsigned char *)port_data.device_read_buffer,
1402 length); // Length of string
1405 for (i = 0; i <= port_data.read_in_pos; i++)
1406 port_data.device_read_buffer[i] = (char)0;
1408 port_data.read_in_pos = 0;
1412 // Check for binary WX station data
1413 if (cin == '\0') // OWW WX daemon sends 0x00's!
1416 if (port_data.read_in_pos < (MAX_DEVICE_BUFFER - 1) ) {
1417 port_data.device_read_buffer[port_data.read_in_pos] = (char)cin;
1418 port_data.read_in_pos++;
1419 port_data.device_read_buffer[port_data.read_in_pos] = (char)0;
1422 port_data.read_in_pos = 0;
1426 } // End of non-AX.25 interface code block
1430 else if (port_data.status == DEVICE_UP) { /* error or close on read */
1432 if (port_data.scan == 0) {
1433 // Should not get this unless the device is down. NOT TRUE!
1434 // We seem to also be able to get here if we're closing/restarting
1435 // another interface. For that reason I commented out the below
1436 // statement so that this interface won't go down. The inactivity
1437 // timer solves that issue now anyway. --we7u.
1438 port_data.status = DEVICE_ERROR;
1440 // If the below statement is enabled, it causes an immediate reconnect
1441 // after one time-period of inactivity, currently 7.5 minutes, as set in
1442 // main.c:UpdateTime(). This means the symbol will never change from green
1443 // to red on the status bar, so the operator might not know about a
1444 // connection that is being constantly reconnected. By leaving it commented
1445 // out we get one time period of red, and then it will reconnect at the 2nd
1446 // time period. This means we can reconnect within 15 minutes if a line
1449 port_data.reconnects = -1; // Causes an immediate reconnect
1451 // Show the latest status in the interface control dialog
1452 // update_interface_list();
1455 if (port_data.scan == -1) {
1456 /* Should only get this if an real error occurs */
1457 port_data.status = DEVICE_ERROR;
1459 // If the below statement is enabled, it causes an immediate reconnect
1460 // after one time-period of inactivity, currently 7.5 minutes, as set in
1461 // main.c:UpdateTime(). This means the symbol will never change from green
1462 // to red on the status bar, so the operator might not know about a
1463 // connection that is being constantly reconnected. By leaving it commented
1464 // out we get one time period of red, and then it will reconnect at the 2nd
1465 // time period. This means we can reconnect within 15 minutes if a line
1468 port_data.reconnects = -1; // Causes an immediate reconnect
1470 // Show the latest status in the
1471 // interface control dialog
1472 // update_interface_list();
1481 // Send any packets queued
1482 // try to get lock, otherwise try next time
1483 if(g_mutex_trylock (_write_buffer[APRS_PORT_TTY].write_lock))
1485 // Store the current end pointer as it may change
1487 while (_write_buffer[APRS_PORT_TTY].write_in_pos != _write_buffer[APRS_PORT_TTY].write_out_pos) {
1490 _write_buffer[APRS_PORT_TTY].device_write_buffer[_write_buffer[APRS_PORT_TTY].write_out_pos],
1493 _write_buffer[APRS_PORT_TTY].write_out_pos++;
1494 if (_write_buffer[APRS_PORT_TTY].write_out_pos >= MAX_DEVICE_BUFFER)
1495 _write_buffer[APRS_PORT_TTY].write_out_pos = 0;
1500 g_mutex_unlock(_write_buffer[APRS_PORT_TTY].write_lock);
1505 if (port_data.active == DEVICE_IN_USE) {
1507 // We need to delay here so that the thread doesn't use
1508 // high amounts of CPU doing nothing.
1510 // This select that waits on data and a timeout, so that if data
1511 // doesn't come in within a certain period of time, we wake up to
1512 // check whether the socket has gone down. Else, we go back into
1513 // the select to wait for more data or a timeout. FreeBSD has a
1514 // problem if this is less than 1ms. Linux works ok down to 100us.
1515 // We don't need it anywhere near that short though. We just need
1516 // to check whether the main thread has requested the interface be
1517 // closed, and so need to have this short enough to have reasonable
1518 // response time to the user.
1520 //sched_yield(); // Yield to other threads
1522 // Set up the select to block until data ready or 100ms
1523 // timeout, whichever occurs first.
1525 FD_SET(port_data.channel, &rd);
1527 tmv.tv_usec = 100000; // 100 ms
1528 (void)select(0,&rd,NULL,NULL,&tmv);
1534 #endif //INCLUDE_APRS