Beginnings of FM networking.

This commit is contained in:
Jonathan Naylor
2020-05-07 16:08:58 +01:00
parent 5410ca3ce8
commit bc791577e7
11 changed files with 416 additions and 14 deletions

View File

@@ -51,6 +51,7 @@ enum SECTION {
SECTION_P25_NETWORK,
SECTION_NXDN_NETWORK,
SECTION_POCSAG_NETWORK,
SECTION_FM_NETWORK,
SECTION_TFTSERIAL,
SECTION_HD44780,
SECTION_NEXTION,
@@ -246,6 +247,13 @@ m_pocsagLocalAddress(),
m_pocsagLocalPort(0U),
m_pocsagNetworkModeHang(3U),
m_pocsagNetworkDebug(false),
m_fmNetworkEnabled(false),
m_fmGatewayAddress(),
m_fmGatewayPort(0U),
m_fmLocalAddress(),
m_fmLocalPort(0U),
m_fmNetworkModeHang(3U),
m_fmNetworkDebug(false),
m_tftSerialPort("/dev/ttyAMA0"),
m_tftSerialBrightness(50U),
m_hd44780Rows(2U),
@@ -351,6 +359,8 @@ bool CConf::read()
section = SECTION_NXDN_NETWORK;
else if (::strncmp(buffer, "[POCSAG Network]", 16U) == 0)
section = SECTION_POCSAG_NETWORK;
else if (::strncmp(buffer, "[FM Network]", 12U) == 0)
section = SECTION_FM_NETWORK;
else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0)
section = SECTION_TFTSERIAL;
else if (::strncmp(buffer, "[HD44780]", 9U) == 0)
@@ -858,6 +868,21 @@ bool CConf::read()
m_pocsagNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_pocsagNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_POCSAG_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_fmNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "LocalAddress") == 0)
m_fmLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_fmLocalPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "GatewayAddress") == 0)
m_fmGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_fmGatewayPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "ModeHang") == 0)
m_fmNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_fmNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_TFTSERIAL) {
if (::strcmp(key, "Port") == 0)
m_tftSerialPort = value;
@@ -1871,6 +1896,41 @@ bool CConf::getPOCSAGNetworkDebug() const
return m_pocsagNetworkDebug;
}
bool CConf::getFMNetworkEnabled() const
{
return m_fmNetworkEnabled;
}
std::string CConf::getFMGatewayAddress() const
{
return m_fmGatewayAddress;
}
unsigned int CConf::getFMGatewayPort() const
{
return m_fmGatewayPort;
}
std::string CConf::getFMLocalAddress() const
{
return m_fmLocalAddress;
}
unsigned int CConf::getFMLocalPort() const
{
return m_fmLocalPort;
}
unsigned int CConf::getFMNetworkModeHang() const
{
return m_fmNetworkModeHang;
}
bool CConf::getFMNetworkDebug() const
{
return m_fmNetworkDebug;
}
std::string CConf::getTFTSerialPort() const
{
return m_tftSerialPort;

17
Conf.h
View File

@@ -257,6 +257,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 TFTSERIAL section
std::string getTFTSerialPort() const;
unsigned int getTFTSerialBrightness() const;
@@ -518,6 +527,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;
std::string m_tftSerialPort;
unsigned int m_tftSerialBrightness;

55
FMControl.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2015-2019 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 "RingBuffer.h"
#include "StopWatch.h"
#include "Defines.h"
#include "Timer.h"
#include "Modem.h"
#include <string>
class CFMControl {
public:
CFMControl(CFMNetwork* network);
~CFMControl();
bool writeModem(unsigned char* data, unsigned int len);
unsigned int readModem(unsigned char* data, unsigned int space);
void clock(unsigned int ms);
void enable(bool enabled);
private:
CFMNetwork* m_network;
CRingBuffer<unsigned char> m_queue;
bool m_enabled;
FILE* m_fp;
bool openFile();
bool writeFile(const unsigned char* data);
void closeFile();
};
#endif

55
FMNetwork.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.
*/
#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);
unsigned int read(unsigned char* data);
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;
};
#endif

View File

@@ -227,6 +227,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
[TFT Serial]
# Port=modem
Port=/dev/ttyAMA0

View File

@@ -119,12 +119,14 @@ m_ysf(NULL),
m_p25(NULL),
m_nxdn(NULL),
m_pocsag(NULL),
m_fm(NULL),
m_dstarNetwork(NULL),
m_dmrNetwork(NULL),
m_ysfNetwork(NULL),
m_p25Network(NULL),
m_nxdnNetwork(NULL),
m_pocsagNetwork(NULL),
m_fmNetwork(NULL),
m_display(NULL),
m_ump(NULL),
m_mode(MODE_IDLE),
@@ -139,6 +141,7 @@ m_ysfNetModeHang(3U),
m_p25NetModeHang(3U),
m_nxdnNetModeHang(3U),
m_pocsagNetModeHang(3U),
m_fmNetModeHang(3U),
m_modeTimer(1000U),
m_dmrTXTimer(1000U),
m_cwIdTimer(1000U),
@@ -317,6 +320,12 @@ int CMMDVMHost::run()
return 1;
}
if (m_fmEnabled && m_conf.getFMNetworkEnabled()) {
ret = createFMNetwork();
if (!ret)
return 1;
}
in_addr transparentAddress;
unsigned int transparentPort = 0U;
CUDPSocket* transparentSocket = NULL;
@@ -606,6 +615,9 @@ int CMMDVMHost::run()
pocsagTimer.start();
}
if (m_fmEnabled)
m_fm = new CFMControl(m_fmNetwork);
bool remoteControlEnabled = m_conf.getRemoteControlEnabled();
if (remoteControlEnabled) {
unsigned int port = m_conf.getRemoteControlPort();
@@ -798,6 +810,22 @@ int CMMDVMHost::run()
}
}
len = m_modem->readFMData(data);
if (m_nxdn != NULL && len > 0U) {
if (m_mode == MODE_IDLE) {
bool ret = m_fm->writeModem(data, len);
if (ret) {
m_modeTimer.setTimeout(m_nxdnRFModeHang);
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->readTransparentData(data);
if (transparentSocket != NULL && len > 0U)
transparentSocket->write(data, len, transparentAddress, transparentPort);
@@ -948,6 +976,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 (transparentSocket != NULL) {
in_addr address;
unsigned int port = 0U;
@@ -980,6 +1027,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);
@@ -993,6 +1042,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);
@@ -1118,6 +1169,11 @@ int CMMDVMHost::run()
delete m_pocsagNetwork;
}
if (m_fmNetwork != NULL) {
m_fmNetwork->close();
delete m_fmNetwork;
}
if (transparentSocket != NULL) {
transparentSocket->close();
delete transparentSocket;
@@ -1134,6 +1190,7 @@ int CMMDVMHost::run()
delete m_p25;
delete m_nxdn;
delete m_pocsag;
delete m_fm;
return 0;
}
@@ -1517,6 +1574,36 @@ 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;
}
void CMMDVMHost::readParams()
{
m_dstarEnabled = m_conf.getDStarEnabled();
@@ -1564,6 +1651,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_dstar != NULL)
m_dstar->enable(true);
if (m_dmr != NULL)
@@ -1598,6 +1687,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1636,6 +1727,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1670,6 +1763,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1704,6 +1799,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1738,6 +1835,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1812,6 +1911,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1852,6 +1953,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_dstar != NULL)
m_dstar->enable(false);
if (m_dmr != NULL)
@@ -1890,6 +1993,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_dstar != NULL)
m_dstar->enable(true);
if (m_dmr != NULL)
@@ -1980,55 +2085,55 @@ 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);
break;
case RCD_ENABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==false)
if (m_dmr != NULL && !m_dmrEnabled)
processEnableCommand(m_dmrEnabled, true);
break;
case RCD_ENABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==false)
if (m_ysf != NULL && !m_ysfEnabled)
processEnableCommand(m_ysfEnabled, true);
break;
case RCD_ENABLE_P25:
if (m_p25 != NULL && m_p25Enabled==false)
if (m_p25 != NULL && !m_p25Enabled)
processEnableCommand(m_p25Enabled, true);
break;
case RCD_ENABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==false)
if (m_nxdn != NULL && !m_nxdnEnabled)
processEnableCommand(m_nxdnEnabled, true);
break;
case RCD_ENABLE_FM:
if (m_fmEnabled==false)
if (!m_fmEnabled)
processEnableCommand(m_fmEnabled, true);
break;
case RCD_DISABLE_DSTAR:
if (m_dstar != NULL && m_dstarEnabled==true)
if (m_dstar != NULL && m_dstarEnabled)
processEnableCommand(m_dstarEnabled, false);
break;
case RCD_DISABLE_DMR:
if (m_dmr != NULL && m_dmrEnabled==true)
if (m_dmr != NULL && m_dmrEnabled)
processEnableCommand(m_dmrEnabled, false);
break;
case RCD_DISABLE_YSF:
if (m_ysf != NULL && m_ysfEnabled==true)
if (m_ysf != NULL && m_ysfEnabled)
processEnableCommand(m_ysfEnabled, false);
break;
case RCD_DISABLE_P25:
if (m_p25 != NULL && m_p25Enabled==true)
if (m_p25 != NULL && m_p25Enabled)
processEnableCommand(m_p25Enabled, false);
break;
case RCD_DISABLE_NXDN:
if (m_nxdn != NULL && m_nxdnEnabled==true)
if (m_nxdn != NULL && m_nxdnEnabled)
processEnableCommand(m_nxdnEnabled, false);
break;
case RCD_DISABLE_FM:
if (m_fmEnabled == true)
if (m_fmEnabled)
processEnableCommand(m_fmEnabled, false);
break;
case RCD_PAGE:

View File

@@ -33,8 +33,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"
@@ -62,12 +64,14 @@ private:
CP25Control* m_p25;
CNXDNControl* m_nxdn;
CPOCSAGControl* m_pocsag;
CFMControl* m_fm;
CDStarNetwork* m_dstarNetwork;
CDMRNetwork* m_dmrNetwork;
CYSFNetwork* m_ysfNetwork;
CP25Network* m_p25Network;
CNXDNNetwork* m_nxdnNetwork;
CPOCSAGNetwork* m_pocsagNetwork;
CFMNetwork* m_fmNetwork;
CDisplay* m_display;
CUMP* m_ump;
unsigned char m_mode;
@@ -82,6 +86,7 @@ private:
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;
@@ -114,6 +119,7 @@ private:
bool createP25Network();
bool createNXDNNetwork();
bool createPOCSAGNetwork();
bool createFMNetwork();
void remoteControl();
void processModeCommand(unsigned char mode, unsigned int timeout);

View File

@@ -181,6 +181,8 @@
<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" />

View File

@@ -299,6 +299,12 @@
<ClInclude Include="UserDBentry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FMControl.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">

View File

@@ -79,6 +79,7 @@ const unsigned char MMDVM_POCSAG_DATA = 0x50U;
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_DATA = 0x65U;
const unsigned char MMDVM_ACK = 0x70U;
const unsigned char MMDVM_NAK = 0x7FU;
@@ -150,6 +151,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(1000U, "Modem RX FM"),
m_txFMData(1000U, "Modem TX FM"),
m_rxTransparentData(1000U, "Modem RX Transparent"),
m_txTransparentData(1000U, "Modem TX Transparent"),
m_sendTransparentDataFrameType(0U),
@@ -163,6 +166,7 @@ m_ysfSpace(0U),
m_p25Space(0U),
m_nxdnSpace(0U),
m_pocsagSpace(0U),
m_fmSpace(0U),
m_tx(false),
m_cd(false),
m_lockout(false),
@@ -572,6 +576,20 @@ 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 char data = m_length - 2U;
m_rxFMData.addData(&data, 1U);
data = TAG_DATA;
m_rxFMData.addData(&data, 1U);
m_rxFMData.addData(m_buffer + 3U, m_length - 3U);
}
break;
case MMDVM_GET_STATUS: {
// if (m_trace)
// CUtils::dump(1U, "GET_STATUS", m_buffer, m_length);
@@ -615,9 +633,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_fmSpace = 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_pocsagSpace, m_fmSpace, int(m_lockout), int(m_cd));
}
break;
@@ -821,6 +841,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_txTransparentData.isEmpty()) {
unsigned char len = 0U;
m_txTransparentData.getData(&len, 1U);
@@ -928,6 +965,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 char len = 0U;
m_rxFMData.getData(&len, 1U);
m_rxFMData.getData(data, len);
return len;
}
unsigned int CModem::readTransparentData(unsigned char* data)
{
assert(data != NULL);
@@ -1169,6 +1220,36 @@ bool CModem::writePOCSAGData(const unsigned char* data, unsigned int length)
return true;
}
unsigned int CModem::getFMSpace() const
{
return (m_txFMData.freeSpace() * 2U) / 3U;
}
bool CModem::writeFMData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
length = (length * 2U) / 3U;
if (length > 252U)
return false;
unsigned char buffer[255U];
buffer[0U] = MMDVM_FRAME_START;
buffer[1U] = length + 3U;
buffer[2U] = MMDVM_FM_DATA;
::memcpy(buffer + 3U, data, length);
unsigned char len = length + 3U;
m_txFMData.addData(&len, 1U);
m_txFMData.addData(buffer, len);
return true;
}
bool CModem::writeTransparentData(const unsigned char* data, unsigned int length)
{
assert(data != NULL);

View File

@@ -57,6 +57,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 readTransparentData(unsigned char* data);
virtual unsigned int readSerial(unsigned char* data, unsigned int length);
@@ -68,6 +69,7 @@ public:
virtual bool hasP25Space() const;
virtual bool hasNXDNSpace() const;
virtual bool hasPOCSAGSpace() const;
virtual unsigned int getFMSpace() const;
virtual bool hasTX() const;
virtual bool hasCD() const;
@@ -83,6 +85,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 writeTransparentData(const unsigned char* data, unsigned int length);
@@ -165,6 +168,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_rxTransparentData;
CRingBuffer<unsigned char> m_txTransparentData;
unsigned int m_sendTransparentDataFrameType;
@@ -178,6 +183,7 @@ private:
unsigned int m_p25Space;
unsigned int m_nxdnSpace;
unsigned int m_pocsagSpace;
unsigned int m_fmSpace;
bool m_tx;
bool m_cd;
bool m_lockout;