parent
8e6f03b5a6
commit
6a4e9bf610
@ -0,0 +1,119 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# D-Star Site Install Script
|
||||||
|
# For Raspberry Pi 3 running Raspberry Pi OS Lite
|
||||||
|
# Usage: sudo bash install.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
MMDVM_SOURCE_DIR="/home/pi/MMDVM-Host"
|
||||||
|
MMDVM_REPO="https://github.com/g4klx/MMDVMHost.git"
|
||||||
|
ZEROTIER_NETWORK="c5029fdad4ccf9c5"
|
||||||
|
|
||||||
|
echo "================================================"
|
||||||
|
echo " D-Star Site Installer"
|
||||||
|
echo "================================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Select site
|
||||||
|
echo "Available sites:"
|
||||||
|
echo " 1) ORNG - Orange Portable"
|
||||||
|
echo " 2) ORNG2 - Orange TXRX"
|
||||||
|
echo ""
|
||||||
|
read -p "Select site [1-2]: " SITE_CHOICE
|
||||||
|
|
||||||
|
case $SITE_CHOICE in
|
||||||
|
1) SITE="ORNG" ;;
|
||||||
|
2) SITE="ORNG2" ;;
|
||||||
|
*) echo "Invalid selection"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Installing site: $SITE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Load site config
|
||||||
|
source "$REPO_DIR/sites/$SITE/site.conf"
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
echo "Installing dependencies..."
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y git build-essential nlohmann-json3-dev libssl-dev python3
|
||||||
|
|
||||||
|
# Install ZeroTier
|
||||||
|
echo "Installing ZeroTier..."
|
||||||
|
curl -s https://install.zerotier.com | bash
|
||||||
|
zerotier-cli join $ZEROTIER_NETWORK
|
||||||
|
echo "ZeroTier installed and joined network $ZEROTIER_NETWORK"
|
||||||
|
echo "NOTE: Approve this device in ZeroTier Central before continuing"
|
||||||
|
echo ""
|
||||||
|
read -p "Press ENTER once device is approved in ZeroTier Central..."
|
||||||
|
|
||||||
|
# Enable serial port
|
||||||
|
echo "Configuring serial port..."
|
||||||
|
raspi-config nonint do_serial_hw 0
|
||||||
|
raspi-config nonint do_serial_cons 1
|
||||||
|
|
||||||
|
# Add pi user to dialout
|
||||||
|
usermod -a -G dialout pi
|
||||||
|
|
||||||
|
# Clone MMDVMHost if not present
|
||||||
|
if [ ! -d "$MMDVM_SOURCE_DIR" ]; then
|
||||||
|
echo "Cloning MMDVMHost..."
|
||||||
|
git clone "$MMDVM_REPO" "$MMDVM_SOURCE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy patched source files
|
||||||
|
echo "Applying patches..."
|
||||||
|
cp "$REPO_DIR/src/DStarNetwork.cpp" "$MMDVM_SOURCE_DIR/"
|
||||||
|
cp "$REPO_DIR/src/DStarNetwork.h" "$MMDVM_SOURCE_DIR/"
|
||||||
|
cp "$REPO_DIR/src/Conf.h" "$MMDVM_SOURCE_DIR/"
|
||||||
|
|
||||||
|
cd "$MMDVM_SOURCE_DIR"
|
||||||
|
python3 "$REPO_DIR/src/patch_conf_cpp.py"
|
||||||
|
python3 "$REPO_DIR/src/patch_mmdvm_host_cpp.py"
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
echo "Compiling MMDVMHost..."
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
# Install binary
|
||||||
|
echo "Installing binary..."
|
||||||
|
cp MMDVM-Host /usr/local/bin/MMDVM-Host
|
||||||
|
chmod 755 /usr/local/bin/MMDVM-Host
|
||||||
|
|
||||||
|
# Generate config from template
|
||||||
|
echo "Generating config for $SITE..."
|
||||||
|
sed \
|
||||||
|
-e "s/%%CALLSIGN%%/$CALLSIGN/g" \
|
||||||
|
-e "s/%%MODULE%%/$MODULE/g" \
|
||||||
|
-e "s/%%SITE_NAME%%/$SITE_NAME/g" \
|
||||||
|
-e "s/%%GATEWAY_ADDRESS%%/$GATEWAY_ADDRESS/g" \
|
||||||
|
-e "s/%%GATEWAY_PORT%%/$GATEWAY_PORT/g" \
|
||||||
|
-e "s/%%LOCAL_PORT%%/$LOCAL_PORT/g" \
|
||||||
|
-e "s/%%MODEM_PORT%%/$MODEM_PORT/g" \
|
||||||
|
-e "s/%%MODEM_SPEED%%/$MODEM_SPEED/g" \
|
||||||
|
"$REPO_DIR/sites/mmdvmhost.template" > /etc/mmdvmhost
|
||||||
|
|
||||||
|
echo "Config written to /etc/mmdvmhost"
|
||||||
|
|
||||||
|
# Install service
|
||||||
|
echo "Installing systemd service..."
|
||||||
|
cp "$REPO_DIR/services/mmdvmhost.service" /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable mmdvmhost
|
||||||
|
systemctl start mmdvmhost
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo " Installation complete for site: $SITE"
|
||||||
|
echo "================================================"
|
||||||
|
echo ""
|
||||||
|
echo "ZeroTier status:"
|
||||||
|
zerotier-cli status
|
||||||
|
echo ""
|
||||||
|
echo "Service status:"
|
||||||
|
systemctl status mmdvmhost --no-pager
|
||||||
|
echo ""
|
||||||
|
echo "Logs:"
|
||||||
|
echo " journalctl -u mmdvmhost -f"
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=MMDVMHost D-Star Site Service
|
||||||
|
After=network.target
|
||||||
|
After=time-sync.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
ExecStart=/usr/local/bin/MMDVM-Host /etc/mmdvmhost
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
User=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# ORANGE-PORTABLE Site Configuration
|
||||||
|
SITE_NAME=ORNG
|
||||||
|
CALLSIGN=N8MFN
|
||||||
|
MODULE=B
|
||||||
|
GATEWAY_ADDRESS=10.121.15.78
|
||||||
|
GATEWAY_PORT=20013
|
||||||
|
LOCAL_PORT=20016
|
||||||
|
MODEM_PORT=/dev/ttyAMA0
|
||||||
|
MODEM_SPEED=115200
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# ORANGE-TXRX Site Configuration
|
||||||
|
SITE_NAME=ORNG2
|
||||||
|
CALLSIGN=N8MFN
|
||||||
|
MODULE=B
|
||||||
|
GATEWAY_ADDRESS=10.121.15.78
|
||||||
|
GATEWAY_PORT=20013
|
||||||
|
LOCAL_PORT=20017
|
||||||
|
MODEM_PORT=/dev/ttyAMA0
|
||||||
|
MODEM_SPEED=115200
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
[General]
|
||||||
|
Callsign=%%CALLSIGN%%
|
||||||
|
Id=0
|
||||||
|
Timeout=180
|
||||||
|
Duplex=1
|
||||||
|
ModeHang=20
|
||||||
|
Daemon=1
|
||||||
|
|
||||||
|
[Info]
|
||||||
|
RXFrequency=444000000
|
||||||
|
TXFrequency=449000000
|
||||||
|
Power=1
|
||||||
|
Latitude=0.0
|
||||||
|
Longitude=0.0
|
||||||
|
Height=0
|
||||||
|
Location=
|
||||||
|
Description=
|
||||||
|
URL=
|
||||||
|
|
||||||
|
[Log]
|
||||||
|
MQTTLevel=0
|
||||||
|
DisplayLevel=2
|
||||||
|
|
||||||
|
[MQTT]
|
||||||
|
Host=10.0.2.147
|
||||||
|
Port=1883
|
||||||
|
Keepalive=60
|
||||||
|
Name=%%SITE_NAME%%
|
||||||
|
Auth=0
|
||||||
|
|
||||||
|
[CW Id]
|
||||||
|
Enable=0
|
||||||
|
Time=10
|
||||||
|
Callsign=%%CALLSIGN%%
|
||||||
|
|
||||||
|
[Modem]
|
||||||
|
Protocol=uart
|
||||||
|
UARTPort=%%MODEM_PORT%%
|
||||||
|
UARTSpeed=%%MODEM_SPEED%%
|
||||||
|
RXInvert=0
|
||||||
|
TXInvert=0
|
||||||
|
PTTInvert=0
|
||||||
|
TXDelay=100
|
||||||
|
RXOffset=0
|
||||||
|
TXOffset=0
|
||||||
|
RXDCOffset=0
|
||||||
|
TXDCOffset=0
|
||||||
|
RFLevel=100
|
||||||
|
RXLevel=50
|
||||||
|
TXLevel=50
|
||||||
|
CWIdTXLevel=50
|
||||||
|
D-StarTXLevel=50
|
||||||
|
DMRTXLevel=50
|
||||||
|
YSFTXLevel=50
|
||||||
|
P25TXLevel=50
|
||||||
|
NXDNTXLevel=50
|
||||||
|
POCSAGTXLevel=50
|
||||||
|
FMTXLevel=50
|
||||||
|
UseCOSAsLockout=0
|
||||||
|
Trace=0
|
||||||
|
Debug=0
|
||||||
|
|
||||||
|
[D-Star]
|
||||||
|
Enable=1
|
||||||
|
Module=%%MODULE%%
|
||||||
|
SelfOnly=0
|
||||||
|
AckReply=1
|
||||||
|
AckTime=750
|
||||||
|
AckMessage=0
|
||||||
|
ErrorReply=1
|
||||||
|
RemoteGateway=0
|
||||||
|
ModeHang=20
|
||||||
|
|
||||||
|
[DMR]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[System Fusion]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[P25]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[NXDN]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[POCSAG]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[FM]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[D-Star Network]
|
||||||
|
Enable=1
|
||||||
|
GatewayAddress=%%GATEWAY_ADDRESS%%
|
||||||
|
GatewayPort=%%GATEWAY_PORT%%
|
||||||
|
LocalAddress=0.0.0.0
|
||||||
|
LocalPort=%%LOCAL_PORT%%
|
||||||
|
Name=%%SITE_NAME%%
|
||||||
|
ModeHang=20
|
||||||
|
Debug=0
|
||||||
|
|
||||||
|
[DMR Network]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[Lock File]
|
||||||
|
Enable=0
|
||||||
|
|
||||||
|
[Remote Control]
|
||||||
|
Enable=0
|
||||||
@ -0,0 +1,649 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2026 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(CONF_H)
|
||||||
|
#define CONF_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class CConf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CConf(const std::string& file);
|
||||||
|
~CConf();
|
||||||
|
|
||||||
|
bool read();
|
||||||
|
|
||||||
|
// The General section
|
||||||
|
std::string getCallsign() const;
|
||||||
|
unsigned int getId() const;
|
||||||
|
unsigned int getTimeout() const;
|
||||||
|
bool getDuplex() const;
|
||||||
|
bool getDaemon() const;
|
||||||
|
|
||||||
|
// The Info section
|
||||||
|
unsigned int getRXFrequency() const;
|
||||||
|
unsigned int getTXFrequency() const;
|
||||||
|
unsigned int getPower() const;
|
||||||
|
float getLatitude() const;
|
||||||
|
float getLongitude() const;
|
||||||
|
int getHeight() const;
|
||||||
|
std::string getLocation() const;
|
||||||
|
std::string getDescription() const;
|
||||||
|
std::string getURL() const;
|
||||||
|
|
||||||
|
// The Log section
|
||||||
|
unsigned int getLogMQTTLevel() const;
|
||||||
|
unsigned int getLogDisplayLevel() const;
|
||||||
|
|
||||||
|
// The MQTT section
|
||||||
|
std::string getMQTTHost() const;
|
||||||
|
unsigned short getMQTTPort() const;
|
||||||
|
unsigned int getMQTTKeepalive() const;
|
||||||
|
std::string getMQTTName() const;
|
||||||
|
bool getMQTTAuthEnabled() const;
|
||||||
|
std::string getMQTTUsername() const;
|
||||||
|
std::string getMQTTPassword() const;
|
||||||
|
|
||||||
|
// The CW ID section
|
||||||
|
bool getCWIdEnabled() const;
|
||||||
|
unsigned int getCWIdTime() const;
|
||||||
|
std::string getCWIdCallsign() const;
|
||||||
|
|
||||||
|
#if defined(USE_DMR) || defined(USE_P25)
|
||||||
|
// The DMR Id section
|
||||||
|
std::string getDMRIdLookupFile() const;
|
||||||
|
unsigned int getDMRIdLookupTime() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
// The NXDN Id section
|
||||||
|
std::string getNXDNIdLookupFile() const;
|
||||||
|
unsigned int getNXDNIdLookupTime() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The Modem section
|
||||||
|
std::string getModemProtocol() const;
|
||||||
|
std::string getModemUARTPort() const;
|
||||||
|
unsigned int getModemUARTSpeed() const;
|
||||||
|
std::string getModemI2CPort() const;
|
||||||
|
unsigned int getModemI2CAddress() const;
|
||||||
|
std::string getModemModemAddress() const;
|
||||||
|
unsigned short getModemModemPort() const;
|
||||||
|
std::string getModemLocalAddress() const;
|
||||||
|
unsigned short getModemLocalPort() const;
|
||||||
|
bool getModemRXInvert() const;
|
||||||
|
bool getModemTXInvert() const;
|
||||||
|
bool getModemPTTInvert() const;
|
||||||
|
unsigned int getModemTXDelay() const;
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
unsigned int getModemDMRDelay() const;
|
||||||
|
#endif
|
||||||
|
int getModemTXOffset() const;
|
||||||
|
int getModemRXOffset() const;
|
||||||
|
int getModemRXDCOffset() const;
|
||||||
|
int getModemTXDCOffset() const;
|
||||||
|
float getModemRFLevel() const;
|
||||||
|
float getModemRXLevel() const;
|
||||||
|
float getModemCWIdTXLevel() const;
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
float getModemDStarTXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
float getModemDMRTXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
float getModemYSFTXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_P25)
|
||||||
|
float getModemP25TXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
float getModemNXDNTXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_POCSAG)
|
||||||
|
float getModemPOCSAGTXLevel() const;
|
||||||
|
#endif
|
||||||
|
#if defined(USE_FM)
|
||||||
|
float getModemFMTXLevel() const;
|
||||||
|
#endif
|
||||||
|
std::string getModemRSSIMappingFile() const;
|
||||||
|
bool getModemUseCOSAsLockout() const;
|
||||||
|
bool getModemTrace() const;
|
||||||
|
bool getModemDebug() const;
|
||||||
|
|
||||||
|
// The Transparent Data section
|
||||||
|
bool getTransparentEnabled() const;
|
||||||
|
std::string getTransparentRemoteAddress() const;
|
||||||
|
unsigned short getTransparentRemotePort() const;
|
||||||
|
unsigned short getTransparentLocalPort() const;
|
||||||
|
unsigned int getTransparentSendFrameType() const;
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
// The D-Star section
|
||||||
|
bool getDStarEnabled() const;
|
||||||
|
std::string getDStarModule() const;
|
||||||
|
bool getDStarSelfOnly() const;
|
||||||
|
std::vector<std::string> getDStarBlackList() const;
|
||||||
|
std::vector<std::string> getDStarWhiteList() const;
|
||||||
|
bool getDStarAckReply() const;
|
||||||
|
unsigned int getDStarAckTime() const;
|
||||||
|
DSTAR_ACK getDStarAckMessage() const;
|
||||||
|
bool getDStarErrorReply() const;
|
||||||
|
bool getDStarRemoteGateway() const;
|
||||||
|
unsigned int getDStarModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
// The DMR section
|
||||||
|
bool getDMREnabled() const;
|
||||||
|
DMR_BEACONS getDMRBeacons() const;
|
||||||
|
unsigned int getDMRBeaconInterval() const;
|
||||||
|
unsigned int getDMRBeaconDuration() const;
|
||||||
|
unsigned int getDMRId() const;
|
||||||
|
unsigned int getDMRColorCode() const;
|
||||||
|
bool getDMREmbeddedLCOnly() const;
|
||||||
|
bool getDMRDumpTAData() const;
|
||||||
|
bool getDMRSelfOnly() const;
|
||||||
|
std::vector<unsigned int> getDMRPrefixes() const;
|
||||||
|
std::vector<unsigned int> getDMRBlackList() const;
|
||||||
|
std::vector<unsigned int> getDMRWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot1TGWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot2TGWhiteList() const;
|
||||||
|
unsigned int getDMRCallHang() const;
|
||||||
|
unsigned int getDMRTXHang() const;
|
||||||
|
unsigned int getDMRModeHang() const;
|
||||||
|
DMR_OVCM getDMROVCM() const;
|
||||||
|
bool getDMRProtect() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
// The System Fusion section
|
||||||
|
bool getFusionEnabled() const;
|
||||||
|
bool getFusionLowDeviation() const;
|
||||||
|
bool getFusionRemoteGateway() const;
|
||||||
|
bool getFusionSelfOnly() const;
|
||||||
|
unsigned int getFusionTXHang() const;
|
||||||
|
unsigned int getFusionModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_P25)
|
||||||
|
// The P25 section
|
||||||
|
bool getP25Enabled() const;
|
||||||
|
unsigned int getP25Id() const;
|
||||||
|
unsigned int getP25NAC() const;
|
||||||
|
bool getP25SelfOnly() const;
|
||||||
|
bool getP25OverrideUID() const;
|
||||||
|
bool getP25RemoteGateway() const;
|
||||||
|
unsigned int getP25TXHang() const;
|
||||||
|
unsigned int getP25ModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
// The NXDN section
|
||||||
|
bool getNXDNEnabled() const;
|
||||||
|
unsigned int getNXDNId() const;
|
||||||
|
unsigned int getNXDNRAN() const;
|
||||||
|
bool getNXDNSelfOnly() const;
|
||||||
|
bool getNXDNRemoteGateway() const;
|
||||||
|
unsigned int getNXDNTXHang() const;
|
||||||
|
unsigned int getNXDNModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_POCSAG)
|
||||||
|
// The POCSAG section
|
||||||
|
bool getPOCSAGEnabled() const;
|
||||||
|
unsigned int getPOCSAGFrequency() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_FM)
|
||||||
|
// The FM Section
|
||||||
|
bool getFMEnabled() const;
|
||||||
|
std::string getFMCallsign() const;
|
||||||
|
unsigned int getFMCallsignSpeed() const;
|
||||||
|
unsigned int getFMCallsignFrequency() const;
|
||||||
|
unsigned int getFMCallsignTime() const;
|
||||||
|
unsigned int getFMCallsignHoldoff() const;
|
||||||
|
float getFMCallsignHighLevel() const;
|
||||||
|
float getFMCallsignLowLevel() const;
|
||||||
|
bool getFMCallsignAtStart() const;
|
||||||
|
bool getFMCallsignAtEnd() const;
|
||||||
|
bool getFMCallsignAtLatch() const;
|
||||||
|
std::string getFMRFAck() const;
|
||||||
|
std::string getFMExtAck() const;
|
||||||
|
unsigned int getFMAckSpeed() const;
|
||||||
|
unsigned int getFMAckFrequency() const;
|
||||||
|
unsigned int getFMAckMinTime() const;
|
||||||
|
unsigned int getFMAckDelay() const;
|
||||||
|
float getFMAckLevel() const;
|
||||||
|
unsigned int getFMTimeout() const;
|
||||||
|
float getFMTimeoutLevel() const;
|
||||||
|
float getFMCTCSSFrequency() const;
|
||||||
|
unsigned int getFMCTCSSHighThreshold() const;
|
||||||
|
unsigned int getFMCTCSSLowThreshold() const;
|
||||||
|
float getFMCTCSSLevel() const;
|
||||||
|
unsigned int getFMKerchunkTime() const;
|
||||||
|
unsigned int getFMHangTime() const;
|
||||||
|
unsigned int getFMAccessMode() const;
|
||||||
|
bool getFMLinkMode() const;
|
||||||
|
bool getFMCOSInvert() const;
|
||||||
|
bool getFMNoiseSquelch() const;
|
||||||
|
unsigned int getFMSquelchHighThreshold() const;
|
||||||
|
unsigned int getFMSquelchLowThreshold() const;
|
||||||
|
unsigned int getFMRFAudioBoost() const;
|
||||||
|
float getFMMaxDevLevel() const;
|
||||||
|
unsigned int getFMExtAudioBoost() const;
|
||||||
|
unsigned int getFMModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
// The D-Star Network section
|
||||||
|
bool getDStarNetworkEnabled() const;
|
||||||
|
std::string getDStarGatewayAddress() const;
|
||||||
|
unsigned short getDStarGatewayPort() const;
|
||||||
|
std::string getDStarLocalAddress() const;
|
||||||
|
unsigned short getDStarLocalPort() const;
|
||||||
|
std::string getDStarNetworkName() const;
|
||||||
|
unsigned int getDStarNetworkModeHang() const;
|
||||||
|
bool getDStarNetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
// The DMR Network section
|
||||||
|
bool getDMRNetworkEnabled() const;
|
||||||
|
std::string getDMRNetworkGatewayAddress() const;
|
||||||
|
unsigned short getDMRNetworkGatewayPort() const;
|
||||||
|
std::string getDMRNetworkLocalAddress() const;
|
||||||
|
unsigned short getDMRNetworkLocalPort() const;
|
||||||
|
bool getDMRNetworkDebug() const;
|
||||||
|
unsigned int getDMRNetworkJitter() const;
|
||||||
|
bool getDMRNetworkSlot1() const;
|
||||||
|
bool getDMRNetworkSlot2() const;
|
||||||
|
unsigned int getDMRNetworkModeHang() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
// The System Fusion Network section
|
||||||
|
bool getFusionNetworkEnabled() const;
|
||||||
|
std::string getFusionNetworkLocalAddress() const;
|
||||||
|
unsigned short getFusionNetworkLocalPort() const;
|
||||||
|
std::string getFusionNetworkGatewayAddress() const;
|
||||||
|
unsigned short getFusionNetworkGatewayPort() const;
|
||||||
|
unsigned int getFusionNetworkModeHang() const;
|
||||||
|
bool getFusionNetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_P25)
|
||||||
|
// The P25 Network section
|
||||||
|
bool getP25NetworkEnabled() const;
|
||||||
|
std::string getP25GatewayAddress() const;
|
||||||
|
unsigned short getP25GatewayPort() const;
|
||||||
|
std::string getP25LocalAddress() const;
|
||||||
|
unsigned short getP25LocalPort() const;
|
||||||
|
unsigned int getP25NetworkModeHang() const;
|
||||||
|
bool getP25NetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
// The NXDN Network section
|
||||||
|
bool getNXDNNetworkEnabled() const;
|
||||||
|
std::string getNXDNNetworkProtocol() const;
|
||||||
|
std::string getNXDNGatewayAddress() const;
|
||||||
|
unsigned short getNXDNGatewayPort() const;
|
||||||
|
std::string getNXDNLocalAddress() const;
|
||||||
|
unsigned short getNXDNLocalPort() const;
|
||||||
|
unsigned int getNXDNNetworkModeHang() const;
|
||||||
|
bool getNXDNNetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_POCSAG)
|
||||||
|
// The POCSAG Network section
|
||||||
|
bool getPOCSAGNetworkEnabled() const;
|
||||||
|
std::string getPOCSAGGatewayAddress() const;
|
||||||
|
unsigned short getPOCSAGGatewayPort() const;
|
||||||
|
std::string getPOCSAGLocalAddress() const;
|
||||||
|
unsigned short getPOCSAGLocalPort() const;
|
||||||
|
unsigned int getPOCSAGNetworkModeHang() const;
|
||||||
|
bool getPOCSAGNetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_FM)
|
||||||
|
// The FM Network section
|
||||||
|
bool getFMNetworkEnabled() const;
|
||||||
|
std::string getFMGatewayAddress() const;
|
||||||
|
unsigned short getFMGatewayPort() const;
|
||||||
|
std::string getFMLocalAddress() const;
|
||||||
|
unsigned short getFMLocalPort() const;
|
||||||
|
bool getFMPreEmphasis() const;
|
||||||
|
bool getFMDeEmphasis() const;
|
||||||
|
float getFMTXAudioGain() const;
|
||||||
|
float getFMRXAudioGain() const;
|
||||||
|
unsigned int getFMNetworkModeHang() const;
|
||||||
|
bool getFMNetworkDebug() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The Lock File section
|
||||||
|
bool getLockFileEnabled() const;
|
||||||
|
std::string getLockFileName() const;
|
||||||
|
|
||||||
|
// The Remote Control section
|
||||||
|
bool getRemoteControlEnabled() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_file;
|
||||||
|
std::string m_callsign;
|
||||||
|
unsigned int m_id;
|
||||||
|
unsigned int m_timeout;
|
||||||
|
bool m_duplex;
|
||||||
|
bool m_daemon;
|
||||||
|
|
||||||
|
unsigned int m_rxFrequency;
|
||||||
|
unsigned int m_txFrequency;
|
||||||
|
unsigned int m_power;
|
||||||
|
float m_latitude;
|
||||||
|
float m_longitude;
|
||||||
|
int m_height;
|
||||||
|
std::string m_location;
|
||||||
|
std::string m_description;
|
||||||
|
std::string m_url;
|
||||||
|
|
||||||
|
unsigned int m_logMQTTLevel;
|
||||||
|
unsigned int m_logDisplayLevel;
|
||||||
|
|
||||||
|
std::string m_mqttHost;
|
||||||
|
unsigned short m_mqttPort;
|
||||||
|
unsigned int m_mqttKeepalive;
|
||||||
|
std::string m_mqttName;
|
||||||
|
bool m_mqttAuthEnabled;
|
||||||
|
std::string m_mqttUsername;
|
||||||
|
std::string m_mqttPassword;
|
||||||
|
|
||||||
|
bool m_cwIdEnabled;
|
||||||
|
unsigned int m_cwIdTime;
|
||||||
|
std::string m_cwIdCallsign;
|
||||||
|
|
||||||
|
#if defined(USE_DMR) || defined(USE_P25)
|
||||||
|
std::string m_dmrIdLookupFile;
|
||||||
|
unsigned int m_dmrIdLookupTime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
std::string m_nxdnIdLookupFile;
|
||||||
|
unsigned int m_nxdnIdLookupTime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string m_modemProtocol;
|
||||||
|
std::string m_modemUARTPort;
|
||||||
|
unsigned int m_modemUARTSpeed;
|
||||||
|
std::string m_modemI2CPort;
|
||||||
|
unsigned int m_modemI2CAddress;
|
||||||
|
std::string m_modemModemAddress;
|
||||||
|
unsigned short m_modemModemPort;
|
||||||
|
std::string m_modemLocalAddress;
|
||||||
|
unsigned short m_modemLocalPort;
|
||||||
|
bool m_modemRXInvert;
|
||||||
|
bool m_modemTXInvert;
|
||||||
|
bool m_modemPTTInvert;
|
||||||
|
unsigned int m_modemTXDelay;
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
unsigned int m_modemDMRDelay;
|
||||||
|
#endif
|
||||||
|
int m_modemTXOffset;
|
||||||
|
int m_modemRXOffset;
|
||||||
|
int m_modemRXDCOffset;
|
||||||
|
int m_modemTXDCOffset;
|
||||||
|
float m_modemRFLevel;
|
||||||
|
float m_modemRXLevel;
|
||||||
|
float m_modemCWIdTXLevel;
|
||||||
|
float m_modemDStarTXLevel;
|
||||||
|
float m_modemDMRTXLevel;
|
||||||
|
float m_modemYSFTXLevel;
|
||||||
|
float m_modemP25TXLevel;
|
||||||
|
float m_modemNXDNTXLevel;
|
||||||
|
float m_modemPOCSAGTXLevel;
|
||||||
|
float m_modemFMTXLevel;
|
||||||
|
std::string m_modemRSSIMappingFile;
|
||||||
|
bool m_modemUseCOSAsLockout;
|
||||||
|
bool m_modemTrace;
|
||||||
|
bool m_modemDebug;
|
||||||
|
|
||||||
|
bool m_transparentEnabled;
|
||||||
|
std::string m_transparentRemoteAddress;
|
||||||
|
unsigned short m_transparentRemotePort;
|
||||||
|
unsigned short m_transparentLocalPort;
|
||||||
|
unsigned int m_transparentSendFrameType;
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
bool m_dstarEnabled;
|
||||||
|
std::string m_dstarModule;
|
||||||
|
bool m_dstarSelfOnly;
|
||||||
|
std::vector<std::string> m_dstarBlackList;
|
||||||
|
std::vector<std::string> m_dstarWhiteList;
|
||||||
|
bool m_dstarAckReply;
|
||||||
|
unsigned int m_dstarAckTime;
|
||||||
|
DSTAR_ACK m_dstarAckMessage;
|
||||||
|
bool m_dstarErrorReply;
|
||||||
|
bool m_dstarRemoteGateway;
|
||||||
|
#endif
|
||||||
|
unsigned int m_dstarModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
bool m_dmrEnabled;
|
||||||
|
DMR_BEACONS m_dmrBeacons;
|
||||||
|
unsigned int m_dmrBeaconInterval;
|
||||||
|
unsigned int m_dmrBeaconDuration;
|
||||||
|
#endif
|
||||||
|
unsigned int m_dmrId;
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
unsigned int m_dmrColorCode;
|
||||||
|
bool m_dmrSelfOnly;
|
||||||
|
bool m_dmrEmbeddedLCOnly;
|
||||||
|
bool m_dmrDumpTAData;
|
||||||
|
std::vector<unsigned int> m_dmrPrefixes;
|
||||||
|
std::vector<unsigned int> m_dmrBlackList;
|
||||||
|
std::vector<unsigned int> m_dmrWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot1TGWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot2TGWhiteList;
|
||||||
|
unsigned int m_dmrCallHang;
|
||||||
|
unsigned int m_dmrTXHang;
|
||||||
|
#endif
|
||||||
|
unsigned int m_dmrModeHang;
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
DMR_OVCM m_dmrOVCM;
|
||||||
|
bool m_dmrProtect;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
bool m_fusionEnabled;
|
||||||
|
bool m_fusionLowDeviation;
|
||||||
|
bool m_fusionRemoteGateway;
|
||||||
|
bool m_fusionSelfOnly;
|
||||||
|
unsigned int m_fusionTXHang;
|
||||||
|
#endif
|
||||||
|
unsigned int m_fusionModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_P25)
|
||||||
|
bool m_p25Enabled;
|
||||||
|
#endif
|
||||||
|
unsigned int m_p25Id;
|
||||||
|
#if defined(USE_P25)
|
||||||
|
unsigned int m_p25NAC;
|
||||||
|
bool m_p25SelfOnly;
|
||||||
|
bool m_p25OverrideUID;
|
||||||
|
bool m_p25RemoteGateway;
|
||||||
|
unsigned int m_p25TXHang;
|
||||||
|
#endif
|
||||||
|
unsigned int m_p25ModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
bool m_nxdnEnabled;
|
||||||
|
unsigned int m_nxdnId;
|
||||||
|
unsigned int m_nxdnRAN;
|
||||||
|
bool m_nxdnSelfOnly;
|
||||||
|
bool m_nxdnRemoteGateway;
|
||||||
|
unsigned int m_nxdnTXHang;
|
||||||
|
#endif
|
||||||
|
unsigned int m_nxdnModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_POCSAG)
|
||||||
|
bool m_pocsagEnabled;
|
||||||
|
#endif
|
||||||
|
unsigned int m_pocsagFrequency;
|
||||||
|
|
||||||
|
#if defined(USE_FM)
|
||||||
|
bool m_fmEnabled;
|
||||||
|
#endif
|
||||||
|
std::string m_fmCallsign;
|
||||||
|
#if defined(USE_FM)
|
||||||
|
unsigned int m_fmCallsignSpeed;
|
||||||
|
unsigned int m_fmCallsignFrequency;
|
||||||
|
unsigned int m_fmCallsignTime;
|
||||||
|
unsigned int m_fmCallsignHoldoff;
|
||||||
|
float m_fmCallsignHighLevel;
|
||||||
|
float m_fmCallsignLowLevel;
|
||||||
|
bool m_fmCallsignAtStart;
|
||||||
|
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;
|
||||||
|
unsigned int m_fmAckDelay;
|
||||||
|
float m_fmAckLevel;
|
||||||
|
#endif
|
||||||
|
unsigned int m_fmTimeout;
|
||||||
|
#if defined(USE_FM)
|
||||||
|
float m_fmTimeoutLevel;
|
||||||
|
float m_fmCTCSSFrequency;
|
||||||
|
unsigned int m_fmCTCSSHighThreshold;
|
||||||
|
unsigned int m_fmCTCSSLowThreshold;
|
||||||
|
float m_fmCTCSSLevel;
|
||||||
|
unsigned int m_fmKerchunkTime;
|
||||||
|
unsigned int m_fmHangTime;
|
||||||
|
unsigned int m_fmAccessMode;
|
||||||
|
bool m_fmLinkMode;
|
||||||
|
bool m_fmCOSInvert;
|
||||||
|
bool m_fmNoiseSquelch;
|
||||||
|
unsigned int m_fmSquelchHighThreshold;
|
||||||
|
unsigned int m_fmSquelchLowThreshold;
|
||||||
|
unsigned int m_fmRFAudioBoost;
|
||||||
|
float m_fmMaxDevLevel;
|
||||||
|
unsigned int m_fmExtAudioBoost;
|
||||||
|
#endif
|
||||||
|
unsigned int m_fmModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
bool m_dstarNetworkEnabled;
|
||||||
|
std::string m_dstarGatewayAddress;
|
||||||
|
unsigned short m_dstarGatewayPort;
|
||||||
|
std::string m_dstarLocalAddress;
|
||||||
|
unsigned short m_dstarLocalPort;
|
||||||
|
std::string m_dstarNetworkName;
|
||||||
|
#endif
|
||||||
|
unsigned int m_dstarNetworkModeHang;
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
bool m_dstarNetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_DMR)
|
||||||
|
bool m_dmrNetworkEnabled;
|
||||||
|
std::string m_dmrNetworkGatewayAddress;
|
||||||
|
unsigned short m_dmrNetworkGatewayPort;
|
||||||
|
std::string m_dmrNetworkLocalAddress;
|
||||||
|
unsigned short m_dmrNetworkLocalPort;
|
||||||
|
bool m_dmrNetworkDebug;
|
||||||
|
unsigned int m_dmrNetworkJitter;
|
||||||
|
bool m_dmrNetworkSlot1;
|
||||||
|
bool m_dmrNetworkSlot2;
|
||||||
|
#endif
|
||||||
|
unsigned int m_dmrNetworkModeHang;
|
||||||
|
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
bool m_fusionNetworkEnabled;
|
||||||
|
std::string m_fusionNetworkLocalAddress;
|
||||||
|
unsigned short m_fusionNetworkLocalPort;
|
||||||
|
std::string m_fusionNetworkGatewayAddress;
|
||||||
|
unsigned short m_fusionNetworkGatewayPort;
|
||||||
|
#endif
|
||||||
|
unsigned int m_fusionNetworkModeHang;
|
||||||
|
#if defined(USE_YSF)
|
||||||
|
bool m_fusionNetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_P25)
|
||||||
|
bool m_p25NetworkEnabled;
|
||||||
|
std::string m_p25GatewayAddress;
|
||||||
|
unsigned short m_p25GatewayPort;
|
||||||
|
std::string m_p25LocalAddress;
|
||||||
|
unsigned short m_p25LocalPort;
|
||||||
|
#endif
|
||||||
|
unsigned int m_p25NetworkModeHang;
|
||||||
|
#if defined(USE_P25)
|
||||||
|
bool m_p25NetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
bool m_nxdnNetworkEnabled;
|
||||||
|
std::string m_nxdnNetworkProtocol;
|
||||||
|
std::string m_nxdnGatewayAddress;
|
||||||
|
unsigned short m_nxdnGatewayPort;
|
||||||
|
std::string m_nxdnLocalAddress;
|
||||||
|
unsigned short m_nxdnLocalPort;
|
||||||
|
#endif
|
||||||
|
unsigned int m_nxdnNetworkModeHang;
|
||||||
|
#if defined(USE_NXDN)
|
||||||
|
bool m_nxdnNetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_POCSAG)
|
||||||
|
bool m_pocsagNetworkEnabled;
|
||||||
|
std::string m_pocsagGatewayAddress;
|
||||||
|
unsigned short m_pocsagGatewayPort;
|
||||||
|
std::string m_pocsagLocalAddress;
|
||||||
|
unsigned short m_pocsagLocalPort;
|
||||||
|
unsigned int m_pocsagNetworkModeHang;
|
||||||
|
bool m_pocsagNetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_FM)
|
||||||
|
bool m_fmNetworkEnabled;
|
||||||
|
std::string m_fmGatewayAddress;
|
||||||
|
unsigned short m_fmGatewayPort;
|
||||||
|
std::string m_fmLocalAddress;
|
||||||
|
unsigned short m_fmLocalPort;
|
||||||
|
bool m_fmPreEmphasis;
|
||||||
|
bool m_fmDeEmphasis;
|
||||||
|
float m_fmTXAudioGain;
|
||||||
|
float m_fmRXAudioGain;
|
||||||
|
#endif
|
||||||
|
unsigned int m_fmNetworkModeHang;
|
||||||
|
#if defined(USE_FM)
|
||||||
|
bool m_fmNetworkDebug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool m_lockFileEnabled;
|
||||||
|
std::string m_lockFileName;
|
||||||
|
|
||||||
|
bool m_remoteControlEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2019,2020,2021,2023,2024,2025 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 "DStarDefines.h"
|
||||||
|
#include "DStarNetwork.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 100U;
|
||||||
|
|
||||||
|
CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned short gatewayPort, const std::string& localAddress, unsigned short localPort, bool duplex, const char* version, const std::string& name, bool debug) :
|
||||||
|
m_socket(localAddress, localPort),
|
||||||
|
m_addr(),
|
||||||
|
m_addrLen(0U),
|
||||||
|
m_duplex(duplex),
|
||||||
|
m_version(version),
|
||||||
|
m_name(name),
|
||||||
|
m_debug(debug),
|
||||||
|
m_enabled(false),
|
||||||
|
m_outId(0U),
|
||||||
|
m_outSeq(0U),
|
||||||
|
m_inId(0U),
|
||||||
|
m_buffer(1000U, "D-Star Network"),
|
||||||
|
m_pollTimer(1000U, 60U),
|
||||||
|
m_linkStatus(LINK_STATUS::NONE),
|
||||||
|
m_linkReflector(nullptr),
|
||||||
|
m_random()
|
||||||
|
{
|
||||||
|
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_addr, m_addrLen) != 0)
|
||||||
|
m_addrLen = 0U;
|
||||||
|
|
||||||
|
m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
|
||||||
|
::memset(m_linkReflector, 0, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 mt(rd());
|
||||||
|
m_random = mt;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarNetwork::~CDStarNetwork()
|
||||||
|
{
|
||||||
|
delete[] m_linkReflector;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::open()
|
||||||
|
{
|
||||||
|
if (m_addrLen == 0U) {
|
||||||
|
LogError("Unable to resolve the address of the ircDDB Gateway");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMessage("Opening D-Star network connection");
|
||||||
|
|
||||||
|
m_pollTimer.start();
|
||||||
|
|
||||||
|
bool ret = m_socket.open(m_addr);
|
||||||
|
if (!ret)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Send registration with site name if configured
|
||||||
|
if (!m_name.empty()) {
|
||||||
|
LogMessage("D-Star registering with split controller as \"%s\"", m_name.c_str());
|
||||||
|
writeRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy)
|
||||||
|
{
|
||||||
|
assert(header != nullptr);
|
||||||
|
|
||||||
|
unsigned char buffer[50U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = busy ? 0x22U : 0x20U;
|
||||||
|
|
||||||
|
// Create a random id for this transmission
|
||||||
|
std::uniform_int_distribution<uint16_t> dist(0x0001, 0xfffe);
|
||||||
|
m_outId = dist(m_random);
|
||||||
|
|
||||||
|
buffer[5] = m_outId / 256U; // Unique session id
|
||||||
|
buffer[6] = m_outId % 256U;
|
||||||
|
|
||||||
|
buffer[7] = 0U;
|
||||||
|
|
||||||
|
::memcpy(buffer + 8U, header, length);
|
||||||
|
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U);
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 2U; i++) {
|
||||||
|
bool ret = m_socket.write(buffer, 49U, m_addr, m_addrLen);
|
||||||
|
if (!ret)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy)
|
||||||
|
{
|
||||||
|
assert(data != nullptr);
|
||||||
|
|
||||||
|
unsigned char buffer[30U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = busy ? 0x23U : 0x21U;
|
||||||
|
|
||||||
|
buffer[5] = m_outId / 256U; // Unique session id
|
||||||
|
buffer[6] = m_outId % 256U;
|
||||||
|
|
||||||
|
// If this is a data sync, reset the sequence to zero
|
||||||
|
if (data[9] == 0x55 && data[10] == 0x2D && data[11] == 0x16)
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
buffer[7] = m_outSeq;
|
||||||
|
if (end)
|
||||||
|
buffer[7] |= 0x40U; // End of data marker
|
||||||
|
|
||||||
|
buffer[8] = errors;
|
||||||
|
|
||||||
|
m_outSeq++;
|
||||||
|
if (m_outSeq > 0x14U)
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
::memcpy(buffer + 9U, data, length);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, length + 9U, m_addr, m_addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writePoll(const char* text)
|
||||||
|
{
|
||||||
|
assert(text != nullptr);
|
||||||
|
|
||||||
|
unsigned char buffer[40U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = 0x0AU; // Poll with text
|
||||||
|
|
||||||
|
unsigned int length = (unsigned int)::strlen(text);
|
||||||
|
|
||||||
|
// Include the nul at the end also
|
||||||
|
::memcpy(buffer + 5U, text, length + 1U);
|
||||||
|
|
||||||
|
// if (m_debug)
|
||||||
|
// CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 6U + length, m_addr, m_addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writeRegister()
|
||||||
|
{
|
||||||
|
unsigned char buffer[40U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = 0x0BU; // NETWORK_REGISTER with name
|
||||||
|
|
||||||
|
unsigned int length = (unsigned int)m_name.length();
|
||||||
|
if (length > 34U) length = 34U; // buffer[40] - offset[5] - null[1]
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < length; i++)
|
||||||
|
buffer[5U + i] = m_name[i];
|
||||||
|
buffer[5U + length] = 0x00U;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Register Sent", buffer, 6U + length);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 6U + length, m_addr, m_addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_pollTimer.clock(ms);
|
||||||
|
if (m_pollTimer.hasExpired()) {
|
||||||
|
char text[60U];
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
if (m_duplex)
|
||||||
|
::sprintf(text, "win_mmdvm-%s", m_version);
|
||||||
|
else
|
||||||
|
::sprintf(text, "win_mmdvm-dvmega-%s", m_version);
|
||||||
|
#else
|
||||||
|
if (m_duplex)
|
||||||
|
::sprintf(text, "linux_mmdvm-%s", m_version);
|
||||||
|
else
|
||||||
|
::sprintf(text, "linux_mmdvm-dvmega-%s", m_version);
|
||||||
|
#endif
|
||||||
|
writePoll(text);
|
||||||
|
|
||||||
|
// Send registration keepalive if name is configured
|
||||||
|
if (!m_name.empty())
|
||||||
|
writeRegister();
|
||||||
|
|
||||||
|
m_pollTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
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("D-Star, packet received from an invalid source");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid packet type?
|
||||||
|
if (::memcmp(buffer, "DSRP", 4U) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (buffer[4]) {
|
||||||
|
case 0x00U: // NETWORK_TEXT;
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Status Received", buffer, length);
|
||||||
|
|
||||||
|
m_linkStatus = LINK_STATUS(buffer[25U]);
|
||||||
|
::memcpy(m_linkReflector, buffer + 26U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
LogMessage("D-Star link status set to \"%20.20s\"", buffer + 5U);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x01U: // NETWORK_TEMPTEXT;
|
||||||
|
case 0x04U: // NETWORK_STATUS1..5
|
||||||
|
case 0x0AU: // POLL
|
||||||
|
case 0x24U: // NETWORK_DD_DATA
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x20U: // NETWORK_HEADER
|
||||||
|
if (m_inId == 0U && m_enabled) {
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Header Received", buffer, length);
|
||||||
|
|
||||||
|
m_inId = buffer[5] * 256U + buffer[6];
|
||||||
|
|
||||||
|
unsigned char c = length - 7U;
|
||||||
|
m_buffer.addData(&c, 1U);
|
||||||
|
|
||||||
|
c = TAG_HEADER;
|
||||||
|
m_buffer.addData(&c, 1U);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer + 8U, length - 8U);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21U: // NETWORK_DATA
|
||||||
|
if (m_enabled) {
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Data Received", buffer, length);
|
||||||
|
|
||||||
|
uint16_t id = buffer[5] * 256U + buffer[6];
|
||||||
|
|
||||||
|
// Check that the stream id matches the valid header, reject otherwise
|
||||||
|
if (id == m_inId && m_enabled) {
|
||||||
|
unsigned char ctrl[3U];
|
||||||
|
|
||||||
|
ctrl[0U] = length - 7U;
|
||||||
|
|
||||||
|
// Is this the last packet in the stream?
|
||||||
|
if ((buffer[7] & 0x40) == 0x40) {
|
||||||
|
m_inId = 0U;
|
||||||
|
ctrl[1U] = TAG_EOT;
|
||||||
|
} else {
|
||||||
|
ctrl[1U] = TAG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl[2U] = buffer[7] & 0x3FU;
|
||||||
|
|
||||||
|
m_buffer.addData(ctrl, 3U);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer + 9U, length - 9U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CUtils::dump("Unknown D-Star packet from the Gateway", buffer, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDStarNetwork::read(unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != nullptr);
|
||||||
|
|
||||||
|
if (m_buffer.isEmpty())
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
unsigned char c = 0U;
|
||||||
|
m_buffer.getData(&c, 1U);
|
||||||
|
|
||||||
|
assert(c <= 100U);
|
||||||
|
assert(c <= length);
|
||||||
|
|
||||||
|
unsigned char buffer[100U];
|
||||||
|
m_buffer.getData(buffer, c);
|
||||||
|
|
||||||
|
switch (buffer[0U]) {
|
||||||
|
case TAG_HEADER:
|
||||||
|
case TAG_DATA:
|
||||||
|
case TAG_EOT:
|
||||||
|
::memcpy(data, buffer, c);
|
||||||
|
return c;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::reset()
|
||||||
|
{
|
||||||
|
m_inId = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::isConnected() const
|
||||||
|
{
|
||||||
|
return (m_addrLen != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::close()
|
||||||
|
{
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
LogMessage("Closing D-Star network connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::enable(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled && !m_enabled)
|
||||||
|
reset();
|
||||||
|
else if (!enabled && m_enabled)
|
||||||
|
m_buffer.clear();
|
||||||
|
|
||||||
|
m_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::getStatus(LINK_STATUS& status, unsigned char* reflector)
|
||||||
|
{
|
||||||
|
assert(reflector != nullptr);
|
||||||
|
|
||||||
|
status = m_linkStatus;
|
||||||
|
|
||||||
|
::memcpy(reflector, m_linkReflector, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2020,2021,2023 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 DStarNetwork_H
|
||||||
|
#define DStarNetwork_H
|
||||||
|
|
||||||
|
#include "DStarDefines.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#if defined(USE_DSTAR)
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
class CDStarNetwork {
|
||||||
|
public:
|
||||||
|
CDStarNetwork(const std::string& gatewayAddress, unsigned short gatewayPort, const std::string& localAddress, unsigned short localPort, bool duplex, const char* version, const std::string& name, bool debug);
|
||||||
|
~CDStarNetwork();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
|
bool writeHeader(const unsigned char* header, unsigned int length, bool busy);
|
||||||
|
bool writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy);
|
||||||
|
|
||||||
|
void getStatus(LINK_STATUS& status, unsigned char* reflector);
|
||||||
|
|
||||||
|
unsigned int read(unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
bool isConnected() const;
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_socket;
|
||||||
|
sockaddr_storage m_addr;
|
||||||
|
unsigned int m_addrLen;
|
||||||
|
bool m_duplex;
|
||||||
|
const char* m_version;
|
||||||
|
std::string m_name;
|
||||||
|
bool m_debug;
|
||||||
|
bool m_enabled;
|
||||||
|
uint16_t m_outId;
|
||||||
|
uint8_t m_outSeq;
|
||||||
|
uint16_t m_inId;
|
||||||
|
CRingBuffer<unsigned char> m_buffer;
|
||||||
|
CTimer m_pollTimer;
|
||||||
|
LINK_STATUS m_linkStatus;
|
||||||
|
unsigned char* m_linkReflector;
|
||||||
|
std::mt19937 m_random;
|
||||||
|
|
||||||
|
bool writePoll(const char* text);
|
||||||
|
bool writeRegister();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Patches Conf.cpp to add DStarNetworkName support"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
with open('Conf.cpp', 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# 1. Add initializer after m_dstarLocalPort(0U),
|
||||||
|
old = 'm_dstarLocalPort(0U),\n#endif\nm_dstarNetworkModeHang(3U),'
|
||||||
|
new = 'm_dstarLocalPort(0U),\nm_dstarNetworkName(),\n#endif\nm_dstarNetworkModeHang(3U),'
|
||||||
|
if old not in content:
|
||||||
|
print("ERROR: Could not find initializer insertion point")
|
||||||
|
sys.exit(1)
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
print("1. Initializer added OK")
|
||||||
|
|
||||||
|
# 2. Add Name= parser - single tabs
|
||||||
|
old = '\t\t\telse if (::strcmp(key, "LocalPort") == 0)\n\t\t\t\tm_dstarLocalPort = (unsigned short)::atoi(value);\n\t\t\telse if (::strcmp(key, "ModeHang") == 0)\n\t\t\t\tm_dstarNetworkModeHang = (unsigned int)::atoi(value);\n\t\t\telse if (::strcmp(key, "Debug") == 0)\n\t\t\t\tm_dstarNetworkDebug = ::atoi(value) == 1;\n#endif\n#if defined(USE_DMR)\n\t\t} else if (section == SECTION::DMR_NETWORK) {'
|
||||||
|
new = '\t\t\telse if (::strcmp(key, "LocalPort") == 0)\n\t\t\t\tm_dstarLocalPort = (unsigned short)::atoi(value);\n\t\t\telse if (::strcmp(key, "Name") == 0)\n\t\t\t\tm_dstarNetworkName = value;\n\t\t\telse if (::strcmp(key, "ModeHang") == 0)\n\t\t\t\tm_dstarNetworkModeHang = (unsigned int)::atoi(value);\n\t\t\telse if (::strcmp(key, "Debug") == 0)\n\t\t\t\tm_dstarNetworkDebug = ::atoi(value) == 1;\n#endif\n#if defined(USE_DMR)\n\t\t} else if (section == SECTION::DMR_NETWORK) {'
|
||||||
|
if old not in content:
|
||||||
|
print("ERROR: Could not find Name= parser insertion point")
|
||||||
|
sys.exit(1)
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
print("2. Name= parser added OK")
|
||||||
|
|
||||||
|
# 3. Add getDStarNetworkName() getter - try tabs first then spaces
|
||||||
|
old = 'unsigned int CConf::getDStarNetworkModeHang() const\n{\n\treturn m_dstarNetworkModeHang;\n}'
|
||||||
|
new = 'std::string CConf::getDStarNetworkName() const\n{\n\treturn m_dstarNetworkName;\n}\n\nunsigned int CConf::getDStarNetworkModeHang() const\n{\n\treturn m_dstarNetworkModeHang;\n}'
|
||||||
|
if old not in content:
|
||||||
|
old = 'unsigned int CConf::getDStarNetworkModeHang() const\n{\n return m_dstarNetworkModeHang;\n}'
|
||||||
|
new = 'std::string CConf::getDStarNetworkName() const\n{\n return m_dstarNetworkName;\n}\n\nunsigned int CConf::getDStarNetworkModeHang() const\n{\n return m_dstarNetworkModeHang;\n}'
|
||||||
|
if old not in content:
|
||||||
|
print("ERROR: Could not find getter insertion point")
|
||||||
|
sys.exit(1)
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
print("3. getDStarNetworkName() getter added OK")
|
||||||
|
|
||||||
|
with open('Conf.cpp', 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print("Conf.cpp patched successfully")
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Patches MMDVM-Host.cpp to add DStarNetworkName support"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
with open('MMDVM-Host.cpp', 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
old = '\tbool debug = m_conf.getDStarNetworkDebug();\n\tm_dstarNetModeHang = m_conf.getDStarNetworkModeHang();\n\n\tLogInfo("D-Star Network Parameters");\n\tLogInfo(" Gateway Address: %s", gatewayAddress.c_str());\n\tLogInfo(" Gateway Port: %hu", gatewayPort);\n\tLogInfo(" Local Address: %s", localAddress.c_str());\n\tLogInfo(" Local Port: %hu", localPort);\n\tLogInfo(" Mode Hang: %us", m_dstarNetModeHang);\n\n\tm_dstarNetwork = new CDStarNetwork(gatewayAddress, gatewayPort, localAddress, localPort, m_duplex, VERSION, debug);'
|
||||||
|
|
||||||
|
new = '\tbool debug = m_conf.getDStarNetworkDebug();\n\tstd::string name = m_conf.getDStarNetworkName();\n\tm_dstarNetModeHang = m_conf.getDStarNetworkModeHang();\n\n\tLogInfo("D-Star Network Parameters");\n\tLogInfo(" Gateway Address: %s", gatewayAddress.c_str());\n\tLogInfo(" Gateway Port: %hu", gatewayPort);\n\tLogInfo(" Local Address: %s", localAddress.c_str());\n\tLogInfo(" Local Port: %hu", localPort);\n\tLogInfo(" Mode Hang: %us", m_dstarNetModeHang);\n\tif (!name.empty())\n\t\tLogInfo(" Name: %s", name.c_str());\n\n\tm_dstarNetwork = new CDStarNetwork(gatewayAddress, gatewayPort, localAddress, localPort, m_duplex, VERSION, name, debug);'
|
||||||
|
|
||||||
|
if old not in content:
|
||||||
|
print("ERROR: Could not find createDStarNetwork insertion point")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
content = content.replace(old, new, 1)
|
||||||
|
print("createDStarNetwork() patched OK")
|
||||||
|
|
||||||
|
with open('MMDVM-Host.cpp', 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print("MMDVM-Host.cpp patched successfully")
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# D-Star Site Update Script
|
||||||
|
# Pulls latest patches and rebuilds MMDVMHost
|
||||||
|
# Usage: sudo bash update.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
MMDVM_SOURCE_DIR="/home/pi/MMDVM-Host"
|
||||||
|
|
||||||
|
echo "================================================"
|
||||||
|
echo " D-Star Site Updater"
|
||||||
|
echo "================================================"
|
||||||
|
|
||||||
|
# Pull latest repo
|
||||||
|
echo "Pulling latest from Gitea..."
|
||||||
|
cd "$REPO_DIR"
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Pull latest MMDVMHost source
|
||||||
|
echo "Pulling latest MMDVMHost source..."
|
||||||
|
cd "$MMDVM_SOURCE_DIR"
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Restore original files before patching
|
||||||
|
echo "Restoring originals..."
|
||||||
|
git checkout DStarNetwork.cpp DStarNetwork.h Conf.h Conf.cpp MMDVM-Host.cpp
|
||||||
|
|
||||||
|
# Apply patches
|
||||||
|
echo "Applying patches..."
|
||||||
|
cp "$REPO_DIR/src/DStarNetwork.cpp" ./
|
||||||
|
cp "$REPO_DIR/src/DStarNetwork.h" ./
|
||||||
|
cp "$REPO_DIR/src/Conf.h" ./
|
||||||
|
python3 "$REPO_DIR/src/patch_conf_cpp.py"
|
||||||
|
python3 "$REPO_DIR/src/patch_mmdvm_host_cpp.py"
|
||||||
|
|
||||||
|
# Recompile
|
||||||
|
echo "Compiling..."
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
# Install
|
||||||
|
echo "Installing..."
|
||||||
|
systemctl stop mmdvmhost
|
||||||
|
cp MMDVM-Host /usr/local/bin/MMDVM-Host
|
||||||
|
systemctl start mmdvmhost
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Update complete"
|
||||||
|
systemctl status mmdvmhost --no-pager
|
||||||
Loading…
Reference in new issue