diff --git a/Makefile b/Makefile
index f4383c57..06e81bbc 100644
--- a/Makefile
+++ b/Makefile
@@ -9,12 +9,13 @@ rpi-armCXX = /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf
rpi-armSTRIP= /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I.
+CCFLAGS = -I..
EXTFLAGS=
LIBS = -lpthread -lutil
LDFLAGS = -g
-BIN = dvmhost
-OBJECTS = \
+HOST_BIN = dvmhost
+HOST_OBJECTS = \
edac/AMBEFEC.o \
edac/BCH.o \
edac/BPTC19696.o \
@@ -88,16 +89,27 @@ OBJECTS = \
StopWatch.o \
Utils.o \
HostMain.o
+CMD_BIN = dvmcmd
+CMD_OBJECTS = \
+ remote/RemoteCommand.cmd.o \
+ edac/SHA256.cmd.o \
+ network/UDPSocket.cmd.o \
+ Log.cmd.o
-all: dvmhost
-dvmhost: $(OBJECTS)
- $($(ARCH)CXX) $(OBJECTS) $(CFLAGS) $(EXTFLAGS) $(LIBS) -o $(BIN)
+all: dvmhost dvmcmd
+dvmhost: $(HOST_OBJECTS)
+ $($(ARCH)CXX) $(HOST_OBJECTS) $(CFLAGS) $(EXTFLAGS) $(LIBS) -o $(HOST_BIN)
+dvmcmd: $(CMD_OBJECTS)
+ $($(ARCH)CXX) $(CMD_OBJECTS) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) $(LIBS) -o $(CMD_BIN)
%.o: %.cpp
$($(ARCH)CXX) $(CFLAGS) $(EXTFLAGS) -c -o $@ $<
+%.cmd.o: %.cpp
+ $($(ARCH)CXX) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) -c -o $@ $<
strip:
- $($(ARCH)STRIP) $(BIN)
+ -$($(ARCH)STRIP) $(HOST_BIN)
+ -$($(ARCH)STRIP) $(CMD_BIN)
clean:
- $(RM) $(BIN) $(OBJECTS) *.o *.d *.bak *~
+ $(RM) $(HOST_BIN) $(HOST_OBJECTS) $(CMD_BIN) $(CMD_OBJECTS) *.o *.d *.bak *~
$(RM) -r dpkg_build
$(RM) dvmhost_1.0.0* dvmhost-dbgsym*.deb
diff --git a/remote/DVMCmd.vcxproj b/remote/DVMCmd.vcxproj
new file mode 100644
index 00000000..1e186e8f
--- /dev/null
+++ b/remote/DVMCmd.vcxproj
@@ -0,0 +1,173 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {7686FC39-EC3C-4FAC-8C7D-32CF98D14F16}
+ Win32Proj
+ DVMCmd
+ dvmcmd
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir);$(IncludePath)
+
+
+ true
+ $(ProjectDir);$(IncludePath)
+
+
+ false
+ $(ProjectDir);$(IncludePath)
+
+
+ false
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ true
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ true
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/remote/DVMCmd.vcxproj.filters b/remote/DVMCmd.vcxproj.filters
new file mode 100644
index 00000000..997fd1e5
--- /dev/null
+++ b/remote/DVMCmd.vcxproj.filters
@@ -0,0 +1,55 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {916a1400-af49-4141-912a-eb51ee88e24a}
+
+
+ {364613af-689a-40ff-9eb0-9ed75ec264d0}
+
+
+ {cf353bb3-7f93-4b59-98fa-c8c2db8a1afb}
+
+
+ {b8c3589b-0d9a-4adf-a14e-45530240b9cb}
+
+
+
+
+ Header Files
+
+
+ Header Files\network
+
+
+ Header Files
+
+
+ Header Files\edac
+
+
+
+
+ Source Files
+
+
+ Source Files\network
+
+
+ Source Files\edac
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/remote/RemoteCommand.cpp b/remote/RemoteCommand.cpp
new file mode 100644
index 00000000..c27173e3
--- /dev/null
+++ b/remote/RemoteCommand.cpp
@@ -0,0 +1,306 @@
+/**
+* Digital Voice Modem - Remote Command Client
+* GPLv2 Open Source. Use is subject to license terms.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* @package DVM / Remote Command Client
+*
+*/
+//
+// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
+// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+//
+/*
+* Copyright (C) 2019 by Jonathan Naylor G4KLX
+* Copyright (C) 2019 by Bryan Biedenkapp
+*
+* 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 "Defines.h"
+#include "edac/SHA256.h"
+#include "network/UDPSocket.h"
+#include "RemoteCommand.h"
+#include "Log.h"
+
+using namespace network;
+
+#include
+#include
+#include
+#include
+
+// ---------------------------------------------------------------------------
+// Constants
+// ---------------------------------------------------------------------------
+
+#undef __PROG_NAME__
+#define __PROG_NAME__ "Digital Voice Modem (DVM) RCON Tool"
+#undef __EXE_NAME__
+#define __EXE_NAME__ "dvmcmd"
+
+const uint32_t START_OF_TEXT = 0x02;
+const uint32_t REC_SEPARATOR = 0x1E;
+
+const uint32_t RC_BUFFER_LENGTH = 140U;
+
+// ---------------------------------------------------------------------------
+// Macros
+// ---------------------------------------------------------------------------
+#define IS(s) (::strcmp(argv[i], s) == 0)
+
+// ---------------------------------------------------------------------------
+// Global Variables
+// ---------------------------------------------------------------------------
+
+static std::string g_progExe = std::string(__EXE_NAME__);
+static std::string g_remoteAddress = std::string("127.0.0.1");
+static uint32_t g_remotePort = RCON_DEFAULT_PORT;
+static std::string g_remotePassword = std::string();
+
+// ---------------------------------------------------------------------------
+// Global Functions
+// ---------------------------------------------------------------------------
+
+void fatal(const char* message)
+{
+ ::fprintf(stderr, "%s: %s\n", g_progExe.c_str(), message);
+ exit(EXIT_FAILURE);
+}
+
+void usage(const char* message, const char* arg)
+{
+ ::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
+ if (message != NULL) {
+ ::fprintf(stderr, "%s: ", g_progExe.c_str());
+ ::fprintf(stderr, message, arg);
+ ::fprintf(stderr, "\n\n");
+ }
+
+ ::fprintf(stdout, "usage: %s [-v] [-a ] [-p ] [-P ] \n\n"
+ " -a remote modem command address\n"
+ " -p remote modem command port\n"
+ " -P remote modem authentication password\n"
+ "\n"
+ " -v show version information\n"
+ " -h show this screen\n"
+ " -- stop handling options\n",
+ g_progExe.c_str());
+ exit(EXIT_FAILURE);
+}
+
+int checkArgs(int argc, char* argv[])
+{
+ int i, p = 0;
+
+ // iterate through arguments
+ for (i = 1; i <= argc; i++)
+ {
+ if (argv[i] == NULL) {
+ break;
+ }
+
+ if (*argv[i] != '-') {
+ continue;
+ }
+ else if (IS("--")) {
+ ++p;
+ break;
+ }
+ else if (IS("-a")) {
+ if ((argc - 1) <= 0)
+ usage("error: %s", "must specify the address to connect to");
+ g_remoteAddress = std::string(argv[++i]);
+
+ if (g_remoteAddress == "")
+ usage("error: %s", "remote address cannot be blank!");
+
+ p += 2;
+ }
+ else if (IS("-p")) {
+ if ((argc - 1) <= 0)
+ usage("error: %s", "must specify the port to connect to");
+ g_remotePort = (uint32_t)::atoi(argv[++i]);
+
+ if (g_remotePort == 0)
+ usage("error: %s", "remote port number cannot be blank or 0!");
+
+ p += 2;
+ }
+ else if (IS("-P")) {
+ if ((argc - 1) <= 0)
+ usage("error: %s", "must specify the auth password");
+ g_remotePassword = std::string(argv[++i]);
+
+ if (g_remotePassword == "")
+ usage("error: %s", "remote auth password cannot be blank!");
+
+ p += 2;
+ }
+ else if (IS("-v")) {
+ ::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
+ if (argc == 2)
+ exit(EXIT_SUCCESS);
+ }
+ else if (IS("-h")) {
+ usage(NULL, NULL);
+ if (argc == 2)
+ exit(EXIT_SUCCESS);
+ }
+ else {
+ usage("unrecognized option `%s'", argv[i]);
+ }
+ }
+
+ if (p < 0 || p > argc) {
+ p = 0;
+ }
+
+ return ++p;
+}
+
+// ---------------------------------------------------------------------------
+// Program Entry Point
+// ---------------------------------------------------------------------------
+
+int main(int argc, char** argv)
+{
+ if (argv[0] != NULL && *argv[0] != 0)
+ g_progExe = std::string(argv[0]);
+
+ if (argc < 2) {
+ usage("error: %s", "must specify the remote command!");
+ return EXIT_FAILURE;
+ }
+
+ if (argc > 1) {
+ // check arguments
+ int i = checkArgs(argc, argv);
+ if (i < argc) {
+ argc -= i;
+ argv += i;
+ }
+ else {
+ argc--;
+ argv++;
+ }
+ }
+
+ // process command
+ std::string cmd = std::string(argv[0]);
+ for (int i = 1; i < argc; i++) {
+ cmd += " ";
+ cmd += std::string(argv[i]);
+ }
+
+ // initialize system logging
+ bool ret = ::LogInitialise("", "", 0U, 1U);
+ if (!ret) {
+ ::fprintf(stderr, "unable to open the log file\n");
+ return 1;
+ }
+
+ CRemoteCommand* command = new CRemoteCommand(g_remoteAddress, g_remotePort, g_remotePassword);
+ int retCode = command->send(cmd);
+
+ ::LogFinalise();
+ return retCode;
+}
+
+// ---------------------------------------------------------------------------
+// Public Class Members
+// ---------------------------------------------------------------------------
+///
+/// Initializes a new instance of the CRemoteCommand class.
+///
+/// Network Hostname/IP address to connect to.
+/// Network port number.
+/// Authentication password.
+CRemoteCommand::CRemoteCommand(const std::string& address, uint32_t port, const std::string& password) :
+ m_address(address),
+ m_port(port),
+ m_password(password)
+{
+ assert(!address.empty());
+ assert(port > 0U);
+}
+
+///
+/// Finalizes a instance of the CRemoteCommand class.
+///
+CRemoteCommand::~CRemoteCommand()
+{
+ /* stub */
+}
+
+///
+/// Sends remote control command to the specified modem.
+///
+/// Command string to send to remote modem.
+/// EXIT_SUCCESS, if command was sent, otherwise EXIT_FAILURE.
+int CRemoteCommand::send(const std::string& command)
+{
+ UDPSocket socket(0U);
+
+ bool ret = socket.open();
+ if (!ret)
+ return EXIT_FAILURE;
+
+ uint8_t buffer[RC_BUFFER_LENGTH];
+ ::memset(buffer, 0x00U, RC_BUFFER_LENGTH);
+
+ sockaddr_storage addr;
+ uint32_t addrLen;
+
+ if (UDPSocket::lookup(m_address, m_port, addr, addrLen) != 0)
+ addrLen = 0U;
+
+ if (addrLen > 0U) {
+ return EXIT_FAILURE;
+ }
+
+ ::LogInfoEx(LOG_HOST, "%s: sending command \"%s\" to %s:%u\r\n", g_progExe.c_str(), command.c_str(),
+ m_address.c_str(), m_port);
+
+ buffer[0U] = START_OF_TEXT;
+
+ if (!m_password.empty()) {
+ size_t size = m_password.size();
+
+ uint8_t* in = new uint8_t[size];
+ for (size_t i = 0U; i < size; i++)
+ in[i] = m_password.at(i);
+
+ uint8_t out[32U];
+ ::memset(out, 0x00U, 32U);
+
+ edac::SHA256 sha256;
+ sha256.buffer(in, (uint32_t)(size), out);
+
+ ::memcpy(buffer + 1U, out, 32U);
+ }
+
+ buffer[33U] = REC_SEPARATOR;
+ ::memcpy(buffer + 34U, command.c_str(), command.size());
+
+ ret = socket.write((uint8_t *)buffer, 34U + command.size(), addr, m_port);
+ if (!ret) {
+ socket.close();
+ ::LogError(LOG_HOST, "Failed to send command: \"%s\"\r\n", command.c_str());
+ return EXIT_FAILURE;
+ }
+
+ socket.close();
+ return EXIT_SUCCESS;
+}
diff --git a/remote/RemoteCommand.h b/remote/RemoteCommand.h
new file mode 100644
index 00000000..6a38631e
--- /dev/null
+++ b/remote/RemoteCommand.h
@@ -0,0 +1,60 @@
+/**
+* Digital Voice Modem - Remote Command Client
+* GPLv2 Open Source. Use is subject to license terms.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* @package DVM / Remote Command Client
+*
+*/
+//
+// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
+// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
+//
+/*
+* Copyright (C) 2019 by Jonathan Naylor G4KLX
+* Copyright (C) 2019 by Bryan Biedenkapp
+*
+* 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(__REMOTE_COMMAND_H__)
+#define __REMOTE_COMMAND_H__
+
+#include "Defines.h"
+
+#include
+
+// ---------------------------------------------------------------------------
+// Class Declaration
+// This class implements the core remote command logic.
+// ---------------------------------------------------------------------------
+
+class HOST_SW_API CRemoteCommand
+{
+public:
+ /// Initializes a new instance of the CRemoteCommand class.
+ CRemoteCommand(const std::string& address, uint32_t port, const std::string& password);
+ /// Finalizes a instance of the CRemoteCommand class.
+ ~CRemoteCommand();
+
+ /// Sends remote control command to the specified modem.
+ int send(const std::string& command);
+
+private:
+ std::string m_address;
+ uint32_t m_port;
+ std::string m_password;
+};
+
+#endif // __REMOTE_COMMAND_H__