diff --git a/.vscode/launch.json b/.vscode/launch.json index bd85764..f15168f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -85,7 +85,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/DGWTimeServer/dgwtimeserver", - "args": [], + "args": ["${workspaceFolder}/Sandbox/__timeserver_test.cfg"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], diff --git a/DGWTimeServer/DGWTimeServerApp.cpp b/DGWTimeServer/DGWTimeServerApp.cpp index ac1c3c2..6b894ec 100644 --- a/DGWTimeServer/DGWTimeServerApp.cpp +++ b/DGWTimeServer/DGWTimeServerApp.cpp @@ -21,6 +21,7 @@ #include #include "DGWTimeServerApp.h" +#include "TimeServerConfig.h" int main(int argc, char * argv[]) { @@ -29,4 +30,11 @@ int main(int argc, char * argv[]) printf(" %s --version\n", argv[0]); return 1; } + + std::string configfile(argv[1]); + CTimeServerConfig config(configfile); + if(!config.load()) + return 0; + + return 1; } \ No newline at end of file diff --git a/DGWTimeServer/Makefile b/DGWTimeServer/Makefile index 5400a76..4ea197d 100644 --- a/DGWTimeServer/Makefile +++ b/DGWTimeServer/Makefile @@ -4,7 +4,6 @@ DEPS = $(SRCS:.cpp=.d) dgwtimeserver: ../VersionInfo/GitVersion.h $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a $(CC) $(CPPFLAGS) -o dgwtimeserver $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a $(LDFLAGS) - echo bla %.o : %.cpp $(CC) -I../BaseCommon -I../DStarBase -I../VersionInfo $(CPPFLAGS) -MMD -MD -c $< -o $@ diff --git a/DGWTimeServer/TimeServerConfig.cpp b/DGWTimeServer/TimeServerConfig.cpp new file mode 100644 index 0000000..ec31444 --- /dev/null +++ b/DGWTimeServer/TimeServerConfig.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 +#include + +#include "TimeServerConfig.h" +#include "Log.h" +#include "StringUtils.h" + +CTimeServerConfig::CTimeServerConfig(const std::string &pathname) : +m_fileName(pathname), +m_repeaters() +{ + +} + +CTimeServerConfig::~CTimeServerConfig() +{ + for(auto repeater : m_repeaters) { + delete repeater; + } + m_repeaters.clear(); +} + +bool CTimeServerConfig::load() +{ + bool ret = false; + CLog::logInfo("Loading Configuration from %s", m_fileName.c_str()); + CConfig cfg(m_fileName); + + ret = open(cfg); + if(ret) { + ret = loadTimeServer(cfg) && ret; + ret = loadRepeaters(cfg) && ret; + ret = loadDaemon(cfg) && ret; + } + + return ret; +} + +bool CTimeServerConfig::open(CConfig & cfg) +{ + try { + return cfg.load(); + } + catch(...) { + CLog::logError("Can't read %s\n", m_fileName.c_str()); + return false; + } + return true; +} + +bool CTimeServerConfig::loadRepeaters(const CConfig & cfg) +{ + m_repeaters.clear(); + + for(unsigned int i = 0; i < 4; i++) { + std::string section = CStringUtils::string_format("repeater_%d", i+ 1); + bool repeaterEnabled; + + bool ret = cfg.getValue(section, "enabled", repeaterEnabled, false); + if(!ret || !repeaterEnabled) + continue; + + TRepeater * repeater = new TRepeater; + ret = cfg.getValue(section, "band", repeater->band, 1, 2, "") && ret; + + bool alreadyConfigured = std::any_of(m_repeaters.begin(), m_repeaters.end(), [repeater](TRepeater * r) { return r->band == repeater->band;}); + if(alreadyConfigured) { + CLog::logWarning("%s-%s repeater already configured, ignoring", m_timeServer.callsign.c_str(), repeater->band.c_str()); + delete repeater; + continue; + } + + m_repeaters.push_back(repeater); + } + + return m_repeaters.size() > 0U; +} + +bool CTimeServerConfig::loadTimeServer(const CConfig & cfg) +{ + bool ret = cfg.getValue("timeserver", "callsign", m_timeServer.callsign, 3, 8, ""); + boost::to_upper(m_timeServer.callsign); + ret = cfg.getValue("timeserver", "address", m_timeServer.address, 0, 1024, "127.0.0.1") && ret; + + std::string format; + ret = cfg.getValue("timeserver", "format", format, "voiceandtext", {"voice", "text", "voiceandtext"}) && ret; + if(format == "voice") m_timeServer.format = FORMAT_VOICE_TIME; + else if(format == "text") m_timeServer.format = FORMAT_TEXT_TIME; + else if(format == "voiceandtext") m_timeServer.format = FORMAT_VOICE_ALL; + + std::string lang; + ret = cfg.getValue("timeserver", "language", lang, "english_uk_1", {"english_uk_1", "english_uk_2", "english_us_1", "english_us_2", "deutsch_1", "deutsch_2", "francais", "nederlands", "svenska", "espanol", "norsk", "portugues"}) && ret;; + if (lang == "english_uk_1") m_timeServer.language = LANG_ENGLISH_UK_1; + else if(lang == "english_uk_2") m_timeServer.language = LANG_ENGLISH_UK_2; + else if(lang == "english_us_1") m_timeServer.language = LANG_ENGLISH_US_1; + else if(lang == "english_us_2") m_timeServer.language = LANG_ENGLISH_US_2; + else if(lang == "deutsch_1" ) m_timeServer.language = LANG_DEUTSCH_1; + else if(lang == "detusch_2" ) m_timeServer.language = LANG_DEUTSCH_2; + else if(lang == "francais" ) m_timeServer.language = LANG_FRANCAIS; + else if(lang == "nederlands" ) m_timeServer.language = LANG_NEDERLANDS; + else if(lang == "svenska" ) m_timeServer.language = LANG_SVENSKA; + else if(lang == "espanol" ) m_timeServer.language = LANG_ESPANOL; + else if(lang == "norsk" ) m_timeServer.language = LANG_NORSK; + else if(lang == "portugues" ) m_timeServer.language = LANG_PORTUGUES; + + std::string interval; + ret = cfg.getValue("timeserver", "interval", interval, "30", {"15", "30", "60"}) && ret; + if(interval == "15") m_timeServer.interval = INTERVAL_15MINS; + else if(interval == "30") m_timeServer.interval = INTERVAL_30MINS; + else if(interval == "60") m_timeServer.interval = INTERVAL_60MINS; + + return ret; +} + +bool CTimeServerConfig::loadDaemon(const CConfig & cfg) +{ + bool ret = cfg.getValue("daemon", "daemon", m_daemon.daemon, false); + ret = cfg.getValue("daemon", "pidfile", m_daemon.pidFile, 0, 1024, "") && ret; + ret = cfg.getValue("daemon", "user", m_daemon.user, 0, 1024, "") && ret; + return ret; +} diff --git a/DGWTimeServer/TimeServerConfig.h b/DGWTimeServer/TimeServerConfig.h new file mode 100644 index 0000000..d17a650 --- /dev/null +++ b/DGWTimeServer/TimeServerConfig.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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. + */ + +#pragma once + +#include +#include + +#include "Config.h" +#include "TimeServerDefs.h" + +typedef struct { + std::string callsign; + std::string address; + FORMAT format; + LANGUAGE language; + INTERVAL interval; +} TTimeServer; + +typedef struct { + bool enabled; + std::string band; +} TRepeater; + +typedef struct { + bool daemon; + std::string pidFile; + std::string user; +} TDaemon; + + +class CTimeServerConfig +{ +public: + CTimeServerConfig(const std::string &pathname); + ~CTimeServerConfig(); + + bool load(); + +private: + bool open(CConfig & cfg); + bool loadRepeaters(const CConfig & cfg); + bool loadTimeServer(const CConfig & cfg); + bool loadDaemon(const CConfig & cfg); + + std::string m_fileName; + std::vector m_repeaters; + TTimeServer m_timeServer; + TDaemon m_daemon; +}; diff --git a/DGWTimeServer/TimeServerDefs.h b/DGWTimeServer/TimeServerDefs.h new file mode 100644 index 0000000..d82a57e --- /dev/null +++ b/DGWTimeServer/TimeServerDefs.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012,2013,2014 by Jonathan Naylor G4KLX + * Copyright (C) 2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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. + */ + +#pragma once + +const std::string APPLICATION_NAME("Time Server"); + +enum LANGUAGE { + LANG_ENGLISH_UK_1, + LANG_ENGLISH_UK_2, + LANG_ENGLISH_US_1, + LANG_ENGLISH_US_2, + LANG_DEUTSCH_1, + LANG_DEUTSCH_2, + LANG_FRANCAIS, + LANG_NEDERLANDS, + LANG_SVENSKA, + LANG_ESPANOL, + LANG_NORSK, + LANG_PORTUGUES +}; + +enum INTERVAL { + INTERVAL_15MINS, + INTERVAL_30MINS, + INTERVAL_60MINS +}; + +enum FORMAT { + FORMAT_VOICE_TIME, + FORMAT_VOICE_ALL, + FORMAT_TEXT_TIME +}; diff --git a/DGWTimeServer/example.cfg b/DGWTimeServer/example.cfg new file mode 100644 index 0000000..cc6b0cf --- /dev/null +++ b/DGWTimeServer/example.cfg @@ -0,0 +1,32 @@ +[TimeServer] +callsign= # call of the gateway to send time beacons without G letter +address= # address of the gateway, defaults to 127.0.0.1 +format= # possible values are voice, text, voiceandtext, defaults to voice and text +language= # valid values: english_uk_1, english_uk_2, english_us_1, english_us_2, deutsch_1, deutsch_2, francais, nederlands, svenska, espanol, norsk, portugues. Defaults to english_uk_1 +interval= # valid values are 15, 30 and 60, defaults to 30 + +# Up to 4 repeaters can be enabled to transmit time beacons +[Repeater_1] +enabled=true # enable time beacons on this repeater +band=B # Module letter of the repeater + +[Repeater_2] +enabled=false # enable time beacons on this repeater +band= # Module letter of the repeater + +[Repeater_3] +enabled=false # enable time beacons on this repeater +band= # Module letter of the repeater + +[Repeater_4] +enabled=false # enable time beacons on this repeater +band= # Module letter of the repeater + + +# Provided install routines install the program as a systemd unit. SystemD does not recommand "old-school" forking daemons nor does systemd +# require a pid file. Moreover system handles the user under which the program is started. This is provided as convenience for people who might +# run the program using sysv or any other old school init system. +[Daemon] +daemon=false +pidfile=/var/run/dstargateway/dstargateway.pid # pid file is in our case useless when running as a daemon using systemd as systemd takes care of the service not being started twice +user=dstar # user account the daemon will run under, ideally a user with low privileges. Switching to this user will only happen when the program is started as root diff --git a/Makefile b/Makefile index e34632e..1ed1c97 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,6 @@ DGWTextTransmit/dgwtexttransmit: VersionInfo/GitVersion.h $(OBJS) DStarBase/DSta DGWTimeServer/dgwtimeserver: VersionInfo/GitVersion.h $(OBJS) DStarBase/DStarBase.a BaseCommon/BaseCommon.a FORCE $(MAKE) -C DGWTimeServer - echo bla DGWVoiceTransmit/dgwvoicetransmit: VersionInfo/GitVersion.h $(OBJS) DStarBase/DStarBase.a BaseCommon/BaseCommon.a FORCE $(MAKE) -C DGWVoiceTransmit