diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj index b0b5d572..5b709d4b 100644 --- a/DVMHost.vcxproj +++ b/DVMHost.vcxproj @@ -190,6 +190,7 @@ + @@ -267,6 +268,7 @@ + diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters index 25cdafd9..e413b15e 100644 --- a/DVMHost.vcxproj.filters +++ b/DVMHost.vcxproj.filters @@ -117,6 +117,12 @@ {bd26735c-6610-4bfe-b1c4-27da1cb18e29} + + {fdb4c489-755e-4655-a0e3-b1174c8e7acc} + + + {145b73dd-7759-4018-9df2-af162f652699} + @@ -353,6 +359,9 @@ Header Files\dmr\lc + + Header Files\host\setup + @@ -568,6 +577,9 @@ Source Files\dmr\lc + + Source Files\host\setup + diff --git a/HostMain.cpp b/HostMain.cpp index b015578a..b194520c 100644 --- a/HostMain.cpp +++ b/HostMain.cpp @@ -12,7 +12,7 @@ // /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX -* Copyright (C) 2020 by Bryan Biedenkapp N2PLL +* Copyright (C) 2020,2021 by Bryan Biedenkapp N2PLL * * 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 @@ -32,6 +32,7 @@ #include "HostMain.h" #include "host/Host.h" #include "host/calibrate/HostCal.h" +#include "host/setup/HostSetup.h" #include "Log.h" using namespace network; @@ -61,6 +62,7 @@ using namespace lookups; int g_signal = 0; bool g_calibrate = false; +bool g_setup = false; std::string g_progExe = std::string(__EXE_NAME__); std::string g_iniFile = std::string(DEFAULT_CONF_FILE); std::string g_lockFile = std::string(DEFAULT_LOCK_FILE); @@ -109,9 +111,10 @@ void usage(const char* message, const char* arg) ::fprintf(stderr, "\n\n"); } - ::fprintf(stdout, "usage: %s [-v] [-f] [--cal] [-c ]\n\n" + ::fprintf(stdout, "usage: %s [-v] [-f] [--cal] [--setup] [-c ]\n\n" " -f foreground mode\n" " --cal calibration mode\n" + " --setup setup mode\n" "\n" " -v show version information\n" " -h show this screen\n" @@ -144,6 +147,9 @@ int checkArgs(int argc, char* argv[]) else if (IS("--cal")) { g_calibrate = true; } + else if (IS("--setup")) { + g_setup = true; + } else if (IS("-c")) { if (argc-- <= 0) usage("error: %s", "must specify the configuration file to use"); @@ -209,10 +215,17 @@ int main(int argc, char** argv) do { g_signal = 0; - if (g_calibrate) { - HostCal* cal = new HostCal(g_iniFile); - ret = cal->run(); - delete cal; + if (g_calibrate || g_setup) { + if (g_setup) { + HostSetup* setup = new HostSetup(g_iniFile); + ret = setup->run(); + delete setup; + } + else { + HostCal* cal = new HostCal(g_iniFile); + ret = cal->run(); + delete cal; + } } else { Host* host = new Host(g_iniFile); diff --git a/Log.h b/Log.h index aece653e..b820ce11 100644 --- a/Log.h +++ b/Log.h @@ -46,6 +46,7 @@ #define LOG_P25 "P25" #define LOG_DMR "DMR" #define LOG_CAL "CAL" +#define LOG_SETUP "SETUP" // --------------------------------------------------------------------------- // Macros diff --git a/Makefile b/Makefile index a46e2bea..887aeefc 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ OBJECTS = \ yaml/Yaml.o \ host/calibrate/Console.o \ host/calibrate/HostCal.o \ + host/setup/HostSetup.o \ host/Host.o \ Log.o \ Mutex.o \ @@ -86,4 +87,4 @@ dvmhost: $(OBJECTS) $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o + $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o host/setup/*.o diff --git a/Makefile.arm b/Makefile.arm index 2cee2e35..effff533 100644 --- a/Makefile.arm +++ b/Makefile.arm @@ -68,6 +68,7 @@ OBJECTS = \ yaml/Yaml.o \ host/calibrate/Console.o \ host/calibrate/HostCal.o \ + host/setup/HostSetup.o \ host/Host.o \ Log.o \ Mutex.o \ @@ -86,4 +87,4 @@ dvmhost: $(OBJECTS) $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o + $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o host/setup/*.o diff --git a/Makefile.rpi-arm b/Makefile.rpi-arm index 84f9fbdd..09dd4dde 100644 --- a/Makefile.rpi-arm +++ b/Makefile.rpi-arm @@ -68,6 +68,7 @@ OBJECTS = \ yaml/Yaml.o \ host/calibrate/Console.o \ host/calibrate/HostCal.o \ + host/setup/HostSetup.o \ host/Host.o \ Log.o \ Mutex.o \ @@ -86,4 +87,4 @@ dvmhost: $(OBJECTS) $(CXX) $(CFLAGS) -c -o $@ $< clean: - $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o + $(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o modem/port/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o host/setup/*.o diff --git a/host/calibrate/Console.cpp b/host/calibrate/Console.cpp index 2959f60d..b674e05a 100644 --- a/host/calibrate/Console.cpp +++ b/host/calibrate/Console.cpp @@ -43,7 +43,6 @@ // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- - #if defined(_WIN32) || defined(_WIN64) /// /// Initializes a new instance of the Console class. @@ -174,3 +173,72 @@ void Console::close() ::fprintf(stderr, "tcsetattr: returned %d\r\n", n); } #endif + +/// +/// Retrieves an array of characters input on the keyboard. +/// +/// +/// +/// +/// +int Console::getLine(char line[], int max, char mask) +{ + int nch = 0; + int c; + bool skipNext = false; + max = max - 1; /* leave room for '\0' */ + + while ((c = getChar()) != '\n') { + if (c != -1) { + if (c == 10 || c == 13) + break; + + // skip "double-byte" control characters + if (c == 224) { + skipNext = true; + continue; + } + + if (skipNext) { + skipNext = false; + continue; + } + + // has characters and backspace character? + if (nch > 0 && (c == 127 || c == 8)) { + // handle backspace + ::fputc(0x8, stdout); + ::fputc(' ', stdout); + ::fputc(0x8, stdout); + ::fflush(stdout); + + line[--nch] = 0; + } + else { + // skip control characters + if (iscntrl(c)) + continue; + + if (nch < max) { + // valid mask character? + if (' ' - 1 < mask && mask < 127) + ::fputc(mask, stdout); + else + ::fputc(c, stdout); + ::fflush(stdout); + + line[nch++] = c; + } + } + } + } + + if (c == EOF && nch == 0) + return EOF; + + ::fputc('\n', stdout); + ::fflush(stdout); + + line[nch] = '\0'; + return nch; +} diff --git a/host/calibrate/Console.h b/host/calibrate/Console.h index 563566ae..16101d3c 100644 --- a/host/calibrate/Console.h +++ b/host/calibrate/Console.h @@ -55,6 +55,9 @@ public: /// Retrieves a character input on the keyboard. int getChar(); + /// Retrieves an array of characters input on the keyboard. + int getLine(char line[], int max, char mask); + /// Closes the terminal console. void close(); diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp index 0c169b4e..d14d82d3 100644 --- a/host/calibrate/HostCal.cpp +++ b/host/calibrate/HostCal.cpp @@ -198,6 +198,7 @@ int HostCal::run() ::LogInfo(">> Modem Calibration"); yaml::Node systemConf = m_conf["system"]; + m_duplex = systemConf["duplex"].as(true); // try to load bandplan identity table std::string idenLookupFile = systemConf["iden_table"]["file"].as(); @@ -442,6 +443,7 @@ int HostCal::run() setTXDCOffset(1); break; + /** Engineering Commands */ case '-': setDMRSymLevel3Adj(-1); break; diff --git a/host/setup/HostSetup.cpp b/host/setup/HostSetup.cpp new file mode 100644 index 00000000..9d3df641 --- /dev/null +++ b/host/setup/HostSetup.cpp @@ -0,0 +1,424 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +// +// Based on code from the MMDVMCal project. (https://github.com/g4klx/MMDVMCal) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2021 by Bryan Biedenkapp N2PLL +* +* 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 "host/setup/HostSetup.h" +#include "HostMain.h" +#include "Log.h" +#include "Utils.h" + +using namespace lookups; + +#include +#include + +#if !defined(_WIN32) && !defined(_WIN64) +#include +#endif + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- +/// +/// Initializes a new instance of the HostSetup class. +/// +/// Full-path to the configuration file. +HostSetup::HostSetup(const std::string& confFile) : + m_confFile(confFile), + m_conf(), + m_console(), + m_duplex(true), + m_identity("ABCD123"), + m_callsign("ABCD123"), + m_rxFrequency(0U), + m_txFrequency(0U), + m_channelId(0U), + m_channelNo(0U), + m_idenTable(NULL) +{ + /* stub */ +} + +/// +/// Finalizes a instance of the HostSetup class. +/// +HostSetup::~HostSetup() +{ + /* stub */ +} + +/// +/// Executes the processing loop. +/// +/// Zero if successful, otherwise error occurred. +int HostSetup::run() +{ + bool ret = yaml::Parse(m_conf, m_confFile.c_str()); + if (!ret) { + ::fatal("cannot read the configuration file, %s\n", m_confFile.c_str()); + } + + // initialize system logging + ret = ::LogInitialise("", "", 0U, 1U); + if (!ret) { + ::fprintf(stderr, "unable to open the log file\n"); + return 1; + } + + getHostVersion(); + ::LogInfo(">> Modem Setup"); + + yaml::Node systemConf = m_conf["system"]; + m_duplex = systemConf["duplex"].as(true); + + // try to load bandplan identity table + std::string idenLookupFile = systemConf["iden_table"]["file"].as(); + uint32_t idenReloadTime = systemConf["iden_table"]["time"].as(0U); + + if (idenLookupFile.length() <= 0U) { + ::LogError(LOG_HOST, "No bandplan identity table? This must be defined!"); + return 1; + } + + LogInfo("Iden Table Lookups"); + LogInfo(" File: %s", idenLookupFile.length() > 0U ? idenLookupFile.c_str() : "None"); + if (idenReloadTime > 0U) + LogInfo(" Reload: %u mins", idenReloadTime); + + m_idenTable = new IdenTableLookup(idenLookupFile, idenReloadTime); + m_idenTable->read(); + + LogInfo("General Parameters"); + + m_identity = systemConf["identity"].as(); + ::LogInfo(" Identity: %s", m_identity.c_str()); + + yaml::Node cwId = systemConf["cwId"]; + uint32_t time = systemConf["cwId"].as(10U); + m_callsign = systemConf["cwId"].as(); + + LogInfo("CW Id Parameters"); + LogInfo(" Time: %u mins", time); + LogInfo(" Callsign: %s", m_callsign.c_str()); + + m_callsign = cwId["callsign"].as(); + + yaml::Node rfssConfig = systemConf["config"]; + m_channelId = (uint8_t)rfssConfig["channelId"].as(0U); + if (m_channelId > 15U) { // clamp to 15 + m_channelId = 15U; + } + + m_channelNo = (uint32_t)::strtoul(rfssConfig["channelNo"].as("1").c_str(), NULL, 16); + if (m_channelNo == 0U) { // clamp to 1 + m_channelNo = 1U; + } + if (m_channelNo > 4095U) { // clamp to 4095 + m_channelNo = 4095U; + } + + if (!calculateRxTxFreq()) { + return false; + } + + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + return false; + } + + LogInfo("System Config Parameters"); + LogInfo(" RX Frequency: %uHz", m_rxFrequency); + LogInfo(" TX Frequency: %uHz", m_txFrequency); + LogInfo(" Base Frequency: %uHz", entry.baseFrequency()); + LogInfo(" TX Offset: %fMHz", entry.txOffsetMhz()); + + // open terminal console + ret = m_console.open(); + if (!ret) { + return 1; + } + + displayHelp(); + + printStatus(); + + bool end = false; + while (!end) { + int c = m_console.getChar(); + switch (c) { + + /** Setup Commands */ + case 'I': + { + char value[9] = { '\0' }; + ::fprintf(stdout, "> Identity ? "); + ::fflush(stdout); + + m_console.getLine(value, 9, 0); + m_identity = std::string(value); + writeConfig(); + } + break; + + case 'i': + { + char value[3] = { '\0' }; + ::fprintf(stdout, "> Channel ID ? "); + ::fflush(stdout); + + m_console.getLine(value, 3, 0); + + uint8_t prevChannelId = m_channelId; + + // bryanb: appease the compiler... + uint32_t channelId = m_channelId; + sscanf(value, "%u", &channelId); + + m_channelId = (uint8_t)channelId; + + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_SETUP, "Channel Id %u has an invalid base frequency.", m_channelId); + m_channelId = prevChannelId; + } + + writeConfig(); + } + break; + + case 'c': + { + char value[5] = { '\0' }; + ::fprintf(stdout, "> Channel No ? "); + ::fflush(stdout); + + m_console.getLine(value, 5, 0); + + uint8_t prevChannelNo = m_channelNo; + sscanf(value, "%u", &m_channelNo); + + if (m_channelNo < 0 || m_channelNo > 4096) { + ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); + m_channelNo = prevChannelNo; + } + + writeConfig(); + } + break; + + case 'f': + { + char value[10] = { '\0' }; + ::fprintf(stdout, "> Tx Frequency (Hz) ? "); + ::fflush(stdout); + + m_console.getLine(value, 10, 0); + + uint32_t txFrequency = m_txFrequency; + sscanf(value, "%u", &txFrequency); + + IdenTable entry = m_idenTable->find(m_channelId); + if (txFrequency < entry.baseFrequency()) { + ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be greater then base frequency!", txFrequency, entry.baseFrequency()); + break; + } + + if (txFrequency > entry.baseFrequency() + 25500000) { + ::LogError(LOG_SETUP, "Tx Frequency %uHz is out of band range for base frequency %uHz. Tx Frequency must be no more then 25.5 Mhz higher then base frequency!", txFrequency, entry.baseFrequency()); + break; + } + + uint32_t prevTxFrequency = m_txFrequency; + m_txFrequency = txFrequency; + uint32_t prevRxFrequency = m_rxFrequency; + m_rxFrequency = m_txFrequency + (entry.txOffsetMhz() * 1000000); + + float spaceHz = entry.chSpaceKhz() * 1000; + + uint32_t rootFreq = m_txFrequency - entry.baseFrequency(); + uint8_t prevChannelNo = m_channelNo; + m_channelNo = rootFreq / spaceHz; + + if (m_channelNo < 0 || m_channelNo > 4096) { + ::LogError(LOG_SETUP, "Channel No %u is invalid.", m_channelNo); + m_channelNo = prevChannelNo; + m_txFrequency = prevTxFrequency; + m_rxFrequency = prevRxFrequency; + break; + } + + writeConfig(); + } + break; + + /** General Commands */ + case '`': + printStatus(); + break; + case 'V': + getHostVersion(); + break; + case 'H': + case 'h': + displayHelp(); + break; + case 'S': + case 's': + { + yaml::Serialize(m_conf, m_confFile.c_str(), yaml::SerializeConfig(4, 64, false, false)); + LogMessage(LOG_SETUP, " - Saved configuration to %s", m_confFile.c_str()); + } + break; + case 'Q': + case 'q': + end = true; + break; + + case 13: + case 10: + case -1: + break; + default: + LogError(LOG_SETUP, "Unknown command - %c (H/h for help)", c); + break; + } + + sleep(5U); + } + + m_console.close(); + return 0; +} + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Helper to print the help to the console. +/// +void HostSetup::displayHelp() +{ + LogMessage(LOG_SETUP, "General Commands:"); + LogMessage(LOG_SETUP, " ` Display current settings"); + LogMessage(LOG_SETUP, " V Display version of host"); + LogMessage(LOG_SETUP, " H/h Display help"); + LogMessage(LOG_SETUP, " S/s Save settings to configuration file"); + LogMessage(LOG_SETUP, " Q/q Quit"); + LogMessage(LOG_SETUP, "Setup Commands:"); + LogMessage(LOG_SETUP, " I Set identity (logical name)"); + LogMessage(LOG_SETUP, " i Set logical channel ID"); + LogMessage(LOG_SETUP, " c Set logical channel number (by channel number)"); + LogMessage(LOG_SETUP, " f Set logical channel number (by Tx frequency)"); +} + +/// +/// Helper to calculate the Rx/Tx frequencies. +/// +bool HostSetup::calculateRxTxFreq() +{ + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + return false; + } + + if (m_channelNo == 0U) { // clamp to 1 + m_channelNo = 1U; + } + if (m_channelNo > 4095U) { // clamp to 4095 + m_channelNo = 4095U; + } + + if (m_duplex) { + if (entry.txOffsetMhz() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid Tx offset.", m_channelId); + return false; + } + + uint32_t calcSpace = (uint32_t)(entry.chSpaceKhz() / 0.125); + float calcTxOffset = entry.txOffsetMhz() * 1000000; + + m_rxFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo)) + calcTxOffset); + m_txFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo))); + } + else { + uint32_t calcSpace = (uint32_t)(entry.chSpaceKhz() / 0.125); + + m_rxFrequency = (uint32_t)((entry.baseFrequency() + ((calcSpace * 125) * m_channelNo))); + m_txFrequency = m_rxFrequency; + } + + return true; +} + +/// +/// Write configuration file. +/// +/// True, if configuration is written, otherwise false. +bool HostSetup::writeConfig() +{ + m_conf["system"]["identity"] = m_identity; + + m_conf["system"]["config"]["channelId"] = __INT_STR(m_channelId); + m_conf["system"]["config"]["channelNo"] = __INT_STR(m_channelNo); + + printStatus(); + return true; +} + +/// +/// Helper to sleep the thread. +/// +/// Milliseconds to sleep. +void HostSetup::sleep(uint32_t ms) +{ +#if defined(_WIN32) || defined(_WIN64) + ::Sleep(ms); +#else + ::usleep(ms * 1000); +#endif +} + +/// +/// Prints the current status of the calibration. +/// +void HostSetup::printStatus() +{ + IdenTable entry = m_idenTable->find(m_channelId); + if (entry.baseFrequency() == 0U) { + ::LogError(LOG_HOST, "Channel Id %u has an invalid base frequency.", m_channelId); + } + + calculateRxTxFreq(); + + LogMessage(LOG_SETUP, " - Channel ID: %u, Channel No: %u", m_channelId, m_channelNo); + LogMessage(LOG_SETUP, " - Base Freq: %uHz, TX Offset: %fMHz, Bandwidth: %fKHz, Channel Spacing: %fKHz", entry.baseFrequency(), entry.txOffsetMhz(), entry.chBandwidthKhz(), entry.chSpaceKhz()); + LogMessage(LOG_SETUP, " - Rx Freq: %uHz, Tx Freq: %uHz, Identity: %s, Callsign: %s", m_rxFrequency, m_txFrequency, m_identity.c_str(), m_callsign.c_str()); +} diff --git a/host/setup/HostSetup.h b/host/setup/HostSetup.h new file mode 100644 index 00000000..a9501fb2 --- /dev/null +++ b/host/setup/HostSetup.h @@ -0,0 +1,89 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +// +// Based on code from the MMDVMCal project. (https://github.com/g4klx/MMDVMCal) +// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) +// +/* +* Copyright (C) 2021 by Bryan Biedenkapp N2PLL +* +* 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(__HOST_SETUP_H__) +#define __HOST_SETUP_H__ + +#include "Defines.h" +#include "host/calibrate/Console.h" +#include "host/Host.h" +#include "lookups/IdenTableLookup.h" +#include "yaml/Yaml.h" + +#include + +// --------------------------------------------------------------------------- +// Class Declaration +// This class implements an interactive session to setup the DVM. +// --------------------------------------------------------------------------- + +class HOST_SW_API HostSetup { +public: + /// Initializes a new instance of the HostSetup class. + HostSetup(const std::string& confFile); + /// Finalizes a instance of the HostSetup class. + ~HostSetup(); + + /// Executes the processing loop. + int run(); + +private: + const std::string& m_confFile; + yaml::Node m_conf; + + Console m_console; + + bool m_duplex; + + std::string m_identity; + std::string m_callsign; + + uint32_t m_rxFrequency; + uint32_t m_txFrequency; + uint8_t m_channelId; + uint32_t m_channelNo; + + lookups::IdenTableLookup* m_idenTable; + + /// Helper to print the help to the console. + void displayHelp(); + + /// Helper to calculate the Rx/Tx frequencies. + bool calculateRxTxFreq(); + + /// Write configuration file. + bool writeConfig(); + /// Helper to sleep the thread. + void sleep(uint32_t ms); + + /// Prints the current status. + void printStatus(); +}; + +#endif // __HOST_SETUP_H__