qnremote uses unix sockets and a new configuration schema

pull/12/head
Tom Early 7 years ago
parent d61154d754
commit 5910117048

@ -0,0 +1,244 @@
/*
* Copyright (C) 2019 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 <cstdio>
#include <cstring>
#include "ConfigureBase.h"
CConfigureBase::CConfigureBase()
{
}
CConfigureBase::~CConfigureBase()
{
defaults.empty();
}
char *CConfigureBase::Trim(char *s)
{
size_t len = strlen(s);
while (len && isspace(s[len-1]))
s[--len] = '\0';
while (*s && len && isspace(*s))
len = strlen(++s);
return s;
}
bool CConfigureBase::ReadConfigFile(const char *configfile, std::map<std::string, std::string> &amap)
{
FILE *fp = fopen(configfile, "r");
if (fp) {
char line[128];
if (fgets(line, 128, fp)) {
char *key = strtok(line, "=");
key = Trim(key);
if (strlen(key) && '#' != *key) {
char *val = strtok(NULL, "\r\n");
char *val2 = Trim(val);
if ('\'' == *val2)
val = strtok(val2, "'");
else
val = strtok(val2, "# \t");
amap[key] = val;
}
}
fclose(fp);
return false;
}
fprintf(stderr, "could not open file %s\n", configfile);
return true;
}
bool CConfigureBase::Initialize(const char *file)
{
std::string filename(CFG_DIR);
filename.append("/qndefaults");
if (ReadConfigFile(filename.c_str(), defaults))
return true;
return ReadConfigFile(file, cfg);
}
bool CConfigureBase::GetDefaultBool(const std::string &path, const std::string &mod, bool &dvalue)
{
std::string value;
if (GetDefaultString(path, mod, value))
return true; // No default value defined!
if ('0'==value.at(0) || 'f'==value.at(0) || 'F'==value.at(0))
dvalue = false;
else if ('1'==value.at(0) || 't'==value.at(0) || 'T'==value.at(0))
dvalue = true;
else {
fprintf(stderr, "%s=%s doesn't seem to be a boolean!\n", path.c_str(), value.c_str());
return true;
}
return false;
}
bool CConfigureBase::GetDefaultDouble(const std::string &path, const std::string &mod, double &dvalue)
{
std::string value;
if (GetDefaultString(path, mod, value))
return true; // No default value defined!
dvalue = std::stod(value);
return false;
}
bool CConfigureBase::GetDefaultInt(const std::string &path, const std::string &mod, int &dvalue)
{
std::string value;
if (GetDefaultString(path, mod, value))
return true; // No default value defined!
dvalue = std::stoi(value);
return false;
}
bool CConfigureBase::GetDefaultString(const std::string &path, const std::string &mod, std::string &dvalue)
{
std::string search, search_again;
if (mod.empty()) {
search = path + "_d"; // there is no mod, so this is a simple search
} else {
search_again = mod; // we're looking from a module value. We may have to look for non-generic module parameters
if (0==path.compare(0, 7, "module_") && ('a'==path.at(7) || 'b'==path.at(7) || 'c'==path.at(7)) && '_'==path.at(8)) {
// path begins with module_{a|b|c}_
if (0==mod.compare("dvrptr") || 0==mod.compare("dvap") || 0==mod.compare("mmdvm") || 0==mod.compare("itap")) {
// and the module is recognized
search = path;
search.replace(7, 1, 1, 'x');
search_again += path.substr(8); // now the search_again path might look like dvap_frequency, for example.
} else {
fprintf(stderr, "Unrecognized module type = '%s'\n", mod.c_str());
return true;
}
} else {
fprintf(stderr, "%s looks like an ilformed request from module '%s'\n", path.c_str(), mod.c_str());
return true;
}
}
auto it = defaults.find(search);
if (defaults.end() == it) {
it = defaults.find(search_again);
if (defaults.end() == it) {
fprintf(stderr, "%s has no default value!\n", path.c_str());
return true;
}
}
dvalue = it->second;
return false;
}
bool CConfigureBase::GetValue(const std::string &path, const std::string &mod, bool &value)
{
auto it = cfg.find(path);
if (cfg.end() == it) {
bool dvalue;
if (GetDefaultBool(path, mod, dvalue)) {
fprintf(stderr, "%s not found in either the cfg file or the defaults file!\n", path.c_str());
return true;
}
value = dvalue; // found a value in the defaults
} else { // found a value in the cfg file
char c = it->second.at(0);
if ('0'==c || 'f'==c || 'F'==c)
value = false;
else if ('1'==c || 't'==c || 'T'==c)
value = true;
else {
fprintf(stderr, "%s=%s doesn't seem to define a boolean\n", path.c_str(), it->second.c_str());
return true;
}
}
printf("%s = %s\n", path.c_str(), value ? "true" : "false");
return false;
}
bool CConfigureBase::GetValue(const std::string &path, const std::string &mod, double &value, const double min, const double max)
{
auto it = cfg.find(path);
if (cfg.end() == it) {
double dvalue;
if (GetDefaultDouble(path, mod, dvalue)) {
fprintf(stderr, "%s not found in either the cfg file or the defaults file!\n", path.c_str());
return true;
}
if (dvalue < min || dvalue > max) {
fprintf(stderr, "Default value %s=%g is out of acceptable range\n", path.c_str(), value);
return true;
}
value = dvalue;
} else {
value = std::stod(it->second);
if (value < min || value > max) {
fprintf(stderr, "%s=%g is out of acceptable range\n", path.c_str(), value);
return true;
}
}
printf("%s = %g\n", path.c_str(), value);
return false;
}
bool CConfigureBase::GetValue(const std::string &path, const std::string &mod, int &value, const int min, const int max)
{
auto it = cfg.find(path);
if (cfg.end() == it) {
int dvalue;
if (GetDefaultInt(path, mod, dvalue)) {
fprintf(stderr, "%s not found in either the cfg file or the defaults file\n", path.c_str());
return true;
}
if (dvalue < min || dvalue > max) {
fprintf(stderr, "Default value %s=%d is out of acceptable range\n", path.c_str(), value);
return true;
}
value = dvalue;
} else {
value = std::stoi(it->second);
if (value < min || value > max) {
fprintf(stderr, "%s=%s is out of acceptable range\n", path.c_str(), it->second.c_str());
return true;
}
}
printf("%s = %d\n", path.c_str(), value);
return false;
}
bool CConfigureBase::GetValue(const std::string &path, const std::string &mod, std::string &value, int min, int max)
{
auto it = cfg.find(path);
if (cfg.end() != it) {
std::string dvalue;
if (GetDefaultString(path, mod, dvalue)) {
fprintf(stderr, "%s not found in either the cfg file for the defaults file\n", path.c_str());
return true;
}
int l = dvalue.length();
if (l<min || l>max) {
printf("Default value %s='%s' is wrong size\n", path.c_str(), value.c_str());
return true;
}
} else {
value = it->second;
int l = value.length();
if (l<min || l>max) {
printf("%s='%s' is wrong size\n", path.c_str(), value.c_str());
return true;
}
}
printf("%s = '%s'\n", path.c_str(), value.c_str());
return false;
}

@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 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.
*/
#pragma once
#include <string>
#include <map>
class CConfigureBase {
public:
CConfigureBase();
virtual ~CConfigureBase();
virtual bool ReadCfgFile() = 0;
bool Initialize(const char *configfile);
protected:
std::map<std::string, std::string> cfg;
char *Trim(char *s);
bool ReadConfigFile(const char *file, std::map<std::string, std::string> &amap);
bool GetValue(const std::string &path, const std::string &mod, bool &value);
bool GetValue(const std::string &path, const std::string &mod, double &value, const double min, const double max);
bool GetValue(const std::string &path, const std::string &mod, int &value, const int min, const int max);
bool GetValue(const std::string &path, const std::string &mod, std::string &value, const int min, const int max);
private:
std::map<std::string, std::string> defaults;
bool GetDefaultBool (const std::string &key, const std::string &mod, bool &dval);
bool GetDefaultDouble(const std::string &key, const std::string &mod, double &dval);
bool GetDefaultInt (const std::string &key, const std::string &mod, int &dval);
bool GetDefaultString(const std::string &key, const std::string &mod, std::string &dval);
};

@ -1,4 +1,4 @@
# Copyright (c) 2018 by Thomas A. Early N7TAE
# Copyright (c) 2018-2019 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
@ -42,18 +42,13 @@ MDV_PROGRAMS=qngateway qnlink qnremote qnvoice qnrelay
DVP_PROGRAMS=qngateway qnlink qnremote qnvoice qndvap
DVR_PROGRAMS=qngateway qnlink qnremote qnvoice qndvrptr
TAP_PROGRAMS=qngateway qnlink qnremote qnvoice qnitap
ICM_PROGRAMS=qnigateway qnlink qnremote qnvoice
all : $(ALL_PROGRAMS)
mmdvm : $(MDV_PROGRAMS)
dvap : $(DVP_PROGRAMS)
dvrptr : $(DVR_PROGRAMS)
icom : $(ICM_PROGRAMS)
itap : $(TAP_PROGRAMS)
qnigateway : $(IRCOBJS) QnetIcomGateway.o aprs.o
g++ $(CPPFLAGS) -o qnigateway QnetIcomGateway.o aprs.o $(IRCOBJS) $(LDFLAGS) -pthread
qngateway : $(IRCOBJS) QnetGateway.o aprs.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qngateway QnetGateway.o aprs.o UnixDgramSocket.o $(IRCOBJS) $(LDFLAGS) -pthread
@ -72,8 +67,8 @@ qndvap : QnetDVAP.o DVAPDongle.o Random.o $(DSTROBJS) UnixDgramSocket.o
qndvrptr : QnetDVRPTR.o $(DSTROBJS) Random.o UnixDgramSocket.o
g++ $(CPPFLAGS) -o qndvrptr QnetDVRPTR.o Random.o UnixDgramSocket.o $(DSTROBJS) $(LDFLAGS)
qnremote : QnetRemote.o Random.o
g++ $(CPPFLAGS) -o qnremote QnetRemote.o Random.o $(LDFLAGS)
qnremote : QnetRemote.o Random.o UnixDgramSocket.o ConfigureBase.o
g++ $(CPPFLAGS) -o qnremote QnetRemote.o Random.o UnixDgramSocket.o ConfigureBase.o $(LDFLAGS)
qnvoice : QnetVoice.o Random.o
g++ $(CPPFLAGS) -o qnvoice QnetVoice.o Random.o $(LDFLAGS)

File diff suppressed because it is too large Load Diff

@ -1,182 +0,0 @@
/*
* Copyright (C) 2018 by Thomas 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 <libconfig.h++>
#include "QnetTypeDefs.h"
#include "SEcho.h"
#include "aprs.h"
using namespace libconfig;
#define IP_SIZE 15
#define MAXHOSTNAMELEN 64
#define CALL_SIZE 8
#define MAX_DTMF_BUF 32
typedef struct to_remote_g2_tag {
unsigned short streamid;
struct sockaddr_in toDst4;
time_t last_time;
} STOREMOTEG2;
typedef struct torepeater_tag {
// help with header re-generation
unsigned char saved_hdr[58]; // repeater format
uint32_t saved_adr;
unsigned short streamid;
uint32_t adr;
struct sockaddr_in band_addr;
time_t last_time;
std::atomic<unsigned short> G2_COUNTER;
unsigned char sequence;
} STOREPEATER;
typedef struct band_txt_tag {
unsigned short streamID;
unsigned char flags[3];
char lh_mycall[CALL_SIZE + 1];
char lh_sfx[5];
char lh_yrcall[CALL_SIZE + 1];
char lh_rpt1[CALL_SIZE + 1];
char lh_rpt2[CALL_SIZE + 1];
time_t last_time;
char txt[64]; // Only 20 are used
unsigned short txt_cnt;
bool sent_key_on_msg;
char dest_rptr[CALL_SIZE + 1];
// try to process GPS mode: GPRMC and ID
char temp_line[256];
unsigned short temp_line_cnt;
char gprmc[256];
char gpid[256];
bool is_gps_sent;
time_t gps_last_time;
int num_dv_frames;
int num_dv_silent_frames;
int num_bit_errors;
} SBANDTXT;
class CQnetGateway {
public:
CQnetGateway();
~CQnetGateway();
void Process();
int Init(char *cfgfile);
private:
// text stuff
bool new_group[3] = { true, true, true };
unsigned char header_type = 0;
short to_print[3] = { 0, 0, 0 };
bool ABC_grp[3] = { false, false, false };
bool C_seen[3] = { false, false, false };
SPORTIP g2_internal, g2_external, g2_link, ircddb;
std::string OWNER, owner, local_irc_ip, status_file, dtmf_dir, dtmf_file, echotest_dir, irc_pass, qnvoicefile;
bool bool_send_qrgs, bool_irc_debug, bool_dtmf_debug, bool_regen_header, bool_qso_details, bool_send_aprs, playNotInCache;
int play_wait, play_delay, echotest_rec_timeout, voicemail_rec_timeout, from_remote_g2_timeout, from_local_rptr_timeout, dtmf_digit;
unsigned int vPacketCount;
std::map <uint32_t, uint16_t> portmap;
// data needed for aprs login and aprs beacon
// RPTR defined in aprs.h
SRPTR rptr;
// local repeater modules being recorded
// This is for echotest and voicemail
SECHO recd[3], vm[3];
SDSVT recbuf; // 56 or 27, max is 56
// the streamids going to remote Gateways from each local module
STOREMOTEG2 to_remote_g2[3]; // 0=A, 1=B, 2=C
// input from remote G2 gateway
int g2_sock = -1;
struct sockaddr_in fromDst4;
// Incoming data from remote systems
// must be fed into our local repeater modules.
STOREPEATER toRptr[3]; // 0=A, 1=B, 2=C
// input from our own local repeater modules
int srv_sock = -1;
SDSTR rptrbuf; // 58 or 29 or 32, max is 58
struct sockaddr_in fromRptr;
SDSTR end_of_audio;
// send packets to g2_link
struct sockaddr_in plug;
// for talking with the irc server
CIRCDDB *ii;
// for handling APRS stuff
CAPRS *aprs;
// text coming from local repeater bands
SBANDTXT band_txt[3]; // 0=A, 1=B, 2=C
/* Used to validate MYCALL input */
regex_t preg;
// CACHE used to cache users, repeaters,
// gateways, IP numbers coming from the irc server
std::map<std::string, std::string> user2rptr_map, rptr2gwy_map, gwy2ip_map;
pthread_mutex_t irc_data_mutex = PTHREAD_MUTEX_INITIALIZER;
int open_port(const SPORTIP &pip);
void calcPFCS(unsigned char *packet, int len);
void GetIRCDataThread();
int get_yrcall_rptr_from_cache(char *call, char *arearp_cs, char *zonerp_cs, char *mod, char *ip, char RoU);
bool get_yrcall_rptr(char *call, char *arearp_cs, char *zonerp_cs, char *mod, char *ip, char RoU);
void PlayFileThread(SECHO &edata);
void compute_aprs_hash();
void APRSBeaconThread();
void ProcessTimeouts();
void ProcessSlowData(unsigned char *data, unsigned short sid);
bool Flag_is_ok(unsigned char flag);
// read configuration file
bool read_config(char *);
bool get_value(const Config &cfg, const std::string path, int &value, int min, int max, int default_value);
bool get_value(const Config &cfg, const std::string path, double &value, double min, double max, double default_value);
bool get_value(const Config &cfg, const std::string path, bool &value, bool default_value);
bool get_value(const Config &cfg, const std::string path, std::string &value, int min, int max, const char *default_value);
/* aprs functions, borrowed from my retired IRLP node 4201 */
void gps_send(short int rptr_idx);
bool verify_gps_csum(char *gps_text, char *csum_text);
void build_aprs_from_gps_and_send(short int rptr_idx);
void qrgs_and_maps();
void set_dest_rptr(int mod_ndx, char *dest_rptr);
bool validate_csum(SBANDTXT &bt, bool is_gps);
};

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
* Copyright (C) 2018 by Thomas A. Early N7TAE
* Copyright (C) 2018-2019 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
@ -32,25 +32,20 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <libconfig.h++>
#include <string>
#include "QnetTypeDefs.h"
#include "Random.h"
#include "ConfigureBase.h"
#include "UnixDgramSocket.h"
using namespace libconfig;
#define VERSION "v1.0"
int sockDst = -1;
struct sockaddr_in toDst;
#define VERSION "v2.0"
char module;
time_t tNow = 0;
short streamid_raw = 0;
bool isdefined[3] = { false, false, false };
std::string REPEATER, IP_ADDRESS;
int PORT, PLAY_WAIT, PLAY_DELAY;
bool is_icom = false;
std::string REPEATER;
int PLAY_WAIT, PLAY_DELAY;
unsigned char silence[9] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 };
@ -74,9 +69,37 @@ unsigned short crc_tabccitt[256] = {
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
void calcPFCS(unsigned char rawbytes[58])
class CConfigure : public CConfigureBase
{
public:
bool ReadCfgFile()
{
const std::string estr;
std::string type;
std::string path = "module_";
path.append(1, module);
if (GetValue(path, estr, type, 1, 16)) {
fprintf(stderr, "%s not found!\n", path.c_str());
return true;
}
if (type.compare("dvap") && type.compare("dvrptr") && type.compare("mmdvm") && type.compare("itap")) {
fprintf(stderr, "module type '%s is invalid!\n", type.c_str());
return true;
}
if (GetValue(path+"_callsign", type, REPEATER, 3, 6)) {
if (GetValue("ircddb.login", estr, REPEATER, 3, 6)) {
fprintf(stderr, "no Callsign for the repeater was found!\n");
return true;
}
}
GetValue("timing_play_wait", estr, PLAY_WAIT, 1,10);
GetValue("timing_play_delay", estr, PLAY_DELAY, 15, 25);
return false;
}
};
void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
@ -94,135 +117,6 @@ void calcPFCS(unsigned char rawbytes[58])
return;
}
bool dst_open(const char *ip, const int port)
{
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1) {
printf("Failed to create DSTAR socket\n");
return true;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
close(sockDst);
sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return true;
}
memset(&toDst,0,sizeof(struct sockaddr_in));
toDst.sin_family = AF_INET;
toDst.sin_port = htons(port);
toDst.sin_addr.s_addr = inet_addr(ip);
fcntl(sockDst,F_SETFL,O_NONBLOCK);
return false;
}
void dst_close()
{
if (sockDst != -1) {
close(sockDst);
sockDst = -1;
}
return;
}
bool get_value(const Config &cfg, const char *path, int &value, int min, int max, int default_value)
{
if (cfg.lookupValue(path, value)) {
if (value < min || value > max)
value = default_value;
} else
value = default_value;
printf("%s = [%d]\n", path, value);
return true;
}
bool get_value(const Config &cfg, const char *path, double &value, double min, double max, double default_value)
{
if (cfg.lookupValue(path, value)) {
if (value < min || value > max)
value = default_value;
} else
value = default_value;
printf("%s = [%lg]\n", path, value);
return true;
}
bool get_value(const Config &cfg, const char *path, bool &value, bool default_value)
{
if (! cfg.lookupValue(path, value))
value = default_value;
printf("%s = [%s]\n", path, value ? "true" : "false");
return true;
}
bool get_value(const Config &cfg, const char *path, std::string &value, int min, int max, const char *default_value)
{
if (cfg.lookupValue(path, value)) {
int l = value.length();
if (l<min || l>max) {
printf("%s is invalid\n", path);
return false;
}
} else
value = default_value;
printf("%s = [%s]\n", path, value.c_str());
return true;
}
/* process configuration file */
bool read_config(const char *cfgFile)
{
Config cfg;
printf("Reading file %s\n", cfgFile);
// Read the file. If there is an error, report it and exit.
try {
cfg.readFile(cfgFile);
} catch(const FileIOException &fioex) {
printf("Can't read %s\n", cfgFile);
return true;
} catch(const ParseException &pex) {
printf("Parse error at %s:%d - %s\n", pex.getFile(), pex.getLine(), pex.getError());
return true;
}
if (! get_value(cfg, "ircddb.login", REPEATER, 3, 6, "UNDEFINED"))
return true;
REPEATER.resize(6, ' ');
printf("REPEATER=[%s]\n", REPEATER.c_str());
for (short int m=0; m<3; m++) {
std::string path = "module.";
path += m + 'a';
std::string type;
if (cfg.lookupValue(std::string(path+".type").c_str(), type)) {
if (type.compare("dvap") && type.compare("dvrptr") && type.compare("mmdvm") && type.compare("icom") && type.compare("itap")) {
printf("module type '%s' is invalid\n", type.c_str());
return true;
}
is_icom = type.compare("icom") ? false : true;
isdefined[m] = true;
}
}
if (false==isdefined[0] && false==isdefined[1] && false==isdefined[2]) {
printf("No repeaters defined!\n");
return true;
}
if (! get_value(cfg, "gateway.internal.ip", IP_ADDRESS, 7, 15, is_icom ? "172.16.0.20" : "127.0.0.1"))
return true;
get_value(cfg, "gateway.internal.port", PORT, 16000, 65535, is_icom ? 20000 : 19000);
get_value(cfg, "timing.play.wait", PLAY_WAIT, 1, 10, 1);
get_value(cfg, "timing.play.delay", PLAY_DELAY, 9, 25, 19);
return false;
}
void ToUpper(std::string &str)
{
for (unsigned int i=0; i<str.size(); i++)
@ -235,18 +129,43 @@ int main(int argc, char *argv[])
unsigned short G2_COUNTER = 0;
if (argc != 4) {
printf("Usage: %s <module> <mycall> <yourcall>\n", argv[0]);
printf("Example: %s c n7tae xrf757al\n", argv[0]);
printf("Where...\n");
printf(" c is the local repeater module\n");
printf(" n7tae is the value of mycall\n");
printf(" xrf757al is the value of yourcall, in this case this is a Link command\n\n");
fprintf(stderr, "Usage: %s <module> <mycall> <yourcall>\n", argv[0]);
fprintf(stderr, "Example: %s c n7tae xrf757al\n", argv[0]);
fprintf(stderr, "Where...\n");
fprintf(stderr, " c is the local repeater module\n");
fprintf(stderr, " n7tae is the value of mycall\n");
fprintf(stderr, " xrf757al is the value of yourcall, in this case this is a Link command\n\n");
return 0;
}
switch (argv[1][0]) {
case '0':
case 'a':
case 'A':
module = 'A';
break;
case '1':
case 'b':
case 'B':
module = 'B';
break;
case '2':
case 'c':
case 'C':
module = 'C';
break;
default:
fprintf(stderr, "module must be 0, a, A, 1, b, B, 2, c or C, not %s\n", argv[1]);
return 1;
}
std::string cfgfile(CFG_DIR);
cfgfile += "/qn.cfg";
if (read_config(cfgfile.c_str()))
CConfigure config;
if (config.Initialize(cfgfile.c_str()))
return 1;
if (config.ReadCfgFile())
return 1;
if (REPEATER.size() > 6) {
@ -255,14 +174,6 @@ int main(int argc, char *argv[])
}
ToUpper(REPEATER);
char module = argv[1][0];
if (islower(module))
module = toupper(module);
if ((module != 'A') && (module != 'B') && (module != 'C')) {
printf("module must be one of A B C\n");
return 1;
}
if (strlen(argv[2]) > 8) {
printf("MYCALL can not be more than 8 characters, %s is invalid\n", argv[2]);
return 1;
@ -287,8 +198,10 @@ int main(int argc, char *argv[])
time(&tNow);
CRandom Random;
if (dst_open(IP_ADDRESS.c_str(), PORT))
CUnixDgramWriter ToGateway;
std::string togateway("modem2gate");
togateway.append(1, module-'A'+'0');
if (ToGateway.Open(togateway.c_str()))
return 1;
SDSTR pkt;
@ -328,10 +241,10 @@ int main(int argc, char *argv[])
calcPFCS(pkt.pkt_id);
// send the header
int sent = sendto(sockDst, pkt.pkt_id, 58, 0, (struct sockaddr *)&toDst, sizeof(toDst));
int sent = ToGateway.Write(pkt.pkt_id, 58);
if (sent != 58) {
printf("%s: ERROR: Couldn't send header!\n", argv[0]);
dst_close();
ToGateway.Close();
return 1;
}
@ -400,13 +313,13 @@ int main(int argc, char *argv[])
break;
}
sent = sendto(sockDst,pkt.pkt_id, 29, 0, (struct sockaddr *)&toDst, sizeof(toDst));
sent = ToGateway.Write(pkt.pkt_id, 29);
if (sent != 29) {
printf("%s: ERROR: could not send voice packet %d\n", argv[0], i);
dst_close();
ToGateway.Close();
return 1;
}
}
dst_close();
ToGateway.Close();
return 0;
}

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 by Thomas Early N7TAE
* Copyright (C) 2019 by Thomas 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

@ -1,6 +1,6 @@
#pragma once
/*
* Copyright (C) 2018 by Thomas Early N7TAE
* Copyright (C) 2019 by Thomas 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

@ -0,0 +1,166 @@
#
# Copyright (c) 2019 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, see <http://www.gnu.org/licenses/>.
#########################################################################################################################
# #
# QnetGateway Default Parameter Values #
# #
#########################################################################################################################
# What follows need to also be valid bash shell variable definitions, therefore:
# No white space on either side of the equal sign (=)
# 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
# Use the single quote (') for quoting strings, not the double quote(")
# Comments can come after a key=value definition, introduced by a pound-sign (#)
##########################################################################################################################
#
# IRCDDB - You MUST use a legal callsign for logging into any IRC network
#
ircddb_login_d='' # login callsign for the ircDDB network
ircddb_host_d='rr.openquad.net' # other irc networks include group1-irc.ircddb.net
ircddb_port_d=9007 # not a good idea to change!
ircddb_password_d='1111111111111' # not needed for rr.openquad.net
##########################################################################################################################
#
# GATEWAY
#
gateway_regen_header_d=true # regenerate headers from incoming data
gateway_send_qrgs_maps_d=true # send frequency, offset, coordinates and url to irc-server
gateway_external_ip_d='0.0.0.0' # this means accept a connection from any source
gateway_external_port_d=40000 # don't change
##########################################################################################################################
#
# APRS - for tracking users and also this repeater.
#
aprs_enable_d=true # send info to APRS
aprs_host_d='rotate.aprs.net' # the APRS network server
aprs_port_d=14580 # and port
aprs_interval_d=40 # keep-alive in minutes
aprs_filter_d='' # advanced feature
##########################################################################################################################
#
# LINK - controls the behaviour of QnetLink (qnlink)
#
link_admin_d='' # these comma-separated list of users can execute scripts, block dongles, reload the gwys.txt
link_link_unlink_d='' # if defined, comma-separated list of users that can link and unlink a repeater
#link_no_link_unlink_d='' # if defined, comma-separated list of users that cannot link or unlink, it's a blacklist
# if the blacklist is defined (even if it's empty), the link_unlink will not be read
link_incoming_ip_d='0.0.0.0' # incoming ip address of qnlink, '0.0.0.0' means accepts any connection.
link_ref_port_d=20001 # port for REF linking, don't change
link_xrf_port_d=30001 # port for XRF linking, don't change
link_dcs_port_d=30051 # port for DCS linking, don't change
link_announce_d=true # do link, unlink, etc. announcements
link_acknowledge_d=true # send text acknowledgment on key-up
link_max_dongles_d=5 # maximum number of linked hot-spots
##########################################################################################################################
#
# GENERIC MODULE - These will be defined for any and all defined modules
#
module_x_link_at_start='' # For example, set to 'REF001CL' to link module to 1-charlie when the module starts.
module_x_inactivity=0 # if no activity for this many minutes unlink reflector. Zero means no timer.
module_x_callsign='' # if you operate in a 'restriction mode', use your personal callsign. Usually leave this empty.
module_x_packet_wait=25 # how many milliseconds to wait on packets in a voicestream
module_x_acknowledge=false # Do you want an ACK back?
module_x_ack_delay=250 # millisecond delay before acknowledgement
module_x_frequency=0 # if you specify here, this frequency will show up on the QuadNet USER GATEWAYS webpage
module_x_offset=0 # usually the duplex tx-rx offset, but for dvap, it's a frequency tweak
module_x_range=0 # the range of this repeater, in meters 1609.344 meters is 1.0 miles
module_x_agl=0 # the height above ground level for this repeater's antenna
module_x_latitude=0 # you can leave this unspecified for a mobile rig
module_x_longitude=0 # like the latitude
module_x_desc1='' # maximum of 20 characters, most special symbols are not allowed
module_x_desc2='' # just like desc1
module_x_url='github.com/n7tae/g2_ircddb' # 80 characters max
##########################################################################################################################
#
# DVAP - Special parameters when: module.x='dvap'
#
dvap_power=10 # TX power level: -12 to 10, 10 is maximum power
dvap_squelch=-100 # RX Squelch: -128 to -45, -100 to -80 usually works best
dvap_serial_number='APXXXXXX' # The serial number of your DVAP is visible through the bottom of the case
##########################################################################################################################
#
# MMDVM - Special parameters when: module_x='mmdvm'
#
mmdvm_internal_ip='0.0.0.0' # where MMDVMHost will find the QnetRelay program
mmdvm_gateway_port=20010 # which port will QnetRelay be sending on
mmdvm_local_port=20011 # which port will MMDVMHost be sending on
##########################################################################################################################
#
# DVRPTR - Special parameters when: module_x='dvrptr'
#
# if you don't know what your DVRPTR serial number is, look in the log file after running qndvrptr
dvrptr_serial_number='00.00.00.00' # the DVRPTR serial number
dvrptr_rf_on='RFON' # put this in YRCALL to disable the channel
dvrptr_rf_off='RFOFF' # put this in YRCALL to enable the channel
dvrptr_rf_rx_level=80 # see the DVRPTR V1 manual
dvrptr_duplex=false # set to true if the module is duplex
dvrptr_tx_delay=250 # milliseconds to allow for switching from rx to tx
dvrptr_rqst_count=10 # number of 2-sec intervals before the an unresponsive system is killed
dvrptr_inverse_rx=true # if you're not hearing anything, try false
dvrptr_inverse_tx=true # if you're not being heard, try false
##########################################################################################################################
#
# LOGGING - Control extra logging - useful for debugging
#
log_qso_d=false # QSO info goes into the log
log_irc_d=false # IRC debug info
log_dtmf_d=false # DTMF debug info
##########################################################################################################################
#
# DPLUS - Control of dplus (trust system) linking to repeaters and REF reflectors
#
# The following settings do not affect your ability to use dplus linking to XRF or XLX reflectors!
# You must be registered on the DPlus system, see www.dstargateway.org, otherwise authorization will fail,
# even if QnetLink reports a successful authorization.
dplus_ref_login_d='' # for logging into REF reflectors, if undefined or empty, ircddb_login will be used
dplus_authorize_d=false # set to true if you want to use the closed-source DPlus reflectors and/or repeaters
dplus_use_reflectors_d=true # set to false if you are not going to link to DPlus reflectors
dplus_use_repeaters_d=true # set to false if you are not going to link to DPlus repeaters
# any gateways in your gwys.txt file will override any reflectors or repeaters that DPlus authorization returns.
##########################################################################################################################
#
# FILE - where important QnetGateway files and directories are found.
#
file_status_d='/usr/local/etc/rptr_status' # where repeater status info is passed between services
file_dtmf_d='/tmp' # where DTMF is decoded
file_echotest_d='/tmp' # echo dat files will end up here
file_qnvoicefile_d='/tmp/qnvoice.txt' # where qnvoice will create the play command
file_gwys_d='/usr/local/etc/gwys.txt' # where the list of gateways and reflectors (with ports) is.
file_announce_dir_d='/usr/local/etc' # where the *.dat files are for the verbal link, unlink, etc. announcements
##########################################################################################################################
#
# TIMINGS - for controlling how to deal with timing issues
#
# most users will not have to override any of these default values
timing_timeout_echo_d=1 # seconds before we assume echo has timed out
timing_timeout_voicemail_d=1 # seconds before we assume voicemail has timed out
timing_timeout_remote_g2_d=2 # after this many seconds with no packets, we assume the tx is closed
timing_timeout_local_rptr_d=1 # local repeater timeout, in seconds
timing_play_wait_d=1 # seconds before echo or voicemail playback occurs, between 1 and 10
timing_play_delay_d=19 # microseconds between frames playback, if echo sounds bad, adjust this up or down 1 or 2 ms

@ -10,19 +10,12 @@ ircddb = {
gateway = {
# regen_header = true # regenerate headers from incoming data
# send_qrgs_maps = true # send frequecy, offset, cooridinates and url to irc-server
# local_irc_ip = "0.0.0.0" # 0.0.0.0 means accept any incoming connections
# aprs_send = true # send info to aprs
# ip = "127.0.0.1" # where the gateway is running
external = {
# ip = "0.0.0.0"
# port = 40000
}
internal = {
# ip = "0.0.0.0"
# port = 19000
}
}
module = {
@ -34,8 +27,6 @@ module = {
# 70 cm modules will use "b"
# 2 M module will use "c"
type = "mmdvm"
# ip = "127.0.0.1"
# port = 19998 # default for mod a, you usually don't need to specify this
# frequency = 0 # if you specify here, this frequency will show up on the QuadNet USER GATEWAYS webpage
# offset = 0
# range = 0 # the range of this repeater, in meters 1609.344 meters is 1.0 miles
@ -116,9 +107,6 @@ module = {
# If you don't know what it is, run the program and look in the log file!
# serial_number = "00.00.00.00"
# internal_ip = "0.0.0.0" # the dvrptr address, usually leave this alone
# port = 19999 # module defaults: A=20000, B=19999, C=19998
# Some settings for your DVRPTR modem (see DVRPTR V1 manual for more info).
# rf_rx_level = 80
@ -227,15 +215,6 @@ module = {
# the url of your repeater, 80 chars max
# url = "github.com/n7tae/QnetGateway"
# where other g2 programs find this repeater software
# ip = "127.0.0.1" # where is the device running? must be a "dotted number"
# the internal ip of this program, "0.0.0.0" is usually best
# internal_ip = "0.0.0.0"
# port number default: A:19998 B:19999 C:20000
# port = 20000 # default for mod C
}
}
@ -243,6 +222,7 @@ module = {
mmdvm = {
# these need to be the same as they are in your MMDVM.ini file (in the [D-Star Network] section
# If you change them there, then change them here!
# internal_ip = "0.0.0.0"
# gateway_port = 20010
# local_port = 20011
}
@ -271,8 +251,6 @@ link = {
# no_link_unlink = [ "CALL7", "CALL8", "CALL9" ] # if defined, these users cannot link or unlink, it's a blacklist
# if the blacklist is defined (even if it's empty), the link_unlink will not be read
# incoming_ip = "0.0.0.0" # incoming ip address, "0.0.0.0" means accepts all connections.
# ip = "127.0.0.1" # where g2_link is running
# port = 18997 # port for communications to g2_link
# ref_port = 20001 # port for REF linking, don't change
# xrf_port = 30001 # port for XRF linking, don't change
# dcs_port = 30051 # port for DCS linking, don't change

Loading…
Cancel
Save

Powered by TurnKey Linux.