port upstream PseudoPTY support; add systemd service file; update Makefile to support install;

pull/12/head
Bryan Biedenkapp 4 years ago
parent f5cb11b467
commit 4fef4a381d

@ -202,6 +202,7 @@
<ClInclude Include="modem\port\ISerialPort.h" />
<ClInclude Include="modem\port\ModemNullPort.h" />
<ClInclude Include="modem\port\UARTPort.h" />
<ClInclude Include="modem\port\PseudoPTYPort.h" />
<ClInclude Include="modem\port\UDPPort.h" />
<ClInclude Include="network\BaseNetwork.h" />
<ClInclude Include="network\Network.h" />
@ -281,6 +282,7 @@
<ClCompile Include="modem\port\ISerialPort.cpp" />
<ClCompile Include="modem\port\ModemNullPort.cpp" />
<ClCompile Include="modem\port\UARTPort.cpp" />
<ClCompile Include="modem\port\PseudoPTYPort.cpp" />
<ClCompile Include="modem\port\UDPPort.cpp" />
<ClCompile Include="network\BaseNetwork.cpp" />
<ClCompile Include="network\Network.cpp" />

@ -353,6 +353,9 @@
<ClInclude Include="modem\port\UARTPort.h">
<Filter>Header Files\modem\port</Filter>
</ClInclude>
<ClInclude Include="modem\port\PseudoPTYPort.h">
<Filter>Header Files\modem\port</Filter>
</ClInclude>
<ClInclude Include="modem\port\ModemNullPort.h">
<Filter>Header Files\modem\port</Filter>
</ClInclude>
@ -571,6 +574,9 @@
<ClCompile Include="modem\port\UARTPort.cpp">
<Filter>Source Files\modem\port</Filter>
</ClCompile>
<ClCompile Include="modem\port\PseudoPTYPort.cpp">
<Filter>Source Files\modem\port</Filter>
</ClCompile>
<ClCompile Include="modem\port\ModemNullPort.cpp">
<Filter>Source Files\modem\port</Filter>
</ClCompile>

@ -10,7 +10,7 @@ rpi-armSTRIP= /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I.
EXTFLAGS=
LIBS = -lpthread
LIBS = -lpthread -lutil
LDFLAGS = -g
BIN = dvmhost
@ -69,6 +69,7 @@ OBJECTS = \
modem/port/ISerialPort.o \
modem/port/ModemNullPort.o \
modem/port/UARTPort.o \
modem/port/PseudoPTYPort.o \
modem/port/UDPPort.o \
modem/Modem.o \
network/UDPSocket.o \
@ -98,3 +99,31 @@ strip:
clean:
$(RM) $(BIN) $(OBJECTS) *.o *.d *.bak *~
install: all
@mkdir -p /opt/dvm
install -m 755 $(BIN) /opt/dvm/bin/
install-config-files:
@mkdir -p /opt/dvm
@cp -n config.example.yml /opt/dvm/config.yml
@cp -n iden_table.example.dat /opt/dvm/iden_table.dat
@cp -n rid_acl.example.dat /opt/dvm/rid_acl.dat
@cp -n tg_acl.example.dat /opt/dvm/tg_acl.dat
@sed -i 's/filePath: ./filePath: \/opt\/dvm\/log\//' /opt/dvm/config.yml
@sed -i 's/activityFilePath: ./activityFilePath: \/opt\/dvm\/log\//' /opt/dvm/config.yml
@sed -i 's/file: iden_table.dat/file: \/opt\/dvm\/iden_table.dat/' /opt/dvm/config.yml
@sed -i 's/file: rid_acl.dat/file: \/opt\/dvm\/rid_acl.dat/' /opt/dvm/config.yml
@sed -i 's/file: tg_acl.dat/file: \/opt\/dvm\/tg_acl.dat/' /opt/dvm/config.yml
install-service: install install-config-files
@useradd --user-group -M --system dvmhost --shell /bin/false || true
@usermod --groups dialout --append dvmhost || true
@mkdir /opt/dvm/log || true
@chown dvmhost:dvmhost /opt/dvm/log
@cp ./linux/dvmhost.service /lib/systemd/system/
@systemctl enable dvmhost.service
uninstall-service:
@systemctl stop dvmhost.service || true
@systemctl disable dvmhost.service || true
@rm -f /lib/systemd/system/dvmhost.service || true

@ -0,0 +1,12 @@
[Unit]
Description=DVMProject Host Radio Service
After=syslog.target network.target
[Service]
User=mmdvm
Type=forking
ExecStart=/opt/dvm/bin/dvmhost -c /opt/dvm/config.yml
Restart=on-abnormal
[Install]
WantedBy=multi-user.target

@ -0,0 +1,117 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "modem/port/PseudoPTYPort.h"
#include "Log.h"
#include <cstring>
#include <cassert>
#include <cstdlib>
using namespace modem::port;
#if !defined(_WIN32) && !defined(_WIN64)
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#if defined(__linux__)
#include <pty.h>
#else
#include <util.h>
#endif
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the PseudoPTYPort class.
/// </summary>
/// <param name="device">Serial port device.</param>
/// <param name="speed">Serial port speed.</param>
/// <param name="assertRTS"></param>
PseudoPTYPort::PseudoPTYPort(const std::string& symlink, SERIAL_SPEED speed, bool assertRTS) : UARTPort(speed, assertRTS),
m_symlink(symlink)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the PseudoPTYPort class.
/// </summary>
PseudoPTYPort::~PseudoPTYPort()
{
/* stub */
}
/// <summary>
/// Opens a connection to the serial port.
/// </summary>
/// <returns>True, if connection is opened, otherwise false.</returns>
bool PseudoPTYPort::open()
{
assert(m_fd == -1);
int slavefd;
char slave[300];
int result = ::openpty(&m_fd, &slavefd, slave, NULL, NULL);
if (result < 0) {
::LogError(LOG_HOST, "Cannot open the pseudo tty - errno : %d", errno);
return false;
}
// remove any previous stale symlink
::unlink(m_symlink.c_str());
int ret = ::symlink(slave, m_symlink.c_str());
if (ret != 0) {
::LogError(LOG_HOST, "Cannot make symlink to %s with %s", slave, m_symlink.c_str());
close();
return false;
}
::LogMessage(LOG_HOST, "Made symbolic link from %s to %s", slave, m_symlink.c_str());
m_device = std::string(::ttyname(m_fd));
return setTermios();
}
/// <summary>
/// Closes the connection to the serial port.
/// </summary>
void PseudoPTYPort::close()
{
UARTPort::close();
::unlink(m_symlink.c_str());
}
#endif

@ -0,0 +1,72 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__PSEUDO_PTY_PORT_H__)
#define __PSEUDO_PTY_PORT_H__
#if !defined(_WIN32) && !defined(_WIN64)
#include "Defines.h"
#include "modem/port/UARTPort.h"
#include <cstring>
namespace modem
{
namespace port
{
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements low-level routines to communicate via a Linux
// PTY serial port.
// ---------------------------------------------------------------------------
class HOST_SW_API PseudoPTYPort : public UARTPort
{
public:
/// <summary>Initializes a new instance of the PseudoPTYPort class.</summary>
PseudoPTYPort(const std::string& symlink, SERIAL_SPEED speed, bool assertRTS = false);
/// <summary>Finalizes a instance of the PseudoPTYPort class.</summary>
virtual ~PseudoPTYPort();
/// <summary>Opens a connection to the serial port.</summary>
virtual bool open();
/// <summary>Closes the connection to the serial port.</summary>
virtual void close();
protected:
std::string m_symlink;
}; // class HOST_SW_API PseudoPTYPort : public UARTPort
} // namespace port
} // namespace Modem
#endif
#endif // __PSEUDO_PTY_PORT_H__

@ -302,101 +302,7 @@ bool UARTPort::open()
return false;
}
termios termios;
if (::tcgetattr(m_fd, &termios) < 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK);
termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
termios.c_oflag &= ~(OPOST);
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
termios.c_cflag |= (CS8 | CLOCAL | CREAD);
termios.c_lflag &= ~(ISIG | ICANON | IEXTEN);
termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
#if defined(__APPLE__)
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 1;
#else
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10;
#endif
switch (m_speed) {
case SERIAL_1200:
::cfsetospeed(&termios, B1200);
::cfsetispeed(&termios, B1200);
break;
case SERIAL_2400:
::cfsetospeed(&termios, B2400);
::cfsetispeed(&termios, B2400);
break;
case SERIAL_4800:
::cfsetospeed(&termios, B4800);
::cfsetispeed(&termios, B4800);
break;
case SERIAL_9600:
::cfsetospeed(&termios, B9600);
::cfsetispeed(&termios, B9600);
break;
case SERIAL_19200:
::cfsetospeed(&termios, B19200);
::cfsetispeed(&termios, B19200);
break;
case SERIAL_38400:
::cfsetospeed(&termios, B38400);
::cfsetispeed(&termios, B38400);
break;
case SERIAL_115200:
::cfsetospeed(&termios, B115200);
::cfsetispeed(&termios, B115200);
break;
case SERIAL_230400:
::cfsetospeed(&termios, B230400);
::cfsetispeed(&termios, B230400);
break;
case SERIAL_460800:
::cfsetospeed(&termios, B460800);
::cfsetispeed(&termios, B460800);
break;
default:
::LogError(LOG_HOST, "Unsupported serial port speed - %u", m_speed);
::close(m_fd);
return false;
}
if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) {
::LogError(LOG_HOST, "Cannot set the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
if (m_assertRTS) {
uint32_t y;
if (::ioctl(m_fd, TIOCMGET, &y) < 0) {
::LogError(LOG_HOST, "Cannot get the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
y |= TIOCM_RTS;
if (::ioctl(m_fd, TIOCMSET, &y) < 0) {
::LogError(LOG_HOST, "Cannot set the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
}
#if defined(__APPLE__)
setNonblock(false);
#endif
m_isOpen = true;
return true;
return setTermios();
}
/// <summary>
@ -515,7 +421,7 @@ void UARTPort::close()
/// <returns></returns>
int UARTPort::setNonblock(bool nonblock)
{
int flag = ::fcntl(m_fd, F_GETFD, 0);
int flag = ::fcntl(m_fd, F_GETFL, 0);
if (nonblock)
flag |= O_NONBLOCK;
@ -530,6 +436,18 @@ int UARTPort::setNonblock(bool nonblock)
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
UARTPort::UARTPort(SERIAL_SPEED speed, bool assertRTS) :
m_isOpen(false),
m_speed(speed),
m_assertRTS(assertRTS),
#if defined(_WIN32) || defined(_WIN64)
m_handle(INVALID_HANDLE_VALUE)
#else
m_fd(-1)
#endif
{
/* stub */
}
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
@ -596,4 +514,107 @@ bool UARTPort::canWrite()
return true;
#endif
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool UARTPort::setTermios()
{
termios termios;
if (::tcgetattr(m_fd, &termios) < 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK);
termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
termios.c_oflag &= ~(OPOST);
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
termios.c_cflag |= (CS8 | CLOCAL | CREAD);
termios.c_lflag &= ~(ISIG | ICANON | IEXTEN);
termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
#if defined(__APPLE__)
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 1;
#else
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10;
#endif
switch (m_speed) {
case SERIAL_1200:
::cfsetospeed(&termios, B1200);
::cfsetispeed(&termios, B1200);
break;
case SERIAL_2400:
::cfsetospeed(&termios, B2400);
::cfsetispeed(&termios, B2400);
break;
case SERIAL_4800:
::cfsetospeed(&termios, B4800);
::cfsetispeed(&termios, B4800);
break;
case SERIAL_9600:
::cfsetospeed(&termios, B9600);
::cfsetispeed(&termios, B9600);
break;
case SERIAL_19200:
::cfsetospeed(&termios, B19200);
::cfsetispeed(&termios, B19200);
break;
case SERIAL_38400:
::cfsetospeed(&termios, B38400);
::cfsetispeed(&termios, B38400);
break;
case SERIAL_115200:
::cfsetospeed(&termios, B115200);
::cfsetispeed(&termios, B115200);
break;
case SERIAL_230400:
::cfsetospeed(&termios, B230400);
::cfsetispeed(&termios, B230400);
break;
case SERIAL_460800:
::cfsetospeed(&termios, B460800);
::cfsetispeed(&termios, B460800);
break;
default:
::LogError(LOG_HOST, "Unsupported serial port speed - %u", m_speed);
::close(m_fd);
return false;
}
if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) {
::LogError(LOG_HOST, "Cannot set the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
if (m_assertRTS) {
uint32_t y;
if (::ioctl(m_fd, TIOCMGET, &y) < 0) {
::LogError(LOG_HOST, "Cannot get the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
y |= TIOCM_RTS;
if (::ioctl(m_fd, TIOCMSET, &y) < 0) {
::LogError(LOG_HOST, "Cannot set the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
}
#if defined(__APPLE__)
setNonblock(false);
#endif
m_isOpen = true;
return true;
}
#endif

@ -94,6 +94,9 @@ namespace modem
#endif
protected:
/// <summary>Initializes a new instance of the UARTPort class.</summary>
UARTPort(SERIAL_SPEED speed, bool assertRTS = false);
bool m_isOpen;
std::string m_device;
@ -111,6 +114,9 @@ namespace modem
#else
/// <summary></summary>
bool canWrite();
/// <summary></summary>
bool setTermios();
#endif
}; // class HOST_SW_API UARTPort : public ISerialPort, public IModemPort
} // namespace port

Loading…
Cancel
Save

Powered by TurnKey Linux.