You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
6.5 KiB

/*
* Copyright (c) 2023 by Thomas A. Early N7TAE
*
* 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 <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <regex>
#include "Configure.h"
// ini file keywords
#define USRPTXGAIN "UsrpTxGain"
#define USRPRXGAIN "UsrpRxGain"
#define DMRGAININ "DmrYsfGainIn"
#define DMRGAINOUT "DmrYsfGainOut"
#define DSTARGAININ "DStarGainIn"
#define DSTARGAINOUT "DStarGainOut"
#define MODULES "Modules"
#define ADDRESS "Address"
#define PORT "Port"
static inline void split(const std::string &s, char delim, std::vector<std::string> &v)
{
std::istringstream iss(s);
std::string item;
while (std::getline(iss, item, delim))
v.push_back(item);
}
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
bool CConfigure::ReadData(const std::string &path)
// returns true on failure
{
std::regex IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended);
std::regex IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended);
std::string modstmp, porttmp;
std::ifstream cfgfile(path.c_str(), std::ifstream::in);
if (! cfgfile.is_open()) {
std::cerr << "ERROR: '" << path << "' was not found!" << std::endl;
return true;
}
std::string line;
while (std::getline(cfgfile, line))
{
trim(line);
if (3 > line.size())
continue; // can't be anything
if ('#' == line.at(0))
continue; // skip comments
std::vector<std::string> tokens;
split(line, '=', tokens);
// check value for end-of-line comment
if (2 > tokens.size())
{
std::cout << "WARNING: '" << line << "' does not contain an equal sign, skipping" << std::endl;
continue;
}
auto pos = tokens[1].find('#');
if (std::string::npos != pos)
{
tokens[1].assign(tokens[1].substr(0, pos));
rtrim(tokens[1]); // whitespace between the value and the end-of-line comment
}
// trim whitespace from around the '='
rtrim(tokens[0]);
ltrim(tokens[1]);
const std::string key(tokens[0]);
const std::string value(tokens[1]);
if (key.empty() || value.empty())
{
std::cout << "WARNING: missing key or value: '" << line << "'" << std::endl;
continue;
}
if (0 == key.compare(ADDRESS))
address.assign(value);
else if (0 == key.compare(PORT))
porttmp.assign(value);
else if (0 == key.compare(MODULES))
modstmp.assign(value);
else if (0 == key.compare(DSTARGAININ))
dstar_in = getSigned(key, value);
else if (0 == key.compare(DSTARGAINOUT))
dstar_out = getSigned(key, value);
else if (0 == key.compare(DMRGAININ))
dmr_in = getSigned(key, value);
else if (0 == key.compare(DMRGAINOUT))
dmr_out = getSigned(key, value);
else if (0 == key.compare(USRPTXGAIN))
usrp_tx = getSigned(key, value);
else if (0 == key.compare(USRPRXGAIN))
usrp_rx = getSigned(key, value);
else
badParam(key);
}
cfgfile.close();
for (auto c : modstmp)
{
if (isalpha(c))
{
if (islower(c))
c = toupper(c);
if (std::string::npos == tcmods.find(c))
tcmods.append(1, c);
}
}
if (tcmods.empty())
{
std::cerr << "ERROR: no identifable module letters in '" << modstmp << "'. Halt." << std::endl;
return true;
}
if (! std::regex_match(address, IPv4RegEx) && ! std::regex_match(address, IPv6RegEx))
{
std::cerr << "ERROR: '" << address << "' is malformed, Halt." << std::endl;
return true;
}
port = std::strtoul(porttmp.c_str(), nullptr, 10);
if (port < 1025 || port > 49000)
{
std::cerr << "ERROR: Port '" << porttmp << "' must be between >1024 and <49000. Halt." << std::endl;
return true;
}
std::cout << MODULES << " = " << tcmods << std::endl;
std::cout << ADDRESS << " = " << address << std::endl;
std::cout << PORT << " = " << port << std::endl;
std::cout << DSTARGAININ << " = " << dstar_in << std::endl;
std::cout << DSTARGAINOUT << " = " << dstar_out << std::endl;
std::cout << DMRGAININ << " = " << dmr_in << std::endl;
std::cout << DMRGAINOUT << " = " << dmr_out << std::endl;
std::cout << USRPTXGAIN << " = " << usrp_tx << std::endl;
std::cout << USRPRXGAIN << " = " << usrp_rx << std::endl;
return false;
}
int CConfigure::getSigned(const std::string &key, const std::string &value) const
{
auto i = std::stoi(value.c_str());
if (i < -24)
{
std::cout << "WARNING: " << key << " = " << value << " is too low. Limit to -24!" << std::endl;
i = -24;
}
else if (i > 24)
{
std::cout << "WARNING: " << key << " = " << value << " is too high. Limit to 24!" << std::endl;
i = 24;
}
return i;
}
void CConfigure::badParam(const std::string &key) const
{
std::cout << "WARNING: Unexpected parameter: '" << key << "'" << std::endl;
}
int CConfigure::GetGain(EGainType gt) const
{
switch (gt)
{
case EGainType::dmrin: return dmr_in;
case EGainType::dmrout: return dmr_out;
case EGainType::dstarin: return dstar_in;
case EGainType::dstarout: return dstar_out;
case EGainType::usrptx: return usrp_tx;
case EGainType::usrprx: return usrp_rx;
default: return 0;
}
}

Powered by TurnKey Linux.