Initial work on the M17 protocol.

This commit is contained in:
Jonathan Naylor 2020-10-14 16:16:54 +01:00
parent ff19408e2d
commit 8536294b76
20 changed files with 2029 additions and 44 deletions

117
Conf.cpp
View file

@ -43,6 +43,7 @@ enum SECTION {
SECTION_FUSION,
SECTION_P25,
SECTION_NXDN,
SECTION_M17,
SECTION_POCSAG,
SECTION_FM,
SECTION_DSTAR_NETWORK,
@ -50,6 +51,7 @@ enum SECTION {
SECTION_FUSION_NETWORK,
SECTION_P25_NETWORK,
SECTION_NXDN_NETWORK,
SECTION_M17_NETWORK,
SECTION_POCSAG_NETWORK,
SECTION_TFTSERIAL,
SECTION_HD44780,
@ -102,6 +104,7 @@ m_modemDMRTXLevel(50.0F),
m_modemYSFTXLevel(50.0F),
m_modemP25TXLevel(50.0F),
m_modemNXDNTXLevel(50.0F),
m_modemM17TXLevel(50.0F),
m_modemPOCSAGTXLevel(50.0F),
m_modemFMTXLevel(50.0F),
m_modemRSSIMappingFile(),
@ -164,6 +167,10 @@ m_nxdnSelfOnly(false),
m_nxdnRemoteGateway(false),
m_nxdnTXHang(5U),
m_nxdnModeHang(10U),
m_m17Enabled(false),
m_m17SelfOnly(false),
m_m17TXHang(5U),
m_m17ModeHang(10U),
m_pocsagEnabled(false),
m_pocsagFrequency(0U),
m_fmEnabled(false),
@ -235,6 +242,12 @@ m_nxdnLocalAddress(),
m_nxdnLocalPort(0U),
m_nxdnNetworkModeHang(3U),
m_nxdnNetworkDebug(false),
m_m17NetworkEnabled(false),
m_m17GatewayAddress(),
m_m17GatewayPort(0U),
m_m17LocalPort(0U),
m_m17NetworkModeHang(3U),
m_m17NetworkDebug(false),
m_pocsagNetworkEnabled(false),
m_pocsagGatewayAddress(),
m_pocsagGatewayPort(0U),
@ -329,6 +342,8 @@ bool CConf::read()
section = SECTION_P25;
else if (::strncmp(buffer, "[NXDN]", 6U) == 0)
section = SECTION_NXDN;
else if (::strncmp(buffer, "[M17]", 5U) == 0)
section = SECTION_M17;
else if (::strncmp(buffer, "[POCSAG]", 8U) == 0)
section = SECTION_POCSAG;
else if (::strncmp(buffer, "[FM]", 4U) == 0)
@ -343,6 +358,8 @@ bool CConf::read()
section = SECTION_P25_NETWORK;
else if (::strncmp(buffer, "[NXDN Network]", 14U) == 0)
section = SECTION_NXDN_NETWORK;
else if (::strncmp(buffer, "[M17 Network]", 13U) == 0)
section = SECTION_M17_NETWORK;
else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0)
section = SECTION_POCSAG_NETWORK;
else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0)
@ -404,12 +421,12 @@ bool CConf::read()
else if (::strcmp(key, "Duplex") == 0)
m_duplex = ::atoi(value) == 1;
else if (::strcmp(key, "ModeHang") == 0)
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang =
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value);
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_m17NetworkModeHang =
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_m17ModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "RFModeHang") == 0)
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = (unsigned int)::atoi(value);
m_dstarModeHang = m_dmrModeHang = m_fusionModeHang = m_p25ModeHang = m_nxdnModeHang = m_m17ModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "NetModeHang") == 0)
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = (unsigned int)::atoi(value);
m_dstarNetworkModeHang = m_dmrNetworkModeHang = m_fusionNetworkModeHang = m_p25NetworkModeHang = m_nxdnNetworkModeHang = m_m17NetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Display") == 0)
m_display = value;
else if (::strcmp(key, "Daemon") == 0)
@ -481,7 +498,7 @@ bool CConf::read()
else if (::strcmp(key, "RXLevel") == 0)
m_modemRXLevel = float(::atof(value));
else if (::strcmp(key, "TXLevel") == 0)
m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = float(::atof(value));
m_modemFMTXLevel = m_modemCWIdTXLevel = m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = m_modemNXDNTXLevel = m_modemM17TXLevel = float(::atof(value));
else if (::strcmp(key, "CWIdTXLevel") == 0)
m_modemCWIdTXLevel = float(::atof(value));
else if (::strcmp(key, "D-StarTXLevel") == 0)
@ -494,6 +511,8 @@ bool CConf::read()
m_modemP25TXLevel = float(::atof(value));
else if (::strcmp(key, "NXDNTXLevel") == 0)
m_modemNXDNTXLevel = float(::atof(value));
else if (::strcmp(key, "M17TXLevel") == 0)
m_modemM17TXLevel = float(::atof(value));
else if (::strcmp(key, "POCSAGTXLevel") == 0)
m_modemPOCSAGTXLevel = float(::atof(value));
else if (::strcmp(key, "FMTXLevel") == 0)
@ -682,13 +701,21 @@ bool CConf::read()
m_nxdnTXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_nxdnModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_M17) {
if (::strcmp(key, "Enable") == 0)
m_m17Enabled = ::atoi(value) == 1;
else if (::strcmp(key, "SelfOnly") == 0)
m_m17SelfOnly = ::atoi(value) == 1;
else if (::strcmp(key, "TXHang") == 0)
m_m17TXHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_m17ModeHang = (unsigned int)::atoi(value);
} else if (section == SECTION_POCSAG) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0)
m_pocsagFrequency = (unsigned int)::atoi(value);
}
else if (section == SECTION_FM) {
if (::strcmp(key, "Enable") == 0)
m_pocsagEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Frequency") == 0)
m_pocsagFrequency = (unsigned int)::atoi(value);
} else if (section == SECTION_FM) {
if (::strcmp(key, "Enable") == 0)
m_fmEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Callsign") == 0) {
@ -843,6 +870,19 @@ bool CConf::read()
m_nxdnNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_nxdnNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_M17_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_m17NetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "LocalPort") == 0)
m_m17LocalPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "GatewayAddress") == 0)
m_m17GatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_m17GatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_m17NetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_m17NetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_POCSAG_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_pocsagNetworkEnabled = ::atoi(value) == 1;
@ -1151,6 +1191,11 @@ float CConf::getModemNXDNTXLevel() const
return m_modemNXDNTXLevel;
}
float CConf::getModemM17TXLevel() const
{
return m_modemM17TXLevel;
}
float CConf::getModemPOCSAGTXLevel() const
{
return m_modemPOCSAGTXLevel;
@ -1461,6 +1506,26 @@ unsigned int CConf::getNXDNModeHang() const
return m_nxdnModeHang;
}
bool CConf::getM17Enabled() const
{
return m_m17Enabled;
}
bool CConf::getM17SelfOnly() const
{
return m_m17SelfOnly;
}
unsigned int CConf::getM17TXHang() const
{
return m_m17TXHang;
}
unsigned int CConf::getM17ModeHang() const
{
return m_m17ModeHang;
}
bool CConf::getPOCSAGEnabled() const
{
return m_pocsagEnabled;
@ -1816,6 +1881,36 @@ bool CConf::getNXDNNetworkDebug() const
return m_nxdnNetworkDebug;
}
bool CConf::getM17NetworkEnabled() const
{
return m_m17NetworkEnabled;
}
std::string CConf::getM17GatewayAddress() const
{
return m_m17GatewayAddress;
}
unsigned int CConf::getM17GatewayPort() const
{
return m_m17GatewayPort;
}
unsigned int CConf::getM17LocalPort() const
{
return m_m17LocalPort;
}
unsigned int CConf::getM17NetworkModeHang() const
{
return m_m17NetworkModeHang;
}
bool CConf::getM17NetworkDebug() const
{
return m_m17NetworkDebug;
}
bool CConf::getPOCSAGNetworkEnabled() const
{
return m_pocsagNetworkEnabled;

28
Conf.h
View file

@ -83,6 +83,7 @@ public:
float getModemYSFTXLevel() const;
float getModemP25TXLevel() const;
float getModemNXDNTXLevel() const;
float getModemM17TXLevel() const;
float getModemPOCSAGTXLevel() const;
float getModemFMTXLevel() const;
std::string getModemRSSIMappingFile() const;
@ -160,6 +161,12 @@ public:
unsigned int getNXDNTXHang() const;
unsigned int getNXDNModeHang() const;
// The M17 section
bool getM17Enabled() const;
bool getM17SelfOnly() const;
unsigned int getM17TXHang() const;
unsigned int getM17ModeHang() const;
// The POCSAG section
bool getPOCSAGEnabled() const;
unsigned int getPOCSAGFrequency() const;
@ -245,6 +252,14 @@ public:
unsigned int getNXDNNetworkModeHang() const;
bool getNXDNNetworkDebug() const;
// The M17 Network section
bool getM17NetworkEnabled() const;
std::string getM17GatewayAddress() const;
unsigned int getM17GatewayPort() const;
unsigned int getM17LocalPort() const;
unsigned int getM17NetworkModeHang() const;
bool getM17NetworkDebug() const;
// The POCSAG Network section
bool getPOCSAGNetworkEnabled() const;
std::string getPOCSAGGatewayAddress() const;
@ -352,6 +367,7 @@ private:
float m_modemYSFTXLevel;
float m_modemP25TXLevel;
float m_modemNXDNTXLevel;
float m_modemM17TXLevel;
float m_modemPOCSAGTXLevel;
float m_modemFMTXLevel;
std::string m_modemRSSIMappingFile;
@ -422,6 +438,11 @@ private:
unsigned int m_nxdnTXHang;
unsigned int m_nxdnModeHang;
bool m_m17Enabled;
bool m_m17SelfOnly;
unsigned int m_m17TXHang;
unsigned int m_m17ModeHang;
bool m_pocsagEnabled;
unsigned int m_pocsagFrequency;
@ -500,6 +521,13 @@ private:
unsigned int m_nxdnNetworkModeHang;
bool m_nxdnNetworkDebug;
bool m_m17NetworkEnabled;
std::string m_m17GatewayAddress;
unsigned int m_m17GatewayPort;
unsigned int m_m17LocalPort;
unsigned int m_m17NetworkModeHang;
bool m_m17NetworkDebug;
bool m_pocsagNetworkEnabled;
std::string m_pocsagGatewayAddress;
unsigned int m_pocsagGatewayPort;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,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
@ -26,6 +26,7 @@ const unsigned char MODE_YSF = 3U;
const unsigned char MODE_P25 = 4U;
const unsigned char MODE_NXDN = 5U;
const unsigned char MODE_POCSAG = 6U;
const unsigned char MODE_M17 = 7U;
const unsigned char MODE_FM = 10U;

1130
M17Control.cpp Normal file

File diff suppressed because it is too large Load diff

98
M17Control.h Normal file
View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2015-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(M17Control_H)
#define M17Control_H
#include "RSSIInterpolator.h"
#include "M17Network.h"
#include "M17Defines.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "Display.h"
#include "Defines.h"
#include "Timer.h"
#include "Modem.h"
#include <string>
class CM17Control {
public:
CM17Control(const std::string& callsign, bool selfOnly, CM17Network* network, CDisplay* display, unsigned int timeout, bool duplex, CRSSIInterpolator* rssiMapper);
~CM17Control();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data);
void clock(unsigned int ms);
bool isBusy() const;
void enable(bool enabled);
private:
std::string m_callsign;
bool m_selfOnly;
CM17Network* m_network;
CDisplay* m_display;
bool m_duplex;
CRingBuffer<unsigned char> m_queue;
RPT_RF_STATE m_rfState;
RPT_NET_STATE m_netState;
CTimer m_rfTimeoutTimer;
CTimer m_netTimeoutTimer;
CTimer m_packetTimer;
CTimer m_networkWatchdog;
CStopWatch m_elapsed;
unsigned int m_rfFrames;
unsigned int m_netFrames;
unsigned int m_rfErrs;
unsigned int m_rfBits;
CNXDNLICH m_rfLastLICH;
CNXDNLayer3 m_rfLayer3;
CNXDNLayer3 m_netLayer3;
unsigned char m_rfMask;
unsigned char m_netMask;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
unsigned char m_maxRSSI;
unsigned char m_minRSSI;
unsigned int m_aveRSSI;
unsigned int m_rssiCount;
bool m_enabled;
FILE* m_fp;
bool processVoice(unsigned char usc, unsigned char option, unsigned char* data);
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
void writeNetwork(const unsigned char* data);
void writeNetwork();
void scrambler(unsigned char* data) const;
void writeEndRF();
void writeEndNet();
bool openFile();
bool writeFile(const unsigned char* data);
void closeFile();
};
#endif

34
M17Defines.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016,2017,2018,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(M17DEFINES_H)
#define M17DEFINES_H
const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
const unsigned int M17_FRAME_LENGTH_SYMBOLS = M17_FRAME_LENGTH_BITS / 2U;
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
const unsigned int M17_SYNC_LENGTH_SYMBOLS = M17_SYNC_LENGTH_BITS / 2U;
const unsigned char M17_SYNC_BYTES[] = {0x32U, 0x43U};
const unsigned int M17_SYNC_BYTES_LENGTH = 2U;
#endif

133
M17Network.cpp Normal file
View file

@ -0,0 +1,133 @@
/*
* Copyright (C) 2009-2014,2016,2019,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 "M17Network.h"
#include "M17Defines.h"
#include "Defines.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CM17Network::CM17Network(unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(localPort),
m_addr(),
m_addrLen(0U),
m_debug(debug),
m_enabled(false),
m_buffer(1000U, "M17 Network")
{
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
}
CM17Network::~CM17Network()
{
}
bool CM17Network::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the M17 Gateway");
return false;
}
LogMessage("Opening M17 network connection");
return m_socket.open(m_addr);
}
bool CM17Network::write(const unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[100U];
buffer[0U] = 'M';
buffer[1U] = '1';
buffer[2U] = '7';
if (m_debug)
CUtils::dump(1U, "M17 data transmitted", buffer, 36U);
return m_socket.write(buffer, 36U, m_addr, m_addrLen);
}
void CM17Network::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage address;
unsigned int addrLen;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, addrLen);
if (length <= 0)
return;
if (!CUDPSocket::match(m_addr, address)) {
LogMessage("M17, packet received from an invalid source");
return;
}
if (!m_enabled)
return;
if (m_debug)
CUtils::dump(1U, "M17 Network Data Received", buffer, length);
if (::memcmp(buffer + 0U, "M17", 3U) != 0)
return;
unsigned char c = length;
m_buffer.addData(&c, 1U);
m_buffer.addData(buffer, length);
}
bool CM17Network::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
unsigned char c = 0U;
m_buffer.getData(&c, 1U);
m_buffer.getData(data, c);
return true;
}
void CM17Network::close()
{
m_socket.close();
LogMessage("Closing M17 network connection");
}
void CM17Network::enable(bool enabled)
{
if (!enabled && m_enabled)
m_buffer.clear();
m_enabled = enabled;
}

56
M17Network.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2009-2014,2016,2018,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 M17Network_H
#define M17Network_H
#include "M17Defines.h"
#include "RingBuffer.h"
#include "UDPSocket.h"
#include <cstdint>
class CM17Network {
public:
CM17Network(unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug);
~CM17Network();
bool open();
void enable(bool enabled);
bool write(const unsigned char* data);
bool read(unsigned char* data);
void reset();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_debug;
bool m_enabled;
CRingBuffer<unsigned char> m_buffer;
};
#endif

View file

@ -58,6 +58,7 @@ RFLevel=100
# YSFTXLevel=50
# P25TXLevel=50
# NXDNTXLevel=50
# M17TXLevel-50
# POCSAGTXLevel=50
# FMTXLevel=50
RSSIMappingFile=RSSI.dat
@ -131,6 +132,12 @@ RemoteGateway=0
TXHang=5
# ModeHang=10
[M17]
Enable=1
SelfOnly=0
TXHang=5
# ModeHang=10
[POCSAG]
Enable=1
Frequency=439987500
@ -215,6 +222,14 @@ GatewayPort=14020
# ModeHang=3
Debug=0
[M17 Network]
Enable=1
GatewayAddress=127.0.0.1
GatewayPort=11657
LocalPort=11657
# ModeHang=3
Debug=0
[POCSAG Network]
Enable=1
LocalAddress=127.0.0.1

View file

@ -120,12 +120,14 @@ m_dmr(NULL),
m_ysf(NULL),
m_p25(NULL),
m_nxdn(NULL),
m_m17(NULL),
m_pocsag(NULL),
m_dstarNetwork(NULL),
m_dmrNetwork(NULL),
m_ysfNetwork(NULL),
m_p25Network(NULL),
m_nxdnNetwork(NULL),
m_m17Network(NULL),
m_pocsagNetwork(NULL),
m_display(NULL),
m_ump(NULL),
@ -135,11 +137,13 @@ m_dmrRFModeHang(10U),
m_ysfRFModeHang(10U),
m_p25RFModeHang(10U),
m_nxdnRFModeHang(10U),
m_m17RFModeHang(10U),
m_dstarNetModeHang(3U),
m_dmrNetModeHang(3U),
m_ysfNetModeHang(3U),
m_p25NetModeHang(3U),
m_nxdnNetModeHang(3U),
m_m17NetModeHang(3U),
m_pocsagNetModeHang(3U),
m_modeTimer(1000U),
m_dmrTXTimer(1000U),
@ -151,6 +155,7 @@ m_dmrEnabled(false),
m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_m17Enabled(false),
m_pocsagEnabled(false),
m_fmEnabled(false),
m_cwIdTime(0U),
@ -317,6 +322,12 @@ int CMMDVMHost::run()
return 1;
}
if (m_m17Enabled && m_conf.getM17NetworkEnabled()) {
ret = createM17Network();
if (!ret)
return 1;
}
if (m_pocsagEnabled && m_conf.getPOCSAGNetworkEnabled()) {
ret = createPOCSAGNetwork();
if (!ret)
@ -496,7 +507,6 @@ int CMMDVMHost::run()
else if (ovcm == DMR_OVCM_ON)
LogInfo(" OVCM: on");
switch (dmrBeacons) {
case DMR_BEACONS_NETWORK: {
unsigned int dmrBeaconDuration = m_conf.getDMRBeaconDuration();
@ -599,6 +609,19 @@ int CMMDVMHost::run()
m_nxdn = new CNXDNControl(ran, id, selfOnly, m_nxdnNetwork, m_display, m_timeout, m_duplex, remoteGateway, m_nxdnLookup, rssi);
}
if (m_m17Enabled) {
bool selfOnly = m_conf.getM17SelfOnly();
unsigned int txHang = m_conf.getM17TXHang();
m_m17RFModeHang = m_conf.getM17ModeHang();
LogInfo("M17 RF Parameters");
LogInfo(" Self Only: %s", selfOnly ? "yes" : "no");
LogInfo(" TX Hang: %us", txHang);
LogInfo(" Mode Hang: %us", m_m17RFModeHang);
m_m17 = new CM17Control(m_callsign, selfOnly, m_m17Network, m_display, m_timeout, m_duplex, rssi);
}
CTimer pocsagTimer(1000U, 30U);
if (m_pocsagEnabled) {
@ -807,6 +830,22 @@ int CMMDVMHost::run()
}
}
len = m_modem->readM17Data(data);
if (m_m17 != NULL && len > 0U) {
if (m_mode == MODE_IDLE) {
bool ret = m_m17->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_m17RFModeHang);
setMode(MODE_M17);
}
} else if (m_mode == MODE_M17) {
m_m17->writeModem(data, len);
m_modeTimer.start();
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("M17 modem data received when in mode %u", m_mode);
}
}
len = m_modem->readTransparentData(data);
if (transparentSocket != NULL && len > 0U)
transparentSocket->write(data, len, transparentAddress, transparentAddrLen);
@ -938,6 +977,25 @@ int CMMDVMHost::run()
}
}
if (m_m17 != NULL) {
ret = m_modem->hasM17Space();
if (ret) {
len = m_m17->readModem(data);
if (len > 0U) {
if (m_mode == MODE_IDLE) {
m_modeTimer.setTimeout(m_m17NetModeHang);
setMode(MODE_M17);
}
if (m_mode == MODE_M17) {
m_modem->writeM17Data(data, len);
m_modeTimer.start();
} else if (m_mode != MODE_LOCKOUT) {
LogWarning("M17 data received when in mode %u", m_mode);
}
}
}
}
if (m_pocsag != NULL) {
ret = m_modem->hasPOCSAGSpace();
if (ret) {
@ -987,6 +1045,8 @@ int CMMDVMHost::run()
m_p25->clock(ms);
if (m_nxdn != NULL)
m_nxdn->clock(ms);
if (m_m17 != NULL)
m_m17->clock(ms);
if (m_pocsag != NULL)
m_pocsag->clock(ms);
@ -1000,6 +1060,8 @@ int CMMDVMHost::run()
m_p25Network->clock(ms);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->clock(ms);
if (m_m17Network != NULL)
m_m17Network->clock(ms);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->clock(ms);
@ -1114,6 +1176,11 @@ int CMMDVMHost::run()
delete m_nxdnNetwork;
}
if (m_m17Network != NULL) {
m_m17Network->close();
delete m_m17Network;
}
if (m_pocsagNetwork != NULL) {
m_pocsagNetwork->close();
delete m_pocsagNetwork;
@ -1134,6 +1201,7 @@ int CMMDVMHost::run()
delete m_ysf;
delete m_p25;
delete m_nxdn;
delete m_m17;
delete m_pocsag;
return 0;
@ -1156,6 +1224,7 @@ bool CMMDVMHost::createModem()
float ysfTXLevel = m_conf.getModemYSFTXLevel();
float p25TXLevel = m_conf.getModemP25TXLevel();
float nxdnTXLevel = m_conf.getModemNXDNTXLevel();
float m17TXLevel = m_conf.getModemM17TXLevel();
float pocsagTXLevel = m_conf.getModemPOCSAGTXLevel();
float fmTXLevel = m_conf.getModemFMTXLevel();
bool trace = m_conf.getModemTrace();
@ -1165,6 +1234,7 @@ bool CMMDVMHost::createModem()
unsigned int ysfTXHang = m_conf.getFusionTXHang();
unsigned int p25TXHang = m_conf.getP25TXHang();
unsigned int nxdnTXHang = m_conf.getNXDNTXHang();
unsigned int m17TXHang = m_conf.getM17TXHang();
unsigned int rxFrequency = m_conf.getRXFrequency();
unsigned int txFrequency = m_conf.getTXFrequency();
unsigned int pocsagFrequency = m_conf.getPOCSAGFrequency();
@ -1197,6 +1267,7 @@ bool CMMDVMHost::createModem()
LogInfo(" YSF TX Level: %.1f%%", ysfTXLevel);
LogInfo(" P25 TX Level: %.1f%%", p25TXLevel);
LogInfo(" NXDN TX Level: %.1f%%", nxdnTXLevel);
LogInfo(" M17 TX Level: %.1f%%", m17TXLevel);
LogInfo(" POCSAG TX Level: %.1f%%", pocsagTXLevel);
LogInfo(" FM TX Level: %.1f%%", fmTXLevel);
LogInfo(" TX Frequency: %uHz (%uHz)", txFrequency, txFrequency + txOffset);
@ -1204,13 +1275,14 @@ bool CMMDVMHost::createModem()
m_modem = CModem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, useCOSAsLockout, trace, debug);
m_modem->setSerialParams(protocol, address);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel);
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_m17Enabled, m_pocsagEnabled, m_fmEnabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, m17TXLevel, pocsagTXLevel, fmTXLevel);
m_modem->setRFParams(rxFrequency, rxOffset, txFrequency, txOffset, txDCOffset, rxDCOffset, rfLevel, pocsagFrequency);
m_modem->setDMRParams(colorCode);
m_modem->setYSFParams(lowDeviation, ysfTXHang);
m_modem->setP25Params(p25TXHang);
m_modem->setNXDNParams(nxdnTXHang);
m_modem->setM17Params(m17TXHang);
if (m_fmEnabled) {
std::string callsign = m_conf.getFMCallsign();
@ -1465,6 +1537,33 @@ bool CMMDVMHost::createNXDNNetwork()
return true;
}
bool CMMDVMHost::createM17Network()
{
std::string gatewayAddress = m_conf.getM17GatewayAddress();
unsigned int gatewayPort = m_conf.getM17GatewayPort();
unsigned int localPort = m_conf.getM17LocalPort();
m_m17NetModeHang = m_conf.getM17NetworkModeHang();
bool debug = m_conf.getM17NetworkDebug();
LogInfo("M17 Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %u", gatewayPort);
LogInfo(" Local Port: %u", localPort);
LogInfo(" Mode Hang: %us", m_m17NetModeHang);
m_m17Network = new CM17Network(localPort, gatewayAddress, gatewayPort, debug);
bool ret = m_m17Network->open();
if (!ret) {
delete m_m17Network;
m_m17Network = NULL;
return false;
}
m_m17Network->enable(true);
return true;
}
bool CMMDVMHost::createPOCSAGNetwork()
{
std::string gatewayAddress = m_conf.getPOCSAGGatewayAddress();
@ -1502,6 +1601,7 @@ void CMMDVMHost::readParams()
m_ysfEnabled = m_conf.getFusionEnabled();
m_p25Enabled = m_conf.getP25Enabled();
m_nxdnEnabled = m_conf.getNXDNEnabled();
m_m17Enabled = m_conf.getM17Enabled();
m_pocsagEnabled = m_conf.getPOCSAGEnabled();
m_fmEnabled = m_conf.getFMEnabled();
m_duplex = m_conf.getDuplex();
@ -1519,6 +1619,7 @@ void CMMDVMHost::readParams()
LogInfo(" YSF: %s", m_ysfEnabled ? "enabled" : "disabled");
LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled");
LogInfo(" NXDN: %s", m_nxdnEnabled ? "enabled" : "disabled");
LogInfo(" M17: %s", m_m17Enabled ? "enabled" : "disabled");
LogInfo(" POCSAG: %s", m_pocsagEnabled ? "enabled" : "disabled");
LogInfo(" FM: %s", m_fmEnabled ? "enabled" : "disabled");
}
@ -1540,6 +1641,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1552,6 +1655,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_DSTAR);
@ -1574,6 +1679,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1586,6 +1693,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_DMR);
@ -1612,6 +1721,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1624,6 +1735,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_YSF);
@ -1646,6 +1759,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(true);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1658,6 +1773,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(true);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_P25);
@ -1680,6 +1797,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1692,6 +1811,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(true);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_NXDN);
@ -1703,6 +1824,44 @@ void CMMDVMHost::setMode(unsigned char mode)
createLockFile("NXDN");
break;
case MODE_M17:
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
if (m_dmrNetwork != NULL)
m_dmrNetwork->enable(false);
if (m_ysfNetwork != NULL)
m_ysfNetwork->enable(false);
if (m_p25Network != NULL)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(true);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
m_dmr->enable(false);
if (m_ysf != NULL)
m_ysf->enable(false);
if (m_p25 != NULL)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(true);
if (m_pocsag != NULL)
m_pocsag->enable(false);
m_modem->setMode(MODE_M17);
if (m_ump != NULL)
m_ump->setMode(MODE_M17);
m_mode = MODE_M17;
m_modeTimer.start();
m_cwIdTimer.stop();
createLockFile("M17");
break;
case MODE_POCSAG:
if (m_dstarNetwork != NULL)
m_dstarNetwork->enable(false);
@ -1714,6 +1873,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(true);
if (m_dstar != NULL)
@ -1726,6 +1887,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(true);
m_modem->setMode(MODE_POCSAG);
@ -1748,6 +1911,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1760,6 +1925,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -1786,6 +1953,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1798,6 +1967,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -1826,6 +1997,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(false);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(false);
if (m_dstar != NULL)
@ -1838,6 +2011,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(false);
if (m_nxdn != NULL)
m_nxdn->enable(false);
if (m_m17 != NULL)
m_m17->enable(false);
if (m_pocsag != NULL)
m_pocsag->enable(false);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -1864,6 +2039,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25Network->enable(true);
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
if (m_m17Network != NULL)
m_m17Network->enable(true);
if (m_pocsagNetwork != NULL)
m_pocsagNetwork->enable(true);
if (m_dstar != NULL)
@ -1876,6 +2053,8 @@ void CMMDVMHost::setMode(unsigned char mode)
m_p25->enable(true);
if (m_nxdn != NULL)
m_nxdn->enable(true);
if (m_m17 != NULL)
m_m17->enable(true);
if (m_pocsag != NULL)
m_pocsag->enable(true);
if (m_mode == MODE_DMR && m_duplex && m_modem->hasTX()) {
@ -1955,6 +2134,10 @@ void CMMDVMHost::remoteControl()
if (m_nxdn != NULL)
processModeCommand(MODE_NXDN, m_nxdnRFModeHang);
break;
case RCD_MODE_M17:
if (m_m17 != NULL)
processModeCommand(MODE_M17, m_m17RFModeHang);
break;
case RCD_MODE_FM:
if (m_fmEnabled != false)
processModeCommand(MODE_FM, 0);
@ -1989,6 +2172,12 @@ void CMMDVMHost::remoteControl()
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(true);
break;
case RCD_ENABLE_M17:
if (m_m17 != NULL && m_m17Enabled == false)
processEnableCommand(m_m17Enabled, true);
if (m_m17Network != NULL)
m_m17Network->enable(true);
break;
case RCD_ENABLE_FM:
if (m_fmEnabled==false)
processEnableCommand(m_fmEnabled, true);
@ -2023,6 +2212,12 @@ void CMMDVMHost::remoteControl()
if (m_nxdnNetwork != NULL)
m_nxdnNetwork->enable(false);
break;
case RCD_DISABLE_M17:
if (m_m17 != NULL && m_m17Enabled == true)
processEnableCommand(m_m17Enabled, false);
if (m_m17Network != NULL)
m_m17Network->enable(false);
break;
case RCD_DISABLE_FM:
if (m_fmEnabled == true)
processEnableCommand(m_fmEnabled, false);
@ -2038,18 +2233,20 @@ void CMMDVMHost::remoteControl()
}
m_pocsag->sendPage(ric, text);
}
break;
case RCD_CW:
setMode(MODE_IDLE); // Force the modem to go idle so that we can send the CW text.
if (!m_modem->hasTX()){
std::string cwtext;
for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) {
if (i > 0U)
cwtext += " ";
cwtext += m_remoteControl->getArgString(i);
}
m_display->writeCW();
m_modem->sendCWId(cwtext);
}
if (!m_modem->hasTX()){
std::string cwtext;
for (unsigned int i = 0U; i < m_remoteControl->getArgCount(); i++) {
if (i > 0U)
cwtext += " ";
cwtext += m_remoteControl->getArgString(i);
}
m_display->writeCW();
m_modem->sendCWId(cwtext);
}
break;
default:
break;
}
@ -2075,9 +2272,11 @@ void CMMDVMHost::processModeCommand(unsigned char mode, unsigned int timeout)
void CMMDVMHost::processEnableCommand(bool& mode, bool enabled)
{
LogDebug("Setting mode current=%s new=%s",mode ? "true" : "false",enabled ? "true" : "false");
mode=enabled;
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_pocsagEnabled, m_fmEnabled);
LogDebug("Setting mode current=%s new=%s", mode ? "true" : "false", enabled ? "true" : "false");
mode = enabled;
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled, m_nxdnEnabled, m_m17Enabled, m_pocsagEnabled, m_fmEnabled);
if (!m_modem->writeConfig())
LogError("Cannot write Config to MMDVM");
}

View file

@ -29,10 +29,12 @@
#include "YSFControl.h"
#include "P25Control.h"
#include "NXDNControl.h"
#include "M17Control.h"
#include "NXDNLookup.h"
#include "YSFNetwork.h"
#include "P25Network.h"
#include "DMRNetwork.h"
#include "M17Network.h"
#include "DMRLookup.h"
#include "Display.h"
#include "Timer.h"
@ -59,12 +61,14 @@ private:
CYSFControl* m_ysf;
CP25Control* m_p25;
CNXDNControl* m_nxdn;
CM17Control* m_m17;
CPOCSAGControl* m_pocsag;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
INXDNNetwork* m_nxdnNetwork;
CM17Network* m_m17Network;
CPOCSAGNetwork* m_pocsagNetwork;
CDisplay* m_display;
CUMP* m_ump;
@ -74,11 +78,13 @@ private:
unsigned int m_ysfRFModeHang;
unsigned int m_p25RFModeHang;
unsigned int m_nxdnRFModeHang;
unsigned int m_m17RFModeHang;
unsigned int m_dstarNetModeHang;
unsigned int m_dmrNetModeHang;
unsigned int m_ysfNetModeHang;
unsigned int m_p25NetModeHang;
unsigned int m_nxdnNetModeHang;
unsigned int m_m17NetModeHang;
unsigned int m_pocsagNetModeHang;
CTimer m_modeTimer;
CTimer m_dmrTXTimer;
@ -90,6 +96,7 @@ private:
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_m17Enabled;
bool m_pocsagEnabled;
bool m_fmEnabled;
unsigned int m_cwIdTime;
@ -110,6 +117,7 @@ private:
bool createYSFNetwork();
bool createP25Network();
bool createNXDNNetwork();
bool createM17Network();
bool createPOCSAGNetwork();
void remoteControl();

View file

@ -188,6 +188,9 @@
<ClInclude Include="I2CController.h" />
<ClInclude Include="LCDproc.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="M17Control.h" />
<ClInclude Include="M17Defines.h" />
<ClInclude Include="M17Network.h" />
<ClInclude Include="MMDVMHost.h" />
<ClInclude Include="Modem.h" />
<ClInclude Include="ModemSerialPort.h" />
@ -283,6 +286,8 @@
<ClCompile Include="I2CController.cpp" />
<ClCompile Include="LCDproc.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="M17Control.cpp" />
<ClCompile Include="M17Network.cpp" />
<ClCompile Include="MMDVMHost.cpp" />
<ClCompile Include="Modem.cpp" />
<ClCompile Include="ModemSerialPort.cpp" />

View file

@ -299,6 +299,15 @@
<ClInclude Include="NXDNKenwoodNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="M17Network.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -562,5 +571,11 @@
<ClCompile Include="NXDNKenwoodNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="M17Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

150
Modem.cpp
View file

@ -23,6 +23,7 @@
#include "P25Defines.h"
#include "NXDNDefines.h"
#include "POCSAGDefines.h"
#include "M17Defines.h"
#include "Thread.h"
#include "Modem.h"
#include "NullModem.h"
@ -74,6 +75,9 @@ const unsigned char MMDVM_P25_LOST = 0x32U;
const unsigned char MMDVM_NXDN_DATA = 0x40U;
const unsigned char MMDVM_NXDN_LOST = 0x41U;
const unsigned char MMDVM_M17_DATA = 0x45U;
const unsigned char MMDVM_M17_LOST = 0x46U;
const unsigned char MMDVM_POCSAG_DATA = 0x50U;
const unsigned char MMDVM_FM_PARAMS1 = 0x60U;
@ -106,6 +110,7 @@ m_ysfLoDev(false),
m_ysfTXHang(4U),
m_p25TXHang(5U),
m_nxdnTXHang(5U),
m_m17TXHang(5U),
m_duplex(duplex),
m_rxInvert(rxInvert),
m_txInvert(txInvert),
@ -119,6 +124,7 @@ m_dmrTXLevel(0.0F),
m_ysfTXLevel(0.0F),
m_p25TXLevel(0.0F),
m_nxdnTXLevel(0.0F),
m_m17TXLevel(0.0F),
m_pocsagTXLevel(0.0F),
m_fmTXLevel(0.0F),
m_rfLevel(0.0F),
@ -133,6 +139,7 @@ m_dmrEnabled(false),
m_ysfEnabled(false),
m_p25Enabled(false),
m_nxdnEnabled(false),
m_m17Enabled(false),
m_pocsagEnabled(false),
m_fmEnabled(false),
m_rxDCOffset(0),
@ -153,6 +160,8 @@ m_rxP25Data(1000U, "Modem RX P25"),
m_txP25Data(1000U, "Modem TX P25"),
m_rxNXDNData(1000U, "Modem RX NXDN"),
m_txNXDNData(1000U, "Modem TX NXDN"),
m_rxM17Data(1000U, "Modem RX M17"),
m_txM17Data(1000U, "Modem TX M17"),
m_txPOCSAGData(1000U, "Modem TX POCSAG"),
m_rxTransparentData(1000U, "Modem RX Transparent"),
m_txTransparentData(1000U, "Modem TX Transparent"),
@ -166,6 +175,7 @@ m_dmrSpace2(0U),
m_ysfSpace(0U),
m_p25Space(0U),
m_nxdnSpace(0U),
m_m17Space(0U),
m_pocsagSpace(0U),
m_tx(false),
m_cd(false),
@ -232,18 +242,19 @@ void CModem::setRFParams(unsigned int rxFrequency, int rxOffset, unsigned int tx
m_pocsagFrequency = pocsagFrequency + txOffset;
}
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool pocsagEnabled, bool fmEnabled)
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool m17Enabled, bool pocsagEnabled, bool fmEnabled)
{
m_dstarEnabled = dstarEnabled;
m_dmrEnabled = dmrEnabled;
m_ysfEnabled = ysfEnabled;
m_p25Enabled = p25Enabled;
m_nxdnEnabled = nxdnEnabled;
m_m17Enabled = m17Enabled;
m_pocsagEnabled = pocsagEnabled;
m_fmEnabled = fmEnabled;
}
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagTXLevel, float fmTXLevel)
void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float m17TXLevel, float pocsagTXLevel, float fmTXLevel)
{
m_rxLevel = rxLevel;
m_cwIdTXLevel = cwIdTXLevel;
@ -252,6 +263,7 @@ void CModem::setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, flo
m_ysfTXLevel = ysfTXLevel;
m_p25TXLevel = p25TXLevel;
m_nxdnTXLevel = nxdnTXLevel;
m_m17TXLevel = m17TXLevel;
m_pocsagTXLevel = pocsagTXLevel;
m_fmTXLevel = fmTXLevel;
}
@ -279,6 +291,11 @@ void CModem::setNXDNParams(unsigned int txHang)
m_nxdnTXHang = txHang;
}
void CModem::setM17Params(unsigned int txHang)
{
m_m17TXHang = txHang;
}
void CModem::setTransparentDataParams(unsigned int sendFrameType)
{
m_sendTransparentDataFrameType = sendFrameType;
@ -587,12 +604,39 @@ void CModem::clock(unsigned int ms)
}
break;
case MMDVM_M17_DATA: {
if (m_trace)
CUtils::dump(1U, "RX M17 Data", m_buffer, m_length);
unsigned char data = m_length - 2U;
m_rxM17Data.addData(&data, 1U);
data = TAG_DATA;
m_rxM17Data.addData(&data, 1U);
m_rxM17Data.addData(m_buffer + 3U, m_length - 3U);
}
break;
case MMDVM_M17_LOST: {
if (m_trace)
CUtils::dump(1U, "RX M17 Lost", m_buffer, m_length);
unsigned char data = 1U;
m_rxM17Data.addData(&data, 1U);
data = TAG_LOST;
m_rxM17Data.addData(&data, 1U);
}
break;
case MMDVM_GET_STATUS: {
// if (m_trace)
// CUtils::dump(1U, "GET_STATUS", m_buffer, m_length);
m_p25Space = 0U;
m_nxdnSpace = 0U;
m_m17Space = 0U;
m_pocsagSpace = 0U;
m_mode = m_buffer[4U];
@ -630,9 +674,11 @@ void CModem::clock(unsigned int ms)
m_nxdnSpace = m_buffer[11U];
if (m_length > 12U)
m_pocsagSpace = m_buffer[12U];
if (m_length > 13U)
m_m17Space = m_buffer[13U];
m_inactivityTimer.start();
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_pocsagSpace, int(m_lockout), int(m_cd));
// LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u,%u,%u,%u lockout=%d, cd=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, m_nxdnSpace, m_m17Space, m_pocsagSpace, int(m_lockout), int(m_cd));
}
break;
@ -819,6 +865,23 @@ void CModem::clock(unsigned int ms)
m_nxdnSpace--;
}
if (m_m17Space > 1U && !m_txM17Data.isEmpty()) {
unsigned char len = 0U;
m_txM17Data.getData(&len, 1U);
m_txM17Data.getData(m_buffer, len);
if (m_trace)
CUtils::dump(1U, "TX M17 Data", m_buffer, len);
int ret = m_serial->write(m_buffer, len);
if (ret != int(len))
LogWarning("Error when writing M17 data to the MMDVM");
m_playoutTimer.start();
m_m17Space--;
}
if (m_pocsagSpace > 1U && !m_txPOCSAGData.isEmpty()) {
unsigned char len = 0U;
m_txPOCSAGData.getData(&len, 1U);
@ -943,6 +1006,20 @@ unsigned int CModem::readNXDNData(unsigned char* data)
return len;
}
unsigned int CModem::readM17Data(unsigned char* data)
{
assert(data != NULL);
if (m_rxM17Data.isEmpty())
return 0U;
unsigned char len = 0U;
m_rxM17Data.getData(&len, 1U);
m_rxM17Data.getData(data, len);
return len;
}
unsigned int CModem::readTransparentData(unsigned char* data)
{
assert(data != NULL);
@ -1157,6 +1234,36 @@ bool CModem::writeNXDNData(const unsigned char* data, unsigned int length)
return true;
}
bool CModem::hasM17Space() const
{
unsigned int space = m_txM17Data.freeSpace() / (M17_FRAME_LENGTH_BYTES + 4U);
return space > 1U;
}
bool CModem::writeM17Data(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (data[0U] != TAG_DATA && data[0U] != TAG_EOT)
return false;
unsigned char buffer[130U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = length + 2U;
buffer[2U] = MMDVM_M17_DATA;
::memcpy(buffer + 3U, data + 1U, length - 1U);
unsigned char len = length + 2U;
m_txM17Data.addData(&len, 1U);
m_txM17Data.addData(buffer, len);
return true;
}
bool CModem::hasPOCSAGSpace() const
{
unsigned int space = m_txPOCSAGData.freeSpace() / (POCSAG_FRAME_LENGTH_BYTES + 4U);
@ -1351,6 +1458,30 @@ bool CModem::writeNXDNInfo(const char* source, bool group, unsigned int dest, co
return m_serial->write(buffer, 31U) != 31;
}
bool CModem::writeM17Info(const char* source, const char* dest, const char* type)
{
assert(m_serial != NULL);
assert(source != NULL);
assert(dest != NULL);
assert(type != NULL);
unsigned char buffer[40U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 31U;
buffer[2U] = MMDVM_QSO_INFO;
buffer[3U] = MODE_M17;
::sprintf((char*)(buffer + 4U), "%9.9s", source);
::sprintf((char*)(buffer + 13U), "%9.9s", dest);
::memcpy(buffer + 22U, type, 1U);
return m_serial->write(buffer, 23U) != 23;
}
bool CModem::writePOCSAGInfo(unsigned int ric, const std::string& message)
{
assert(m_serial != NULL);
@ -1523,7 +1654,7 @@ bool CModem::setConfig()
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = 24U;
buffer[1U] = 26U;
buffer[2U] = MMDVM_SET_CONFIG;
@ -1558,6 +1689,8 @@ bool CModem::setConfig()
buffer[4U] |= 0x20U;
if (m_fmEnabled && m_duplex)
buffer[4U] |= 0x40U;
if (m_m17Enabled)
buffer[4U] |= 0x80U;
buffer[5U] = m_txDelay / 10U; // In 10ms units
@ -1593,10 +1726,13 @@ bool CModem::setConfig()
buffer[23U] = (unsigned char)m_nxdnTXHang;
// CUtils::dump(1U, "Written", buffer, 24U);
buffer[24U] = (unsigned char)(m_m17TXLevel * 2.55F + 0.5F);
buffer[25U] = (unsigned char)m_m17TXHang;
int ret = m_serial->write(buffer, 24U);
if (ret != 24)
// CUtils::dump(1U, "Written", buffer, 26U);
int ret = m_serial->write(buffer, 26U);
if (ret != 26)
return false;
unsigned int count = 0U;

15
Modem.h
View file

@ -39,12 +39,13 @@ public:
virtual void setSerialParams(const std::string& protocol, unsigned int address);
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);
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float pocsagLevel, float fmTXLevel);
virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled, bool nxdnEnabled, bool m17Enabled, bool pocsagEnabled, bool fmEnabled);
virtual void setLevels(float rxLevel, float cwIdTXLevel, float dstarTXLevel, float dmrTXLevel, float ysfTXLevel, float p25TXLevel, float nxdnTXLevel, float m17TXLevel, float pocsagLevel, float fmTXLevel);
virtual void setDMRParams(unsigned int colorCode);
virtual void setYSFParams(bool loDev, unsigned int txHang);
virtual void setP25Params(unsigned int txHang);
virtual void setNXDNParams(unsigned int txHang);
virtual void setM17Params(unsigned int txHang);
virtual void setTransparentDataParams(unsigned int sendFrameType);
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);
@ -59,6 +60,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 readM17Data(unsigned char* data);
virtual unsigned int readTransparentData(unsigned char* data);
virtual unsigned int readSerial(unsigned char* data, unsigned int length);
@ -69,6 +71,7 @@ public:
virtual bool hasYSFSpace() const;
virtual bool hasP25Space() const;
virtual bool hasNXDNSpace() const;
virtual bool hasM17Space() const;
virtual bool hasPOCSAGSpace() const;
virtual bool hasTX() const;
@ -84,6 +87,7 @@ public:
virtual bool writeYSFData(const unsigned char* data, unsigned int length);
virtual bool writeP25Data(const unsigned char* data, unsigned int length);
virtual bool writeNXDNData(const unsigned char* data, unsigned int length);
virtual bool writeM17Data(const unsigned char* data, unsigned int length);
virtual bool writePOCSAGData(const unsigned char* data, unsigned int length);
virtual bool writeTransparentData(const unsigned char* data, unsigned int length);
@ -93,6 +97,7 @@ public:
virtual bool writeYSFInfo(const char* source, const char* dest, unsigned char dgid, const char* type, const char* origin);
virtual bool writeP25Info(const char* source, bool group, unsigned int dest, const char* type);
virtual bool writeNXDNInfo(const char* source, bool group, unsigned int dest, const char* type);
virtual bool writeM17Info(const char* source, const char* dest, const char* type);
virtual bool writePOCSAGInfo(unsigned int ric, const std::string& message);
virtual bool writeIPInfo(const std::string& address);
@ -122,6 +127,7 @@ private:
unsigned int m_ysfTXHang;
unsigned int m_p25TXHang;
unsigned int m_nxdnTXHang;
unsigned int m_m17TXHang;
bool m_duplex;
bool m_rxInvert;
bool m_txInvert;
@ -135,6 +141,7 @@ private:
float m_ysfTXLevel;
float m_p25TXLevel;
float m_nxdnTXLevel;
float m_m17TXLevel;
float m_pocsagTXLevel;
float m_fmTXLevel;
float m_rfLevel;
@ -149,6 +156,7 @@ private:
bool m_ysfEnabled;
bool m_p25Enabled;
bool m_nxdnEnabled;
bool m_m17Enabled;
bool m_pocsagEnabled;
bool m_fmEnabled;
int m_rxDCOffset;
@ -169,6 +177,8 @@ private:
CRingBuffer<unsigned char> m_txP25Data;
CRingBuffer<unsigned char> m_rxNXDNData;
CRingBuffer<unsigned char> m_txNXDNData;
CRingBuffer<unsigned char> m_rxM17Data;
CRingBuffer<unsigned char> m_txM17Data;
CRingBuffer<unsigned char> m_txPOCSAGData;
CRingBuffer<unsigned char> m_rxTransparentData;
CRingBuffer<unsigned char> m_txTransparentData;
@ -182,6 +192,7 @@ private:
unsigned int m_ysfSpace;
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_m17Space;
unsigned int m_pocsagSpace;
bool m_tx;
bool m_cd;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Jonathan Naylor G4KLX
* Copyright (C) 2019,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
@ -89,6 +89,8 @@ REMOTE_COMMAND CRemoteControl::getCommand()
m_command = RCD_MODE_P25;
else if (m_args.at(1U) == "nxdn")
m_command = RCD_MODE_NXDN;
else if (m_args.at(1U) == "m17")
m_command = RCD_MODE_M17;
} else if (m_args.at(0U) == "enable" && m_args.size() >= ENABLE_ARGS) {
if (m_args.at(1U) == "dstar")
m_command = RCD_ENABLE_DSTAR;
@ -100,6 +102,8 @@ REMOTE_COMMAND CRemoteControl::getCommand()
m_command = RCD_ENABLE_P25;
else if (m_args.at(1U) == "nxdn")
m_command = RCD_ENABLE_NXDN;
else if (m_args.at(1U) == "m17")
m_command = RCD_ENABLE_M17;
else if (m_args.at(1U) == "fm")
m_command = RCD_ENABLE_FM;
} else if (m_args.at(0U) == "disable" && m_args.size() >= DISABLE_ARGS) {
@ -113,6 +117,8 @@ REMOTE_COMMAND CRemoteControl::getCommand()
m_command = RCD_DISABLE_P25;
else if (m_args.at(1U) == "nxdn")
m_command = RCD_DISABLE_NXDN;
else if (m_args.at(1U) == "m17")
m_command = RCD_DISABLE_M17;
else if (m_args.at(1U) == "fm")
m_command = RCD_DISABLE_FM;
} else if (m_args.at(0U) == "page" && m_args.size() >= PAGE_ARGS) {
@ -144,6 +150,7 @@ unsigned int CRemoteControl::getArgCount() const
case RCD_MODE_YSF:
case RCD_MODE_P25:
case RCD_MODE_NXDN:
case RCD_MODE_M17:
return m_args.size() - SET_MODE_ARGS;
case RCD_PAGE:
return m_args.size() - 1U;
@ -164,14 +171,15 @@ std::string CRemoteControl::getArgString(unsigned int n) const
case RCD_MODE_YSF:
case RCD_MODE_P25:
case RCD_MODE_NXDN:
case RCD_MODE_M17:
n += SET_MODE_ARGS;
break;
case RCD_PAGE:
n += 1U;
break;
case RCD_CW:
n += 1U;
break;
n += 1U;
break;
default:
return "";
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Jonathan Naylor G4KLX
* Copyright (C) 2019,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
@ -33,18 +33,21 @@ enum REMOTE_COMMAND {
RCD_MODE_YSF,
RCD_MODE_P25,
RCD_MODE_NXDN,
RCD_MODE_M17,
RCD_MODE_FM,
RCD_ENABLE_DSTAR,
RCD_ENABLE_DMR,
RCD_ENABLE_YSF,
RCD_ENABLE_P25,
RCD_ENABLE_NXDN,
RCD_ENABLE_M17,
RCD_ENABLE_FM,
RCD_DISABLE_DSTAR,
RCD_DISABLE_DMR,
RCD_DISABLE_YSF,
RCD_DISABLE_P25,
RCD_DISABLE_NXDN,
RCD_DISABLE_M17,
RCD_DISABLE_FM,
RCD_PAGE,
RCD_CW

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,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
@ -23,6 +23,7 @@
#include "YSFDefines.h"
#include "P25Defines.h"
#include "NXDNDefines.h"
#include "M17Defines.h"
#include <cstdio>
#include <cassert>
@ -83,3 +84,10 @@ void CSync::addNXDNSync(unsigned char* data)
for (unsigned int i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
data[i] = (data[i] & ~NXDN_FSW_BYTES_MASK[i]) | NXDN_FSW_BYTES[i];
}
void CSync::addM17Sync(unsigned char* data)
{
assert(data != NULL);
::memcpy(data, M17_SYNC_BYTES, M17_SYNC_BYTES_LENGTH);
}

4
Sync.h
View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,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
@ -33,6 +33,8 @@ public:
static void addNXDNSync(unsigned char* data);
static void addM17Sync(unsigned char* data);
private:
};

View file

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