KISS TNC enhancements: Multiple TCP clients, serial port for Linux, polling for Bluetooth device.

This commit is contained in:
WB2OSZ 2017-05-03 17:41:37 -04:00
parent 15b0f59e3a
commit bef8a97323
18 changed files with 613 additions and 730 deletions

View File

@ -2,6 +2,24 @@
# Revision History #
## Version 1.5 -- Development snapshot A -- May 2017 ##
This is a snapshot of ongoing development towards version of 1.5. Some features might be incomplete or broken or not documented properly.
### New Features: ###
- TCP KISS can now handle multiple concurrent applications.
- Linux can use serial port for KISS in addition to a pseudo terminal.
- New document ***Bluetooth-KISS-TNC.pdf*** explaining how to use KISS over Bluetooth.
### Bugs Fixed: ###
- Little spelling errors in messages ????
----------
## Version 1.4 -- April 2017 ##

View File

@ -292,7 +292,7 @@ z := $(notdir ${CURDIR})
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_psk.o demod_9600.o hdlc_rec.o \
hdlc_rec2.o multi_modem.o rdq.o rrbb.o dlq.o \
fcs_calc.o ax25_pad.o ax25_pad2.o xid.o \
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
decode_aprs.o symbols.o server.o kiss.o kissserial.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
gen_tone.o audio.o audio_stats.o digipeater.o cdigipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
ptt.o beacon.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.o \
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o waypoint.o serial_port.o log.o telemetry.o \
@ -570,15 +570,22 @@ install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon
# doc/README.md contains an overview of the PDF file contents and is more useful here.
#
$(INSTALL) -D --mode=644 doc/README.md $(INSTALLDIR)/share/doc/direwolf/README.md
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
$(INSTALL) -D --mode=644 doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf $(INSTALLDIR)/share/doc/direwolf/2400-4800-PSK-for-APRS-Packet-Radio.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf $(INSTALLDIR)/share/doc/direwolf/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Listening-Example.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Listening-Example.pdf
$(INSTALL) -D --mode=644 doc/Bluetooth-KISS-TNC.pdf $(INSTALLDIR)/share/doc/direwolf/Bluetooth-KISS-TNC.pdf
$(INSTALL) -D --mode=644 doc/Going-beyond-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/Going-beyond-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/Successful-APRS-IGate-Operation.pdf $(INSTALLDIR)/share/doc/direwolf/Successful-APRS-IGate-Operation.pdf
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
$(INSTALL) -D --mode=644 doc/WA8LMF-TNC-Test-CD-Results.pdf $(INSTALLDIR)/share/doc/direwolf/WA8LMF-TNC-Test-CD-Results.pdf
#
# Various sample config and other files go into examples under the doc directory.
# When building from source, these can be put in home directory with "make install-conf".

View File

@ -237,7 +237,7 @@ direwolf : direwolf.o aprs_tt.o audio_portaudio.o audio_stats.o ax25_link.o ax25
demod.o digipeater.o cdigipeater.o dlq.o dsp.o dtime_now.o dtmf.o dwgps.o \
encode_aprs.o encode_aprs.o fcs_calc.o fcs_calc.o gen_tone.o \
geotranz.a hdlc_rec.o hdlc_rec2.o hdlc_send.o igate.o kiss_frame.o \
kiss.o kissnet.o latlong.o latlong.o log.o morse.o multi_modem.o \
kiss.o kissserial.o kissnet.o latlong.o latlong.o log.o morse.o multi_modem.o \
waypoint.o serial_port.o pfilter.o ptt.o rdq.o recv.o rrbb.o server.o \
symbols.o telemetry.o textcolor.o tq.o tt_text.o tt_user.o xid.o xmit.o \
dwgps.o dwgpsnmea.o mheard.o
@ -359,15 +359,26 @@ install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon
$(INSTALL) -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
$(INSTALL) -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
#
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
# ./README.md is an overview for the project main page.
# doc/README.md contains an overview of the PDF file contents and is more useful here.
#
$(INSTALL) -D --mode=644 doc/README.md $(INSTALLDIR)/share/doc/direwolf/README.md
$(INSTALL) -D --mode=644 doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf $(INSTALLDIR)/share/doc/direwolf/2400-4800-PSK-for-APRS-Packet-Radio.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf $(INSTALLDIR)/share/doc/direwolf/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Listening-Example.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Listening-Example.pdf
$(INSTALL) -D --mode=644 doc/Bluetooth-KISS-TNC.pdf $(INSTALLDIR)/share/doc/direwolf/Bluetooth-KISS-TNC.pdf
$(INSTALL) -D --mode=644 doc/Going-beyond-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/Going-beyond-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
$(INSTALL) -D --mode=644 doc/Successful-APRS-IGate-Operation.pdf $(INSTALLDIR)/share/doc/direwolf/Successful-APRS-IGate-Operation.pdf
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
$(INSTALL) -D --mode=644 doc/WA8LMF-TNC-Test-CD-Results.pdf $(INSTALLDIR)/share/doc/direwolf/WA8LMF-TNC-Test-CD-Results.pdf
#
# Sample config files also go into the doc directory.
# When building from source, these can be put in home directory with "make install-conf".

View File

@ -98,7 +98,7 @@ demod_psk.o : fsk_demod_state.h
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_psk.o demod_9600.o hdlc_rec.o \
hdlc_rec2.o multi_modem.o rdq.o rrbb.o dlq.o \
fcs_calc.o ax25_pad.o ax25_pad2.o xid.o \
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
decode_aprs.o symbols.o server.o kiss.o kissserial.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o cdigipeater.o pfilter.o dedupe.o tq.o xmit.o \
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o waypoint.o serial_port.o log.o telemetry.o \
@ -193,6 +193,12 @@ gen_packets : gen_packets.o ax25_pad.o hdlc_send.o fcs_calc.o gen_tone.o morse.
$(CC) $(CFLAGS) -o $@ $^
# Connected mode packet application server.
appserver : appserver.o textcolor.o ax25_pad.o fcs_calc.o misc.a
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
# ------------------------------------------- Libraries --------------------------------------------
@ -600,20 +606,25 @@ dist-win : direwolf.exe decode_aprs.exe text2tt.exe tt2text.exe ll2utm.exe utm2l
rm -f ../$z-win.zip
egrep '^C|^W' generic.conf | cut -c2-999 > direwolf.conf
unix2dos direwolf.conf
cp doc/README.md README-doc.md
zip --junk-paths ../$z-win.zip \
README.md \
CHANGES.md \
doc/User-Guide.pdf \
doc/Raspberry-Pi-APRS.pdf \
README-doc.md \
doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf \
doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf \
doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf \
doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf \
doc/APRS-Telemetry-Toolkit.pdf \
doc/APRStt-Implementation-Notes.pdf \
doc/APRStt-interface-for-SARTrack.pdf \
doc/APRStt-Listening-Example.pdf \
doc/Bluetooth-KISS-TNC.pdf \
doc/Going-beyond-9600-baud.pdf \
doc/Raspberry-Pi-APRS.pdf \
doc/Raspberry-Pi-APRS-Tracker.pdf \
doc/Raspberry-Pi-SDR-IGate.pdf \
doc/Successful-APRS-IGate-Operation.pdf \
doc/User-Guide.pdf \
doc/WA8LMF-TNC-Test-CD-Results.pdf \
LICENSE* \
@ -630,6 +641,7 @@ dist-win : direwolf.exe decode_aprs.exe text2tt.exe tt2text.exe ll2utm.exe utm2l
ttcalc.exe \
dwespeak.bat \
telemetry-toolkit/*
rm README-doc.md
# Reminders if pdf files are not up to date.
@ -668,3 +680,4 @@ backup :
#
# DO NOT DELETE

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -870,8 +870,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
/* Ideally we'd like to figure out if com0com is installed */
/* and automatically enable this. */
//strlcpy (p_misc_config->nullmodem, DEFAULT_NULLMODEM, sizeof(p_misc_config->nullmodem));
strlcpy (p_misc_config->nullmodem, "", sizeof(p_misc_config->nullmodem));
strlcpy (p_misc_config->kiss_serial_port, "", sizeof(p_misc_config->kiss_serial_port));
p_misc_config->kiss_serial_speed = 0;
p_misc_config->kiss_serial_poll = 0;
strlcpy (p_misc_config->gpsnmea_port, "", sizeof(p_misc_config->gpsnmea_port));
strlcpy (p_misc_config->waypoint_port, "", sizeof(p_misc_config->waypoint_port));
@ -4102,17 +4103,58 @@ void config_init (char *fname, struct audio_s *p_audio_config,
}
/*
* NULLMODEM - Device name for our end of the virtual "null modem"
* NULLMODEM name [ speed ] - Device name for serial port or our end of the virtual "null modem"
* SERIALKISS name [ speed ]
*
* Version 1.5: Added SERIALKISS which is equivalent to NULLMODEM.
* The original name sort of made sense when it was used only for one end of a virtual
* null modem cable on Windows only. Now it is also available for Linux.
* TODO1.5: In retrospect, this doesn't seem like such a good name.
*/
else if (strcasecmp(t, "nullmodem") == 0) {
else if (strcasecmp(t, "NULLMODEM") == 0 || strcasecmp(t, "SERIALKISS") == 0) {
t = split(NULL,0);
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Missing device name for my end of the 'null modem' on line %d.\n", line);
dw_printf ("Config file: Missing serial port name on line %d.\n", line);
continue;
}
else {
strlcpy (p_misc_config->nullmodem, t, sizeof(p_misc_config->nullmodem));
if (strlen(p_misc_config->kiss_serial_port) > 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Warning serial port name on line %d replaces earlier value.\n", line);
}
strlcpy (p_misc_config->kiss_serial_port, t, sizeof(p_misc_config->kiss_serial_port));
p_misc_config->kiss_serial_speed = 0;
p_misc_config->kiss_serial_poll = 0;
}
t = split(NULL,0);
if (t != NULL) {
p_misc_config->kiss_serial_speed = atoi(t);
}
}
/*
* SERIALKISSPOLL name - Poll for serial port name that might come and go.
* e.g. /dev/rfcomm0 for bluetooth.
*/
else if (strcasecmp(t, "SERIALKISSPOLL") == 0) {
t = split(NULL,0);
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Missing serial port name on line %d.\n", line);
continue;
}
else {
if (strlen(p_misc_config->kiss_serial_port) > 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Warning serial port name on line %d replaces earlier value.\n", line);
}
strlcpy (p_misc_config->kiss_serial_port, t, sizeof(p_misc_config->kiss_serial_port));
p_misc_config->kiss_serial_speed = 0;
p_misc_config->kiss_serial_poll = 1; // set polling.
}
}

View File

@ -34,13 +34,24 @@ enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
struct misc_config_s {
int agwpe_port; /* Port number for the "AGW TCPIP Socket Interface" */
int kiss_port; /* Port number for the "KISS" protocol. */
int kiss_port; /* Port number for the "TCP KISS" protocol. */
int enable_kiss_pt; /* Enable pseudo terminal for KISS. */
/* Want this to be off by default because it hangs */
/* after a while if nothing is reading from other end. */
char nullmodem[20]; /* Serial port name for our end of the */
char kiss_serial_port[20];
/* Serial port name for our end of the */
/* virtual null modem for native Windows apps. */
/* Version 1.5 add same capability for Linux. */
int kiss_serial_speed; /* Speed, in bps, for the KISS serial port. */
/* If 0, just leave what was already there. */
int kiss_serial_poll; /* When using Bluetooth KISS, the /dev/rfcomm0 device */
/* will appear and disappear as the remote application */
/* opens and closes the virtual COM port. */
/* When this is non-zero, we will check periodically to */
/* see if the device has appeared and we will open it. */
char gpsnmea_port[20]; /* Serial port name for reading NMEA sentences from GPS. */
/* e.g. COM22, /dev/ttyACM0 */

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -94,6 +94,7 @@
#include "server.h"
#include "kiss.h"
#include "kissnet.h"
#include "kissserial.h"
#include "kiss_frame.h"
#include "waypoint.h"
#include "gen_tone.h"
@ -260,8 +261,8 @@ int main (int argc, char *argv[])
text_color_init(t_opt);
text_color_set(DW_COLOR_INFO);
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
//dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "H", __DATE__);
dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "A", __DATE__);
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)
dw_printf ("Includes optional support for: ");
@ -466,7 +467,7 @@ int main (int argc, char *argv[])
case 'a': server_set_debug(1); break;
case 'k': d_k_opt++; kiss_serial_set_debug (d_k_opt); break;
case 'k': d_k_opt++; kissserial_set_debug (d_k_opt); kisspt_set_debug (d_k_opt); break;
case 'n': d_n_opt++; kiss_net_set_debug (d_n_opt); break;
case 'u': d_u_opt = 1; break;
@ -766,7 +767,8 @@ int main (int argc, char *argv[])
/*
* Create a pseudo terminal and KISS TNC emulator.
*/
kiss_init (&misc_config);
kisspt_init (&misc_config);
kissserial_init (&misc_config);
kiss_frame_init (&audio_config);
/*
@ -1084,9 +1086,10 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
flen = ax25_pack(pp, fbuf);
server_send_rec_packet (chan, pp, fbuf, flen);
kissnet_send_rec_packet (chan, fbuf, flen);
kiss_send_rec_packet (chan, fbuf, flen);
server_send_rec_packet (chan, pp, fbuf, flen); // AGW net protocol
kissnet_send_rec_packet (chan, fbuf, flen, -1); // KISS TCP
kissserial_send_rec_packet (chan, fbuf, flen, -1); // KISS serial port
kisspt_send_rec_packet (chan, fbuf, flen, -1); // KISS pseudo terminal
/*
* If it came from DTMF decoder, send it to APRStt gateway.
@ -1204,7 +1207,7 @@ static void usage (char **argv)
dw_printf (" -D n Divide audio sample rate by n for channel 0.\n");
dw_printf (" -d Debug options:\n");
dw_printf (" a a = AGWPE network protocol client.\n");
dw_printf (" k k = KISS serial port client.\n");
dw_printf (" k k = KISS serial port or pseudo terminal client.\n");
dw_printf (" n n = KISS network client.\n");
dw_printf (" u u = Display non-ASCII text in hexadecimal.\n");
dw_printf (" p p = dump Packets in hexadecimal.\n");

View File

@ -87,6 +87,22 @@ unsigned short fcs_calc (unsigned char *data, int len)
}
/*
* CRC is also used for duplicate checking for the digipeater and IGate.
* A packet is considered a duplicate if the source, destination, and
* information parts match. In other words, we ignore the via path
* which changes along the way.
* Rather than keeping a variable length string we just keep a 16 bit
* CRC which takes less memory and processing to compare.
*
* This can result in occasional false matches. If we had a random
* 16 bit number, there is a 1/65536 ( = 0.0015 % ) chance that it will
* match and we will drop something that should be passed along.
*
* Looking at it another way, there is a 0.9999847412109375 (out of 1)
* probability of doing the right thing.
*/
/*
* This can be used when we want to calculate a single CRC over disjoint data.
*

610
kiss.c
View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2013, 2014, 2016 John Langner, WB2OSZ
// Copyright (C) 2011, 2013, 2014, 2016, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -24,11 +24,7 @@
* Module: kiss.c
*
* Purpose: Act as a virtual KISS TNC for use by other packet radio applications.
* On Windows, it is a serial port. On Linux, a pseudo terminal.
*
* Input:
*
* Outputs:
* This file implements it with a pseudo terminal for Linux only.
*
* Description: It implements the KISS TNC protocol as described in:
* http://www.ka9q.net/papers/kiss.html
@ -49,94 +45,82 @@
*
* Commands from application recognized:
*
* 0 Data Frame AX.25 frame in raw format.
* _0 Data Frame AX.25 frame in raw format.
*
* 1 TXDELAY See explanation in xmit.c.
* _1 TXDELAY See explanation in xmit.c.
*
* 2 Persistence " "
* _2 Persistence " "
*
* 3 SlotTime " "
* _3 SlotTime " "
*
* 4 TXtail " "
* _4 TXtail " "
* Spec says it is obsolete but Xastir
* sends it and we respect it.
*
* 5 FullDuplex Ignored. Always full duplex.
* _5 FullDuplex Ignored.
*
* 6 SetHardware TNC specific. Ignored.
* _6 SetHardware TNC specific.
*
* FF Return Exit KISS mode. Ignored.
*
*
* Messages sent to client application:
*
* 0 Data Frame Received AX.25 frame in raw format.
*
* _0 Data Frame Received AX.25 frame in raw format.
*
*
* Platform differences:
*
* We can use a pseudo terminal for Linux or Cygwin applications.
* However, Microsoft Windows doesn't seem to have similar functionality.
* Native Windows applications expect to see a device named COM1,
* COM2, COM3, or COM4. Some might offer more flexibility but others
* might be limited to these four choices.
*
* The documentation instucts the user to install the com0com
* "Null-modem emulator" from http://sourceforge.net/projects/com0com/
* and configure it for COM3 & COM4.
*
* By default Dire Wolf will use COM3 (/dev/ttyS2 or /dev/com3 - lower case!)
* and the client application will use COM4 (available as /dev/ttyS or
* /dev/com4 for Cygwin applications).
*
*
* This can get confusing.
*
* If __WIN32__ is defined,
* We use the Windows interface to the specfied serial port.
* This could be a real serial port or the nullmodem driver
* connected to another application.
*
* If __CYGWIN__ is defined,
* We connect to a serial port as in the previous case but
* use the Linux I/O interface.
* We also supply a pseudo terminal for any Cygwin applications
* such as Xastir so the null modem is not needed.
*
* For the Linux case,
* We supply a pseudo terminal for use by other applications.
*
*
* Reference: http://www.robbayer.com/files/serial-win.pdf
* Version 1.5: Split serial port version off into its own file.
*
*---------------------------------------------------------------*/
#if __WIN32__ // Stub for Windows.
#include "direwolf.h"
#include "kiss.h"
void kisspt_init (struct misc_config_s *mc)
{
return;
}
void kisspt_set_debug (int n)
{
return;
}
void kisspt_send_rec_packet (int chan, unsigned char *fbuf, int flen, int client)
{
return;
}
#else // Rest of file is for Linux only.
#include "direwolf.h"
#include <stdio.h>
#include <unistd.h>
#if __WIN32__
#include <stdlib.h>
#else
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef __OpenBSD__
#include <errno.h>
#else
#include <sys/errno.h>
#endif
#endif
#include <assert.h>
#include <string.h>
#include "tq.h"
#include "ax25_pad.h"
@ -146,71 +130,38 @@
#include "xmit.h"
#if __WIN32__
typedef HANDLE MYFDTYPE;
#define MYFDERROR INVALID_HANDLE_VALUE
#else
typedef int MYFDTYPE;
#define MYFDERROR (-1)
#endif
/*
* Accumulated KISS frame and state of decoder.
*/
static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */
static kiss_frame_t kf;
/*
* These are for a Linux/Cygwin pseudo terminal.
* These are for a Linux pseudo terminal.
*/
#if ! __WIN32__
static MYFDTYPE pt_master_fd = MYFDERROR; /* File descriptor for my end. */
static int pt_master_fd = -1; /* File descriptor for my end. */
static char pt_slave_name[32]; /* Pseudo terminal slave name */
/* like /dev/pts/999 */
/*
* Symlink to pseudo terminal name which changes.
*/
#define TMP_KISSTNC_SYMLINK "/tmp/kisstnc"
#endif
/*
* This is for native Windows applications and a virtual null modem.
*/
#if __CYGWIN__ || __WIN32__
static MYFDTYPE nullmodem_fd = MYFDERROR;
#endif
static void * kisspt_listen_thread (void *arg);
// TODO: define in one place, use everywhere.
#if __WIN32__
#define THREAD_F unsigned __stdcall
#else
#define THREAD_F void *
#endif
static int kisspt_debug = 0; /* Print information flowing from and to client. */
static THREAD_F kiss_listen_thread (void *arg);
#if DEBUG9
static FILE *log_fp;
#endif
static int kiss_debug = 0; /* Print information flowing from and to client. */
void kiss_serial_set_debug (int n)
void kisspt_set_debug (int n)
{
kiss_debug = n;
kisspt_debug = n;
}
@ -224,12 +175,12 @@ void hex_dump (unsigned char *p, int len);
/*-------------------------------------------------------------------
*
* Name: kiss_init
* Name: kisspt_init
*
* Purpose: Set up a pseudo terminal acting as a virtual KISS TNC.
*
*
* Inputs: mc->nullmodem - name of device for our end of nullmodem.
* Inputs:
*
* Outputs:
*
@ -240,43 +191,28 @@ void hex_dump (unsigned char *p, int len);
*
*--------------------------------------------------------------------*/
#if __WIN32__
static MYFDTYPE kiss_open_nullmodem (char *device);
#else
static MYFDTYPE kiss_open_pt (void);
#endif
static int kisspt_open_pt (void);
void kiss_init (struct misc_config_s *mc)
void kisspt_init (struct misc_config_s *mc)
{
#if __WIN32__
HANDLE kiss_nullmodem_listen_th;
#else
pthread_t kiss_pterm_listen_tid;
//pthread_t kiss_nullmodem_listen_tid;
int e;
#endif
memset (&kf, 0, sizeof(kf));
/*
* This reads messages from client.
*/
#if ! __WIN32__
/*
* Pseudo terminal for Cygwin and Linux versions.
*/
pt_master_fd = MYFDERROR;
pt_master_fd = -1;
if (mc->enable_kiss_pt) {
pt_master_fd = kiss_open_pt ();
pt_master_fd = kisspt_open_pt ();
if (pt_master_fd != MYFDERROR) {
e = pthread_create (&kiss_pterm_listen_tid, (pthread_attr_t*)NULL, kiss_listen_thread, NULL);
if (pt_master_fd != -1) {
e = pthread_create (&kiss_pterm_listen_tid, (pthread_attr_t*)NULL, kisspt_listen_thread, NULL);
if (e != 0) {
text_color_set(DW_COLOR_ERROR);
perror("Could not create kiss listening thread for Linux pseudo terminal");
@ -287,72 +223,22 @@ void kiss_init (struct misc_config_s *mc)
text_color_set(DW_COLOR_INFO);
dw_printf ("Use -p command line option to enable KISS pseudo terminal.\n");
}
#endif
#if __CYGWIN__ || __WIN32
/*
* Cygwin and native Windows versions have serial port connection.
*/
if (strlen(mc->nullmodem) > 0) {
#if ! __WIN32__
/* Translate Windows device name into Linux name. */
/* COM1 -> /dev/ttyS0, etc. */
if (strncasecmp(mc->nullmodem, "COM", 3) == 0) {
int n = atoi (mc->nullmodem + 3);
text_color_set(DW_COLOR_INFO);
dw_printf ("Converted nullmodem device '%s'", mc->nullmodem);
if (n < 1) n = 1;
snprintf (mc->nullmodem, sizeof(mc->nullmodem), "/dev/ttyS%d", n-1);
dw_printf (" to Linux equivalent '%s'\n", mc->nullmodem);
}
#endif
nullmodem_fd = kiss_open_nullmodem (mc->nullmodem);
if (nullmodem_fd != MYFDERROR) {
#if __WIN32__
kiss_nullmodem_listen_th = (HANDLE)_beginthreadex (NULL, 0, kiss_listen_thread, NULL, 0, NULL);
if (kiss_nullmodem_listen_th == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Could not create kiss nullmodem thread\n");
return;
}
#else
e = pthread_create (&kiss_nullmodem_listen_tid, NULL, kiss_listen_thread, NULL);
if (e != 0) {
text_color_set(DW_COLOR_ERROR);
perror("Could not create kiss listening thread for Windows virtual COM port.");
}
#endif
}
}
#endif
#if DEBUG
text_color_set (DW_COLOR_DEBUG);
#if ! __WIN32__
dw_printf ("end of kiss_init: pt_master_fd = %d\n", pt_master_fd);
#endif
#if __CYGWIN__ || __WIN32__
dw_printf ("end of kiss_init: nullmodem_fd = %d\n", nullmodem_fd);
dw_printf ("end of kisspt_init: pt_master_fd = %d\n", pt_master_fd);
#endif
#endif
}
/*
* Returns fd for master side of pseudo terminal or MYFDERROR for error.
* Returns fd for master side of pseudo terminal or -1 for error.
*/
#if ! __WIN32__
static MYFDTYPE kiss_open_pt (void)
static int kisspt_open_pt (void)
{
int fd;
char *pts;
@ -362,19 +248,18 @@ static MYFDTYPE kiss_open_pt (void)
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf ("kiss_open_pt ( )\n");
dw_printf ("kisspt_open_pt ( )\n");
#endif
fd = posix_openpt(O_RDWR|O_NOCTTY);
if (fd == MYFDERROR
|| grantpt (fd) == MYFDERROR
|| unlockpt (fd) == MYFDERROR
if (fd == -1
|| grantpt (fd) == -1
|| unlockpt (fd) == -1
|| (pts = ptsname (fd)) == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Could not create pseudo terminal for KISS TNC.\n");
return (MYFDERROR);
return (-1);
}
strlcpy (pt_slave_name, pts, sizeof(pt_slave_name));
@ -430,11 +315,11 @@ static MYFDTYPE kiss_open_pt (void)
#if 1
// Sample code shows this. Why would we open it here?
// On Ubuntu, the slave side disappears after a few
// seconds if no one opens it. Same on Raspian which
// seconds if no one opens it. Same on Raspbian which
// is also based on Debian.
// Need to revisit this.
MYFDTYPE pt_slave_fd;
int pt_slave_fd;
pt_slave_fd = open(pt_slave_name, O_RDWR|O_NOCTTY);
@ -442,7 +327,7 @@ static MYFDTYPE kiss_open_pt (void)
text_color_set(DW_COLOR_ERROR);
dw_printf ("Can't open %s\n", pt_slave_name);
perror ("");
return MYFDERROR;
return -1;
}
#endif
@ -471,149 +356,11 @@ static MYFDTYPE kiss_open_pt (void)
return (fd);
}
#endif
/*
* Returns fd for our side of null modem or MYFDERROR for error.
*/
#if __CYGWIN__ || __WIN32__
static MYFDTYPE kiss_open_nullmodem (char *devicename)
{
#if __WIN32__
MYFDTYPE fd;
DCB dcb;
int ok;
char bettername[50];
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf ("kiss_open_nullmodem ( '%s' )\n", devicename);
#endif
#if DEBUG9
log_fp = fopen ("kiss-debug.txt", "w");
#endif
// Need to use FILE_FLAG_OVERLAPPED for full duplex operation.
// Without it, write blocks when waiting on read.
// Read http://support.microsoft.com/kb/156932
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
// http://support.microsoft.com/kb/115831
strlcpy (bettername, devicename, sizeof(bettername));
if (strncasecmp(devicename, "COM", 3) == 0) {
int n;
n = atoi(devicename+3);
if (n >= 10) {
strlcpy (bettername, "\\\\.\\", sizeof(bettername));
strlcat (bettername, devicename, sizeof(bettername));
}
}
fd = CreateFile(bettername, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (fd == MYFDERROR) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Could not connect to %s side of null modem for Windows KISS TNC.\n", devicename);
return (MYFDERROR);
}
/* Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363201(v=vs.85).aspx */
memset (&dcb, 0, sizeof(dcb));
dcb.DCBlength = sizeof(DCB);
ok = GetCommState (fd, &dcb);
if (! ok) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("kiss_open_nullmodem: GetCommState failed.\n");
}
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx */
dcb.DCBlength = sizeof(DCB);
dcb.BaudRate = CBR_9600; // shouldn't matter
dcb.fBinary = 1;
dcb.fParity = 0;
dcb.fOutxCtsFlow = 0;
dcb.fOutxDsrFlow = 0;
dcb.fDtrControl = 0;
dcb.fDsrSensitivity = 0;
dcb.fOutX = 0;
dcb.fInX = 0;
dcb.fErrorChar = 0;
dcb.fNull = 0; /* Don't drop nul characters! */
dcb.fRtsControl = 0;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
ok = SetCommState (fd, &dcb);
if (! ok) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("kiss_open_nullmodem: SetCommState failed.\n");
}
text_color_set(DW_COLOR_INFO);
dw_printf("Virtual KISS TNC is connected to %s side of null modem.\n", devicename);
#else
/* Cygwin version. */
int fd;
struct termios ts;
int e;
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf ("kiss_open_nullmodem ( '%s' )\n", devicename);
#endif
fd = open (devicename, O_RDWR);
if (fd == MYFDERROR) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Could not connect to %s side of null modem for Windows KISS TNC.\n", devicename);
return (MYFDERROR);
}
e = tcgetattr (fd, &ts);
if (e != 0) { perror ("nm tcgetattr"); }
cfmakeraw (&ts);
ts.c_cc[VMIN] = 1; /* wait for at least one character */
ts.c_cc[VTIME] = 0; /* no fancy timing. */
e = tcsetattr (fd, TCSANOW, &ts);
if (e != 0) { perror ("nm tcsetattr"); }
text_color_set(DW_COLOR_INFO);
dw_printf("Virtual KISS TNC is connected to %s side of null modem.\n", devicename);
#endif
return (fd);
}
#endif
/*-------------------------------------------------------------------
*
* Name: kiss_send_rec_packet
* Name: kisspt_send_rec_packet
*
* Purpose: Send a received packet or text string to the client app.
*
@ -628,6 +375,10 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
* flen - Length of raw received frame not including the FCS
* or -1 for a text string.
*
* client - Not used for pseudo terminal.
* Here so that 3 related functions all have
* the same parameter list.
*
* Description: Send message to client.
* We really don't care if anyone is listening or not.
* I don't even know if we can find out.
@ -635,28 +386,20 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
*--------------------------------------------------------------------*/
void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
void kisspt_send_rec_packet (int chan, unsigned char *fbuf, int flen, int client)
{
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
int kiss_len;
int err;
#if ! __WIN32__
if (pt_master_fd == MYFDERROR) {
if (pt_master_fd == -1) {
return;
}
#endif
#if __CYGWIN__ || __WIN32__
if (nullmodem_fd == MYFDERROR) {
return;
}
#endif
if (flen < 0) {
flen = strlen((char*)fbuf);
if (kiss_debug) {
if (kisspt_debug) {
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
}
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
@ -664,15 +407,18 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
}
else {
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
assert (flen < (int)(sizeof(stemp)));
if (flen > (int)(sizeof(stemp)) - 1) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nPseudo Terminal KISS buffer too small. Truncated.\n\n");
flen = (int)(sizeof(stemp)) - 1;
}
stemp[0] = (chan << 4) + 0;
memcpy (stemp+1, fbuf, flen);
if (kiss_debug >= 2) {
if (kisspt_debug >= 2) {
/* AX.25 frame with the CRC removed. */
text_color_set(DW_COLOR_DEBUG);
dw_printf ("\n");
@ -684,16 +430,12 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
/* This has KISS framing and escapes for sending to client app. */
if (kiss_debug) {
if (kisspt_debug) {
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
}
}
#if ! __WIN32__
/* Pseudo terminal for Cygwin and Linux. */
err = write (pt_master_fd, kiss_buff, (size_t)kiss_len);
if (err == -1 && errno == EWOULDBLOCK) {
@ -709,84 +451,18 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
perror ("pt write");
}
#endif
#if __CYGWIN__ || __WIN32__
/*
* This write can block if nothing is connected to the other end.
* The solution is found in the com0com ReadMe file:
*
* Q. My application hangs during its startup when it sends anything to one paired
* COM port. The only way to unhang it is to start HyperTerminal, which is connected
* to the other paired COM port. I didn't have this problem with physical serial
* ports.
* A. Your application can hang because receive buffer overrun is disabled by
* default. You can fix the problem by enabling receive buffer overrun for the
* receiving port. Also, to prevent some flow control issues you need to enable
* baud rate emulation for the sending port. So, if your application use port CNCA0
* and other paired port is CNCB0, then:
*
* 1. Launch the Setup Command Prompt shortcut.
* 2. Enter the change commands, for example:
*
* command> change CNCB0 EmuOverrun=yes
* command> change CNCA0 EmuBR=yes
*/
#if __WIN32__
DWORD nwritten;
/* Without this, write blocks while we are waiting on a read. */
static OVERLAPPED ov_wr;
memset (&ov_wr, 0, sizeof(ov_wr));
if ( ! WriteFile (nullmodem_fd, kiss_buff, kiss_len, &nwritten, &ov_wr))
{
err = GetLastError();
if (err != ERROR_IO_PENDING)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError sending KISS message to client application thru null modem. Error %d.\n\n", (int)GetLastError());
//CloseHandle (nullmodem_fd);
//nullmodem_fd = MYFDERROR;
}
}
else if ((int)nwritten != kiss_len)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError sending KISS message to client application thru null modem. Only %d of %d written.\n\n", (int)nwritten, kiss_len);
//CloseHandle (nullmodem_fd);
//nullmodem_fd = MYFDERROR;
}
#else
err = write (nullmodem_fd, kiss_buf, (size_t)kiss_len);
if (err != len)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError sending KISS message to client application thru null modem. err=%d\n\n", err);
//close (nullmodem_fd);
//nullmodem_fd = MYFDERROR;
}
#endif
#endif
} /* kiss_send_rec_packet */
} /* kisspt_send_rec_packet */
/*-------------------------------------------------------------------
*
* Name: kiss_get
* Name: kisspt_get
*
* Purpose: Read one byte from the KISS client app.
*
* Global In: nullmodem_fd (Windows) or pt_master_fd (Linux)
* Global In: pt_master_fd
*
* Returns: one byte (value 0 - 255) or terminate thread on error.
*
@ -799,78 +475,10 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
*--------------------------------------------------------------------*/
static int kiss_get (/* MYFDTYPE fd*/ void )
static int kisspt_get (void)
{
unsigned char ch;
#if __WIN32__ /* Native Windows version. */
DWORD n;
static OVERLAPPED ov_rd;
memset (&ov_rd, 0, sizeof(ov_rd));
ov_rd.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
/* Overlapped I/O makes reading rather complicated. */
/* See: http://msdn.microsoft.com/en-us/library/ms810467.aspx */
/* It seems that the read completes OK with a count */
/* of 0 every time we send a message to the serial port. */
n = 0; /* Number of characters read. */
while (n == 0) {
if ( ! ReadFile (nullmodem_fd, &ch, 1, &n, &ov_rd))
{
int err1 = GetLastError();
if (err1 == ERROR_IO_PENDING)
{
/* Wait for completion. */
if (WaitForSingleObject (ov_rd.hEvent, INFINITE) == WAIT_OBJECT_0)
{
if ( ! GetOverlappedResult (nullmodem_fd, &ov_rd, &n, 1))
{
int err3 = GetLastError();
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nKISS GetOverlappedResult error %d.\n\n", err3);
}
else
{
/* Success! n should be 1 */
}
}
}
else
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nKISS ReadFile error %d. Closing connection.\n\n", err1);
CloseHandle (nullmodem_fd);
nullmodem_fd = MYFDERROR;
//pthread_exit (NULL);
}
}
} /* end while n==0 */
CloseHandle(ov_rd.hEvent);
if (n != 1) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nKISS failed to get one byte. n=%d.\n\n", (int)n);
#if DEBUG9
fprintf (log_fp, "n=%d\n", n);
#endif
}
#else /* Linux/Cygwin version */
int n = 0;
fd_set fd_in, fd_ex;
int rc;
@ -934,7 +542,7 @@ static int kiss_get (/* MYFDTYPE fd*/ void )
continue; // When could we get a 0?
}
if (rc == MYFDERROR
if (rc == -1
|| (n = read(pt_master_fd, &ch, (size_t)1)) != 1)
{
@ -944,70 +552,52 @@ static int kiss_get (/* MYFDTYPE fd*/ void )
close (pt_master_fd);
pt_master_fd = MYFDERROR;
pt_master_fd = -1;
unlink (TMP_KISSTNC_SYMLINK);
pthread_exit (NULL);
}
}
#endif
#if DEBUGx
text_color_set(DW_COLOR_DEBUG);
dw_printf ("kiss_get(%d) returns 0x%02x\n", fd, ch);
dw_printf ("kisspt_get(%d) returns 0x%02x\n", fd, ch);
#endif
#if DEBUG9
fprintf (log_fp, "%02x %c %c", ch,
isprint(ch) ? ch : '.' ,
(isupper(ch>>1) || isdigit(ch>>1) || (ch>>1) == ' ') ? (ch>>1) : '.');
if (ch == FEND) fprintf (log_fp, " FEND");
if (ch == FESC) fprintf (log_fp, " FESC");
if (ch == TFEND) fprintf (log_fp, " TFEND");
if (ch == TFESC) fprintf (log_fp, " TFESC");
if (ch == '\r') fprintf (log_fp, " CR");
if (ch == '\n') fprintf (log_fp, " LF");
fprintf (log_fp, "\n");
if (ch == FEND) fflush (log_fp);
#endif
return (ch);
}
/*-------------------------------------------------------------------
*
* Name: kiss_listen_thread
* Name: kisspt_listen_thread
*
* Purpose: Read messages from serial port KISS client application.
*
* Global In: nullmodem_fd (Windows) or pt_master_fd (Linux)
* Global In:
*
* Description: Reads bytes from the KISS client app and
* sends them to kiss_rec_byte for processing.
*
*--------------------------------------------------------------------*/
static THREAD_F kiss_listen_thread (void *arg)
static void * kisspt_listen_thread (void *arg)
{
unsigned char ch;
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf ("kiss_listen_thread ( %d )\n", fd);
dw_printf ("kisspt_listen_thread ( %d )\n", fd);
#endif
while (1) {
ch = kiss_get();
kiss_rec_byte (&kf, ch, kiss_debug, kiss_send_rec_packet);
ch = kisspt_get();
kiss_rec_byte (&kf, ch, kisspt_debug, -1, kisspt_send_rec_packet);
}
#if __WIN32__
return(0);
#else
return (THREAD_F) 0; /* Unreachable but avoids compiler warning. */
#endif
return (void *) 0; /* Unreachable but avoids compiler warning. */
}
#endif // Linux version
/* end kiss.c */

8
kiss.h
View File

@ -1,6 +1,8 @@
/*
* Name: kiss.h
*
* This is for the pseudo terminal KISS interface.
*/
@ -11,11 +13,11 @@
void kiss_init (struct misc_config_s *misc_config);
void kisspt_init (struct misc_config_s *misc_config);
void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen);
void kisspt_send_rec_packet (int chan, unsigned char *fbuf, int flen, int client);
void kiss_serial_set_debug (int n);
void kisspt_set_debug (int n);
/* end kiss.h */

View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
// Copyright (C) 2013, 2014, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -43,28 +43,28 @@
*
* Commands from application recognized:
*
* 0 Data Frame AX.25 frame in raw format.
* _0 Data Frame AX.25 frame in raw format.
*
* 1 TXDELAY See explanation in xmit.c.
* _1 TXDELAY See explanation in xmit.c.
*
* 2 Persistence " "
* _2 Persistence " "
*
* 3 SlotTime " "
* _3 SlotTime " "
*
* 4 TXtail " "
* _4 TXtail " "
* Spec says it is obsolete but Xastir
* sends it and we respect it.
*
* 5 FullDuplex Ignored. Always full duplex.
* _5 FullDuplex Ignored.
*
* 6 SetHardware TNC specific. Ignored.
* _6 SetHardware TNC specific.
*
* FF Return Exit KISS mode. Ignored.
*
*
* Messages sent to client application:
*
* 0 Data Frame Received AX.25 frame in raw format.
* _0 Data Frame Received AX.25 frame in raw format.
*
*---------------------------------------------------------------*/
@ -291,6 +291,8 @@ static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
* Inputs: kf - Current state of building a frame.
* ch - A byte from the input stream.
* debug - Activates debug output.
* client - Client app number for TCP KISS.
* Ignored for pseudo termal and serial port.
* sendfun - Function to send something to the client application.
*
* Outputs: kf - Current state is updated.
@ -326,7 +328,7 @@ static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int))
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,unsigned char*,int,int))
{
//dw_printf ("kiss_frame ( %c %02x ) \n", ch, ch);
@ -367,10 +369,10 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfu
/* Try to appease client app by sending something back. */
if (strcasecmp("restart\r", (char*)(kf->noise)) == 0 ||
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
(*sendfun) (0, (unsigned char *)"\xc0\xc0", -1);
(*sendfun) (0, (unsigned char *)"\xc0\xc0", -1, client);
}
else {
(*sendfun) (0, (unsigned char *)"\r\ncmd:", -1);
(*sendfun) (0, (unsigned char *)"\r\ncmd:", -1, client);
}
kf->noise_len = 0;
}
@ -550,19 +552,22 @@ static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug)
case 5: /* FullDuplex */
text_color_set(DW_COLOR_INFO);
dw_printf ("KISS protocol set FullDuplex = %d, port %d\n", kiss_msg[1], port);
dw_printf ("KISS protocol set FullDuplex = %d, port %d - Ignored\n", kiss_msg[1], port);
break;
case 6: /* TNC specific */
text_color_set(DW_COLOR_INFO);
dw_printf ("KISS protocol set hardware - ignored.\n");
dw_printf ("KISS protocol set hardware - Ignored.\n");
// TODO: kiss_set_hardware (...)
break;
case 15: /* End KISS mode, port should be 15. */
/* Ignore it. */
text_color_set(DW_COLOR_INFO);
dw_printf ("KISS protocol end KISS mode\n");
dw_printf ("KISS protocol end KISS mode - Ignored.\n");
break;
default:
@ -581,6 +586,57 @@ static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug)
} /* end kiss_process_msg */
/*-------------------------------------------------------------------
*
* Name: kiss_set_hardware
*
* Purpose: Process the "set hardware" command.
*
* Inputs:
*
*
* Description: This is new in version 1.5. "Set hardware" was previously ignored.
*
* There are times when the client app might want to send configuration
* commands, such as modem speed, to the KISS TNC or inquire about its
* current state.
*
* The immediate motivation for adding this is that one application wants
* to know how many frames are currently in the transmit queue. This can
* be used for throttling of large transmissions and performing some action
* after the last frame has been sent.
*
* The original KISS protocol spec offers no guidance on what this might look
* like. I'm aware of only two, drastically different, implementations:
*
* fldigi - http://www.w1hkj.com/FldigiHelp-3.22/kiss_command_page.html
*
* Everything is in human readable text in the form of:
* COMMAND : [ parameter [ , parameter ... ] ]
*
* Used by applications, http://www.w1hkj.com/FldigiHelp/kiss_host_prgs_page.html
* - BPQ32
* - UIChar
* - YAAC
*
* mobilinkd - https://raw.githubusercontent.com/mobilinkd/tnc1/tnc2/bertos/net/kiss.c
*
* Single byte with the command / response code, followed by
* zero or more value bytes.
*
* Used by applications:
* - APRSdroid
*
* It would be beneficial to adopt one of them rather than doing something
* completely different. It might even be possible to recognize both.
* This might allow leveraging of other existing applications.
*
*--------------------------------------------------------------------*/
// static void kiss_set_hardware (...)
/*-------------------------------------------------------------------
*
* Name: kiss_debug_print

View File

@ -15,7 +15,8 @@
enum kiss_state_e {
KS_SEARCHING, /* Looking for FEND to start KISS frame. */
KS_SEARCHING = 0, /* Looking for FEND to start KISS frame. */
/* Must be 0 so we can simply zero whole structure to initialize. */
KS_COLLECTING}; /* In process of collecting KISS frame. */
@ -44,7 +45,7 @@ void kiss_frame_init (struct audio_s *pa);
int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out);
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int));
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,unsigned char*,int,int));
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;

233
kissnet.c
View File

@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011-2014, 2015 John Langner, WB2OSZ
// Copyright (C) 2011-2014, 2015, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -49,28 +49,28 @@
*
* Commands from application recognized:
*
* 0 Data Frame AX.25 frame in raw format.
* _0 Data Frame AX.25 frame in raw format.
*
* 1 TXDELAY See explanation in xmit.c.
* _1 TXDELAY See explanation in xmit.c.
*
* 2 Persistence " "
* _2 Persistence " "
*
* 3 SlotTime " "
* _3 SlotTime " "
*
* 4 TXtail " "
* _4 TXtail " "
* Spec says it is obsolete but Xastir
* sends it and we respect it.
*
* 5 FullDuplex Ignored. Always full duplex.
* _5 FullDuplex Ignored.
*
* 6 SetHardware TNC specific. Ignored.
* _6 SetHardware TNC specific.
*
* FF Return Exit KISS mode. Ignored.
*
*
* Messages sent to client application:
*
* 0 Data Frame Received AX.25 frame in raw format.
* _0 Data Frame Received AX.25 frame in raw format.
*
*
*
@ -91,7 +91,6 @@
/*
* Native Windows: Use the Winsock interface.
* Linux: Use the BSD socket interface.
* Cygwin: Can use either one.
*/
@ -131,15 +130,27 @@
void hex_dump (unsigned char *p, int len); // This should be in a .h file.
static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */
// TODO: multiple instances if multiple KISS network clients!
/*
* Early on we allowed one AGW connection and one KISS TCP connection at a time.
* In version 1.1, we allowed multiple concurrent client apps to attach with the AGW network protocol.
* In Version 1.5, we do essentially the same here to allow multiple concurrent KISS TCP clients.
* The default is a limit of 3 client applications at the same time.
* You can increase the limit by changing the line below.
* A larger number consumes more resources so don't go crazy by making it larger than needed.
*/
#define MAX_NET_CLIENTS 3
static int client_sock; /* File descriptor for socket for */
static int client_sock[MAX_NET_CLIENTS];
/* File descriptor for socket for */
/* communication with client application. */
/* Set to -1 if not connected. */
/* (Don't use SOCKET type because it is unsigned.) */
static kiss_frame_t kf[MAX_NET_CLIENTS];
/* Accumulated KISS frame and state of decoder. */
// TODO: define in one place, use everywhere.
#if __WIN32__
@ -187,12 +198,14 @@ void kiss_net_set_debug (int n)
void kissnet_init (struct misc_config_s *mc)
{
int client;
#if __WIN32__
HANDLE connect_listen_th;
HANDLE cmd_listen_th;
HANDLE cmd_listen_th[MAX_NET_CLIENTS];
#else
pthread_t connect_listen_tid;
pthread_t cmd_listen_tid;
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
int e;
#endif
int kiss_port = mc->kiss_port;
@ -203,9 +216,11 @@ void kissnet_init (struct misc_config_s *mc)
dw_printf ("kissnet_init ( %d )\n", kiss_port);
#endif
memset (&kf, 0, sizeof(kf));
client_sock = -1;
for (client=0; client<MAX_NET_CLIENTS; client++) {
client_sock[client] = -1;
memset (&(kf[client]), 0, sizeof(kf[client]));
}
if (kiss_port == 0) {
text_color_set(DW_COLOR_INFO);
@ -214,7 +229,7 @@ void kissnet_init (struct misc_config_s *mc)
}
/*
* This waits for a client to connect and sets client_sock.
* This waits for a client to connect and sets client_sock[n].
*/
#if __WIN32__
connect_listen_th = (HANDLE)_beginthreadex (NULL, 0, connect_listen_thread, (void *)kiss_port, 0, NULL);
@ -233,17 +248,21 @@ void kissnet_init (struct misc_config_s *mc)
#endif
/*
* This reads messages from client when client_sock is valid.
* These read messages from client when client_sock[n] is valid.
* Currently we start up a separate thread for each potential connection.
* Possible later refinement. Start one now, others only as needed.
*/
for (client = 0; client < MAX_NET_CLIENTS; client++) {
#if __WIN32__
cmd_listen_th = (HANDLE)_beginthreadex (NULL, 0, kissnet_listen_thread, NULL, 0, NULL);
if (cmd_listen_th == NULL) {
cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, kissnet_listen_thread, (void*)client, 0, NULL);
if (cmd_listen_th[client] == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Could not create KISS socket command listening thread\n");
return;
}
#else
e = pthread_create (&cmd_listen_tid, NULL, kissnet_listen_thread, NULL);
e = pthread_create (&(cmd_listen_tid[client]), NULL, kissnet_listen_thread, NULL);
if (e != 0) {
text_color_set(DW_COLOR_ERROR);
perror("Could not create KISS socket command listening thread");
@ -251,6 +270,7 @@ void kissnet_init (struct misc_config_s *mc)
}
#endif
}
}
/*-------------------------------------------------------------------
@ -352,13 +372,22 @@ static THREAD_F connect_listen_thread (void *arg)
while (1) {
while (client_sock > 0) {
SLEEP_SEC(1); /* Already connected. Try again later. */
int client;
int c;
client = -1;
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
if (client_sock[c] <= 0) {
client = c;
}
}
#define QUEUE_SIZE 5
/*
* Listen for connection if we have not reached maximum.
*/
if (client >= 0) {
if(listen(listen_sock,QUEUE_SIZE) == SOCKET_ERROR)
if(listen(listen_sock, MAX_NET_CLIENTS) == SOCKET_ERROR)
{
text_color_set(DW_COLOR_ERROR);
dw_printf("Listen failed with error: %d\n", WSAGetLastError());
@ -366,11 +395,11 @@ static THREAD_F connect_listen_thread (void *arg)
}
text_color_set(DW_COLOR_INFO);
dw_printf("Ready to accept KISS client application on port %s ...\n", kiss_port_str);
dw_printf("Ready to accept KISS TCP client application %d on port %s ...\n", client, kiss_port_str);
client_sock = accept(listen_sock, NULL, NULL);
client_sock[client] = accept(listen_sock, NULL, NULL);
if (client_sock == -1) {
if (client_sock[client] == -1) {
text_color_set(DW_COLOR_ERROR);
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
closesocket(listen_sock);
@ -379,8 +408,14 @@ static THREAD_F connect_listen_thread (void *arg)
}
text_color_set(DW_COLOR_INFO);
dw_printf("\nConnected to KISS client application ...\n\n");
dw_printf("\nAttached to KISS TCP client application %d ...\n\n", client);
// Reset the state and buffer.
memset (&(kf[client]), 0, sizeof(kf[client]));
}
else {
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
}
}
@ -430,18 +465,24 @@ static THREAD_F connect_listen_thread (void *arg)
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf("opened KISS socket as fd (%d) on port (%d) for stream i/o\n", listen_sock, ntohs(sockaddr.sin_port) );
dw_printf("opened KISS TCP socket as fd (%d) on port (%d) for stream i/o\n", listen_sock, ntohs(sockaddr.sin_port) );
#endif
while (1) {
while (client_sock > 0) {
SLEEP_SEC(1); /* Already connected. Try again later. */
int client;
int c;
client = -1;
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
if (client_sock[c] <= 0) {
client = c;
}
}
#define QUEUE_SIZE 5
if (client >= 0) {
if(listen(listen_sock,QUEUE_SIZE) == -1)
if(listen(listen_sock,MAX_NET_CLIENTS) == -1)
{
text_color_set(DW_COLOR_ERROR);
perror ("connect_listen_thread: Listen failed");
@ -449,13 +490,19 @@ static THREAD_F connect_listen_thread (void *arg)
}
text_color_set(DW_COLOR_INFO);
dw_printf("Ready to accept KISS client application on port %d ...\n", kiss_port);
dw_printf("Ready to accept KISS TCP client application %d on port %d ...\n", client, kiss_port);
client_sock = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
text_color_set(DW_COLOR_INFO);
dw_printf("\nConnected to KISS client application ...\n\n");
dw_printf("\nAttached to KISS TCP client application %d...\n\n", client);
// Reset the state and buffer.
memset (&(kf[client]), 0, sizeof(kf[client]));
}
else {
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
}
}
#endif
}
@ -477,26 +524,67 @@ static THREAD_F connect_listen_thread (void *arg)
* or a text string.
*
* flen - Number of bytes for AX.25 frame.
* or -1 for a text string.
* When called from kiss_rec_byte, flen will be -1
* indicating a text string rather than frame content.
* This is used to fake out an application that thinks
* it is using a traditional TNC and tries to put it
* into KISS mode.
*
* tcpclient - It is possible to have more than client attached
* at the same time with TCP KISS.
* When a frame is received from the radio we want it
* to go to all of the clients. In this case specify -1.
* When responding to a command from the client, we want
* to send only to that one client app. In this case
* use the value 0 .. MAX_NET_CLIENTS-1.
*
* Description: Send message to client if connected.
* Description: Send message to client(s) if connected.
* Disconnect from client, and notify user, if any error.
*
*--------------------------------------------------------------------*/
void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen, int tcpclient)
{
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
int kiss_len;
int err;
int first, last, client;
// Something received over the radio would be sent to all attached clients.
// However, there are times we want to send a response only to a particular client.
// In the case of a serial port or pseudo terminal, there is only one potential client.
// so the response would be sent to only one place. A new parameter has been added for this.
if (client_sock == -1) {
if (tcpclient >= 0 && tcpclient < MAX_NET_CLIENTS) {
first = tcpclient;
last = tcpclient;
}
else if (tcpclient == -1) {
first = 0;
last = MAX_NET_CLIENTS - 1;
}
else {
text_color_set(DW_COLOR_ERROR);
dw_printf ("KISS TCP: Internal error, kissnet_send_rec_packet, tcpclient = %d.\n", tcpclient);
return;
}
for (client = first; client <= last; client++) {
if (client_sock[client] != -1) {
if (flen < 0) {
// A client app might think it is attached to a traditional TNC.
// It might try sending commands over and over again trying to get the TNC into KISS mode.
// We recognize this attempt and send it something to keep it happy.
text_color_set(DW_COLOR_ERROR);
dw_printf ("KISS TCP: Something unexpected from client application.\n");
dw_printf ("Is client app treating this like an old TNC with command mode?\n");
flen = strlen((char*)fbuf);
if (kiss_debug) {
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
@ -505,8 +593,6 @@ void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
kiss_len = strlen((char *)kiss_buff);
}
else {
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
assert (flen < (int)(sizeof(stemp)));
@ -532,25 +618,27 @@ void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
}
#if __WIN32__
err = send (client_sock, (char*)kiss_buff, kiss_len, 0);
err = send (client_sock[client], (char*)kiss_buff, kiss_len, 0);
if (err == SOCKET_ERROR)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError %d sending message to KISS client application. Closing connection.\n\n", WSAGetLastError());
closesocket (client_sock);
client_sock = -1;
closesocket (client_sock[client]);
client_sock[client] = -1;
WSACleanup();
}
#else
err = write (client_sock, kiss_buff, kiss_len);
err = write (client_sock[client], kiss_buff, kiss_len);
if (err <= 0)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError sending message to KISS client application. Closing connection.\n\n");
close (client_sock);
client_sock = -1;
close (client_sock[client]);
client_sock[client] = -1;
}
#endif
}
}
} /* end kissnet_send_rec_packet */
@ -586,15 +674,13 @@ static int read_from_socket (int fd, char *ptr, int len)
int n;
#if __WIN32__
//TODO: any flags for send/recv?
//TODO: Would be useful to have more detailed explanation from the error code.
n = recv (fd, ptr + got_bytes, len - got_bytes, 0);
#else
n = read (fd, ptr + got_bytes, len - got_bytes);
#endif
//Would be useful to have more detailed explanation from the error code.
#if DEBUG
text_color_set(DW_COLOR_DEBUG);
dw_printf ("read_from_socket: n = %d\n", n);
@ -621,9 +707,9 @@ static int read_from_socket (int fd, char *ptr, int len)
*
* Purpose: Wait for KISS messages from an application.
*
* Inputs: arg - Not used.
* Inputs: arg - client number, 0 .. MAX_NET_CLIENTS-1
*
* Outputs: client_sock - File descriptor for communicating with client app.
* Outputs: client_sock[n] - File descriptor for communicating with client app.
*
* Description: Process messages from the client application.
* Note that the client can go away and come back again and
@ -635,20 +721,20 @@ static int read_from_socket (int fd, char *ptr, int len)
/* Return one byte (value 0 - 255) */
static int kiss_get (void)
static int kiss_get (int client)
{
unsigned char ch;
int n;
while (1) {
while (client_sock <= 0) {
while (client_sock[client] <= 0) {
SLEEP_SEC(1); /* Not connected. Try again later. */
}
/* Just get one byte at a time. */
n = read_from_socket (client_sock, (char *)(&ch), 1);
n = read_from_socket (client_sock[client], (char *)(&ch), 1);
if (n == 1) {
#if DEBUG9
@ -668,13 +754,13 @@ static int kiss_get (void)
}
text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError reading KISS byte from client application. Closing connection.\n\n");
dw_printf ("\nError reading KISS byte from client application %d. Closing connection.\n\n", client);
#if __WIN32__
closesocket (client_sock);
closesocket (client_sock[client]);
#else
close (client_sock);
close (client_sock[client]);
#endif
client_sock = -1;
client_sock[client] = -1;
}
}
@ -689,9 +775,26 @@ static THREAD_F kissnet_listen_thread (void *arg)
dw_printf ("kissnet_listen_thread ( socket = %d )\n", client_sock);
#endif
int client = (int)(long)arg;
assert (client >= 0 && client < MAX_NET_CLIENTS);
// So why is kissnet_send_rec_packet mentioned here for incoming from the client app?
// The logic exists for the serial port case where the client might think it is
// attached to a traditional TNC. It might try sending commands over and over again
// trying to get the TNC into KISS mode. To keep it happy, we recognize this attempt
// and send it something to keep it happy.
// In the case of a serial port or pseudo terminal, there is only one potential client
// so the response would be sent to only one place.
// Starting in version 1.5, this now can have multiple attached clients. We wouldn't
// want to send the response to all of them. Actually, we should be providing only
// "Simply KISS" as some call it.
while (1) {
ch = kiss_get();
kiss_rec_byte (&kf, ch, kiss_debug, kissnet_send_rec_packet);
ch = kiss_get(client);
kiss_rec_byte (&(kf[client]), ch, kiss_debug, client, kissnet_send_rec_packet);
}
#if __WIN32__

View File

@ -13,7 +13,7 @@
void kissnet_init (struct misc_config_s *misc_config);
void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen);
void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen, int client);
void kiss_net_set_debug (int n);

View File

@ -1,13 +1,7 @@
// TODO: Needs more clean up and testing of error conditions.
// TODO: use this in place of other similar code.
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2014, 2015 John Langner, WB2OSZ
// Copyright (C) 2014, 2015, 2017 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -73,8 +67,10 @@
* Inputs: devicename - For Windows, usually like COM5.
* For Linux, usually /dev/tty...
* "COMn" also allowed and converted to /dev/ttyS(n-1)
* Could be /dev/rfcomm0 for Bluetooth.
*
* baud - Speed. 4800, 9600, etc.
* baud - Speed. 1200, 4800, 9600 bps, etc.
* If 0, leave it alone.
*
* Returns Handle for serial port or MYFDERROR for error.
*
@ -143,6 +139,7 @@ MYFDTYPE serial_port_open (char *devicename, int baud)
switch (baud) {
case 0: /* Leave it alone. */ break;
case 1200: dcb.BaudRate = CBR_1200; break;
case 2400: dcb.BaudRate = CBR_2400; break;
case 4800: dcb.BaudRate = CBR_4800; break;
@ -233,6 +230,7 @@ MYFDTYPE serial_port_open (char *devicename, int baud)
switch (baud) {
case 0: /* Leave it alone. */ break;
case 1200: cfsetispeed (&ts, B1200); cfsetospeed (&ts, B1200); break;
case 2400: cfsetispeed (&ts, B2400); cfsetospeed (&ts, B2400); break;
case 4800: cfsetispeed (&ts, B4800); cfsetospeed (&ts, B4800); break;
@ -305,8 +303,10 @@ int serial_port_write (MYFDTYPE fd, char *str, int len)
}
else if ((int)nwritten != len)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing to serial port. Only %d of %d written.\n\n", (int)nwritten, len);
// Do we want this message here?
// Or rely on caller to check and provide something more meaningful for the usage?
//text_color_set(DW_COLOR_ERROR);
//dw_printf ("Error writing to serial port. Only %d of %d written.\n\n", (int)nwritten, len);
}
return (nwritten);
@ -317,8 +317,10 @@ int serial_port_write (MYFDTYPE fd, char *str, int len)
written = write (fd, str, (size_t)len);
if (written != len)
{
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing to serial port. err=%d\n\n", written);
// Do we want this message here?
// Or rely on caller to check and provide something more meaningful for the usage?
//text_color_set(DW_COLOR_ERROR);
//dw_printf ("Error writing to serial port. err=%d\n\n", written);
return (-1);
}
@ -402,8 +404,9 @@ int serial_port_get1 (MYFDTYPE fd)
CloseHandle(ov_rd.hEvent);
if (n != 1) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Serial port failed to get one byte. n=%d.\n\n", (int)n);
//text_color_set(DW_COLOR_ERROR);
//dw_printf ("Serial port failed to get one byte. n=%d.\n\n", (int)n);
return (-1);
}
@ -414,8 +417,8 @@ int serial_port_get1 (MYFDTYPE fd)
n = read(fd, &ch, (size_t)1);
if (n != 1) {
text_color_set(DW_COLOR_DEBUG);
dw_printf ("serial_port_get1(%d) returns -1 for error.\n", fd);
//text_color_set(DW_COLOR_DEBUG);
//dw_printf ("serial_port_get1(%d) returns -1 for error.\n", fd);
return (-1);
}
@ -447,8 +450,14 @@ int serial_port_get1 (MYFDTYPE fd)
*
*--------------------------------------------------------------------*/
// TODO:
void serial_port_close (MYFDTYPE fd)
{
#if __WIN32__
CloseHandle (fd);
#else
close (fd);
#endif
}
/* end serial_port.c */

View File

@ -637,8 +637,7 @@ static THREAD_F connect_listen_thread (void *arg)
}
text_color_set(DW_COLOR_INFO);
// TODO: "attached" or some other term would be better because "connected" has a different meaning for AX.25.
dw_printf("\nConnected to AGW client application %d ...\n\n", client);
dw_printf("\nAttached to AGW client application %d ...\n\n", client);
/*
* The command to change this is actually a toggle, not explicit on or off.
@ -729,7 +728,7 @@ static THREAD_F connect_listen_thread (void *arg)
client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
text_color_set(DW_COLOR_INFO);
dw_printf("\nConnected to AGW client application %d...\n\n", client);
dw_printf("\nAttached to AGW client application %d...\n\n", client);
/*
* The command to change this is actually a toggle, not explicit on or off.

View File

@ -58,6 +58,7 @@
#include "server.h"
#include "kiss.h"
#include "kissserial.h"
#include "kissnet.h"
@ -895,8 +896,9 @@ static void xmit_object_report (int i, int first_time)
flen = ax25_pack(pp, fbuf);
server_send_rec_packet (save_tt_config_p->obj_recv_chan, pp, fbuf, flen);
kissnet_send_rec_packet (save_tt_config_p->obj_recv_chan, fbuf, flen);
kiss_send_rec_packet (save_tt_config_p->obj_recv_chan, fbuf, flen);
kissnet_send_rec_packet (save_tt_config_p->obj_recv_chan, fbuf, flen, -1);
kissserial_send_rec_packet (save_tt_config_p->obj_recv_chan, fbuf, flen, -1);
kisspt_send_rec_packet (save_tt_config_p->obj_recv_chan, fbuf, flen, -1);
}
if (first_time && save_tt_config_p->obj_send_to_ig) {

View File

@ -1,8 +1,8 @@
/* Dire Wolf version 1.4 */
/* Dire Wolf version 1.5 */
#define APP_TOCALL "APDW"
#define MAJOR_VERSION 1
#define MINOR_VERSION 4
#define MINOR_VERSION 5
//#define EXTRA_VERSION "Beta Test"