]> git.itanic.dy.fi Git - maemo-mapper/blob - src/aprs_kiss.c
Improved APRS bluetouth TNC functionality.
[maemo-mapper] / src / aprs_kiss.c
1 /*
2  * 
3  * This file is part of Maemo Mapper.
4  *
5  * Maemo Mapper is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Maemo Mapper is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
17  * 
18  * 
19  * Parts of this code have been ported from Xastir by Rob Williams (10 Aug 2008):
20  * 
21  *  * XASTIR, Amateur Station Tracking and Information Reporting
22  * Copyright (C) 1999,2000  Frank Giannandrea
23  * Copyright (C) 2000-2007  The Xastir Group
24  * 
25  */
26
27
28 #ifdef HAVE_CONFIG_H
29 #    include "config.h"
30 #endif
31
32 #ifdef INCLUDE_APRS
33
34 #include "aprs_kiss.h"
35 #include "aprs.h"
36 #include "defines.h"
37 #include "data.h"
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
40
41 #include <pthread.h>
42
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <assert.h>
47 #include <ctype.h>
48 #include <sys/stat.h>
49 #include <sys/file.h>
50 #include <unistd.h>
51 #include <dirent.h>
52 #include <signal.h>
53 #include <termios.h>
54 #include <pwd.h>
55 #include <termios.h>
56 #include <setjmp.h>
57 #include <sys/socket.h>
58 #include <fcntl.h>
59
60 #include <netinet/in.h>     // Moved ahead of inet.h as reports of some *BSD's not
61                             // including this as they should.
62
63
64 #define _GNU_SOURCE
65
66 #include <errno.h>
67 #include <unistd.h>
68 #include <fcntl.h>
69 #include <string.h>
70 #include <signal.h>
71 #include <sys/types.h>
72 #include <sys/stat.h>
73 #include <sys/wait.h>
74 #include <sys/time.h>
75 #include <time.h>
76
77 #define DBUS_API_SUBJECT_TO_CHANGE
78 #include <dbus/dbus-glib.h>
79
80
81 #define DISABLE_SETUID_PRIVILEGE do { \
82 seteuid(getuid()); \
83 setegid(getgid()); \
84 } while(0)
85 #define ENABLE_SETUID_PRIVILEGE do { \
86 seteuid(euid); \
87 setegid(egid); \
88 } while(0)
89
90
91
92
93 #define MAX_INPUT_QUEUE 1000
94 gint decode_ax25_line(gchar *line, TAprsPort port);
95
96 typedef struct
97 {
98     pthread_mutex_t lock;
99     pthread_t threadID;
100 } xastir_mutex;
101
102 xastir_mutex connect_lock;              // Protects port_data[].thread_status and port_data[].connect_status
103
104 // Read/write pointers for the circular input queue
105 /*
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;
111 */
112 uid_t euid;
113 gid_t egid;
114
115
116
117 iface port_data;     // shared port data
118
119
120 //WE7U2
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.
126 //
127 // Inputs:  string          Raw input string
128 //          asterisk        1 = add "digipeated" asterisk
129 //
130 // Outputs: callsign        Processed string
131 //          returned int    1=more callsigns follow, 0=end of address field
132 //
133 gint decode_ax25_address(gchar *string, gchar *callsign, gint asterisk) {
134     gint i,j;
135     gchar ssid;
136     gchar t;
137     gint more = 0;
138     gint digipeated = 0;
139
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.
142     j = 0;
143     for (i = 0; i < 6; i++) {
144         t = ((unsigned char)string[i] >> 1) & 0x7f;
145         if (t != ' ') {
146             callsign[j++] = t;
147         }
148     }
149
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];
153
154     // Check the digipeat bit
155     if ( (ssid & 0x80) && asterisk)
156         digipeated++;   // Has been digipeated
157
158     // Check whether it is the end of the address field
159     if ( !(ssid & 0x01) )
160         more++; // More callsigns to come after this one
161
162     // Snag the four SSID bits
163     ssid = (ssid >> 1) & 0x0f;
164
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.
167     if (ssid) {
168         callsign[j++] = '-';
169         if (ssid > 9) {
170             callsign[j++] = '1';
171         }
172         ssid = ssid % 10;
173         callsign[j++] = '0' + ssid;
174     }
175
176     // Add an asterisk if the packet has been digipeated through
177     // this callsign
178     if (digipeated)
179         callsign[j++] = '*';
180
181     // Terminate the string
182     callsign[j] = '\0';
183
184     return(more);
185 }
186
187
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
194 // format.
195 //
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.
205 //
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:
210 //
211 // KISS               No CRC, one radio port
212 //
213 // SMACK              16-bit CRC, multiport TNC's
214 //
215 // KISS-CRC
216 //
217 // 6-PACK
218 //
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
222 //
223 // JKISS              (AGWPE and BPQ32 compatible)
224 //
225 // MKISS              Linux driver which supports KISS/BPQ and
226 //                    hardware handshaking?  Also Paccomm command to
227 //                    immediately enter KISS mode.
228 //
229 // FlexKISS           -,
230 // FlexCRC            -|-- These are all the same!
231 // RMNC-KISS          -|
232 // CRC-RMNC           -'
233 //
234 //
235 // It appears that none of the above protocols implement any form of
236 // hardware flow control.
237 // 
238 // 
239 // Compare this function with interface.c:process_ax25_packet() to
240 // see if we're missing anything important.
241 //
242 //
243 // Inputs:  data_string         Raw string (must be MAX_LINE_SIZE or bigger)
244 //          length              Length of raw string (may get changed here)
245 //
246 // Outputs: int                 0 if it is a bad packet,
247 //                              1 if it is good
248 //          data_string         Processed string
249 //
250 gint decode_ax25_header(
251                 unsigned char *data_string, 
252                 gint *length) {
253     gchar temp[20];
254     gchar result[MAX_LINE_SIZE+100];
255     gchar dest[15];
256     gint i, ptr;
257     gchar callsign[15];
258     gchar more;
259     gchar num_digis = 0;
260
261
262     // Do we have a string at all?
263     if (data_string == NULL)
264         return(0);
265
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
268     // data itself.
269     if (*length > 1024) {
270         data_string[0] = '\0';
271         *length = 0;
272         return(0);
273     }
274
275     // Start with an empty string for the result
276     result[0] = '\0';
277
278     ptr = 0;
279
280     // Process the destination address
281     for (i = 0; i < 7; i++)
282         temp[i] = data_string[ptr++];
283     temp[7] = '\0';
284     more = decode_ax25_address(temp, callsign, 0); // No asterisk
285     snprintf(dest,sizeof(dest),"%s",callsign);
286
287     // Process the source address
288     for (i = 0; i < 7; i++)
289         temp[i] = data_string[ptr++];
290     temp[7] = '\0';
291     more = decode_ax25_address(temp, callsign, 0); // No asterisk
292
293     // Store the two callsigns we have into "result" in the correct
294     // order
295     snprintf(result,sizeof(result),"%s>%s",callsign,dest);
296
297     // Process the digipeater addresses (if any)
298     num_digis = 0;
299     while (more && num_digis < 8) {
300         for (i = 0; i < 7; i++)
301             temp[i] = data_string[ptr++];
302         temp[7] = '\0';
303
304         more = decode_ax25_address(temp, callsign, 1); // Add asterisk
305         strncat(result,
306             ",",
307             sizeof(result) - strlen(result));
308         
309         strncat(result,
310             callsign,
311             sizeof(result) - strlen(result));
312         num_digis++;
313     }
314
315     strncat(result,
316         ":",
317         sizeof(result) - strlen(result));
318
319
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.
323
324
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) {
328         return(0);
329     }
330
331
332     // PID byte should be 0xf0 (normal AX.25 text)
333     if (data_string[ptr++] != 0xf0)
334         return(0);
335
336
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
341 // end.
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
346             break;
347         }
348     }
349
350     // Add the Info field to the decoded header info
351     strncat(result,
352         (char *)(&data_string[ptr]),
353         sizeof(result) - strlen(result));
354
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.
360     //
361     snprintf((char *)data_string,
362         MAX_LINE_SIZE,
363         "%s",
364         result);
365
366     // Write out the new length
367     *length = strlen(result); 
368
369 //fprintf(stderr,"%s\n",data_string);
370
371     return(1);
372 }
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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.
393 // Currently:
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.
398 //
399 // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER,
400 // which is currently set to 4096.
401 //
402 void tnc_data_clean(gchar *buf) {
403
404     while (!strncmp(buf,"cmd:",4)) {
405         int ii;
406
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
411         // other problems.
412         for (ii = 0; ; ii++) {
413             buf[ii] = buf[ii+4];
414             if (buf[ii] == '\0')
415                 break;
416         }
417     }
418 }
419
420
421
422 static gboolean aprs_parse_tty_packet(gchar *packet)
423 {
424     decode_ax25_line(packet, APRS_PORT_TTY);
425
426     g_free(packet);
427
428     return FALSE;
429 }
430
431
432 static gboolean kiss_parse_packet(unsigned char *data_string, gint data_length)
433 {
434         
435         
436         //fprintf(stderr, "Parse: %s\n", data_string);
437         
438         gint devicetype = port_data.device_type;
439         
440         
441         switch(devicetype)
442         {
443     case DEVICE_SERIAL_KISS_TNC:
444     case DEVICE_SERIAL_MKISS_TNC:
445             if ( !decode_ax25_header( data_string,
446                     &data_length ) ) {
447                 // Had a problem decoding it.  Drop
448                 // it on the floor.
449                 break;
450             }
451             else {
452                 // Good decode.  Drop through to the
453                 // next block to log and decode the
454                 // packet.
455             }
456         
457         case DEVICE_SERIAL_TNC:
458             tnc_data_clean((char *)data_string);
459
460         case DEVICE_AX25_TNC:   
461
462
463
464                 
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);
468                 break;
469                 
470         default:
471                 break;
472         }
473
474     
475     
476         return FALSE; 
477 }
478
479 // Add one record to the circular queue.  Returns 1 if queue is
480 // full, 0 if successful.
481 //
482 /*
483 int push_incoming_data(unsigned char *data_string, int length) {
484         
485     int next_write_ptr = (incoming_write_ptr + 1) % MAX_INPUT_QUEUE;
486
487     // Check whether queue is full
488     if (incoming_read_ptr == next_write_ptr) {
489         // Yep, it's full!
490         return(1);
491     }
492
493     // Advance the write pointer
494     incoming_write_ptr = next_write_ptr;
495
496     incoming_data_queue[incoming_write_ptr].length = length;
497
498 //    incoming_data_queue[incoming_write_ptr].port = port;
499
500     snprintf((char *)incoming_data_queue[incoming_write_ptr].data,
501         (length < MAX_LINE_SIZE) ? length : MAX_LINE_SIZE,
502         "%s",
503         data_string);
504
505     queue_depth++;
506     push_count++;
507
508     return(0);
509 }
510 */
511
512
513
514
515
516
517
518
519
520 //***********************************************************
521 // channel_data()
522 //
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.
526 //
527 // port #                                                    
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.
531 //
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) {
539     int max;
540 //    struct timeval tmv;
541     // Some messiness necessary because we're using xastir_mutex's
542     // instead of pthread_mutex_t's.
543     int process_it = 0;
544
545
546     //fprintf(stderr,"channel_data: %x %d\n",string[0],length);
547
548     
549     max = 0;
550
551     if (string == NULL)
552     {
553         return;
554     }
555
556     if (string[0] == '\0')
557     {
558         return;
559     }
560
561     if (length == 0) {
562         // Compute length of string including terminator
563         length = strlen((const char *)string) + 1;
564     }
565
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.
569
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
575         return;
576     }
577
578
579     // This protects channel_data from being run by more than one
580     // thread at the same time.
581
582     if (length > 0) {
583
584
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.
591
592
593
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.
599         //
600         process_it++;
601
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);
608
609  
610 //fprintf(stderr,"Channel data on Port [%s]\n",(char *)string);
611
612         if (process_it) {
613
614             // Wait for empty space in queue
615 //fprintf(stderr,"\n== %s", string);
616                 
617                 
618 /*
619             while (push_incoming_data(string, length) && max < 5400) {
620                 sched_yield();  // Yield to other threads
621                 tmv.tv_sec = 0;
622                 tmv.tv_usec = 2;  // 2 usec
623                 (void)select(0,NULL,NULL,NULL,&tmv);
624                 max++;
625             }
626 */
627                 
628                 kiss_parse_packet(g_strdup(string), length);
629             //g_idle_add((GSourceFunc)kiss_parse_packet, g_strdup(string));
630
631             
632         }
633 //        else
634 //        {
635 //              fprintf(stderr,"Channel data on Port [%s]\n",(char *)string);
636 //        }
637     }
638
639 }
640
641
642
643
644 //****************************************************************
645 // get device name only (the portion at the end of the full path)
646 // device_name current full name of device
647 //****************************************************************
648
649 char *get_device_name_only(char *device_name) {
650     int i,len,done;
651
652     if (device_name == NULL)
653         return(NULL);
654
655     done = 0;
656     len = (int)strlen(device_name);
657     for(i = len; i > 0 && !done; i--){
658         if(device_name[i] == '/'){
659             device_name += (i+1);
660             done = 1;
661         }
662     }
663     return(device_name);
664 }
665
666
667 int filethere(char *fn) {
668     FILE *f;
669     int ret;
670
671     ret =0;
672     f=fopen(fn,"r");
673     if (f != NULL) {
674         ret=1;
675         (void)fclose(f);
676     }
677     return(ret);
678 }
679
680
681
682 /*
683  * Close the serial port
684  * */
685 gint serial_detach() {
686     int ok;
687     ok = -1;
688
689     if (port_data.active == DEVICE_IN_USE && port_data.status == DEVICE_UP) 
690     {
691         // Close port first
692         (void)tcsetattr(port_data.channel, TCSANOW, &port_data.t_old);
693         if (close(port_data.channel) == 0) 
694         {
695             port_data.status = DEVICE_DOWN;
696             usleep(200);
697             port_data.active = DEVICE_NOT_IN_USE;
698             ok = 1;
699
700         }
701         else 
702         {
703             fprintf(stderr,"Could not close port %s\n",port_data.device_name);
704
705             port_data.status = DEVICE_DOWN;
706             usleep(200);
707             port_data.active = DEVICE_NOT_IN_USE;
708
709         }
710
711     }
712
713     return(ok);
714 }
715
716
717 typedef struct {
718   char *adapter;  /* do not free this, it is freed somewhere else */
719   char *bonding;  /* allocated from heap, you must free this */
720 } bonding_t;
721
722 static inline DBusGConnection *get_dbus_gconn(GError **error)
723 {
724   DBusGConnection *conn;
725
726   conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, error);
727   return conn;
728 }
729
730
731
732 void close_tnc_port()
733 {
734
735         if (port_data.device_name != NULL) {
736                 fprintf(stderr, "in close_tnc_port()\n");
737                 serial_detach();
738                 
739             int skip_dbus = 0;
740             DBusGConnection *bus = NULL;
741             DBusGProxy *proxy = NULL;
742             GError *error = NULL;
743
744             bus = get_dbus_gconn(&error);
745             if (!bus) {
746               errno = ECONNREFUSED; /* close enough :) */
747               skip_dbus = 1;
748             }
749
750
751             if (!skip_dbus) {
752                 /* Disconnect the device */
753                 proxy = dbus_g_proxy_new_for_name(bus,
754                     BTCOND_DBUS, BTCOND_PATH, BTCOND_INTERFACE);
755                 error = NULL;
756                 if(!dbus_g_proxy_call(proxy, BTCOND_DISCONNECT, &error,
757                       G_TYPE_STRING, port_data.device_name, G_TYPE_INVALID, G_TYPE_INVALID)
758                     || error){
759 //                      PDEBUG("Cannot send msg (service=%s, object=%s, interface=%s, "
760 //                                      "method=%s) [%s]\n",
761 //                       BTCOND_DBUS,
762 //                       BTCOND_PATH,
763 //                       BTCOND_INTERFACE,
764 //                       BTCOND_DISCONNECT,
765 //                       error->message ? error->message : "<no error msg>");
766                 }
767                 g_object_unref(proxy);
768             }
769
770             free(port_data.device_name);
771             port_data.device_name[0]=0;
772             
773
774             if (bus) {
775               dbus_g_connection_unref(bus);
776             }
777         }
778 }
779
780 gboolean open_bluetooth_tty_connection(gchar *bda, gchar **aprs_bt_port)
781 {
782         gint i, st, num_bondings = 0, num_rfcomms = 0, num_posdev = 0;  
783         GError *error = NULL;
784         DBusGConnection *bus = NULL;
785         DBusGProxy *proxy = NULL;
786         gchar **rfcomms = 0;
787         bonding_t *bondings = 0; /* points to array of bonding_t */
788         bonding_t *posdev = 0; /* bondings with positioning bit on */
789         gchar *tmp;
790         const gchar const *spp="SPP";
791   
792         /* Use the dbus interface to get the BT information */
793         
794
795 #if (__GNUC__ > 2) && ((__GNUC__ > 3) || (__GNUC_MINOR__ > 2))
796 #define ERRSTR(fmt, args...)                                     \
797   if (error_buf && error_buf_max_len>0) {                        \
798     set_error_msg(error_buf, error_buf_max_len, fmt, args);      \
799   } else {                                                       \
800     PDEBUG(fmt, args);                                           \
801   }
802 #else
803 #define ERRSTR(fmt, args...)                                     \
804   if (error_buf && error_buf_max_len>0) {                        \
805     set_error_msg(error_buf, error_buf_max_len, fmt, ##args);    \
806   } else {                                                       \
807     PDEBUG(fmt, ##args);                                         \
808   }
809 #endif  
810
811
812         error = NULL;
813         bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
814
815         if (error) 
816         {
817             st = -1;
818             errno = ECONNREFUSED; /* close enough :) */
819             //ERRSTR("%s", error->message);
820             //PDEBUG("Cannot get reply message [%s]\n", error->message);
821             goto OUT;
822     }
823
824         /* We need BT information only if the caller does not specify
825          * the BT address. If address is defined, it is assumed that
826          * it is already bonded and we just create RFCOMM connection
827          * to it.
828          */
829         if (!bda) 
830         {
831                 // May want to support auto detect for serial ports?
832         } else {  /* if (!bda) */
833             /* Caller supplied BT address so use it */
834             num_posdev = 1;
835             posdev = calloc(1, sizeof(bonding_t *));
836             if (!posdev) 
837             {
838               st = -1;
839               errno = ENOMEM;
840               goto OUT;
841             }
842             posdev[0].bonding = strdup(bda);
843
844             /* Adapter information is not needed */
845             posdev[0].adapter = "<not avail>";
846         }
847         
848         /* For each bondend BT GPS device, try to create rfcomm */
849         for (i=0; i<num_posdev; i++) 
850         {
851                 /* Note that bluez does not provide this interface (its defined but not
852              * yet implemented) so we use btcond for creating rfcomm device(s)
853              */
854
855             proxy = dbus_g_proxy_new_for_name(bus,
856                 BTCOND_DBUS, BTCOND_PATH, BTCOND_INTERFACE);
857
858             error = NULL;
859             tmp = NULL;
860             if(!dbus_g_proxy_call(proxy, BTCOND_CONNECT, &error,
861                   G_TYPE_STRING, posdev[i].bonding,
862                   G_TYPE_STRING, spp,
863               G_TYPE_BOOLEAN, TRUE,
864                   G_TYPE_INVALID,
865                   G_TYPE_STRING, &tmp,
866                   G_TYPE_INVALID)
867                 || error || !tmp || !*tmp) 
868             {
869                 /*PDEBUG("dbus_g_proxy_call returned an error: (error=(%d,%s), tmp=%s\n",
870                   error ? error->code : -1,
871                   error ? error->message : "<null>",
872                   tmp ? tmp : "<null>");
873 */
874                 /* No error if already connected */
875                 if (error && !strstr(error->message,
876                     "com.nokia.btcond.error.connected")) 
877                 {
878                         ERROR:
879                                 fprintf(stderr, "Cannot send msg (service=%s, object=%s, interface=%s, "
880                                                 "method=%s) [%s]\n",
881                                                 BTCOND_DBUS,
882                                                 BTCOND_PATH,
883                                                 BTCOND_INTERFACE,
884                                                 BTCOND_CONNECT,
885                                                 error->message ? error->message : "<no error msg>");
886
887                                 continue;
888                 } 
889                 else if(!tmp || !*tmp) 
890                 {
891                         /* hack: rfcommX device name is at the end of error message */
892                         char *last_space = strstr(error->message, " rfcomm");
893                         if (!last_space) 
894                         {
895                                 goto ERROR;
896                         }
897
898                         g_free(tmp);
899                         tmp = g_strdup_printf("/dev/%s", last_space+1);
900                 }
901             }
902             g_object_unref(proxy);
903
904             if (tmp && tmp[0]) 
905             {
906                 rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
907                 if (!rfcomms) 
908                 {
909                         st = -1;
910                         errno = ENOMEM;
911                         goto OUT;
912                 }
913
914                 rfcomms[num_rfcomms] = tmp;
915                 num_rfcomms++;
916
917                 fprintf(stderr, "BT addr=%s, RFCOMM %s now exists (adapter=%s)\n",
918                       posdev[i].bonding, tmp, posdev[i].adapter);
919
920                 tmp = NULL;
921             }
922             else 
923             {
924                 g_free(tmp);
925             }
926         }
927
928         if (num_rfcomms==0) 
929         {
930             /* serial device creation failed */
931             fprintf(stderr, "No rfcomm created\n");
932             st = -1;
933             errno = EINVAL;
934
935         } 
936         else 
937         {
938             /* Add null at the end */
939             rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
940             if (!rfcomms) 
941             {
942                 st = -1;
943                 errno = ENOMEM;
944
945             } 
946             else 
947             {
948                 rfcomms[num_rfcomms] = NULL;
949
950                 /* Just start the beast (to be done if everything is ok) */
951                 st = 0;
952                                 
953                 *aprs_bt_port = g_strdup_printf("%s",rfcomms[0]);
954
955             }
956         }
957
958 OUT:
959 /*      if (adapters) 
960         {
961             g_strfreev(adapters);
962         }
963 */
964         if (posdev) 
965         {
966             for (i=0; i<num_posdev; i++) 
967             {
968                 if (posdev[i].bonding) 
969                 {
970                         free(posdev[i].bonding);
971                         memset(&posdev[i], 0, sizeof(bonding_t)); /* just in case */
972                 }
973             }
974             free(posdev);
975             posdev = 0;
976         }
977
978         if (bondings) 
979         {
980             for (i=0; i<num_bondings; i++) 
981             {
982                 if (bondings[i].bonding) 
983                 {
984                         free(bondings[i].bonding);
985                         memset(&bondings[i], 0, sizeof(bonding_t)); /* just in case */
986                 }
987             }
988             free(bondings);
989             bondings = 0;
990         }
991
992         if (rfcomms) 
993         {
994                 for (i=0; i<num_rfcomms; i++) 
995                 {
996                         if (rfcomms[i]) 
997                         {
998                                 free(rfcomms[i]);
999                                 rfcomms[i]=0;
1000                         }
1001            }
1002            free(rfcomms);
1003            rfcomms = 0;
1004         }
1005
1006         if (bus) 
1007         {
1008                 dbus_g_connection_unref(bus);
1009         }
1010
1011         return st>-1;
1012 }
1013
1014
1015
1016
1017
1018
1019
1020 //***********************************************************
1021 // Serial port INIT
1022 //***********************************************************
1023 void update_aprs_tty_status()
1024 {
1025         /*
1026         _aprs_tty_enable = (_aprs_tty_state == RCVR_UP);
1027         
1028         gtk_check_menu_item_set_active(
1029             GTK_CHECK_MENU_ITEM(_menu_enable_aprs_tty_item), _aprs_tty_enable);
1030             */
1031 }
1032
1033 int serial_init () {
1034     int speed;
1035     
1036     euid = geteuid();
1037     egid = getegid();
1038
1039     fprintf(stderr, "in serial_init\n");
1040
1041     // clear port_channel
1042     port_data.channel = -1;
1043
1044     // clear port active
1045     port_data.active = DEVICE_NOT_IN_USE;
1046     
1047     // clear port status
1048     port_data.status = DEVICE_DOWN;
1049     //set_aprs_tty_conn_state(RCVR_DOWN);
1050     
1051     update_aprs_tty_status();
1052
1053     //gw-obex.h
1054     if(_aprs_tnc_method == TNC_CONNECTION_BT)
1055     {
1056         // Bluetooth connection
1057         gchar * aprs_bt_port = NULL;
1058         
1059         //fprintf(stderr, "Connecting to BT device...\n");
1060         
1061         if(!open_bluetooth_tty_connection(_aprs_tnc_bt_mac, &aprs_bt_port) || aprs_bt_port == NULL)
1062         {
1063                 fprintf(stderr, "Failed to connect to BT device\n");
1064                 // Failed to connect
1065                 return -1;
1066         }
1067         
1068         
1069         snprintf(port_data.device_name, MAX_DEVICE_NAME, aprs_bt_port);
1070         g_free(aprs_bt_port);
1071         
1072         fprintf(stderr, "BT Port: %s\n", port_data.device_name);
1073     }
1074     else
1075     {
1076         snprintf(port_data.device_name, MAX_DEVICE_NAME, _aprs_tty_port);
1077     }
1078     
1079     
1080     // TODO - make these configurable
1081     port_data.device_type = DEVICE_SERIAL_KISS_TNC;
1082     port_data.sp = B9600; 
1083     
1084
1085     // check for lock file
1086     
1087     // Try to open the serial port now
1088     ENABLE_SETUID_PRIVILEGE;
1089     port_data.channel = open(port_data.device_name, O_RDWR|O_NOCTTY);
1090     DISABLE_SETUID_PRIVILEGE;
1091     if (port_data.channel == -1){
1092
1093         fprintf(stderr,"Could not open channel on port!\n");
1094
1095         return (-1);
1096     }
1097     
1098     // get port attributes for new and old
1099     if (tcgetattr(port_data.channel, &port_data.t) != 0) {
1100         fprintf(stderr,"Could not get t port attributes for port!\n");
1101
1102         // Here we should close the port and remove the lock.
1103         serial_detach();
1104
1105         return (-1);
1106     }
1107
1108     if (tcgetattr(port_data.channel, &port_data.t_old) != 0) {
1109
1110         fprintf(stderr,"Could not get t_old port attributes for port!\n");
1111
1112         // Here we should close the port and remove the lock.
1113         serial_detach();
1114
1115         return (-1);
1116     }
1117
1118     // set time outs
1119     port_data.t.c_cc[VMIN] = (cc_t)0;
1120     port_data.t.c_cc[VTIME] = (cc_t)20;
1121
1122     // set port flags
1123     port_data.t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
1124     port_data.t.c_iflag = (tcflag_t)(IGNBRK | IGNPAR);
1125
1126     port_data.t.c_oflag = (0);
1127     port_data.t.c_lflag = (0);
1128
1129 #ifdef    CBAUD
1130     speed = (int)(port_data.t.c_cflag & CBAUD);
1131 #else   // CBAUD
1132     speed = 0;
1133 #endif  // CBAUD
1134     
1135     port_data.t.c_cflag = (tcflag_t)(HUPCL|CLOCAL|CREAD);
1136     port_data.t.c_cflag &= ~PARENB;
1137     switch (port_data.style){
1138         case(0):
1139             // No parity (8N1)
1140             port_data.t.c_cflag &= ~CSTOPB;
1141             port_data.t.c_cflag &= ~CSIZE;
1142             port_data.t.c_cflag |= CS8;
1143             break;
1144
1145         case(1):
1146             // Even parity (7E1)
1147             port_data.t.c_cflag &= ~PARODD;
1148             port_data.t.c_cflag &= ~CSTOPB;
1149             port_data.t.c_cflag &= ~CSIZE;
1150             port_data.t.c_cflag |= CS7;
1151             break;
1152
1153         case(2):
1154             // Odd parity (7O1):
1155             port_data.t.c_cflag |= PARODD;
1156             port_data.t.c_cflag &= ~CSTOPB;
1157             port_data.t.c_cflag &= ~CSIZE;
1158             port_data.t.c_cflag |= CS7;
1159             break;
1160
1161         default:
1162             break;
1163     }
1164
1165     port_data.t.c_cflag |= speed;
1166     // set input and out put speed
1167     if (cfsetispeed(&port_data.t, port_data.sp) == -1) 
1168     {
1169         fprintf(stderr,"Could not set port input speed for port!\n");
1170
1171         // Here we should close the port and remove the lock.
1172         serial_detach();
1173
1174         return (-1);
1175     }
1176
1177     if (cfsetospeed(&port_data.t, port_data.sp) == -1) {
1178
1179         fprintf(stderr,"Could not set port output speed for port!\n");
1180
1181         // Here we should close the port and remove the lock.
1182         serial_detach();
1183
1184         return (-1);
1185     }
1186
1187     if (tcflush(port_data.channel, TCIFLUSH) == -1) {
1188
1189         fprintf(stderr,"Could not flush data for port!\n");
1190
1191         // Here we should close the port and remove the lock.
1192         serial_detach();
1193
1194         return (-1);
1195     }
1196
1197     if (tcsetattr(port_data.channel,TCSANOW, &port_data.t) == -1) 
1198     {
1199         fprintf(stderr,"Could not set port attributes for port!\n");
1200
1201         // Here we should close the port and remove the lock.
1202         serial_detach();
1203
1204         return (-1);
1205     }
1206
1207     // clear port active
1208     port_data.active = DEVICE_IN_USE;
1209
1210     // clear port status
1211     port_data.status = DEVICE_UP;
1212     set_aprs_tty_conn_state(RCVR_UP);
1213     
1214     // Show the latest status in the interface control dialog
1215     update_aprs_tty_status();
1216
1217     // Ensure we are in KISS mode
1218     if(port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1219     {
1220         // Send KISS init string
1221         gchar * cmd = g_strdup("\nINT KISS\nRESTART\n");
1222         port_write_string(cmd, strlen(cmd), APRS_PORT_TTY);
1223     }
1224     
1225     // return good condition
1226     return (1);
1227 }
1228
1229 gboolean read_port_data()
1230 {
1231     unsigned char cin, last;
1232     gint i;
1233 //    struct timeval tmv;
1234 //    fd_set rd;
1235
1236     cin = (unsigned char)0;
1237     last = (unsigned char)0;
1238
1239         int skip = 0;
1240         
1241     // Handle all EXCEPT AX25_TNC interfaces here
1242     // Get one character
1243 //fprintf(stderr,"waiting for tty in... ");
1244         port_data.scan = (int)read(port_data.channel,&cin,1);
1245   
1246         if(port_data.scan == 0) return TRUE;
1247         else if(port_data.scan < 0) return FALSE;
1248         
1249 //fprintf(stderr,"%02x \n",cin);
1250
1251
1252     // Below is code for ALL types of interfaces
1253     if (port_data.scan > 0 && port_data.status == DEVICE_UP ) {
1254
1255         if (port_data.device_type != DEVICE_AX25_TNC)
1256             port_data.bytes_input += port_data.scan;      // Add character to read buffer
1257
1258
1259
1260         // Handle all EXCEPT AX25_TNC interfaces here
1261         if (port_data.device_type != DEVICE_AX25_TNC){
1262
1263
1264             // Do special KISS packet processing here.
1265             // We save the last character in
1266             // port_data.channel2, as it is
1267             // otherwise only used for AX.25 ports.
1268
1269             if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1270                     || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1271
1272
1273                 if (port_data.channel2 == KISS_FESC) { // Frame Escape char
1274                     if (cin == KISS_TFEND) { // Transposed Frame End char
1275
1276                         // Save this char for next time
1277                         // around
1278                         port_data.channel2 = cin;
1279
1280                         cin = KISS_FEND;
1281                     }
1282                     else if (cin == KISS_TFESC) { // Transposed Frame Escape char
1283
1284                         // Save this char for next time
1285                         // around
1286                         port_data.channel2 = cin;
1287
1288                         cin = KISS_FESC;
1289                     }
1290                     else {
1291                         port_data.channel2 = cin;
1292                     }
1293                 }
1294                 else if (port_data.channel2 == KISS_FEND) { // Frame End char
1295                     // Frame start or frame end.  Drop
1296                     // the next character which should
1297                     // either be another frame end or a
1298                     // type byte.
1299
1300 // Note this "type" byte is where it specifies which KISS interface
1301 // the packet came from.  We may want to use this later for
1302 // multi-drop KISS or other types of KISS protocols.
1303
1304                     // Save this char for next time
1305                     // around
1306                         port_data.channel2 = cin;
1307
1308                     skip++;
1309                 }
1310                 else if (cin == KISS_FESC) { // Frame Escape char
1311                         port_data.channel2 = cin;
1312                     skip++;
1313                 }
1314                 else {
1315                         port_data.channel2 = cin;
1316                 }
1317             }   // End of first special KISS processing
1318
1319
1320             // We shouldn't see any AX.25 flag
1321             // characters on a KISS interface because
1322             // they are stripped out by the KISS code.
1323             // What we should see though are KISS_FEND
1324             // characters at the beginning of each
1325             // packet.  These characters are where we
1326             // should break the data apart in order to
1327             // send strings to the decode routines.  It
1328             // may be just fine to still break it on \r
1329             // or \n chars, as the KISS_FEND should
1330             // appear immediately afterwards in
1331             // properly formed packets.
1332
1333
1334             if ( (!skip)
1335                     && (cin == (unsigned char)'\r'
1336                         || cin == (unsigned char)'\n'
1337                         || port_data.read_in_pos >= (MAX_DEVICE_BUFFER - 1)
1338                         || ( (cin == KISS_FEND) && (port_data.device_type == DEVICE_SERIAL_KISS_TNC) )
1339                         || ( (cin == KISS_FEND) && (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) )
1340                    && port_data.data_type == 0) {     // If end-of-line
1341
1342 // End serial/net type data send it to the decoder Put a terminating
1343 // zero at the end of the read-in data
1344
1345                 port_data.device_read_buffer[port_data.read_in_pos] = (char)0;
1346
1347                 if (port_data.status == DEVICE_UP && port_data.read_in_pos > 0) {
1348                     int length;
1349
1350                     // Compute length of string in
1351                     // circular queue
1352
1353                     //fprintf(stderr,"%d\t%d\n",port_data.read_in_pos,port_data.read_out_pos);
1354
1355                     // KISS TNC sends binary data
1356                     if ( (port_data.device_type == DEVICE_SERIAL_KISS_TNC)
1357                             || (port_data.device_type == DEVICE_SERIAL_MKISS_TNC) ) {
1358
1359                         length = port_data.read_in_pos - port_data.read_out_pos;
1360                         if (length < 0)
1361                             length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER;
1362
1363                         length++;
1364                     }
1365                     else {  // ASCII data
1366                         length = 0;
1367                     }
1368
1369                     channel_data(
1370                         (unsigned char *)port_data.device_read_buffer,
1371                         length);   // Length of string
1372                 }
1373
1374                 for (i = 0; i <= port_data.read_in_pos; i++)
1375                     port_data.device_read_buffer[i] = (char)0;
1376
1377                 port_data.read_in_pos = 0;
1378             }
1379             else if (!skip) {
1380
1381                 // Check for binary WX station data
1382                 if (cin == '\0')    // OWW WX daemon sends 0x00's!
1383                     cin = '\n';
1384
1385                 if (port_data.read_in_pos < (MAX_DEVICE_BUFFER - 1) ) {
1386                     port_data.device_read_buffer[port_data.read_in_pos] = (char)cin;
1387                     port_data.read_in_pos++;
1388                     port_data.device_read_buffer[port_data.read_in_pos] = (char)0;
1389                 }
1390                 else {
1391                     port_data.read_in_pos = 0;
1392                 }
1393             }
1394
1395         }   // End of non-AX.25 interface code block
1396
1397
1398         return TRUE;
1399     }
1400 //    else if (port_data.status == DEVICE_UP) {    /* error or close on read */
1401 //      // cause re-connect
1402 //
1403 //
1404 //    }
1405         
1406     return TRUE;
1407 }
1408
1409
1410 #endif //INCLUDE_APRS