2015-07-27 00:35:07 +00:00
|
|
|
//
|
|
|
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
|
|
|
//
|
2017-05-03 21:41:37 +00:00
|
|
|
// Copyright (C) 2011, 2013, 2014, 2016, 2017 John Langner, WB2OSZ
|
2015-07-27 00:35:07 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
// the Free Software Foundation, either version 2 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Module: kiss.c
|
|
|
|
*
|
|
|
|
* Purpose: Act as a virtual KISS TNC for use by other packet radio applications.
|
2017-05-03 21:41:37 +00:00
|
|
|
* This file implements it with a pseudo terminal for Linux only.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2016-03-26 02:20:27 +00:00
|
|
|
* Description: It implements the KISS TNC protocol as described in:
|
2015-07-27 00:35:07 +00:00
|
|
|
* http://www.ka9q.net/papers/kiss.html
|
|
|
|
*
|
|
|
|
* Briefly, a frame is composed of
|
|
|
|
*
|
|
|
|
* * FEND (0xC0)
|
|
|
|
* * Contents - with special escape sequences so a 0xc0
|
|
|
|
* byte in the data is not taken as end of frame.
|
|
|
|
* as part of the data.
|
|
|
|
* * FEND
|
|
|
|
*
|
|
|
|
* The first byte of the frame contains:
|
|
|
|
*
|
|
|
|
* * port number in upper nybble.
|
|
|
|
* * command in lower nybble.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Commands from application recognized:
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _0 Data Frame AX.25 frame in raw format.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _1 TXDELAY See explanation in xmit.c.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _2 Persistence " "
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _3 SlotTime " "
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _4 TXtail " "
|
2015-07-27 00:35:07 +00:00
|
|
|
* Spec says it is obsolete but Xastir
|
|
|
|
* sends it and we respect it.
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _5 FullDuplex Ignored.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _6 SetHardware TNC specific.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* FF Return Exit KISS mode. Ignored.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Messages sent to client application:
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* _0 Data Frame Received AX.25 frame in raw format.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Platform differences:
|
|
|
|
*
|
|
|
|
* For the Linux case,
|
|
|
|
* We supply a pseudo terminal for use by other applications.
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Version 1.5: Split serial port version off into its own file.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
*---------------------------------------------------------------*/
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
|
|
|
|
#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.
|
|
|
|
|
|
|
|
|
2016-07-03 22:09:34 +00:00
|
|
|
#include "direwolf.h"
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
2017-05-03 21:41:37 +00:00
|
|
|
#include <string.h>
|
2015-07-27 00:35:07 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <termios.h>
|
2017-01-01 16:49:55 +00:00
|
|
|
#include <sys/select.h>
|
2015-07-27 00:35:07 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ioctl.h>
|
2017-05-03 21:41:37 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
#ifdef __OpenBSD__
|
|
|
|
#include <errno.h>
|
|
|
|
#else
|
2015-07-27 00:35:07 +00:00
|
|
|
#include <sys/errno.h>
|
|
|
|
#endif
|
2016-07-03 22:09:34 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
#include "tq.h"
|
|
|
|
#include "ax25_pad.h"
|
|
|
|
#include "textcolor.h"
|
|
|
|
#include "kiss.h"
|
|
|
|
#include "kiss_frame.h"
|
|
|
|
#include "xmit.h"
|
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
/*
|
|
|
|
* Accumulated KISS frame and state of decoder.
|
|
|
|
*/
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static kiss_frame_t kf;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2017-05-03 21:41:37 +00:00
|
|
|
* These are for a Linux pseudo terminal.
|
2015-07-27 00:35:07 +00:00
|
|
|
*/
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static int pt_master_fd = -1; /* File descriptor for my end. */
|
2015-07-27 01:05:48 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static char pt_slave_name[32]; /* Pseudo terminal slave name */
|
|
|
|
/* like /dev/pts/999 */
|
2015-07-27 01:05:48 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Symlink to pseudo terminal name which changes.
|
|
|
|
*/
|
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
#define TMP_KISSTNC_SYMLINK "/tmp/kisstnc"
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static void * kisspt_listen_thread (void *arg);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static int kisspt_debug = 0; /* Print information flowing from and to client. */
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
void kisspt_set_debug (int n)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
2017-05-03 21:41:37 +00:00
|
|
|
kisspt_debug = n;
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* In server.c. Should probably move to some misc. function file. */
|
|
|
|
|
|
|
|
void hex_dump (unsigned char *p, int len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Name: kisspt_init
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* Purpose: Set up a pseudo terminal acting as a virtual KISS TNC.
|
|
|
|
*
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Inputs:
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* Outputs:
|
|
|
|
*
|
|
|
|
* Description: (1) Create a pseudo terminal for the client to use.
|
|
|
|
* (2) Start a new thread to listen for commands from client app
|
|
|
|
* so the main application doesn't block while we wait.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static int kisspt_open_pt (void);
|
2016-07-03 22:09:34 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
void kisspt_init (struct misc_config_s *mc)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
2016-07-03 22:09:34 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
pthread_t kiss_pterm_listen_tid;
|
2016-07-03 22:09:34 +00:00
|
|
|
int e;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
memset (&kf, 0, sizeof(kf));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This reads messages from client.
|
|
|
|
*/
|
2017-05-03 21:41:37 +00:00
|
|
|
pt_master_fd = -1;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
if (mc->enable_kiss_pt) {
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
pt_master_fd = kisspt_open_pt ();
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (pt_master_fd != -1) {
|
|
|
|
e = pthread_create (&kiss_pterm_listen_tid, (pthread_attr_t*)NULL, kisspt_listen_thread, NULL);
|
2015-07-27 00:35:07 +00:00
|
|
|
if (e != 0) {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
perror("Could not create kiss listening thread for Linux pseudo terminal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
text_color_set(DW_COLOR_INFO);
|
|
|
|
dw_printf ("Use -p command line option to enable KISS pseudo terminal.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
text_color_set (DW_COLOR_DEBUG);
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
dw_printf ("end of kisspt_init: pt_master_fd = %d\n", pt_master_fd);
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
2017-05-03 21:41:37 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Returns fd for master side of pseudo terminal or -1 for error.
|
2015-07-27 00:35:07 +00:00
|
|
|
*/
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static int kisspt_open_pt (void)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
|
|
|
int fd;
|
2015-07-27 01:05:48 +00:00
|
|
|
char *pts;
|
2015-07-27 00:35:07 +00:00
|
|
|
struct termios ts;
|
|
|
|
int e;
|
2016-03-26 02:20:27 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2017-05-03 21:41:37 +00:00
|
|
|
dw_printf ("kisspt_open_pt ( )\n");
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
fd = posix_openpt(O_RDWR|O_NOCTTY);
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (fd == -1
|
|
|
|
|| grantpt (fd) == -1
|
|
|
|
|| unlockpt (fd) == -1
|
2015-07-27 01:05:48 +00:00
|
|
|
|| (pts = ptsname (fd)) == NULL) {
|
2015-07-27 00:35:07 +00:00
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("ERROR - Could not create pseudo terminal for KISS TNC.\n");
|
2017-05-03 21:41:37 +00:00
|
|
|
return (-1);
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
2015-11-08 01:57:02 +00:00
|
|
|
strlcpy (pt_slave_name, pts, sizeof(pt_slave_name));
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
e = tcgetattr (fd, &ts);
|
|
|
|
if (e != 0) {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("Can't get pseudo terminal attributes, err=%d\n", e);
|
|
|
|
perror ("pt 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) {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("Can't set pseudo terminal attributes, err=%d\n", e);
|
|
|
|
perror ("pt tcsetattr");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-03-26 02:20:27 +00:00
|
|
|
* We had a problem here since the beginning.
|
|
|
|
* If no one was reading from the other end of the pseudo
|
|
|
|
* terminal, the buffer space would eventually fill up,
|
|
|
|
* the write here would block, and the receive decode
|
|
|
|
* thread would get stuck.
|
|
|
|
*
|
|
|
|
* March 2016 - A "select" was put before the read to
|
|
|
|
* solve a different problem. With that in place, we can
|
|
|
|
* now use non-blocking I/O and detect the buffer full
|
|
|
|
* condition here.
|
2015-07-27 00:35:07 +00:00
|
|
|
*/
|
|
|
|
|
2016-03-26 02:20:27 +00:00
|
|
|
// text_color_set(DW_COLOR_DEBUG);
|
|
|
|
// dw_printf("Debug: Try using non-blocking mode for pseudo terminal.\n");
|
|
|
|
|
|
|
|
int flags = fcntl(fd, F_GETFL, 0);
|
2015-07-27 00:35:07 +00:00
|
|
|
e = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
if (e != 0) {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("Can't set pseudo terminal to nonblocking, fcntl returns %d, errno = %d\n", e, errno);
|
|
|
|
perror ("pt fcntl");
|
|
|
|
}
|
2016-03-26 02:20:27 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
text_color_set(DW_COLOR_INFO);
|
2015-07-27 01:05:48 +00:00
|
|
|
dw_printf("Virtual KISS TNC is available on %s\n", pt_slave_name);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
|
|
|
|
#if 1
|
|
|
|
// Sample code shows this. Why would we open it here?
|
|
|
|
// On Ubuntu, the slave side disappears after a few
|
2017-05-03 21:41:37 +00:00
|
|
|
// seconds if no one opens it. Same on Raspbian which
|
2015-07-27 01:05:48 +00:00
|
|
|
// is also based on Debian.
|
|
|
|
// Need to revisit this.
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
int pt_slave_fd;
|
2015-07-27 01:05:48 +00:00
|
|
|
|
|
|
|
pt_slave_fd = open(pt_slave_name, O_RDWR|O_NOCTTY);
|
|
|
|
|
|
|
|
if (pt_slave_fd < 0) {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("Can't open %s\n", pt_slave_name);
|
|
|
|
perror ("");
|
2017-05-03 21:41:37 +00:00
|
|
|
return -1;
|
2015-07-27 01:05:48 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/*
|
|
|
|
* The device name is not the same every time.
|
|
|
|
* This is inconvenient for the application because it might
|
|
|
|
* be necessary to change the device name in the configuration.
|
|
|
|
* Create a symlink, /tmp/kisstnc, so the application configuration
|
|
|
|
* does not need to change when the pseudo terminal name changes.
|
|
|
|
*/
|
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
unlink (TMP_KISSTNC_SYMLINK);
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
|
|
|
|
// TODO: Is this removed when application exits?
|
|
|
|
|
|
|
|
if (symlink (pt_slave_name, TMP_KISSTNC_SYMLINK) == 0) {
|
|
|
|
dw_printf ("Created symlink %s -> %s\n", TMP_KISSTNC_SYMLINK, pt_slave_name);
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
2015-07-27 01:05:48 +00:00
|
|
|
dw_printf ("Failed to create symlink %s\n", TMP_KISSTNC_SYMLINK);
|
2015-07-27 00:35:07 +00:00
|
|
|
perror ("");
|
|
|
|
}
|
|
|
|
|
|
|
|
return (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Name: kisspt_send_rec_packet
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
* Purpose: Send a received packet or text string to the client app.
|
|
|
|
*
|
|
|
|
* Inputs: chan - Channel number where packet was received.
|
|
|
|
* 0 = first, 1 = second if any.
|
|
|
|
*
|
|
|
|
* pp - Identifier for packet object.
|
|
|
|
*
|
|
|
|
* fbuf - Address of raw received frame buffer
|
|
|
|
* or a text string.
|
|
|
|
*
|
|
|
|
* flen - Length of raw received frame not including the FCS
|
|
|
|
* or -1 for a text string.
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* client - Not used for pseudo terminal.
|
|
|
|
* Here so that 3 related functions all have
|
|
|
|
* the same parameter list.
|
|
|
|
*
|
2015-07-27 00:35:07 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
void kisspt_send_rec_packet (int chan, unsigned char *fbuf, int flen, int client)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
2015-07-27 01:05:48 +00:00
|
|
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
2015-07-27 00:35:07 +00:00
|
|
|
int kiss_len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (pt_master_fd == -1) {
|
2015-07-27 00:35:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-05-03 21:41:37 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
if (flen < 0) {
|
|
|
|
flen = strlen((char*)fbuf);
|
2017-05-03 21:41:37 +00:00
|
|
|
if (kisspt_debug) {
|
2015-07-27 00:35:07 +00:00
|
|
|
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
|
|
|
|
}
|
2015-11-08 01:57:02 +00:00
|
|
|
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
|
2015-07-27 00:35:07 +00:00
|
|
|
kiss_len = strlen((char *)kiss_buff);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
stemp[0] = (chan << 4) + 0;
|
|
|
|
memcpy (stemp+1, fbuf, flen);
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (kisspt_debug >= 2) {
|
2015-07-27 01:05:48 +00:00
|
|
|
/* AX.25 frame with the CRC removed. */
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf ("\n");
|
|
|
|
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
2016-01-31 16:42:58 +00:00
|
|
|
hex_dump (fbuf, flen);
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
|
|
|
|
|
|
|
/* This has KISS framing and escapes for sending to client app. */
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (kisspt_debug) {
|
2015-07-27 01:05:48 +00:00
|
|
|
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
err = write (pt_master_fd, kiss_buff, (size_t)kiss_len);
|
|
|
|
|
|
|
|
if (err == -1 && errno == EWOULDBLOCK) {
|
|
|
|
text_color_set (DW_COLOR_INFO);
|
2016-03-26 02:20:27 +00:00
|
|
|
dw_printf ("KISS SEND - Discarding message because no one is listening.\n");
|
|
|
|
dw_printf ("This happens when you use the -p option and don't read from the pseudo terminal.\n");
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
else if (err != kiss_len)
|
|
|
|
{
|
|
|
|
text_color_set(DW_COLOR_ERROR);
|
|
|
|
dw_printf ("\nError sending KISS message to client application on pseudo terminal. fd=%d, len=%d, write returned %d, errno = %d\n\n",
|
|
|
|
pt_master_fd, kiss_len, err, errno);
|
|
|
|
perror ("pt write");
|
|
|
|
}
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
} /* kisspt_send_rec_packet */
|
2015-07-27 00:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2016-03-26 02:20:27 +00:00
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Name: kisspt_get
|
2016-03-26 02:20:27 +00:00
|
|
|
*
|
|
|
|
* Purpose: Read one byte from the KISS client app.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Global In: pt_master_fd
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2016-03-26 02:20:27 +00:00
|
|
|
* Returns: one byte (value 0 - 255) or terminate thread on error.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
2016-03-26 02:20:27 +00:00
|
|
|
* Description: There is room for improvment here. Reading one byte
|
|
|
|
* at a time is inefficient. We could read a large block
|
|
|
|
* into a local buffer and return a byte from that most of the time.
|
|
|
|
* Is it worth the effort? I don't know. With GHz processors and
|
|
|
|
* the low data rate here it might not make a noticable difference.
|
2015-07-27 00:35:07 +00:00
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static int kisspt_get (void)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
|
|
|
unsigned char ch;
|
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
int n = 0;
|
2016-03-26 02:20:27 +00:00
|
|
|
fd_set fd_in, fd_ex;
|
2016-03-17 08:46:48 +00:00
|
|
|
int rc;
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
while ( n == 0 ) {
|
2016-03-26 02:20:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since the beginning we've always had a couple annoying problems with
|
|
|
|
* the pseudo terminal KISS interface.
|
|
|
|
* When using "kissattach" we would sometimes get the error message:
|
|
|
|
*
|
|
|
|
* kissattach: Error setting line discipline: TIOCSETD: Device or resource busy
|
|
|
|
* Are you sure you have enabled MKISS support in the kernel
|
|
|
|
* or, if you made it a module, that the module is loaded?
|
|
|
|
*
|
|
|
|
* martinhpedersen came up with the interesting idea of putting in a "select"
|
|
|
|
* before the "read" and explained it like this:
|
|
|
|
*
|
|
|
|
* "Reading from master fd of the pty before the client has connected leads
|
|
|
|
* to trouble with kissattach. Use select to check if the slave has sent
|
|
|
|
* any data before trying to read from it."
|
|
|
|
*
|
|
|
|
* "This fix resolves the issue by not reading from the pty's master fd, until
|
|
|
|
* kissattach has opened and configured the slave. This is implemented using
|
|
|
|
* select() to wait for data before reading from the master fd."
|
|
|
|
*
|
|
|
|
* The submitted code looked like this:
|
|
|
|
*
|
|
|
|
* FD_ZERO(&fd_in);
|
|
|
|
* rc = select(pt_master_fd + 1, &fd_in, NULL, &fd_in, NULL);
|
|
|
|
*
|
|
|
|
* That doesn't look right to me for a couple reasons.
|
|
|
|
* First, I would expect to use FD_SET for the fd.
|
|
|
|
* Second, using the same bit mask for two arguments doesn't seem
|
|
|
|
* like a good idea because select modifies them.
|
|
|
|
* When I tried running it, we don't get the failure message
|
|
|
|
* anymore but the select never returns so we can't read data from
|
|
|
|
* the KISS client app.
|
|
|
|
*
|
|
|
|
* I think this is what we want.
|
|
|
|
*
|
|
|
|
* Tested on Raspian (ARM) and Ubuntu (x86_64).
|
|
|
|
* We don't get the error from kissattach anymore.
|
|
|
|
*/
|
|
|
|
|
2016-03-17 08:46:48 +00:00
|
|
|
FD_ZERO(&fd_in);
|
2016-03-26 02:20:27 +00:00
|
|
|
FD_SET(pt_master_fd, &fd_in);
|
|
|
|
|
|
|
|
FD_ZERO(&fd_ex);
|
|
|
|
FD_SET(pt_master_fd, &fd_ex);
|
|
|
|
|
|
|
|
rc = select(pt_master_fd + 1, &fd_in, NULL, &fd_ex, NULL);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
|
|
|
dw_printf ("select returns %d, errno=%d, fd=%d, fd_in=%08x, fd_ex=%08x\n", rc, errno, pt_master_fd, *((int*)(&fd_in)), *((int*)(&fd_in)));
|
|
|
|
#endif
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2016-03-17 08:46:48 +00:00
|
|
|
if (rc == 0)
|
|
|
|
{
|
2016-03-26 02:20:27 +00:00
|
|
|
continue; // When could we get a 0?
|
2016-03-17 08:46:48 +00:00
|
|
|
}
|
2015-07-27 01:05:48 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
if (rc == -1
|
2016-03-17 08:46:48 +00:00
|
|
|
|| (n = read(pt_master_fd, &ch, (size_t)1)) != 1)
|
|
|
|
{
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2015-07-27 01:05:48 +00:00
|
|
|
text_color_set(DW_COLOR_ERROR);
|
2016-03-26 02:20:27 +00:00
|
|
|
dw_printf ("\nError receiving KISS message from client application. Closing %s.\n\n", pt_slave_name);
|
2015-07-27 01:05:48 +00:00
|
|
|
perror ("");
|
|
|
|
|
|
|
|
close (pt_master_fd);
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
pt_master_fd = -1;
|
2015-07-27 01:05:48 +00:00
|
|
|
unlink (TMP_KISSTNC_SYMLINK);
|
|
|
|
pthread_exit (NULL);
|
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUGx
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2017-05-03 21:41:37 +00:00
|
|
|
dw_printf ("kisspt_get(%d) returns 0x%02x\n", fd, ch);
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return (ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-26 02:20:27 +00:00
|
|
|
/*-------------------------------------------------------------------
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Name: kisspt_listen_thread
|
2016-03-26 02:20:27 +00:00
|
|
|
*
|
|
|
|
* Purpose: Read messages from serial port KISS client application.
|
|
|
|
*
|
2017-05-03 21:41:37 +00:00
|
|
|
* Global In:
|
2016-03-26 02:20:27 +00:00
|
|
|
*
|
|
|
|
* Description: Reads bytes from the KISS client app and
|
|
|
|
* sends them to kiss_rec_byte for processing.
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------------*/
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
static void * kisspt_listen_thread (void *arg)
|
2015-07-27 00:35:07 +00:00
|
|
|
{
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
text_color_set(DW_COLOR_DEBUG);
|
2017-05-03 21:41:37 +00:00
|
|
|
dw_printf ("kisspt_listen_thread ( %d )\n", fd);
|
2015-07-27 00:35:07 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2017-05-03 21:41:37 +00:00
|
|
|
ch = kisspt_get();
|
|
|
|
kiss_rec_byte (&kf, ch, kisspt_debug, -1, kisspt_send_rec_packet);
|
2015-07-27 01:05:48 +00:00
|
|
|
}
|
2015-07-27 00:35:07 +00:00
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
return (void *) 0; /* Unreachable but avoids compiler warning. */
|
2015-07-27 00:35:07 +00:00
|
|
|
}
|
|
|
|
|
2017-05-03 21:41:37 +00:00
|
|
|
#endif // Linux version
|
|
|
|
|
2015-07-27 00:35:07 +00:00
|
|
|
/* end kiss.c */
|