dashboard with last heard

pull/14/head
Tom Early 6 years ago
parent 0497271ad0
commit a125cb0778

@ -170,7 +170,7 @@ installdtmf : qndtmf
systemctl start qndtmf.service systemctl start qndtmf.service
installdash : index.php installdash : index.php
/usr/bin/apt install -y php-common php-fpm /usr/bin/apt install -y php-common php-fpm sqlite3 libsqlite3-dev php-sqlite3
mkdir -p $(WWWDIR) mkdir -p $(WWWDIR)
/bin/cp -f index.php $(WWWDIR) /bin/cp -f index.php $(WWWDIR)
/bin/cp -f system/qndash.service $(SYSDIR) /bin/cp -f system/qndash.service $(SYSDIR)

@ -19,9 +19,9 @@
#include <string> #include <string>
#include "QnetDB.h" #include "QnetDB.h"
bool CQnetDB::Open(const char *name, const bool disable) bool CQnetDB::Open(const char *name, const bool enable)
{ {
if (disable) if (! enable)
return false; return false;
if (sqlite3_open(name, &db)) if (sqlite3_open(name, &db))
@ -29,9 +29,11 @@ bool CQnetDB::Open(const char *name, const bool disable)
std::string sql = "DROP TABLE IF EXISTS LHEARD; " std::string sql = "DROP TABLE IF EXISTS LHEARD; "
"CREATE TABLE LHEARD(" "CREATE TABLE LHEARD("
"callsign TEXT PRIMARY KEY, " "mycall TEXT PRIMARY KEY, "
"sfx TEXT, "
"urcall TEXT, " "urcall TEXT, "
"source TEXT, " "module TEXT, "
"gateway TEXT, "
"lasttime INT NOT NULL" "lasttime INT NOT NULL"
") WITHOUT ROWID;"; ") WITHOUT ROWID;";
@ -45,16 +47,20 @@ bool CQnetDB::Open(const char *name, const bool disable)
return false; return false;
} }
bool CQnetDB::Update(const char *callsign, const char *urcall, const char *source) bool CQnetDB::Update(const char *mycall, const char *sfx, const char *urcall, const char *module, const char *gateway)
{ {
if (NULL == db) if (NULL == db)
return false; return false;
std::string sql = "REPLACE INTO LHEARD (callsign,urcall,source,lasttime) VALUES ("; std::string sql = "REPLACE INTO LHEARD (mycall,sfx,urcall,module,gateway,lasttime) VALUES (";
sql.append(callsign); sql.append(mycall);
sql.append("\",\"");
sql.append(sfx);
sql.append("\",\""); sql.append("\",\"");
sql.append(urcall); sql.append(urcall);
sql.append("\",\""); sql.append("\",\"");
sql.append(source); sql.append(module);
sql.append("\",\"");
sql.append(gateway);
sql.append("\","); sql.append("\",");
sql.append("strftime('%s','now'));"); sql.append("strftime('%s','now'));");

@ -25,7 +25,7 @@ public:
CQnetDB() : db(NULL) {} CQnetDB() : db(NULL) {}
~CQnetDB() { if (db) sqlite3_close(db); } ~CQnetDB() { if (db) sqlite3_close(db); }
bool Open(const char *name, const bool disable = false); bool Open(const char *name, const bool disable = false);
bool Update(const char *callsign, const char *urcall, const char *source); bool Update(const char *mycall, const char *sfx, const char *urcall, const char *module, const char *gateway);
private: private:
sqlite3 *db; sqlite3 *db;

@ -48,6 +48,7 @@
#include "IRCutils.h" #include "IRCutils.h"
#include "QnetConfigure.h" #include "QnetConfigure.h"
#include "QnetGateway.h" #include "QnetGateway.h"
#include "Utilities.h"
const std::string IRCDDB_VERSION("QnetGateway-9.2"); const std::string IRCDDB_VERSION("QnetGateway-9.2");
@ -277,11 +278,6 @@ bool CQnetGateway::ReadConfig(char *cfgFile)
} }
cfg.GetValue(path+"range", type, rptr.mod[m].range, 0.0, 1609344.0); cfg.GetValue(path+"range", type, rptr.mod[m].range, 0.0, 1609344.0);
cfg.GetValue(path+"agl", type, rptr.mod[m].agl, 0.0, 1000.0); cfg.GetValue(path+"agl", type, rptr.mod[m].agl, 0.0, 1000.0);
// make the long description for the log
if (rptr.mod[m].desc1.length())
rptr.mod[m].desc = rptr.mod[m].desc1 + ' ';
rptr.mod[m].desc += rptr.mod[m].desc2;
} }
} }
if (! (rptr.mod[0].defined || rptr.mod[1].defined || rptr.mod[2].defined)) { if (! (rptr.mod[0].defined || rptr.mod[1].defined || rptr.mod[2].defined)) {
@ -308,6 +304,7 @@ bool CQnetGateway::ReadConfig(char *cfgFile)
cfg.GetValue(path+"desc1", estr, rptr.mod[m].desc1, 0, 20); cfg.GetValue(path+"desc1", estr, rptr.mod[m].desc1, 0, 20);
cfg.GetValue(path+"desc2", estr, rptr.mod[m].desc2, 0, 20); cfg.GetValue(path+"desc2", estr, rptr.mod[m].desc2, 0, 20);
cfg.GetValue(path+"url", estr, rptr.mod[m].url, 0, 80); cfg.GetValue(path+"url", estr, rptr.mod[m].url, 0, 80);
rptr.mod[m].desc = trim_copy(rptr.mod[m].desc1) + " " + trim_copy(rptr.mod[m].desc2);
} }
} }
path.append("find_route"); path.append("find_route");
@ -352,10 +349,9 @@ bool CQnetGateway::ReadConfig(char *cfgFile)
// dashboard // dashboard
path.assign("dashboard_"); path.assign("dashboard_");
cfg.GetValue(path+"disable_lastheard", estr, DASHBOARD_DISABLE_LASTHEARD); cfg.GetValue(path+"enable_lastheard", estr, DASHBOARD_ENABLE_LASTHEARD);
cfg.GetValue(path+"sql_filename", estr, DASHBOARD_SQL_NAME, 1, 32); cfg.GetValue(path+"sql_filename", estr, DASHBOARD_SQL_NAME, 1, 32);
cfg.GetValue(path+"refresh", estr, DASHBOARD_REFRESH, 10, 60); cfg.GetValue(path+"refresh", estr, DASHBOARD_REFRESH, 10, 60);
cfg.GetValue(path+"lastheard_max", estr, DASHBOARD_LASTHEARD_MAX, 5, 100);
return false; return false;
} }
@ -1123,19 +1119,16 @@ void CQnetGateway::ProcessG2(const ssize_t g2buflen, const SDSVT &g2buf, const i
printf("UnixSock=%s\n", link2gate.c_str()); printf("UnixSock=%s\n", link2gate.c_str());
} }
if (! DASHBOARD_DISABLE_LASTHEARD) { if (DASHBOARD_ENABLE_LASTHEARD) {
char cs[14] = { 0 }; char nm[5] = { 0 }; std::string mycall((const char *)g2buf.hdr.mycall, 8);
for (int j=0; g2buf.hdr.mycall[j] && ' '!=g2buf.hdr.mycall[j]; j++) std::string sfx((const char *)g2buf.hdr.sfx, 4);
cs[j] = g2buf.hdr.mycall[j]; std::string urcall((const char *)g2buf.hdr.urcall, 8);
if (strlen(cs)) { std::string module((const char *)g2buf.hdr.rpt1, 8);
for (int j=0; g2buf.hdr.sfx[j] && ' '!=g2buf.hdr.sfx[j]; j++) std::string gateway((const char *)g2buf.hdr.rpt2, 8);
nm[j] = g2buf.hdr.sfx[j]; rtrim(mycall);
if (strlen(nm)) { rtrim(sfx);
strcat(cs, "/"); rtrim(urcall);
strcat(cs, nm); qnDB.Update(mycall.c_str(), sfx.c_str(), urcall.c_str(), module.c_str(), gateway.c_str());
}
qnDB.Update(cs, (const char *)g2buf.hdr.urcall, (source_sock>=0) ? fromDstar.GetAddress() : band_txt[i].dest_rptr);
}
} }
Gate2Modem[i].Write(g2buf.title, 56); Gate2Modem[i].Write(g2buf.title, 56);
@ -2135,7 +2128,7 @@ void CQnetGateway::APRSBeaconThread()
time(&tnow); time(&tnow);
if ((tnow - last_beacon_time) > (rptr.aprs_interval * 60)) { if ((tnow - last_beacon_time) > (rptr.aprs_interval * 60)) {
for (short int i=0; i<3; i++) { for (short int i=0; i<3; i++) {
if (rptr.mod[i].desc[0] != '\0') { if (rptr.mod[i].defined) {
float tmp_lat = fabs(rptr.mod[i].latitude); float tmp_lat = fabs(rptr.mod[i].latitude);
float tmp_lon = fabs(rptr.mod[i].longitude); float tmp_lon = fabs(rptr.mod[i].longitude);
float lat = floor(tmp_lat); float lat = floor(tmp_lat);
@ -2170,8 +2163,8 @@ void CQnetGateway::APRSBeaconThread()
lat_s, (rptr.mod[i].latitude < 0.0) ? 'S' : 'N', lat_s, (rptr.mod[i].latitude < 0.0) ? 'S' : 'N',
lon_s, (rptr.mod[i].longitude < 0.0) ? 'W' : 'E', lon_s, (rptr.mod[i].longitude < 0.0) ? 'W' : 'E',
(unsigned int)rptr.mod[i].range, rptr.mod[i].band.c_str(), rptr.mod[i].desc.c_str()); (unsigned int)rptr.mod[i].range, rptr.mod[i].band.c_str(), rptr.mod[i].desc.c_str());
if (LOG_DEBUG)
// printf("APRS Beacon =[%s]\n", snd_buf); printf("APRS Beacon =[%s]\n", snd_buf);
strcat(snd_buf, "\r\n"); strcat(snd_buf, "\r\n");
while (keep_running) { while (keep_running) {
@ -2468,7 +2461,7 @@ bool CQnetGateway::Init(char *cfgfile)
} }
// open database // open database
if (qnDB.Open(DASHBOARD_SQL_NAME.c_str(), DASHBOARD_DISABLE_LASTHEARD)) if (qnDB.Open(DASHBOARD_SQL_NAME.c_str(), DASHBOARD_ENABLE_LASTHEARD))
return true; return true;
playNotInCache = false; playNotInCache = false;

@ -105,9 +105,9 @@ private:
std::string OWNER, owner, FILE_STATUS, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASHBOARD_SQL_NAME; std::string OWNER, owner, FILE_STATUS, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASHBOARD_SQL_NAME;
bool GATEWAY_SEND_QRGS_MAP, GATEWAY_HEADER_REGEN, APRS_ENABLE, playNotInCache; bool GATEWAY_SEND_QRGS_MAP, GATEWAY_HEADER_REGEN, APRS_ENABLE, playNotInCache;
bool LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO, DASHBOARD_DISABLE_LASTHEARD; bool LOG_DEBUG, LOG_IRC, LOG_DTMF, LOG_QSO, DASHBOARD_ENABLE_LASTHEARD;
int DASHBOARD_REFRESH, DASHBOARD_LASTHEARD_MAX, TIMING_PLAY_WAIT, TIMING_PLAY_DELAY, TIMING_TIMEOUT_ECHO, TIMING_TIMEOUT_VOICEMAIL, TIMING_TIMEOUT_REMOTE_G2, TIMING_TIMEOUT_LOCAL_RPTR, dtmf_digit; int DASHBOARD_REFRESH, TIMING_PLAY_WAIT, TIMING_PLAY_DELAY, TIMING_TIMEOUT_ECHO, TIMING_TIMEOUT_VOICEMAIL, TIMING_TIMEOUT_REMOTE_G2, TIMING_TIMEOUT_LOCAL_RPTR, dtmf_digit;
unsigned int vPacketCount[3] = { 0, 0, 0 }; unsigned int vPacketCount[3] = { 0, 0, 0 };

@ -0,0 +1,41 @@
#include <algorithm>
#include <cctype>
#include <locale>
// 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);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}

@ -245,14 +245,15 @@ void CAPRS::Open(const std::string OWNER)
} }
/* login to aprs */ /* login to aprs */
sprintf(snd_buf, "user %s pass %d vers qngateway 2.99 UDP 5 ", OWNER.c_str(), m_rptr->aprs_hash); //sprintf(snd_buf, "user %s pass %d vers QnetGateway 9 UDP 5 ", OWNER.c_str(), m_rptr->aprs_hash);
sprintf(snd_buf, "user %s pass %d vers QnetGateway 9 ", OWNER.c_str(), m_rptr->aprs_hash);
/* add the user's filter */ /* add the user's filter */
if (m_rptr->aprs_filter.length()) { if (m_rptr->aprs_filter.length()) {
strcat(snd_buf, "filter "); strcat(snd_buf, "filter ");
strcat(snd_buf, m_rptr->aprs_filter.c_str()); strcat(snd_buf, m_rptr->aprs_filter.c_str());
} }
// printf("APRS login command:[%s]\n", snd_buf); printf("APRS login command:[%s]\n", snd_buf);
strcat(snd_buf, "\r\n"); strcat(snd_buf, "\r\n");
while (true) { while (true) {
@ -271,7 +272,7 @@ void CAPRS::Open(const std::string OWNER)
} }
} }
aprs_sock.Read((unsigned char *)rcv_buf, sizeof(rcv_buf)); aprs_sock.Read((unsigned char *)rcv_buf, sizeof(rcv_buf));
printf("APRS Login returned: %s", rcv_buf);
return; return;
} }

@ -20,14 +20,16 @@
# # # #
######################################################################################################################### #########################################################################################################################
# What follows need to also be valid bash shell variable definitions, therefore: # What follows need to also be valid bash shell variable definitions, therefore:
# No white space on either side of the equal sign (=) # No white space on either side of the equal sign (=).
# String values should be quoted if they contain any special chars, including white space # String values should be quoted if they contain any special chars, including white space.
# If a string value is a simple word, it doesn't need to be quoted # If a string value is a simple word, it doesn't need to be quoted.
# Use the single quote (') for quoting strings, not the double quote(") # Use the single quote (') for quoting strings, not the double quote(").
# Comments can come after a key=value definition, introduced by a pound-sign (#) # Comments can come after a key=value definition, introduced by a pound-sign (#).
# This file should not contain any tab characters. Use spaces instead.
# #
# if a definition is commented out, it means that key has no default value. And it is # if a definition is commented out, it means that key has no default value. And it is
# include here just as a reference. # include here just as a reference. The 'ircddb_login' value is requred for every
# configure file
########################################################################################################################## ##########################################################################################################################
# #
@ -59,8 +61,8 @@ gateway_gate2modemb_d='gate2modemb'
gateway_gate2modemc_d='gate2modemc' gateway_gate2modemc_d='gate2modemc'
gateway_latitude_d=0 # you can leave this unspecified for a mobile rig gateway_latitude_d=0 # you can leave this unspecified for a mobile rig
gateway_longitude_d=0 # like the latitude gateway_longitude_d=0 # like the latitude
gateway_desc1_d='' # maximum of 20 characters, most special symbols are not allowed gateway_desc1_d='QnetGateway' # maximum of 20 characters, most special symbols are not allowed
gateway_desc2_d='' # just like desc1 gateway_desc2_d='by N7TAE' # just like desc1
gateway_url_d='github.com/n7tae/QnetGateway' # 80 characters max gateway_url_d='github.com/n7tae/QnetGateway' # 80 characters max
gateway_find_route_d='' # CSV list of route(s) to load on boot-up (prevents the "not in cache" message) gateway_find_route_d='' # CSV list of route(s) to load on boot-up (prevents the "not in cache" message)
@ -214,7 +216,7 @@ timing_play_delay_d=19 # milliseconds between frames playback, if echo so
# #
# Dashboard - for the php/sqlite webpage # Dashboard - for the php/sqlite webpage
# #
dashboard_disable_lastheard_d=false # set to true if you don't want a last heard section in the dashboard dashboard_enable_lastheard_d=true # set to false if you don't want a last heard section in the dashboard
dashboard_sql_filename_d='qn.db' # name for the sqlite database dashboard_sql_filename_d='qn.db' # name for the sqlite database
dashboard_refresh_d=20 # seconds for the webpage to reload dashboard_refresh_d=20 # seconds for the webpage to reload
dashbaord_lastheard_max_d=20 # maximum number of last heard entries to display dashbaord_lastheard_count_d=20 # maximum number of last heard entries to display

@ -7,24 +7,45 @@
<body> <body>
<?php <?php
$fmodule = $furcall = ''; $fmodule = $furcall = '';
$cfgdir = '/usr/local/etc';
function parse(string $filename) function ParseKVFile(string $filename, &$kvarray)
{ {
$ret = array();
if ($lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) { if ($lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) {
foreach ($lines as $line) { foreach ($lines as $line) {
$line = trim($line); $line = trim($line);
if ($line[0] == '#') continue; if ($line[0] == '#') continue;
if (! strpos($line, '=')) continue; if (! strpos($line, '=')) continue;
list( $key, $value ) = explode('=', $line); list( $key, $value ) = explode('=', $line);
$value = trim($value, "'"); if ("'" == $value[0])
$ret[$key] = $value; list ( $value ) = explode("'", substr($value, 1));
else
list ( $value ) = explode(' ', $value);
$value = trim($value);
$kvarray[$key] = $value;
}
}
}
function GetCFGValue(string $key, array &$cfgarray, array &$defaultarray)
{
if (array_key_exists($key, $cfgarray))
return $cfgarray[$key];
if ('module_' == substr($key, 0, 7)) {
$mod = substr($key, 0, 8);
if (array_key_exists($mod, $cfgarray)) {
$key = $cfgarray[$mod].substr($key, 8);
if (array_key_exists($key, $defaultarray))
return $defaultarray[$key];
} }
} else {
if (array_key_exists($key.'_d', $defaultarray))
return $defaultarray[$key.'_d'];
} }
return $ret; return '';
} }
function getip(string $type) function GetIP(string $type)
{ {
if ('internal' == $type) { if ('internal' == $type) {
$iplist = explode(' ', `hostname -I`); $iplist = explode(' ', `hostname -I`);
@ -40,7 +61,7 @@
return $ip; return $ip;
} }
function getstatus(string $mod, array &$kv) function GetStatus(string $mod, array &$kv)
{ {
$mod = strtoupper(substr($mod, 0, 1)); $mod = strtoupper(substr($mod, 0, 1));
if (array_key_exists('file_status', $kv)) if (array_key_exists('file_status', $kv))
@ -56,10 +77,54 @@
} }
return explode(',', ',,,,,'); return explode(',', ',,,,,');
} }
function SecToString(int $secs) {
$days = $secs / 86400;
if ($days >= 1.0)
return sprintf("%0.2f days", $days);
$hrs = intdiv($secs, 3600);
$sec %= 3600;
$min = intdiv($sec, 3600);
$sec %= 60;
if ($hrs > 9)
return sprintf("%d hr %2d min %2d sec", $hrs, $min, $sec);
if ($hrs)
return sprintf("%2d min $2 sec", $min, $sec);
if ($min > 9)
return sprintf("%d min %2d sec", $min, $sec);
if ($sec > 9)
return sprintf("%d sec", $sec);
return sprintf("%2d sec", $sec);
}
$cfg = parse("/usr/local/etc/qn.cfg"); function LastHeardPage()
{
echo 'Last Heard:<br><code>', "\n";
$rstr = 'MyCall Sfx URCall Module Gateway Time<br>';
echo str_replace(' ', '&nbsp;', $rstr), "\n";
echo '</code><br>', "\n";
$dbname = GetCFGValue('dashboard_sql_filename');
$db = new SQLite3($dbname, SQLITE3_OPEN_READONLY);
$ss = 'SELECT mycall,sfx,urcall,module,gateway,strftime("%s","now")-lastime FROM LHEARD ORDER BY strftime("%s","now")-lastime LIMIT '.GetCFGValue('dashboard_lastheard_count', $cfg, $defaults);
if ($stmnt = $db->prepare()) {
if ($result = $stmnt->execute()) {
while ($row = $result->FetchArray(SQLITE3_NUM)) {
$rstr = $row[0].'/'.$row[1].' '.$row[2].' '.$row[3].' '.$row[4].' '.SecToStrstring($row[4]).'<br>';
echo str_replace(' ', '&nbsp;', $rstr), "\n";
}
$result->finalize();
}
$stmnt->close();
}
$db->Close();
echo '</code><br>', "\n";
}
$cfg = array();
$defaults = array();
ParseKVFile($cfgdir.'/qn.cfg', $cfg);
ParseKVFile($cfgdir.'/defaults', $defaults);
?> ?>
<h2>QnetGateway <?php echo $cfg['ircddb_login']; ?> Dashboard</h2> <h2>QnetGateway <?php echo GetCFGValue('ircddb_login', $cfg, $defaults); ?> Dashboard</h2>
<?php <?php
if (`ps -aux | grep -e qn -e MMDVMHost | wc -l` > 2) { if (`ps -aux | grep -e qn -e MMDVMHost | wc -l` > 2) {
echo 'Processes:<br><code>', "\n"; echo 'Processes:<br><code>', "\n";
@ -70,11 +135,14 @@ if (`ps -aux | grep -e qn -e MMDVMHost | wc -l` > 2) {
} }
echo '</code>', "\n"; echo '</code>', "\n";
} }
if ('true' == GetCFGValue('dashboard', $cfg, $defaults))
LastHeardPage();
?> ?>
IP Addresses:<br> IP Addresses:<br>
<table cellpadding='1' border='1' style='font-family: monospace'> <table cellpadding='1' border='1' style='font-family: monospace'>
<tr><td style="text-align:center">Internal</td><td style="text-align:center">IPV4</td><td style="text-align:center">IPV6</td></tr> <tr><td style="text-align:center">Internal</td><td style="text-align:center">IPV4</td><td style="text-align:center">IPV6</td></tr>
<tr><td><?php echo getip('internal');?></td><td><?php echo getip('ipv4');?></td><td><?php echo getip('ipv6');?></td></tr> <tr><td><?php echo GetIP('internal');?></td><td><?php echo GetIP('ipv4');?></td><td><?php echo GetIP('ipv6');?></td></tr>
</table><br> </table><br>
Modules:<br> Modules:<br>
<table cellpadding='1' border='1' style='font-family: monospace'> <table cellpadding='1' border='1' style='font-family: monospace'>
@ -89,7 +157,7 @@ foreach (array('a', 'b', 'c') as $mod) {
$freq = $cfg[$module.'_tx_frequency']; $freq = $cfg[$module.'_tx_frequency'];
else if (array_key_exists($module.'_frequency', $cfg)) else if (array_key_exists($module.'_frequency', $cfg))
$freq = $cfg[$module.'_frequency']; $freq = $cfg[$module.'_frequency'];
$stat = getstatus($mod, $cfg); $stat = GetStatus($mod, $cfg);
if (8==strlen($stat[1]) && 1==strlen($stat[2])) if (8==strlen($stat[1]) && 1==strlen($stat[2]))
$linkstatus = substr($stat[1], 0, 7).$stat[2]; $linkstatus = substr($stat[1], 0, 7).$stat[2];
else else

@ -137,7 +137,7 @@ module_c='itap'
# #
# DVAP - Here is an example 2M dvap # DVAP - Here is an example 2M dvap
# #
module_c='itap' module_c='dvap'
#module_c_link_at_start='' # For example, set to 'REF001 C' to link module to reflector 1-charlie when the module starts. #module_c_link_at_start='' # For example, set to 'REF001 C' to link module to reflector 1-charlie when the module starts.
#module_c_inactivity=0 # if no activity for this many minutes unlink any linked reflector. Zero means no timer. #module_c_inactivity=0 # if no activity for this many minutes unlink any linked reflector. Zero means no timer.
#module_c_callsign='' # if you operate in a 'restriction mode', use your personal callsign. Usually leave this empty. #module_c_callsign='' # if you operate in a 'restriction mode', use your personal callsign. Usually leave this empty.

Loading…
Cancel
Save

Powered by TurnKey Linux.