Merge branch 'FM_Ext' into AX25_FM

This commit is contained in:
Jonathan Naylor 2020-06-25 13:41:19 +01:00
commit 2953ce85a0
31 changed files with 2053 additions and 894 deletions

View file

@ -30,7 +30,7 @@ const unsigned int BUFFER_LENGTH = 500U;
CAX25Network::CAX25Network(const std::string& port, unsigned int speed, bool debug) :
m_serial(port, SERIAL_SPEED(speed), false), // XXX
m_serial(port, speed, false),
m_txData(NULL),
m_rxData(NULL),
m_rxLength(0U),

1490
Conf.cpp

File diff suppressed because it is too large Load diff

23
Conf.h
View file

@ -71,6 +71,7 @@ public:
// The Modem section
std::string getModemPort() const;
std::string getModemProtocol() const;
unsigned int getModemSpeed() const;
unsigned int getModemAddress() const;
bool getModemRXInvert() const;
bool getModemTXInvert() const;
@ -204,12 +205,14 @@ public:
unsigned int getFMCTCSSLowThreshold() const;
float getFMCTCSSLevel() const;
unsigned int getFMKerchunkTime() const;
bool getFMKerchunkTX() const;
unsigned int getFMHangTime() const;
bool getFMUseCOS() const;
bool getFMCOSInvert() const;
unsigned int getFMRFAudioBoost() const;
float getFMMaxDevLevel() const;
unsigned int getFMExtAudioBoost() const;
unsigned int getFMModeHang() const;
// The D-Star Network section
bool getDStarNetworkEnabled() const;
@ -268,6 +271,15 @@ public:
unsigned int getPOCSAGNetworkModeHang() const;
bool getPOCSAGNetworkDebug() const;
// The FM Network section
bool getFMNetworkEnabled() const;
std::string getFMGatewayAddress() const;
unsigned int getFMGatewayPort() const;
std::string getFMLocalAddress() const;
unsigned int getFMLocalPort() const;
unsigned int getFMNetworkModeHang() const;
bool getFMNetworkDebug() const;
// The AX.25 Network section
bool getAX25NetworkEnabled() const;
std::string getAX25NetworkPort() const;
@ -364,6 +376,7 @@ private:
std::string m_modemPort;
std::string m_modemProtocol;
unsigned int m_modemSpeed;
unsigned int m_modemAddress;
bool m_modemRXInvert;
bool m_modemTXInvert;
@ -487,12 +500,14 @@ private:
unsigned int m_fmCTCSSLowThreshold;
float m_fmCTCSSLevel;
unsigned int m_fmKerchunkTime;
bool m_fmKerchunkTX;
unsigned int m_fmHangTime;
bool m_fmUseCOS;
bool m_fmCOSInvert;
unsigned int m_fmRFAudioBoost;
float m_fmMaxDevLevel;
unsigned int m_fmExtAudioBoost;
unsigned int m_fmModeHang;
bool m_dstarNetworkEnabled;
std::string m_dstarGatewayAddress;
@ -545,6 +560,14 @@ private:
unsigned int m_pocsagNetworkModeHang;
bool m_pocsagNetworkDebug;
bool m_fmNetworkEnabled;
std::string m_fmGatewayAddress;
unsigned int m_fmGatewayPort;
std::string m_fmLocalAddress;
unsigned int m_fmLocalPort;
unsigned int m_fmNetworkModeHang;
bool m_fmNetworkDebug;
bool m_ax25NetworkEnabled;
std::string m_ax25NetworkPort;
unsigned int m_ax25NetworkSpeed;

View file

@ -511,7 +511,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem)
if (port == "modem")
serial = new CModemSerialPort(modem);
else
serial = new CSerialController(port, (type == "TFT Serial") ? SERIAL_9600 : SERIAL_115200);
serial = new CSerialController(port, (type == "TFT Serial") ? 9600U : 115200U);
if (type == "TFT Surenoo")
display = new CTFTSurenoo(conf.getCallsign(), dmrid, serial, brightness, conf.getDuplex());
@ -565,11 +565,11 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem)
display = new CNullDisplay;
}
} else {
SERIAL_SPEED baudrate = SERIAL_9600;
if (screenLayout&0x0cU)
baudrate = SERIAL_115200;
unsigned int baudrate = 9600U;
if (screenLayout == 4U)
baudrate = 115200U;
LogInfo(" Display baudrate: %u ",baudrate);
LogInfo(" Display baudrate: %u ", baudrate);
ISerialPort* serial = new CSerialController(port, baudrate);
display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
}

189
FMControl.cpp Normal file
View file

@ -0,0 +1,189 @@
/*
* Copyright (C) 2020 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 "FMControl.h"
#include <string>
#if defined(DUMP_RF_AUDIO)
#include <cstdio>
#endif
#define SWAP_BYTES_16(a) (((a >> 8) & 0x00FFU) | ((a << 8) & 0xFF00U))
const float DEEMPHASIS_GAIN_DB = 0.0F;
const float PREEMPHASIS_GAIN_DB = 13.0F;
const float FILTER_GAIN_DB = 0.0F;
const unsigned int FM_MASK = 0x00000FFFU;
CFMControl::CFMControl(CFMNetwork* network) :
m_network(network),
m_enabled(false),
m_incomingRFAudio(1600U, "Incoming RF FM Audio"),
m_preemphasis (NULL),
m_deemphasis (NULL),
m_filterStage1(NULL),
m_filterStage2(NULL),
m_filterStage3(NULL)
{
m_preemphasis = new CIIRDirectForm1Filter(8.315375384336983F,-7.03334621603483F,0.0F,1.0F,0.282029168302153F,0.0F, PREEMPHASIS_GAIN_DB);
m_deemphasis = new CIIRDirectForm1Filter(0.07708787090460224F,0.07708787090460224F,0.0F,1.0F,-0.8458242581907955F,0.0F, DEEMPHASIS_GAIN_DB);
//cheby type 1 0.2dB cheby type 1 3rd order 300-2700Hz fs=8000
m_filterStage1 = new CIIRDirectForm1Filter(0.29495028f, 0.0f, -0.29495028f, 1.0f, -0.61384624f, -0.057158668f, FILTER_GAIN_DB);
m_filterStage2 = new CIIRDirectForm1Filter(1.0f, 2.0f, 1.0f, 1.0f, 0.9946123f, 0.6050482f, FILTER_GAIN_DB);
m_filterStage3 = new CIIRDirectForm1Filter(1.0f, -2.0f, 1.0f, 1.0f, -1.8414584f, 0.8804949f, FILTER_GAIN_DB);
}
CFMControl::~CFMControl()
{
delete m_preemphasis ;
delete m_deemphasis ;
delete m_filterStage1;
delete m_filterStage2;
delete m_filterStage3;
}
bool CFMControl::writeModem(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_network == NULL)
return true;
if (data[0U] == TAG_HEADER)
return true;
if (data[0U] == TAG_EOT)
return m_network->writeEOT();
if (data[0U] != TAG_DATA)
return false;
m_incomingRFAudio.addData(data + 1U, length - 1U);
unsigned int bufferLength = m_incomingRFAudio.dataSize();
if (bufferLength > 252U)//168 samples 12-bit
bufferLength = 252U;
if (bufferLength >= 3U) {
bufferLength = bufferLength - bufferLength % 3U; //round down to nearest multiple of 3
unsigned char bufferData[252U];
m_incomingRFAudio.getData(bufferData, bufferLength);
unsigned int pack = 0U;
unsigned char* packPointer = (unsigned char*)&pack;
unsigned short out[168U];
unsigned int nOut = 0U;
short unpackedSamples[2U];
for (unsigned int i = 0U; i < bufferLength; i += 3U) {
//extract unsigned 12 bit unsigned sample pairs packed into 3 bytes to 16 bit signed
packPointer[0U] = bufferData[i];
packPointer[1U] = bufferData[i + 1U];
packPointer[2U] = bufferData[i + 2U];
unpackedSamples[1U] = short(int(pack & FM_MASK) - 2048);
unpackedSamples[0U] = short(int(pack >> 12) - 2048);
//process unpacked sample pair
for(unsigned char j = 0U; j < 2U; j++) {
//Convert to float (-1.0 to +1.0)
float sampleFloat = float(unpackedSamples[j]) / 2048.0F;
//De-emphasise and remove CTCSS
sampleFloat = m_deemphasis->filter(sampleFloat);
sampleFloat = m_filterStage3->filter(m_filterStage2->filter(m_filterStage1->filter(sampleFloat)));
// Repack the float data to 16 bit unsigned
unsigned short sampleUShort = (unsigned short)((sampleFloat + 1.0F) * 32767.0F + 0.5F);
out[nOut++] = SWAP_BYTES_16(sampleUShort);
}
}
#if defined(DUMP_RF_AUDIO)
FILE * audiofile = fopen("./audiodump.bin", "ab");
if(audiofile != NULL) {
fwrite(out, sizeof(unsigned short), nOut, audiofile);
fclose(audiofile);
}
#endif
return m_network->writeData((unsigned char*)out, nOut * sizeof(unsigned short));
}
return true;
}
unsigned int CFMControl::readModem(unsigned char* data, unsigned int space)
{
assert(data != NULL);
assert(space > 0U);
if (m_network == NULL)
return 0U;
if (space > 252U)
space = 252U;
unsigned short netData[168U];//modem can handle up to 168 samples at a time
unsigned int length = m_network->read((unsigned char*)netData, 168U * sizeof(unsigned short));
length /= sizeof(unsigned short);
if (length == 0U)
return 0U;
unsigned int pack = 0U;
unsigned char* packPointer = (unsigned char*)&pack;
unsigned int nData = 0U;
for(unsigned int i = 0; i < length; i++) {
unsigned short netSample = SWAP_BYTES_16(netData[i]);
// Convert the unsigned 16-bit data (+65535 - 0) to float (+1.0 - -1.0)
float sampleFloat = (float(netSample) / 32768.0F) - 1.0F;
//preemphasis
sampleFloat = m_preemphasis->filter(sampleFloat);
// Convert float to 12-bit samples (0 to 4095)
unsigned int sample12bit = (unsigned int)((sampleFloat + 1.0F) * 2048.0F + 0.5F);
// pack 2 samples onto 3 bytes
if((i & 1U) == 0) {
pack = 0U;
pack = sample12bit << 12;
} else {
pack |= sample12bit;
data[nData++] = packPointer[0U];
data[nData++] = packPointer[1U];
data[nData++] = packPointer[2U];
}
}
return nData;
}
void CFMControl::clock(unsigned int ms)
{
// May not be needed
}
void CFMControl::enable(bool enabled)
{
// May not be needed
}

55
FMControl.h Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2020 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(FMControl_H)
#define FMControl_H
#include "FMNetwork.h"
#include "Defines.h"
#include "IIRDirectForm1Filter.h"
// Uncomment this to dump audio to a raw audio file
// The file will be written in same folder as executable
// Toplay the file : ffplay -autoexit -f u16be -ar 8000 audiodump.bin
// #define DUMP_RF_AUDIO
class CFMControl {
public:
CFMControl(CFMNetwork* network);
~CFMControl();
bool writeModem(const unsigned char* data, unsigned int length);
unsigned int readModem(unsigned char* data, unsigned int space);
void clock(unsigned int ms);
void enable(bool enabled);
private:
CFMNetwork* m_network;
bool m_enabled;
CRingBuffer<unsigned char> m_incomingRFAudio;
CIIRDirectForm1Filter * m_preemphasis;
CIIRDirectForm1Filter * m_deemphasis;
CIIRDirectForm1Filter * m_filterStage1;
CIIRDirectForm1Filter * m_filterStage2;
CIIRDirectForm1Filter * m_filterStage3;
};
#endif

188
FMNetwork.cpp Normal file
View file

@ -0,0 +1,188 @@
/*
* Copyright (C) 2020 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 "FMNetwork.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 500U;
CFMNetwork::CFMNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(localAddress, localPort),
m_address(),
m_port(gatewayPort),
m_debug(debug),
m_enabled(false),
m_buffer(2000U, "FM Network"),
m_pollTimer(1000U, 5U)
{
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
m_address = CUDPSocket::lookup(gatewayAddress);
}
CFMNetwork::~CFMNetwork()
{
}
bool CFMNetwork::open()
{
LogMessage("Opening FM network connection");
if (m_address.s_addr == INADDR_NONE)
return false;
m_pollTimer.start();
return m_socket.open();
}
bool CFMNetwork::writeData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
unsigned char buffer[500U];
::memset(buffer, 0x00U, 500U);
buffer[0U] = 'F';
buffer[1U] = 'M';
buffer[2U] = 'D';
::memcpy(buffer + 3U, data, length);
if (m_debug)
CUtils::dump(1U, "FM Network Data Sent", buffer, length + 3U);
return m_socket.write(buffer, length + 3U, m_address, m_port);
}
bool CFMNetwork::writeEOT()
{
unsigned char buffer[10U];
::memset(buffer, 0x00U, 10U);
buffer[0U] = 'F';
buffer[1U] = 'M';
buffer[2U] = 'E';
if (m_debug)
CUtils::dump(1U, "FM Network End of Transmission Sent", buffer, 3U);
return m_socket.write(buffer, 3U, m_address, m_port);
}
void CFMNetwork::clock(unsigned int ms)
{
m_pollTimer.clock(ms);
if (m_pollTimer.hasExpired()) {
writePoll();
m_pollTimer.start();
}
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != m_port) {
LogMessage("FM packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Ignore incoming polls
if (::memcmp(buffer, "FMP", 3U) == 0)
return;
// Invalid packet type?
if (::memcmp(buffer, "FMD", 3U) != 0)
return;
if (!m_enabled)
return;
if (m_debug)
CUtils::dump(1U, "FM Network Data Received", buffer, length);
m_buffer.addData(buffer + 3U, length - 3U);
}
unsigned int CFMNetwork::read(unsigned char* data, unsigned int space)
{
assert(data != NULL);
unsigned int bytes = m_buffer.dataSize();
if (bytes == 0U)
return 0U;
if (bytes < space)
space = bytes;
//we store usignedshorts, therefore ensure we always return and even number of data
if(space > 0 && space % 2 != 0)
space--;//round down to multiple of 2
m_buffer.getData(data, space);
return space;
}
void CFMNetwork::reset()
{
}
void CFMNetwork::close()
{
m_socket.close();
LogMessage("Closing FM network connection");
}
void CFMNetwork::enable(bool enabled)
{
if (enabled && !m_enabled)
reset();
else if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}
bool CFMNetwork::writePoll()
{
unsigned char buffer[3U];
buffer[0U] = 'F';
buffer[1U] = 'M';
buffer[2U] = 'P';
if (m_debug)
CUtils::dump(1U, "FM Network Poll Sent", buffer, 3U);
return m_socket.write(buffer, 3U, m_address, m_port);
}

62
FMNetwork.h Normal file
View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2020 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.
*/
#ifndef FMNetwork_H
#define FMNetwork_H
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CFMNetwork {
public:
CFMNetwork(const std::string& myAddress, unsigned int myPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug);
~CFMNetwork();
bool open();
void enable(bool enabled);
bool writeData(const unsigned char* data, unsigned int length);
bool writeEOT();
unsigned int read(unsigned char* data, unsigned int space);
void reset();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
bool m_debug;
bool m_enabled;
CRingBuffer<unsigned char> m_buffer;
CTimer m_pollTimer;
bool writePoll();
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
*
* This program is free software; you can redistribute it and/or modify
@ -17,6 +17,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(__linux__)
#include "I2CController.h"
#include "Log.h"
@ -24,52 +26,18 @@
#include <cassert>
#include <sys/types.h>
#if defined(_WIN32) || defined(_WIN64)
#include <setupapi.h>
#include <winioctl.h>
CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
CSerialController(device, speed, assertRTS),
m_address(address)
{
}
CI2CController::~CI2CController()
{
}
bool CI2CController::open()
{
return CSerialController::open();
}
int CI2CController::read(unsigned char* buffer, unsigned int length)
{
return CSerialController::read(buffer, length);
}
int CI2CController::write(const unsigned char* buffer, unsigned int length)
{
return CSerialController::write(buffer, length);
}
#else
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#if defined(__linux__)
#include <linux/i2c-dev.h>
#endif
CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
CSerialController(device, speed, assertRTS),
m_address(address)
CI2CController::CI2CController(const std::string& device, unsigned int address) :
m_device(device),
m_address(address),
m_fd(-1)
{
}
@ -81,7 +49,6 @@ bool CI2CController::open()
{
assert(m_fd == -1);
#if defined(__linux__)
m_fd = ::open(m_device.c_str(), O_RDWR);
if (m_fd < 0) {
LogError("Cannot open device - %s", m_device.c_str());
@ -89,19 +56,16 @@ bool CI2CController::open()
}
if (::ioctl(m_fd, I2C_TENBIT, 0) < 0) {
LogError("CI2C: failed to set 7bitaddress");
LogError("I2C: failed to set 7bitaddress");
::close(m_fd);
return false;
}
if (::ioctl(m_fd, I2C_SLAVE, m_address) < 0) {
LogError("CI2C: Failed to acquire bus access/talk to slave 0x%02X", m_address);
LogError("I2C: Failed to acquire bus access/talk to slave 0x%02X", m_address);
::close(m_fd);
return false;
}
#else
#warning "I2C controller supports Linux only"
#endif
return true;
}
@ -117,7 +81,6 @@ int CI2CController::read(unsigned char* buffer, unsigned int length)
unsigned int offset = 0U;
while (offset < length) {
#if defined(__linux__)
ssize_t n = ::read(m_fd, buffer + offset, 1U);
if (n < 0) {
if (errno != EAGAIN) {
@ -128,7 +91,6 @@ int CI2CController::read(unsigned char* buffer, unsigned int length)
if (n > 0)
offset += n;
#endif
}
return length;
@ -144,10 +106,7 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length)
unsigned int ptr = 0U;
while (ptr < length) {
ssize_t n = 0U;
#if defined(__linux__)
n = ::write(m_fd, buffer + ptr, 1U);
#endif
ssize_t n = ::write(m_fd, buffer + ptr, 1U);
if (n < 0) {
if (errno != EAGAIN) {
LogError("Error returned from write(), errno=%d", errno);
@ -162,4 +121,12 @@ int CI2CController::write(const unsigned char* buffer, unsigned int length)
return length;
}
void CI2CController::close()
{
assert(m_fd != -1);
::close(m_fd);
m_fd = -1;
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
*
* This program is free software; you can redistribute it and/or modify
@ -20,11 +20,15 @@
#ifndef I2CController_H
#define I2CController_H
#include "SerialController.h"
#if defined(__linux__)
class CI2CController : public CSerialController {
#include "SerialPort.h"
#include <string>
class CI2CController : public ISerialPort {
public:
CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address = 0x22U, bool assertRTS = false);
CI2CController(const std::string& device, unsigned int address = 0x22U);
virtual ~CI2CController();
virtual bool open();
@ -33,8 +37,14 @@ public:
virtual int write(const unsigned char* buffer, unsigned int length);
virtual void close();
private:
std::string m_device;
unsigned int m_address;
int m_fd;
};
#endif
#endif

60
IIRDirectForm1Filter.cpp Normal file
View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck - F4FXL KC3FRA
*
* 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 "IIRDirectForm1Filter.h"
#include "math.h"
CIIRDirectForm1Filter::CIIRDirectForm1Filter(float b0, float b1, float b2, float , float a1, float a2, float addtionalGaindB) :
m_x2(0.0F),
m_y2(0.0F),
m_x1(0.0F),
m_y1(0.0F),
m_b0(b0),
m_b1(b1),
m_b2(b2),
m_a1(a1),
m_a2(a2),
m_additionalGainLin(0.0F)
{
m_additionalGainLin = ::powf(10.0F, addtionalGaindB / 20.0F);
}
float CIIRDirectForm1Filter::filter(float sample)
{
float output = m_b0 * sample
+ m_b1 * m_x1
+ m_b2 * m_x2
- m_a1 * m_y1
- m_a2 * m_y2;
m_x2 = m_x1;
m_y2 = m_y1;
m_x1 = sample;
m_y1 = output;
return output * m_additionalGainLin;
}
void CIIRDirectForm1Filter::reset()
{
m_x1 = 0.0f;
m_x2 = 0.0f;
m_y1 = 0.0f;
m_y2 = 0.0f;
}

50
IIRDirectForm1Filter.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck - F4FXL KC3FRA
*
* 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(IIRDIRECTFORM1FILTER_H)
#define IIRDIRECTFORM1FILTER_H
class CIIRDirectForm1Filter
{
public:
CIIRDirectForm1Filter(float b0, float b1, float b2, float, float a1, float a2, float additionalGaindB);
float filter(float sample);
void reset();
private:
// delay line
float m_x2; // x[n-2]
float m_y2; // y[n-2]
float m_x1; // x[n-1]
float m_y1; // y[n-1]
// coefficients
// FIR
float m_b0;
float m_b1;
float m_b2;
// IIR
float m_a1;
float m_a2;
float m_additionalGainLin;
};
#endif

View file

@ -45,6 +45,7 @@ Time=24
# Port=/dev/ttyAMA0
Port=\\.\COM4
Protocol=uart
Speed=115200
# Address=0x22
TXInvert=1
RXInvert=0
@ -169,12 +170,14 @@ CTCSSThreshold=30
# CTCSSLowThreshold=20
CTCSSLevel=20
KerchunkTime=0
KerchunkTX=1
HangTime=7
UseCOS=1
COSInvert=0
RFAudioBoost=1
MaxDevLevel=90
ExtAudioBoost=1
# ModeHang=10
[AX.25]
Enable=1
@ -239,6 +242,15 @@ GatewayPort=4800
# ModeHang=3
Debug=0
[FM Network]
Enable=1
LocalAddress=127.0.0.1
LocalPort=3810
GatewayAddress=127.0.0.1
GatewayPort=4810
# ModeHang=3
Debug=0
[AX.25 Network]
Enable=1
Port=/dev/ttyp7

View file

@ -121,6 +121,7 @@ m_ysf(NULL),
m_p25(NULL),
m_nxdn(NULL),
m_pocsag(NULL),
m_fm(NULL),
m_ax25(NULL),
m_dstarNetwork(NULL),
m_dmrNetwork(NULL),
@ -128,6 +129,7 @@ m_ysfNetwork(NULL),
m_p25Network(NULL),
m_nxdnNetwork(NULL),
m_pocsagNetwork(NULL),
m_fmNetwork(NULL),
m_ax25Network(NULL),
m_display(NULL),
m_ump(NULL),
@ -137,12 +139,14 @@ m_dmrRFModeHang(10U),
m_ysfRFModeHang(10U),
m_p25RFModeHang(10U),
m_nxdnRFModeHang(10U),
m_fmRFModeHang(10U),
m_dstarNetModeHang(3U),
m_dmrNetModeHang(3U),
m_ysfNetModeHang(3U),
m_p25NetModeHang(3U),
m_nxdnNetModeHang(3U),
m_pocsagNetModeHang(3U),
m_fmNetModeHang(3U),
m_modeTimer(1000U),
m_dmrTXTimer(1000U),
m_cwIdTimer(1000U),
@ -325,6 +329,12 @@ int CMMDVMHost::run()
return 1;
}
if (m_fmEnabled && m_conf.getFMNetworkEnabled()) {
ret = createFMNetwork();
if (!ret)
return 1;
}
if (m_ax25Enabled && m_conf.getAX25NetworkEnabled()) {
ret = createAX25Network();
if (!ret)
@ -638,6 +648,12 @@ int CMMDVMHost::run()
m_ax25 = new CAX25Control(m_ax25Network, trace);
}
if (m_fmEnabled) {
m_fmRFModeHang = m_conf.getFMModeHang();
m_fm = new CFMControl(m_fmNetwork);
}
bool remoteControlEnabled = m_conf.getRemoteControlEnabled();
if (remoteControlEnabled) {
unsigned int port = m_conf.getRemoteControlPort();
@ -675,12 +691,6 @@ int CMMDVMHost::run()
else if (!error && m_mode == MODE_ERROR)
setMode(MODE_IDLE);
unsigned char mode = m_modem->getMode();
if (mode == MODE_FM && m_mode != MODE_FM)
setMode(mode);
else if (mode != MODE_FM && m_mode == MODE_FM)
setMode(mode);
if (m_ump != NULL) {
bool tx = m_modem->hasTX();
m_ump->setTX(tx);
@ -830,11 +840,28 @@ int CMMDVMHost::run()
}
}
len = m_modem->readFMData(data);
if (m_fm != NULL && len > 0U) {
if (m_mode == MODE_IDLE) {
bool ret = m_fm->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_fmRFModeHang);
setMode(MODE_FM);
}
} else if (m_mode == MODE_FM) {
m_fm->writeModem(data, len);
m_modeTimer.start();
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("FM modem data received when in mode %u", m_mode);
}
}
len = m_modem->readAX25Data(data);
if (m_ax25 != NULL && len > 0U) {
if (m_mode == MODE_IDLE || m_mode == MODE_FM) {
m_ax25->writeModem(data, len);
} else if (m_mode != MODE_LOCKOUT) {
}
else if (m_mode != MODE_LOCKOUT) {
LogWarning("NXDN modem data received when in mode %u", m_mode);
}
}
@ -989,6 +1016,25 @@ int CMMDVMHost::run()
}
}
if (m_fm != NULL) {
unsigned int space = m_modem->getFMSpace();
if (space > 0U) {
len = m_fm->readModem(data, space);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_fmNetModeHang);
setMode(MODE_FM);
}
if (m_mode == MODE_FM) {
m_modem->writeFMData(data, len);
m_modeTimer.start();
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("FM data received when in mode %u", m_mode);
}
}
}
}
if (m_ax25 != NULL) {
ret = m_modem->hasAX25Space();
if (ret) {
@ -996,7 +1042,8 @@ int CMMDVMHost::run()
if (len > 0U) {
if (m_mode == MODE_IDLE || m_mode == MODE_FM) {
m_modem->writeAX25Data(data, len);
} else if (m_mode != MODE_LOCKOUT) {
}
else if (m_mode != MODE_LOCKOUT) {
LogWarning("AX.25 data received when in mode %u", m_mode);
}
}
@ -1035,6 +1082,8 @@ int CMMDVMHost::run()
m_nxdn->clock(ms);
if (m_pocsag != NULL)
m_pocsag->clock(ms);
if (m_fm != NULL)
m_fm->clock(ms);
if (m_dstarNetwork != NULL)
m_dstarNetwork->clock(ms);
@ -1048,6 +1097,8 @@ int CMMDVMHost::run()
m_nxdnNetwork->clock(ms);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->clock(ms);
if (m_fmNetwork != NULL)
m_fmNetwork->clock(ms);
if (m_mobileGPS != NULL)
m_mobileGPS->clock(ms);
@ -1173,6 +1224,11 @@ int CMMDVMHost::run()
delete m_pocsagNetwork;
}
if (m_fmNetwork != NULL) {
m_fmNetwork->close();
delete m_fmNetwork;
}
if (m_ax25Network != NULL) {
m_ax25Network->close();
delete m_ax25Network;
@ -1194,6 +1250,7 @@ int CMMDVMHost::run()
delete m_p25;
delete m_nxdn;
delete m_pocsag;
delete m_fm;
delete m_ax25;
return 0;
@ -1203,6 +1260,7 @@ bool CMMDVMHost::createModem()
{
std::string port = m_conf.getModemPort();
std::string protocol = m_conf.getModemProtocol();
unsigned int speed = m_conf.getModemSpeed();
unsigned int address = m_conf.getModemAddress();
bool rxInvert = m_conf.getModemRXInvert();
bool txInvert = m_conf.getModemTXInvert();
@ -1239,9 +1297,13 @@ bool CMMDVMHost::createModem()
LogInfo("Modem Parameters");
LogInfo(" Port: %s", port.c_str());
#if defined(__linux__)
LogInfo(" Protocol: %s", protocol.c_str());
if (protocol == "i2c")
LogInfo(" i2c Address: %02X", address);
LogInfo(" I2C Address: %02X", address);
else
#endif
LogInfo(" Speed: %u", speed);
LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no");
LogInfo(" TX Invert: %s", txInvert ? "yes" : "no");
LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no");
@ -1265,7 +1327,7 @@ bool CMMDVMHost::createModem()
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, trace, debug);
m_modem->setSerialParams(protocol,address);
m_modem->setSerialParams(protocol, address, speed);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled, m_ax25Enabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency);
@ -1287,7 +1349,6 @@ bool CMMDVMHost::createModem()
bool callsignAtEnd = m_conf.getFMCallsignAtEnd();
bool callsignAtLatch = m_conf.getFMCallsignAtLatch();
std::string rfAck = m_conf.getFMRFAck();
std::string extAck = m_conf.getFMExtAck();
unsigned int ackSpeed = m_conf.getFMAckSpeed();
unsigned int ackFrequency = m_conf.getFMAckFrequency();
unsigned int ackMinTime = m_conf.getFMAckMinTime();
@ -1300,12 +1361,13 @@ bool CMMDVMHost::createModem()
unsigned int ctcssLowThreshold = m_conf.getFMCTCSSLowThreshold();
float ctcssLevel = m_conf.getFMCTCSSLevel();
unsigned int kerchunkTime = m_conf.getFMKerchunkTime();
bool kerchunkTX = m_conf.getFMKerchunkTX();
unsigned int hangTime = m_conf.getFMHangTime();
bool useCOS = m_conf.getFMUseCOS();
bool cosInvert = m_conf.getFMCOSInvert();
unsigned int rfAudioBoost = m_conf.getFMRFAudioBoost();
float maxDevLevel = m_conf.getFMMaxDevLevel();
unsigned int extAudioBoost = m_conf.getFMExtAudioBoost();
unsigned int modeHangTime = m_conf.getFMModeHang();
LogInfo("FM Parameters");
LogInfo(" Callsign: %s", callsign.c_str());
@ -1319,7 +1381,6 @@ bool CMMDVMHost::createModem()
LogInfo(" Callsign At End: %s", callsignAtEnd ? "yes" : "no");
LogInfo(" Callsign At Latch: %s", callsignAtLatch ? "yes" : "no");
LogInfo(" RF Ack: %s", rfAck.c_str());
// LogInfo(" Ext. Ack: %s", extAck.c_str());
LogInfo(" Ack Speed: %uWPM", ackSpeed);
LogInfo(" Ack Frequency: %uHz", ackFrequency);
LogInfo(" Ack Min Time: %us", ackMinTime);
@ -1332,16 +1393,27 @@ bool CMMDVMHost::createModem()
LogInfo(" CTCSS Low Threshold: %u", ctcssLowThreshold);
LogInfo(" CTCSS Level: %.1f%%", ctcssLevel);
LogInfo(" Kerchunk Time: %us", kerchunkTime);
LogInfo(" Kerchunk TX: %s", kerchunkTX ? "yes" : "no");
LogInfo(" Hang Time: %us", hangTime);
LogInfo(" Use COS: %s", useCOS ? "yes" : "no");
LogInfo(" COS Invert: %s", cosInvert ? "yes" : "no");
LogInfo(" RF Audio Boost: x%u", rfAudioBoost);
LogInfo(" Max. Deviation Level: %.1f%%", maxDevLevel);
// LogInfo(" Ext. Audio Boost: x%u", extAudioBoost);
LogInfo(" Mode Hang: %us", modeHangTime);
m_modem->setFMCallsignParams(callsign, callsignSpeed, callsignFrequency, callsignTime, callsignHoldoff, callsignHighLevel, callsignLowLevel, callsignAtStart, callsignAtEnd, callsignAtLatch);
m_modem->setFMAckParams(rfAck, ackSpeed, ackFrequency, ackMinTime, ackDelay, ackLevel);
m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel);
m_modem->setFMMiscParams(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, kerchunkTX, hangTime, useCOS, cosInvert, rfAudioBoost, maxDevLevel);
if (m_conf.getFMNetworkEnabled()) {
std::string extAck = m_conf.getFMExtAck();
unsigned int extAudioBoost = m_conf.getFMExtAudioBoost();
LogInfo(" Ext. Ack: %s", extAck.c_str());
LogInfo(" Ext. Audio Boost: x%u", extAudioBoost);
m_modem->setFMExtParams(extAck, extAudioBoost);
}
}
bool ret = m_modem->open();
@ -1594,11 +1666,41 @@ bool CMMDVMHost::createPOCSAGNetwork()
return true;
}
bool CMMDVMHost::createFMNetwork()
{
std::string gatewayAddress = m_conf.getFMGatewayAddress();
unsigned int gatewayPort = m_conf.getFMGatewayPort();
std::string localAddress = m_conf.getFMLocalAddress();
unsigned int localPort = m_conf.getFMLocalPort();
m_fmNetModeHang = m_conf.getFMNetworkModeHang();
bool debug = m_conf.getFMNetworkDebug();
LogInfo("FM Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_fmNetModeHang);
m_fmNetwork = new CFMNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug);
bool ret = m_fmNetwork->open();
if (!ret) {
delete m_fmNetwork;
m_fmNetwork = NULL;
return false;
}
m_fmNetwork->enable(true);
return true;
}
bool CMMDVMHost::createAX25Network()
{
std::string port = m_conf.getAX25NetworkPort();
std::string port = m_conf.getAX25NetworkPort();
unsigned int speed = m_conf.getAX25NetworkSpeed();
bool debug = m_conf.getAX25NetworkDebug();
bool debug = m_conf.getAX25NetworkDebug();
LogInfo("AX.25 Network Parameters");
LogInfo(" Port: %s", port.c_str());
@ -1667,6 +1769,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1681,6 +1785,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_DSTAR);
@ -1705,6 +1811,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1719,6 +1827,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_DMR);
@ -1747,6 +1857,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1761,6 +1873,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_YSF);
@ -1785,6 +1899,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1799,6 +1915,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_P25);
@ -1823,6 +1941,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(true);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1837,6 +1957,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(true);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_NXDN);
@ -1861,6 +1983,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(true);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1875,6 +1999,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(true);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
m_modem->setMode(MODE_POCSAG);
@ -1899,6 +2025,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(true);
if (m_ax25Network != NULL)
m_ax25Network->enable(true);
if (m_dstar != NULL)
@ -1913,17 +2041,20 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(true);
if (m_ax25 != NULL)
m_ax25->enable(true);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false);
m_dmrTXTimer.stop();
}
m_modem->setMode(MODE_FM);
if (m_ump != NULL)
m_ump->setMode(MODE_FM);
m_display->setFM();
m_mode = MODE_FM;
m_modeTimer.stop();
m_modeTimer.start();
m_cwIdTimer.stop();
createLockFile("FM");
break;
@ -1941,6 +2072,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1955,6 +2088,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -1985,6 +2120,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(false);
if (m_ax25Network != NULL)
m_ax25Network->enable(false);
if (m_dstar != NULL)
@ -1999,6 +2136,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_fm != NULL)
m_fm->enable(false);
if (m_ax25 != NULL)
m_ax25->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -2027,6 +2166,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdnNetwork->enable(true);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(true);
if (m_fmNetwork != NULL)
m_fmNetwork->enable(true);
if (m_ax25Network != NULL)
m_ax25Network->enable(true);
if (m_dstar != NULL)
@ -2041,6 +2182,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_nxdn->enable(true);
if (m_pocsag != NULL)
m_pocsag->enable(true);
if (m_fm != NULL)
m_fm->enable(true);
if (m_ax25 != NULL)
m_ax25->enable(true);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -2121,38 +2264,38 @@ void CMMDVMHost::remoteControl()
processModeCommand(MODE_NXDN, m_nxdnRFModeHang);
break;
case RCD_MODE_FM:
if (m_fmEnabled != false)
if (m_fmEnabled)
processModeCommand(MODE_FM, 0);
break;
case RCD_ENABLE_DSTAR:
if (m_dstar != NULL && m_dstarEnabled==false)
if (m_dstar != NULL && !m_dstarEnabled)
processEnableCommand(m_dstarEnabled, true);
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(true);
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(true);
break;
case RCD_ENABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==false)
if (m_dmr != NULL && !m_dmrEnabled)
processEnableCommand(m_dmrEnabled, true);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(true);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(true);
break;
case RCD_ENABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==false)
if (m_ysf != NULL && !m_ysfEnabled)
processEnableCommand(m_ysfEnabled, true);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(true);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(true);
break;
case RCD_ENABLE_P25:
if (m_p25 != NULL && m_p25Enabled==false)
if (m_p25 != NULL && !m_p25Enabled)
processEnableCommand(m_p25Enabled, true);
if (m_p25Network != NULL)
m_p25Network->enable(true);
if (m_p25Network != NULL)
m_p25Network->enable(true);
break;
case RCD_ENABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==false)
if (m_nxdn != NULL && !m_nxdnEnabled)
processEnableCommand(m_nxdnEnabled, true);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
break;
case RCD_ENABLE_FM:
if (!m_fmEnabled)
@ -2163,37 +2306,37 @@ void CMMDVMHost::remoteControl()
processEnableCommand(m_ax25Enabled, true);
break;
case RCD_DISABLE_DSTAR:
if (m_dstar != NULL && m_dstarEnabled==true)
if (m_dstar != NULL && m_dstarEnabled)
processEnableCommand(m_dstarEnabled, false);
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
break;
case RCD_DISABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==true)
if (m_dmr != NULL && m_dmrEnabled)
processEnableCommand(m_dmrEnabled, false);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(false);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(false);
break;
case RCD_DISABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==true)
if (m_ysf != NULL && m_ysfEnabled)
processEnableCommand(m_ysfEnabled, false);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(false);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(false);
break;
case RCD_DISABLE_P25:
if (m_p25 != NULL && m_p25Enabled==true)
if (m_p25 != NULL && m_p25Enabled)
processEnableCommand(m_p25Enabled, false);
if (m_p25Network != NULL)
m_p25Network->enable(false);
if (m_p25Network != NULL)
m_p25Network->enable(false);
break;
case RCD_DISABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==true)
if (m_nxdn != NULL && m_nxdnEnabled)
processEnableCommand(m_nxdnEnabled, false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
break;
case RCD_DISABLE_FM:
if (m_fmEnabled == true)
if (m_fmEnabled)
processEnableCommand(m_fmEnabled, false);
break;
case RCD_DISABLE_AX25:

View file

@ -35,8 +35,10 @@
#include "YSFNetwork.h"
#include "P25Network.h"
#include "DMRNetwork.h"
#include "FMNetwork.h"
#include "DMRLookup.h"
#include "MobileGPS.h"
#include "FMControl.h"
#include "Display.h"
#include "Timer.h"
#include "Modem.h"
@ -64,6 +66,7 @@ private:
CP25Control* m_p25;
CNXDNControl* m_nxdn;
CPOCSAGControl* m_pocsag;
CFMControl* m_fm;
CAX25Control* m_ax25;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
@ -71,6 +74,7 @@ private:
CP25Network* m_p25Network;
INXDNNetwork* m_nxdnNetwork;
CPOCSAGNetwork* m_pocsagNetwork;
CFMNetwork* m_fmNetwork;
CAX25Network* m_ax25Network;
CDisplay* m_display;
CUMP* m_ump;
@ -80,12 +84,14 @@ private:
unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang;
unsigned int m_nxdnRFModeHang;
unsigned int m_fmRFModeHang;
unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang;
unsigned int m_nxdnNetModeHang;
unsigned int m_pocsagNetModeHang;
unsigned int m_fmNetModeHang;
CTimer m_modeTimer;
CTimer m_dmrTXTimer;
CTimer m_cwIdTimer;
@ -119,6 +125,7 @@ private:
bool createP25Network();
bool createNXDNNetwork();
bool createPOCSAGNetwork();
bool createFMNetwork();
bool createAX25Network();
void remoteControl();

View file

@ -184,11 +184,13 @@
<ClInclude Include="DStarHeader.h" />
<ClInclude Include="DStarNetwork.h" />
<ClInclude Include="DStarSlowData.h" />
<ClInclude Include="FMControl.h" />
<ClInclude Include="FMNetwork.h" />
<ClInclude Include="Golay2087.h" />
<ClInclude Include="Golay24128.h" />
<ClInclude Include="Hamming.h" />
<ClInclude Include="DMRLookup.h" />
<ClInclude Include="I2CController.h" />
<ClInclude Include="IIRDirectForm1Filter.h" />
<ClInclude Include="LCDproc.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="MMDVMHost.h" />
@ -284,10 +286,12 @@
<ClCompile Include="DStarHeader.cpp" />
<ClCompile Include="DStarNetwork.cpp" />
<ClCompile Include="DStarSlowData.cpp" />
<ClCompile Include="FMControl.cpp" />
<ClCompile Include="FMNetwork.cpp" />
<ClCompile Include="Golay2087.cpp" />
<ClCompile Include="Golay24128.cpp" />
<ClCompile Include="Hamming.cpp" />
<ClCompile Include="I2CController.cpp" />
<ClCompile Include="IIRDirectForm1Filter.cpp" />
<ClCompile Include="LCDproc.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="MMDVMHost.cpp" />

View file

@ -275,9 +275,6 @@
<ClInclude Include="POCSAGDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="I2CController.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MobileGPS.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -314,6 +311,15 @@
<ClInclude Include="AX25Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMControl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IIRDirectForm1Filter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -553,9 +559,6 @@
<ClCompile Include="POCSAGControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="I2CController.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MobileGPS.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -589,5 +592,14 @@
<ClCompile Include="NXDNKenwoodNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FMNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FMControl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IIRDirectForm1Filter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -9,12 +9,12 @@ LDFLAGS = -g
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \
NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \
P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \
SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o \
YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \
YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost RemoteCommand

View file

@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \

View file

@ -10,8 +10,8 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \

View file

@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \

View file

@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o I2CController.o IIRDirectForm1Filter.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \

View file

@ -10,8 +10,8 @@ LDFLAGS = -g -L/usr/local/lib
OBJECTS = AX25Control.o AX25Network.o \
AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \
DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \
DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \
NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \
DStarSlowData.o FMControl.o FMNetwork.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o IIRDirectForm1Filter.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o \
ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o \
NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \
P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \

236
Modem.cpp
View file

@ -16,7 +16,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "SerialController.h"
#if defined(__linux__)
#include "I2CController.h"
#endif
#include "DStarDefines.h"
#include "DMRDefines.h"
#include "YSFDefines.h"
@ -82,6 +85,10 @@ const unsigned char MMDVM_AX25_DATA = 0x55U;
const unsigned char MMDVM_FM_PARAMS1 = 0x60U;
const unsigned char MMDVM_FM_PARAMS2 = 0x61U;
const unsigned char MMDVM_FM_PARAMS3 = 0x62U;
const unsigned char MMDVM_FM_PARAMS4 = 0x63U;
const unsigned char MMDVM_FM_DATA = 0x65U;
const unsigned char MMDVM_FM_CONTROL = 0x66U;
const unsigned char MMDVM_FM_EOT = 0x67U;
const unsigned char MMDVM_ACK = 0x70U;
const unsigned char MMDVM_NAK = 0x7FU;
@ -160,6 +167,8 @@ m_txP25Data(1000U, "Modem TX P25"),
m_rxNXDNData(1000U, "Modem RX NXDN"),
m_txNXDNData(1000U, "Modem TX NXDN"),
m_txPOCSAGData(1000U, "Modem TX POCSAG"),
m_rxFMData(5000U, "Modem RX FM"),
m_txFMData(5000U, "Modem TX FM"),
m_rxAX25Data(1000U, "Modem RX AX.25"),
m_txAX25Data(1000U, "Modem TX AX.25"),
m_rxTransparentData(1000U, "Modem RX Transparent"),
@ -175,6 +184,7 @@ m_ysfSpace(0U),
m_p25Space(0U),
m_nxdnSpace(0U),
m_pocsagSpace(0U),
m_fmSpace(0U),
m_ax25Space(0U),
m_tx(false),
m_cd(false),
@ -195,6 +205,7 @@ m_fmCallsignAtStart(true),
m_fmCallsignAtEnd(true),
m_fmCallsignAtLatch(true),
m_fmRfAck("K"),
m_fmExtAck("N"),
m_fmAckSpeed(20U),
m_fmAckFrequency(1750U),
m_fmAckMinTime(4U),
@ -207,11 +218,14 @@ m_fmCtcssHighThreshold(30U),
m_fmCtcssLowThreshold(20U),
m_fmCtcssLevel(10.0F),
m_fmKerchunkTime(0U),
m_fmKerchunkTX(true),
m_fmHangTime(5U),
m_fmUseCOS(true),
m_fmCOSInvert(false),
m_fmRFAudioBoost(1U),
m_fmMaxDevLevel(90.0F)
m_fmExtAudioBoost(1U),
m_fmMaxDevLevel(90.0F),
m_fmExtEnable(false)
{
m_buffer = new unsigned char[BUFFER_LENGTH];
@ -224,13 +238,15 @@ CModem::~CModem()
delete[] m_buffer;
}
void CModem::setSerialParams(const std::string& protocol, unsigned int address)
void CModem::setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed)
{
// Create the serial controller instance according the protocol specified in conf.
#if defined(__linux__)
if (protocol == "i2c")
m_serial = new CI2CController(m_port, SERIAL_115200, address, true);
m_serial = new CI2CController(m_port, address);
else
m_serial = new CSerialController(m_port, SERIAL_115200, true);
#endif
m_serial = new CSerialController(m_port, speed, true);
}
void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency)
@ -363,6 +379,16 @@ bool CModem::open()
m_serial = NULL;
return false;
}
if (m_fmExtEnable) {
ret = setFMExtParams();
if (!ret) {
m_serial->close();
delete m_serial;
m_serial = NULL;
return false;
}
}
}
m_statusTimer.start();
@ -408,7 +434,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX D-Star Header", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxDStarData.addData(&data, 1U);
data = TAG_HEADER;
@ -422,7 +448,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX D-Star Data", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxDStarData.addData(&data, 1U);
data = TAG_DATA;
@ -460,7 +486,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX DMR Data 1", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxDMRData1.addData(&data, 1U);
if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC))
@ -477,7 +503,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX DMR Data 2", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxDMRData2.addData(&data, 1U);
if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC))
@ -518,7 +544,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX YSF Data", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxYSFData.addData(&data, 1U);
data = TAG_DATA;
@ -544,7 +570,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX P25 Header", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxP25Data.addData(&data, 1U);
data = TAG_HEADER;
@ -558,7 +584,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxP25Data.addData(&data, 1U);
data = TAG_DATA;
@ -584,7 +610,7 @@ void CModem::clock(unsigned int ms)
if (m_trace)
CUtils::dump(1U, "RX NXDN Data", m_buffer, m_length);
unsigned char data = m_length - 2U;
unsigned char data = m_length - m_offset + 1U;
m_rxNXDNData.addData(&data, 1U);
data = TAG_DATA;
@ -606,12 +632,54 @@ void CModem::clock(unsigned int ms)
}
break;
case MMDVM_FM_DATA: {
if (m_trace)
CUtils::dump(1U, "RX FM Data", m_buffer, m_length);
unsigned int data1 = m_length - m_offset + 1U;
m_rxFMData.addData((unsigned char*)&data1, sizeof(unsigned int));
unsigned char data2 = TAG_DATA;
m_rxFMData.addData(&data2, 1U);
m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset);
}
break;
case MMDVM_FM_CONTROL: {
if (m_trace)
CUtils::dump(1U, "RX FM Control", m_buffer, m_length);
unsigned char data = m_length - m_offset + 1U;
m_rxFMData.addData(&data, 1U);
data = TAG_HEADER;
m_rxFMData.addData(&data, 1U);
m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset);
}
break;
case MMDVM_FM_EOT: {
if(m_trace)
CUtils::dump(1U, "RX FM End of transmission", m_buffer, m_length);
unsigned char data = m_length - m_offset + 1U;
m_rxFMData.addData(&data, 1U);
data = TAG_EOT;
m_rxFMData.addData(&data, 1U);
m_rxFMData.addData(m_buffer + m_offset, m_length - m_offset);
}
break;
case MMDVM_AX25_DATA: {
if (m_trace)
CUtils::dump(1U, "RX AX.25 Data", m_buffer, m_length);
unsigned char data = m_length - 3U;
m_rxAX25Data.addData(&data, 1U);
unsigned int data = m_length - m_offset;
m_rxAX25Data.addData((unsigned char*)&data, sizeof(unsigned int));
m_rxAX25Data.addData(m_buffer + m_offset, m_length - m_offset);
}
@ -624,6 +692,7 @@ void CModem::clock(unsigned int ms)
m_p25Space = 0U;
m_nxdnSpace = 0U;
m_pocsagSpace = 0U;
m_fmSpace = 0U;
m_ax25Space = 0U;
m_mode = m_buffer[m_offset + 1U];
@ -662,10 +731,12 @@ void CModem::clock(unsigned int ms)
if (m_length > (m_offset + 9U))
m_pocsagSpace = m_buffer[m_offset + 9U];
if (m_length > (m_offset + 10U))
m_ax25Space = m_buffer[m_offset + 10U] * 8U;
m_fmSpace = m_buffer[m_offset + 10U];
if (m_length > (m_offset + 11U))
m_ax25Space = m_buffer[m_offset + 11U];
m_inactivityTimer.start();
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_ax25Space, int(m_lockout), int(m_cd));
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[m_offset + 2U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, m_fmSpace, m_ax25Space, int(m_lockout), int(m_cd));
}
break;
@ -869,6 +940,23 @@ void CModem::clock(unsigned int ms)
m_pocsagSpace--;
}
if (m_fmSpace > 1U && !m_txFMData.isEmpty()) {
unsigned char len = 0U;
m_txFMData.getData(&len, 1U);
m_txFMData.getData(m_buffer, len);
if (m_trace)
CUtils::dump(1U, "TX FM Data", m_buffer, len);
int ret = m_serial->write(m_buffer, len);
if (ret != int(len))
LogWarning("Error when writing FM data to the MMDVM");
m_playoutTimer.start();
m_fmSpace--;
}
if (m_ax25Space > 0U && !m_txAX25Data.isEmpty()) {
unsigned char len = 0U;
m_txAX25Data.getData((unsigned char*)&len, sizeof(unsigned int));
@ -993,6 +1081,20 @@ unsigned int CModem::readNXDNData(unsigned char* data)
return len;
}
unsigned int CModem::readFMData(unsigned char* data)
{
assert(data != NULL);
if (m_rxFMData.isEmpty())
return 0U;
unsigned int len = 0U;
m_rxFMData.getData((unsigned char*)&len, sizeof(unsigned int));
m_rxFMData.getData(data, len);
return len;
}
unsigned int CModem::readAX25Data(unsigned char* data)
{
assert(data != NULL);
@ -1000,8 +1102,8 @@ unsigned int CModem::readAX25Data(unsigned char* data)
if (m_rxAX25Data.isEmpty())
return 0U;
unsigned char len = 0U;
m_rxAX25Data.getData(&len, 1U);
unsigned int len = 0U;
m_rxAX25Data.getData((unsigned char*)&len, sizeof(unsigned int));
m_rxAX25Data.getData(data, len);
return len;
@ -1248,6 +1350,40 @@ bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length)
return true;
}
unsigned int CModem::getFMSpace() const
{
return m_txFMData.freeSpace();
}
bool CModem::writeFMData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
unsigned char buffer[500U];
unsigned int len;
if (length > 252U) {
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 0U;
buffer[2U] = (length + 4U) - 255U;
buffer[3U] = MMDVM_FM_DATA;
::memcpy(buffer + 4U, data, length);
len = length + 4U;
} else {
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = length + 3U;
buffer[2U] = MMDVM_FM_DATA;
::memcpy(buffer + 3U, data, length);
len = length + 3U;
}
m_txFMData.addData((unsigned char*)&len, sizeof(unsigned int));
m_txFMData.addData(buffer, len);
return true;
}
bool CModem::hasAX25Space() const
{
unsigned int space = m_txAX25Data.freeSpace() / (AX25_MAX_FRAME_LENGTH_BYTES + 5U);
@ -2044,7 +2180,7 @@ void CModem::setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, uns
m_fmAckLevel = ackLevel;
}
void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel)
void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel)
{
m_fmTimeout = timeout;
m_fmTimeoutLevel = timeoutLevel;
@ -2055,6 +2191,8 @@ void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctc
m_fmCtcssLevel = ctcssLevel;
m_fmKerchunkTime = kerchunkTime;
m_fmKerchunkTX = kerchunkTX;
m_fmHangTime = hangTime;
m_fmUseCOS = useCOS;
@ -2064,6 +2202,13 @@ void CModem::setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctc
m_fmMaxDevLevel = maxDevLevel;
}
void CModem::setFMExtParams(const std::string& ack, unsigned int audioBoost)
{
m_fmExtAck = ack;
m_fmExtAudioBoost = audioBoost;
m_fmExtEnable = true;
}
bool CModem::setFMCallsignParams()
{
assert(m_serial != NULL);
@ -2203,6 +2348,8 @@ bool CModem::setFMMiscParams()
buffer[11U] |= 0x01U;
if (m_fmCOSInvert)
buffer[11U] |= 0x02U;
if (m_fmKerchunkTX)
buffer[11U] |= 0x04U;
buffer[12U] = m_fmRFAudioBoost;
@ -2241,6 +2388,57 @@ bool CModem::setFMMiscParams()
return true;
}
bool CModem::setFMExtParams()
{
assert(m_serial != NULL);
unsigned char buffer[80U];
unsigned char len = 7U + m_fmExtAck.size();
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = len;
buffer[2U] = MMDVM_FM_PARAMS4;
buffer[3U] = m_fmExtAudioBoost;
buffer[4U] = m_fmAckSpeed;
buffer[5U] = m_fmAckFrequency / 10U;
buffer[6U] = (unsigned char)(m_fmAckLevel * 2.55F + 0.5F);
for (unsigned int i = 0U; i < m_fmExtAck.size(); i++)
buffer[7U + i] = m_fmExtAck.at(i);
// CUtils::dump(1U, "Written", buffer, len);
int ret = m_serial->write(buffer, len);
if (ret != len)
return false;
unsigned int count = 0U;
RESP_TYPE_MMDVM resp;
do {
CThread::sleep(10U);
resp = getResponse();
if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) {
count++;
if (count >= MAX_RESPONSES) {
LogError("The MMDVM is not responding to the SET_FM_PARAMS4 command");
return false;
}
}
} while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK);
// CUtils::dump(1U, "Response", m_buffer, m_length);
if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) {
LogError("Received a NAK to the SET_FM_PARAMS4 command from the modem");
return false;
}
return true;
}
void CModem::printDebug()
{
if (m_buffer[2U] == MMDVM_DEBUG1) {

20
Modem.h
View file

@ -19,7 +19,7 @@
#ifndef MODEM_H
#define MODEM_H
#include "SerialController.h"
#include "SerialPort.h"
#include "RingBuffer.h"
#include "Defines.h"
#include "Timer.h"
@ -45,7 +45,7 @@ public:
CModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int dmrDelay, bool trace, bool debug);
virtual ~CModem();
virtual void setSerialParams(const std::string& protocol, unsigned int address);
virtual void setSerialParams(const std::string& protocol, unsigned int address, unsigned int speed);
virtual void setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int txFrequency, int txOffset, int txDCOffset, int rxDCOffset, float rfLevel, unsigned int pocsagFrequency);
virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled, bool ax25Enabled);
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel, float ax25TXLevel);
@ -58,7 +58,8 @@ public:
virtual void setFMCallsignParams(const std::string& callsign, unsigned int callsignSpeed, unsigned int callsignFrequency, unsigned int callsignTime, unsigned int callsignHoldoff, float callsignHighLevel, float callsignLowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
virtual void setFMAckParams(const std::string& rfAck, unsigned int ackSpeed, unsigned int ackFrequency, unsigned int ackMinTime, unsigned int ackDelay, float ackLevel);
virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel);
virtual void setFMMiscParams(unsigned int timeout, float timeoutLevel, float ctcssFrequency, unsigned int ctcssHighThreshold, unsigned int ctcssLowThreshold, float ctcssLevel, unsigned int kerchunkTime, bool kerchunkTX, unsigned int hangTime, bool useCOS, bool cosInvert, unsigned int rfAudioBoost, float maxDevLevel);
virtual void setFMExtParams(const std::string& ack, unsigned int audioBoost);
virtual bool open();
@ -68,6 +69,7 @@ public:
virtual unsigned int readYSFData(unsigned char* data);
virtual unsigned int readP25Data(unsigned char* data);
virtual unsigned int readNXDNData(unsigned char* data);
virtual unsigned int readFMData(unsigned char* data);
virtual unsigned int readAX25Data(unsigned char* data);
virtual unsigned int readTransparentData(unsigned char* data);
@ -80,6 +82,7 @@ public:
virtual bool hasP25Space() const;
virtual bool hasNXDNSpace() const;
virtual bool hasPOCSAGSpace() const;
virtual unsigned int getFMSpace() const;
virtual bool hasAX25Space() const;
virtual bool hasTX() const;
@ -96,6 +99,7 @@ public:
virtual bool writeP25Data(const unsigned char* data, unsigned int length);
virtual bool writeNXDNData(const unsigned char* data, unsigned int length);
virtual bool writePOCSAGData(const unsigned char* data, unsigned int length);
virtual bool writeFMData(const unsigned char* data, unsigned int length);
virtual bool writeAX25Data(const unsigned char* data, unsigned int length);
virtual bool writeTransparentData(const unsigned char* data, unsigned int length);
@ -166,7 +170,7 @@ private:
bool m_ax25Enabled;
int m_rxDCOffset;
int m_txDCOffset;
CSerialController* m_serial;
ISerialPort* m_serial;
unsigned char* m_buffer;
unsigned int m_length;
unsigned int m_offset;
@ -185,6 +189,8 @@ private:
CRingBuffer<unsigned char> m_rxNXDNData;
CRingBuffer<unsigned char> m_txNXDNData;
CRingBuffer<unsigned char> m_txPOCSAGData;
CRingBuffer<unsigned char> m_rxFMData;
CRingBuffer<unsigned char> m_txFMData;
CRingBuffer<unsigned char> m_rxAX25Data;
CRingBuffer<unsigned char> m_txAX25Data;
CRingBuffer<unsigned char> m_rxTransparentData;
@ -200,6 +206,7 @@ private:
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_pocsagSpace;
unsigned int m_fmSpace;
unsigned int m_ax25Space;
bool m_tx;
bool m_cd;
@ -221,6 +228,7 @@ private:
bool m_fmCallsignAtEnd;
bool m_fmCallsignAtLatch;
std::string m_fmRfAck;
std::string m_fmExtAck;
unsigned int m_fmAckSpeed;
unsigned int m_fmAckFrequency;
unsigned int m_fmAckMinTime;
@ -233,11 +241,14 @@ private:
unsigned int m_fmCtcssLowThreshold;
float m_fmCtcssLevel;
unsigned int m_fmKerchunkTime;
bool m_fmKerchunkTX;
unsigned int m_fmHangTime;
bool m_fmUseCOS;
bool m_fmCOSInvert;
unsigned int m_fmRFAudioBoost;
unsigned int m_fmExtAudioBoost;
float m_fmMaxDevLevel;
bool m_fmExtEnable;
bool readVersion();
bool readStatus();
@ -246,6 +257,7 @@ private:
bool setFMCallsignParams();
bool setFMAckParams();
bool setFMMiscParams();
bool setFMExtParams();
void printDebug();

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2019 by Jonathan Naylor G4KLX
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017,2019,2020 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
*
* This program is free software; you can redistribute it and/or modify
@ -23,12 +23,11 @@
#include <cstring>
#include <cassert>
#include <sys/types.h>
#if defined(_WIN32) || defined(_WIN64)
#include <setupapi.h>
#include <winioctl.h>
#else
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cerrno>
@ -40,7 +39,7 @@
#if defined(_WIN32) || defined(_WIN64)
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
CSerialController::CSerialController(const std::string& device, unsigned int speed, bool assertRTS) :
m_device(device),
m_speed(speed),
m_assertRTS(assertRTS),
@ -221,7 +220,7 @@ void CSerialController::close()
#else
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
CSerialController::CSerialController(const std::string& device, unsigned int speed, bool assertRTS) :
m_device(device),
m_speed(speed),
m_assertRTS(assertRTS),
@ -273,40 +272,44 @@ bool CSerialController::open()
#endif
switch (m_speed) {
case SERIAL_1200:
case 1200U:
::cfsetospeed(&termios, B1200);
::cfsetispeed(&termios, B1200);
break;
case SERIAL_2400:
case 2400U:
::cfsetospeed(&termios, B2400);
::cfsetispeed(&termios, B2400);
break;
case SERIAL_4800:
case 4800U:
::cfsetospeed(&termios, B4800);
::cfsetispeed(&termios, B4800);
break;
case SERIAL_9600:
case 9600U:
::cfsetospeed(&termios, B9600);
::cfsetispeed(&termios, B9600);
break;
case SERIAL_19200:
case 19200U:
::cfsetospeed(&termios, B19200);
::cfsetispeed(&termios, B19200);
break;
case SERIAL_38400:
case 38400U:
::cfsetospeed(&termios, B38400);
::cfsetispeed(&termios, B38400);
break;
case SERIAL_115200:
case 115200U:
::cfsetospeed(&termios, B115200);
::cfsetispeed(&termios, B115200);
break;
case SERIAL_230400:
case 230400U:
::cfsetospeed(&termios, B230400);
::cfsetispeed(&termios, B230400);
break;
case 460800U:
::cfsetospeed(&termios, B460800);
::cfsetispeed(&termios, B460800);
break;
default:
LogError("Unsupported serial port speed - %d", int(m_speed));
LogError("Unsupported serial port speed - %u", m_speed);
::close(m_fd);
return false;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
*
* This program is free software; you can redistribute it and/or modify
@ -28,21 +28,9 @@
#include <windows.h>
#endif
enum SERIAL_SPEED {
SERIAL_1200 = 1200,
SERIAL_2400 = 2400,
SERIAL_4800 = 4800,
SERIAL_9600 = 9600,
SERIAL_19200 = 19200,
SERIAL_38400 = 38400,
SERIAL_76800 = 76800,
SERIAL_115200 = 115200,
SERIAL_230400 = 230400
};
class CSerialController : public ISerialPort {
public:
CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS = false);
CSerialController(const std::string& device, unsigned int speed, bool assertRTS = false);
virtual ~CSerialController();
virtual bool open();
@ -59,7 +47,7 @@ public:
protected:
std::string m_device;
SERIAL_SPEED m_speed;
unsigned int m_speed;
bool m_assertRTS;
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;

43
Tools/DeEmphasis.py Normal file
View file

@ -0,0 +1,43 @@
#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py
import math
import cmath
import numpy as np
import scipy.signal as signal
import pylab as pl
tau = 750e-6
fs = 8000
fh = 2700
# Digital corner frequency
w_c = 1.0 / tau
# Prewarped analog corner frequency
w_ca = 2.0 * fs * math.tan(w_c / (2.0 * fs))
# Resulting digital pole, zero, and gain term from the bilinear
# transformation of H(s) = w_ca / (s + w_ca) to
# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
k = -w_ca / (2.0 * fs)
z1 = -1.0
p1 = (1.0 + k) / (1.0 - k)
b0 = -k / (1.0 - k)
btaps = [ b0 * 1.0, b0 * -z1, 0 ]
ataps = [ 1.0, -p1, 0 ]
# Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC
taps = np.concatenate((btaps, ataps), axis=0)
print("Taps")
print(*taps, "", sep=",", end="\n")
f,h = signal.freqz(btaps,ataps, fs=fs)
pl.plot(f, 20*np.log10(np.abs(h)))
pl.xlabel('frequency/Hz')
pl.ylabel('gain/dB')
pl.ylim(top=0,bottom=-30)
pl.xlim(left=0, right=fh*2.5)
pl.show()

51
Tools/PreEmphasis.py Normal file
View file

@ -0,0 +1,51 @@
#based on https://github.com/gnuradio/gnuradio/blob/master/gr-analog/python/analog/fm_emph.py
import math
import cmath
import numpy as np
import scipy.signal as signal
import pylab as pl
tau = 750e-6
fs = 8000
fh = 2700
# Digital corner frequencies
w_cl = 1.0 / tau
w_ch = 2.0 * math.pi * fh
# Prewarped analog corner frequencies
w_cla = 2.0 * fs * math.tan(w_cl / (2.0 * fs))
w_cha = 2.0 * fs * math.tan(w_ch / (2.0 * fs))
# Resulting digital pole, zero, and gain term from the bilinear
# transformation of H(s) = (s + w_cla) / (s + w_cha) to
# H(z) = b0 (1 - z1 z^-1)/(1 - p1 z^-1)
kl = -w_cla / (2.0 * fs)
kh = -w_cha / (2.0 * fs)
z1 = (1.0 + kl) / (1.0 - kl)
p1 = (1.0 + kh) / (1.0 - kh)
b0 = (1.0 - kl) / (1.0 - kh)
# Since H(s = infinity) = 1.0, then H(z = -1) = 1.0 and
# this filter has 0 dB gain at fs/2.0.
# That isn't what users are going to expect, so adjust with a
# gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC.
w_0dB = 2.0 * math.pi * 0.0
g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \
/ (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB)))
btaps = [ g * b0 * 1.0, g * b0 * -z1, 0]
ataps = [ 1.0, -p1, 0]
taps = np.concatenate((btaps, ataps), axis=0)
print("Taps")
print(*taps, "", sep=",", end="\n")
f,h = signal.freqz(btaps,ataps, fs=fs)
pl.plot(f, 20*np.log10(np.abs(h)))
pl.xlabel('frequency/Hz')
pl.ylabel('gain/dB')
pl.ylim(top=30,bottom=0)
pl.xlim(left=0, right=fh*2.5)
pl.show()

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2020 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
@ -41,7 +41,7 @@ const unsigned char UMP_STATUS = 0x50U;
const unsigned int BUFFER_LENGTH = 255U;
CUMP::CUMP(const std::string& port) :
m_serial(port, SERIAL_115200),
m_serial(port, 115200U),
m_open(false),
m_buffer(NULL),
m_length(0U),

View file

@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20200624";
const char* VERSION = "20200625";
#endif