Merge branch 'unstable'

pull/3/head
Tom Early 8 years ago
commit e586e147c6

2
.gitignore vendored

@ -4,6 +4,6 @@ qndvap
qndvrptr
qnlink
qngateway
qnlinktest
qnremote
qnlinktestaudio
qnrelay

@ -0,0 +1,54 @@
####### DTMF ########
DTMF is available with the QnetGateway Software. You can do things like linking
and unlinking from you radio's keyboard, if present. For example, typing
"B75703" should link you to XRF757 C.
DTMF is not enabled by default. To enable it, first create a DTMF script called
"qndtmf" in the build directory. A complete, functional script is included
and is called "qndtmf.sh", so you can start by just copying it to the target:
cp qndtmf.sh qndtmf
Then you can install DTMF: sudo make installdtmf
To uninstall DTMF: sudo make uninstalldtmf
Be sure to look at the script. It contains examples of all the DTMF commands it
supports. You can add more if you are good at shell programming and understand
how qnremote works.
######## QnetRemote #########
QnetRemote is a program used to send any arbitrary YourCall to your QnetGateway
system. It is install automatically when you install any of the supported modems:
MMDVMHost, QnetDVAP or QnetDVRPTR. It's a very simple, yet powerful program.
Open a shell to you system and type "qnremote" and it will remind you of the
format it expects:
pi@raspberrypi:~ $ qnremote
Usage: qnremote <module> <mycall> <yourcall>
Example: qnremote c n7tae xrf757cl
Where...
c is the local repeater module
n7tae is the value of mycall
xrf757cl is the value of yourcall, in this case this is a Link command
You simple specify the module the command will be sent to, and the MyCall and
YourCall parameters. Here are some more examples:
qnremote b w4wwm u # W4WWM is unlinking module B.
qnremote c w1bwb i # W1BSB is requesting the status of module C
Modules, callsigns and YourCall can all be in lowercase, qnremote will convert
them to uppercase. QnetLink will validate that the specific MyCall is allowed
to link or unlink, according to the configuration. (By default, any user can
link or unlink a module, unless link_unlink is specified in the configuration
file, see qn.everything.cfg.)
qnremote can be used by the linux cron facility to automatically execute jobs
at a certain time. If you want to link to XRF002 A on Saturday at 6:00 PM
Mountain Time for the D-Star Users Net, don't forget to include an unlink
command in your cron-executed script before you link! For instructions on how
to do this search the web with "linux cron job".

@ -21,8 +21,7 @@ your start. On a Raspberry Pi, you can do all of this with the configureation me
3) cd into the MMDVMHost directory and compile: make
If you're system has multiple processors, use: make -jx
where x is the number of processors on you system.
To tell how many processors you have on Raspbian Stretch:
cat /proc/cpuinfo | grep processor | wc -l
To tell how many processors you have: cat /proc/cpuinfo | grep processor | wc -l
4) Copy the ini file template: cp MMDVM.ini MMDVM.qn
@ -91,4 +90,10 @@ your start. On a Raspberry Pi, you can do all of this with the configureation me
Being able to detach from a screen session is very useful, especially if you are
operating "headless"!
17) Build and start other MMDVMHost services...
17) DTMF is _not_ enabled by default if you want it, you need to do two things:
First, create a working DTMF script: cp qndtmf.sh qndtmf
Then, install the DTMF service: sudo make installdtmf
You should be good to go, The DTMF command "00" should announce the linked
status of you module. See DTMF+REMOTE.README for more information.
18) Build and start other MMDVMHost services...

@ -24,10 +24,10 @@ SYSDIR=/lib/systemd/system
IRC=ircddb
# use this if you want debugging help in the case of a crash
#CPPFLAGS=-g -ggdb -W -Wall -std=c++11 -Iircddb
#CPPFLAGS=-g -ggdb -W -Wall -std=c++11 -Iircddb -DCFG_DIR=\"$(CFGDIR)\"
# or, you can choose this for a much smaller executable without debugging help
CPPFLAGS=-W -Wall -std=c++11 -Iircddb
CPPFLAGS=-W -Wall -std=c++11 -Iircddb -DCFG_DIR=\"$(CFGDIR)\"
LDFLAGS=-L/usr/lib -lconfig++ -lrt
@ -36,7 +36,7 @@ IRCOBJS = $(IRC)/IRCDDB.o $(IRC)/IRCClient.o $(IRC)/IRCReceiver.o $(IRC)/IRCMess
SRCS = $(wildcard *.cpp) $(wildcard $(IRC)/*.cpp)
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
PROGRAMS=qngateway qnlink qnrelay qndvap qndvrptr qnlinktest qnlinktestaudio
PROGRAMS=qngateway qnlink qnrelay qndvap qndvrptr qnremote qnlinktestaudio
all : $(PROGRAMS)
@ -55,8 +55,8 @@ qndvap : QnetDVAP.o DVAPDongle.o $(DSTROBJS)
qndvrptr : QnetDVRPTR.o $(DSTROBJS)
g++ $(CPPFLAGS) -o qndvrptr QnetDVRPTR.o $(DSTROBJS) $(LDFLAGS)
qnlinktest : QnetLinkTest.o
g++ $(CPPFLAGS) -o qnlinktest QnetLinkTest.o -lrt
qnremote : QnetRemote.o
g++ $(CPPFLAGS) -o qnremote QnetRemote.o $(LDFLAGS)
qnlinktestaudio : QnetLinkTestAudio.o
g++ $(CPPFLAGS) -o qnlinktestaudio QnetLinkTestAudio.o -lrt
@ -74,6 +74,7 @@ clean:
install : qngateway qnlink qnrelay
######### QnetGateway #########
/bin/cp -f qngateway $(BINDIR)
/bin/cp -f qnremote $(BINDIR)
/bin/cp -f qn.cfg $(CFGDIR)
/bin/cp -f system/qngateway.service $(SYSDIR)
systemctl enable qngateway.service
@ -98,6 +99,7 @@ install : qngateway qnlink qnrelay
installdvap : qngateway qnlink qndvap
######### QnetGateway #########
/bin/cp -f qngateway $(BINDIR)
/bin/cp -f qnremote $(BINDIR)
/bin/cp -f qn.cfg $(CFGDIR)
/bin/cp -f system/qngateway.service $(SYSDIR)
systemctl enable qngateway.service
@ -122,6 +124,7 @@ installdvap : qngateway qnlink qndvap
installdvrptr : qngateway qnlink qndvrptr
######### QnetGateway #########
/bin/cp -f qngateway $(BINDIR)
/bin/cp -f qnremote $(BINDIR)
/bin/cp -f qn.cfg $(CFGDIR)
/bin/cp -f system/qngateway.service $(SYSDIR)
systemctl enable qngateway.service
@ -143,13 +146,12 @@ installdvrptr : qngateway qnlink qndvrptr
systemctl daemon-reload
systemctl start qndvrptr.service
installdtmfs : qnlinktest
/bin/cp -f qnlinktest $(BINDIR)
/bin/cp -f proc_qnlinktest $(BINDIR)
/bin/cp -f system/qnlinktest.service $(SYSDIR)
systemctl enable qnlinktest.service
installdtmf : qndtmf
/bin/cp -f qndtmf $(BINDIR)
/bin/cp -f system/qndtmf.service $(SYSDIR)
systemctl enable qndtmf.service
systemctl daemon-reload
systemctl start qnlinktest.service
systemctl start qndtmf.service
installmmdvm :
/bin/cp -f $(MMPATH)/MMDVMHost $(BINDIR)
@ -175,6 +177,7 @@ uninstall :
systemctl disable qngateway.service
/bin/rm -f $(SYSDIR)/qngateway.service
/bin/rm -f $(BINDIR)/qngateway
/bin/rm -f $(BINDIR)/qnremote
/bin/rm -f $(CFGDIR)/qn.cfg
######### QnetLink #########
systemctl stop qnlink.service
@ -203,6 +206,7 @@ uninstalldvap :
systemctl disable qngateway.service
/bin/rm -f $(SYSDIR)/qngateway.service
/bin/rm -f $(BINDIR)/qngateway
/bin/rm -f $(BINDIR)/qnremote
/bin/rm -f $(CFGDIR)/qn.cfg
######### QnetLink #########
systemctl stop qnlink.service
@ -231,6 +235,7 @@ uninstalldvrptr :
systemctl disable qngateway.service
/bin/rm -f $(SYSDIR)/qngateway.service
/bin/rm -f $(BINDIR)/qngateway
/bin/rm -f $(BINDIR)/qnremote
/bin/rm -f $(CFGDIR)/qn.cfg
######### QnetLink #########
systemctl stop qnlink.service
@ -253,11 +258,9 @@ uninstalldvrptr :
/bin/rm -f $(BINDIR)/qndvrptr
systemctl daemon-reload
uninstalldtmfs:
systemctl stop qnlinktest.service
systemctl disable qnlinktest.service
/bin/rm -f $(SYSDIR)/qnlinktest.service
systemctl daemon-reload
/bin/rm -f $(BINDIR)/qnlinktest
/bin/rm -f $(BINDIR)/proc_qnlinktest
uninstalldtmf :
systemctl stop qndtmf.service
systemctl disable qndtmf.service
/bin/rm -f $(SYSDIR)/qndtmf.service
systemctl daemon-reload
/bin/rm -f $(BINDIR)/qndtmf

@ -623,6 +623,12 @@ void CQnetGateway::process()
std::future<void> aprs_future, irc_data_future;
// dtmf stuff
int dtmf_buf_count[3] = {0, 0, 0};
char dtmf_buf[3][MAX_DTMF_BUF + 1] = { {""}, {""}, {""} };
int dtmf_last_frame[3] = { 0, 0, 0 };
unsigned int dtmf_counter[3] = { 0, 0, 0 };
/* START: TEXT crap */
bool new_group[3] = { true, true, true };
int header_type = 0;
@ -982,10 +988,6 @@ void CQnetGateway::process()
(rptrbuf.remaining == 0x13) || /* 19 bytes follow */
(rptrbuf.remaining == 0x16)) ) { /* 22 bytes follow */
int dtmf_buf_count[3] = {0, 0, 0};
char dtmf_buf[3][MAX_DTMF_BUF + 1] = { {""}, {""}, {""} };
int dtmf_last_frame[3] = { 0, 0, 0 };
unsigned int dtmf_counter[3] = { 0, 0, 0 };
if (recvlen == 58) {
if (bool_qso_details)
@ -1006,6 +1008,8 @@ void CQnetGateway::process()
int i = rptrbuf.vpkt.hdr.r1[7] - 'A';
if (i>=0 && i<3) {
if (bool_dtmf_debug)
printf("resetting dtmf[%d] (got a header)\n", i);
dtmf_last_frame[i] = 0;
dtmf_counter[i] = 0;
memset(dtmf_buf[i], 0, sizeof(dtmf_buf[i]));
@ -1515,6 +1519,8 @@ void CQnetGateway::process()
printf("Failed to create dtmf file %s\n", dtmf_file.c_str());
if (bool_dtmf_debug)
printf("resetting dtmf[%d] (printed dtmf code %s from %s)\n", i, dtmf_buf[i], band_txt[i].lh_mycall);
memset(dtmf_buf[i], 0, sizeof(dtmf_buf[i]));
dtmf_buf_count[i] = 0;
dtmf_counter[i] = 0;
@ -1552,7 +1558,7 @@ void CQnetGateway::process()
band_txt[i].num_dv_silent_frames = 0;
band_txt[i].num_bit_errors = 0;
} else {
} else { // not the end of the voice stream
int ber_data[3];
int ber_errs = dstar_dv_decode(rptrbuf.vpkt.vasd.voice, ber_data);
if (ber_data[0] == 0xf85)
@ -1563,6 +1569,9 @@ void CQnetGateway::process()
if ((ber_data[0] & 0x0ffc) == 0xfc0) {
dtmf_digit = (ber_data[0] & 0x03) | ((ber_data[2] & 0x60) >> 3);
if (dtmf_counter[i] > 0) {
if (bool_dtmf_debug)
printf("new digit=%d, counter[%d]=%d, lastframe=%d\n",
dtmf_digit, i, dtmf_counter[i], dtmf_last_frame[i]);
if (dtmf_last_frame[i] != dtmf_digit)
dtmf_counter[i] = 0;
}
@ -1574,9 +1583,12 @@ void CQnetGateway::process()
const char *dtmf_chars = "147*2580369#ABCD";
dtmf_buf[i][ dtmf_buf_count[i] ] = dtmf_chars[dtmf_digit];
dtmf_buf_count[i]++;
if (bool_dtmf_debug)
printf("dtmf_buf[%d] = %s\n", i, dtmf_buf[i]);
}
}
const unsigned char silence[9] = { 0x4e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8 };
// const unsigned char silence[9] = { 0x4e, 0x8d, 0x32, 0x88, 0x26, 0x1a, 0x3f, 0x61, 0xe8 };
const unsigned char silence[9] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 };
memcpy(rptrbuf.vpkt.vasd.voice, silence, 9);
} else
dtmf_counter[i] = 0;

@ -176,7 +176,7 @@ static regex_t preg;
const char* G2_html = "<table border=\"0\" width=\"95%\"><tr>"
"<td width=\"4%\"><img border=\"0\" src=g2ircddb.jpg></td>"
"<td width=\"96%\"><font size=\"2\">"
"<b>REPEATER</b> G2_IRCDDB Gateway v3.09+"
"<b>REPEATER</b> QnetGateway v1.0+"
"</font></td>"
"</tr></table>";

@ -1,383 +0,0 @@
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
*
* 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.
*/
/* by KI4LKF */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#define VERSION "v3.2"
static int sockDst = -1;
static struct sockaddr_in toDst;
static void dst_close();
static bool dst_open(char *ip, int port);
static void calcPFCS(unsigned char rawbytes[58]);
static time_t tNow = 0;
static short streamid_raw = 0;
//static unsigned char silence[12] = { 0x4e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8,0x70,0x4f,0x93 };
static unsigned char silence[12] = { 0xfa,0x87,0x1e,0x32,0x30,0x2f,0xea,0x45,0x66,0x70,0x4f,0x93 };
static unsigned short crc_tabccitt[256] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
static void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++) {
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
return;
}
static bool dst_open(char *ip, int port)
{
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1) {
printf("Failed to create DSTAR socket\n");
return false;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
close(sockDst);
sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return false;
}
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 true;
}
static void dst_close()
{
if (sockDst != -1) {
close(sockDst);
sockDst = -1;
}
return;
}
int main(int argc, char **argv)
{
unsigned char dstar_buf[58];
static unsigned short G2_COUNTER = 0;
unsigned long delay;
char RADIO_ID[21];
short int i;
if (argc != 10) {
printf("Usage: g2link_test <IPaddress> <port> <textMessage> <repeaterCallsign> <module> <delay_between> <delay_before> <MYCALL> <YRCALL>\n");
printf("Example: g2link_test 127.0.0.1 20010 \"HELLO\" KJ4NHF B 20 2 KI4LKF XRF005AL\n");
printf("Where...\n\n");
printf(" 127.0.0.1 is the G2 INTERNAL IP of the G2 gateway\n");
printf(" 20010 is the the G2 INTERNAL port of the G2 gateway\n");
printf(" HELLO is the text message that we will send, no more than 20 characters\n");
printf(" Note: the text message will be converted to UPPERCASE\n");
printf(" KJ4NHF is your dstar repeater callsign\n");
printf(" B is the local repeater module\n");
printf(" 20 millisecond delay before each packet is sent\n");
printf(" 2 second delay before the program starts processing your input \n");
printf(" KI4LKF is the value of mycall\n");
printf(" XRF005AL is the value of yrcall, in this case this is a Link command\n\n");
return 0;
}
if (strlen(argv[4]) > 6) {
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", argv[4]);
return 0;
}
for (i = 0; i < 6; i++)
argv[4][i] = toupper(argv[4][i]);
if (strlen(argv[8]) > 8) {
printf("MYCALL can not be nore than 8 characters, %s is invalid\n", argv[8]);
return 0;
}
for (i = 0; i < 8; i++)
argv[8][i] = toupper(argv[8][i]);
if (strlen(argv[9]) > 8) {
printf("YRCALL can not be nore than 8 characters, %s is invalid\n", argv[9]);
return 0;
}
for (i = 0; i < 8; i++)
argv[9][i] = toupper(argv[9][i]);
if ((argv[5][0] != 'A') && (argv[5][0] != 'B') && (argv[5][0] != 'C')) {
printf("module must be one of A B C\n");
return 0;
}
delay = atol(argv[6]) * 1000L;
sleep(atoi(argv[7]));
memset(RADIO_ID, ' ', 20);
RADIO_ID[20] = '\0';
memcpy(RADIO_ID, argv[3], (strlen(argv[3]) > 20)?20:strlen(argv[3]));
/***
for (i = 0; i < 20; i++)
RADIO_ID[i] = toupper(RADIO_ID[i]);
***/
time(&tNow);
srand(tNow + getpid());
if (dst_open(argv[1], atoi(argv[2]))) {
streamid_raw = (short)(::rand() & 0xFFFF);
memcpy(dstar_buf,"DSTR", 4);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[6] = 0x73;
dstar_buf[7] = 0x12;
dstar_buf[8] = 0x00;
dstar_buf[9] = 0x30;
dstar_buf[10] = 0x20;
dstar_buf[11] = 0x00;
dstar_buf[12] = 0x01;
if (argv[5][0] == 'A')
dstar_buf[13] = 0x03;
else if (argv[5][0] == 'B')
dstar_buf[13] = 0x01;
else if (argv[5][0] == 'C')
dstar_buf[13] = 0x02;
else
dstar_buf[13] = 0x00;
dstar_buf[14] = (unsigned char)(streamid_raw & 0xFF);
dstar_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
dstar_buf[16] = 0x80;
dstar_buf[17] = 0x00;
dstar_buf[18] = 0x00;
dstar_buf[19] = 0x00;
/* RPT2 */
memcpy(dstar_buf + 20, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 20 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[26] = ' ';
dstar_buf[27] = 'G';
/* RPT1 */
memcpy(dstar_buf + 28, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 28 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[34] = ' ';
dstar_buf[35] = argv[5][0];
/* YRCALL */
memcpy(dstar_buf + 36, argv[9], strlen(argv[9]));
if (strlen(argv[9]) < 8)
memset(dstar_buf + 36 + strlen(argv[9]), ' ', 8 - strlen(argv[9]));
/* MYCALL */
memcpy(dstar_buf + 44, argv[8], strlen(argv[8]));
if (strlen(argv[8]) < 8)
memset(dstar_buf + 44 + strlen(argv[8]), ' ', 8 - strlen(argv[8]));
/* suffix */
memcpy(dstar_buf + 52, " ", 4);
calcPFCS(dstar_buf);
(void)sendto(sockDst,(char *)dstar_buf,58,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[9] = 0x13;
memcpy((char *)dstar_buf + 17, silence, 9);
/* start sending silence + text */
/* SYNC */
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x00;
dstar_buf[26] = 0x55;
dstar_buf[27] = 0x2d;
dstar_buf[28] = 0x16;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x01;
dstar_buf[26] = '@' ^ 0x70;
dstar_buf[27] = RADIO_ID[0] ^ 0x4f;
dstar_buf[28] = RADIO_ID[1] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x02;
dstar_buf[26] = RADIO_ID[2] ^ 0x70;
dstar_buf[27] = RADIO_ID[3] ^ 0x4f;
dstar_buf[28] = RADIO_ID[4] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x03;
dstar_buf[26] = 'A' ^ 0x70;
dstar_buf[27] = RADIO_ID[5] ^ 0x4f;
dstar_buf[28] = RADIO_ID[6] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x04;
dstar_buf[26] = RADIO_ID[7] ^ 0x70;
dstar_buf[27] = RADIO_ID[8] ^ 0x4f;
dstar_buf[28] = RADIO_ID[9] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x05;
dstar_buf[26] = 'B' ^ 0x70;
dstar_buf[27] = RADIO_ID[10] ^ 0x4f;
dstar_buf[28] = RADIO_ID[11] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x06;
dstar_buf[26] = RADIO_ID[12] ^ 0x70;
dstar_buf[27] = RADIO_ID[13] ^ 0x4f;
dstar_buf[28] = RADIO_ID[14] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x07;
dstar_buf[26] = 'C' ^ 0x70;
dstar_buf[27] = RADIO_ID[15] ^ 0x4f;
dstar_buf[28] = RADIO_ID[16] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x08;
dstar_buf[26] = RADIO_ID[17] ^ 0x70;
dstar_buf[27] = RADIO_ID[18] ^ 0x4f;
dstar_buf[28] = RADIO_ID[19] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x09 | 0x40;
memset((char *)dstar_buf + 17, '\0', 9);
dstar_buf[26] = 0x70;
dstar_buf[27] = 0x4f;
dstar_buf[28] = 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dst_close();
}
printf("g2link_test exiting...\n");
return 0;
}

@ -0,0 +1,409 @@
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
* Copyright (C) 2018 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 <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <libconfig.h++>
#include <string>
#include "QnetTypeDefs.h"
using namespace libconfig;
#define VERSION "v1.0"
int sockDst = -1;
struct sockaddr_in toDst;
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;
unsigned char silence[9] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 };
unsigned short crc_tabccitt[256] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++) {
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
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 (strcasecmp(type.c_str(), "dvap") && strcasecmp(type.c_str(), "dvrptr") && strcasecmp(type.c_str(), "mmdvm")) {
printf("module type '%s' is invalid\n", type.c_str());
return 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, "127.0.0.1"))
return true;
get_value(cfg, "gateway.internal.port", PORT, 16000, 65535, 19000);
get_value(cfg, "timing.play.wait", PLAY_WAIT, 1, 10, 2);
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++)
if (islower(str[i]))
str[i] = toupper(str[i]);
}
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 xrf757cl\n", argv[0]);
printf("Where...\n");
printf(" c is the local repeater module\n");
printf(" n7tae is the value of mycall\n");
printf(" xrf757cl is the value of yourcall, in this case this is a Link command\n\n");
return 0;
}
std::string cfgfile(CFG_DIR);
cfgfile += "/qn.cfg";
if (read_config(cfgfile.c_str()))
return 1;
if (REPEATER.size() > 6) {
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", REPEATER.c_str());
return 1;
}
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[8]);
return 1;
}
std::string mycall(argv[2]);
ToUpper(mycall);
if (strlen(argv[3]) > 8) {
printf("YOURCALL can not be more than 8 characters, %s is invalid\n", argv[9]);
return 1;
}
std::string yourcall(argv[3]);
ToUpper(yourcall);
unsigned long int delay = PLAY_DELAY * 1000;
sleep(PLAY_WAIT);
std::string RADIO_ID("QnetRemote ");
RADIO_ID.append(VERSION);
RADIO_ID.resize(20, ' ');
time(&tNow);
srand(tNow + getpid());
if (dst_open(IP_ADDRESS.c_str(), PORT))
return 1;
SDSTR pkt;
memcpy(pkt.pkt_id,"DSTR", 4);
pkt.counter = htons(G2_COUNTER);
pkt.flag[0] = 0x73;
pkt.flag[1] = 0x12;
pkt.flag[2] = 0x00;
pkt.remaining = 0x30;
pkt.vpkt.icm_id = 0x20;
pkt.vpkt.dst_rptr_id = 0x00;
pkt.vpkt.snd_rptr_id = 0x01;
if (module == 'A')
pkt.vpkt.snd_term_id = 0x03;
else if (module == 'B')
pkt.vpkt.snd_term_id = 0x01;
else if (module == 'C')
pkt.vpkt.snd_term_id = 0x02;
else
pkt.vpkt.snd_term_id = 0x00;
streamid_raw = (unsigned short)(::rand() & 0xFFFF);
pkt.vpkt.streamid = htons(streamid_raw);
pkt.vpkt.ctrl = 0x80;
pkt.vpkt.hdr.flag[0] = pkt.vpkt.hdr.flag[1] = pkt.vpkt.hdr.flag[2] = 0x00;
REPEATER.resize(7, ' ');
memcpy(pkt.vpkt.hdr.r2, std::string(REPEATER + 'G').c_str(), 8);
memcpy(pkt.vpkt.hdr.r1, std::string(REPEATER + module).c_str(), 8);
mycall.resize(8, ' ');
memcpy(pkt.vpkt.hdr.my, mycall.c_str(), 8);
memcpy(pkt.vpkt.hdr.nm, "QNET", 4);
if (yourcall.size() < 3)
yourcall = std::string(8-yourcall.size(), ' ') + yourcall; // right justify 1 or 2 letter commands
else
yourcall.resize(8, ' ');
memcpy(pkt.vpkt.hdr.ur, yourcall.c_str(), 8);
calcPFCS(pkt.pkt_id);
// send the header
int sent = sendto(sockDst, pkt.pkt_id, 58, 0, (struct sockaddr *)&toDst, sizeof(toDst));
if (sent != 58) {
printf("%s: ERROR: Couldn't send header!\n", argv[0]);
dst_close();
return 1;
}
// prepare and send 10 voice packets
pkt.remaining = 0x13;
memcpy(pkt.vpkt.vasd.voice, silence, 9);
for (int i=0; i<10; i++) {
usleep(delay);
/* start sending silence + text */
pkt.counter = htons(++G2_COUNTER);
pkt.vpkt.ctrl = i;
switch (i) {
case 0: // sync voice frame
pkt.vpkt.vasd.text[0] = 0x55;
pkt.vpkt.vasd.text[1] = 0x2d;
pkt.vpkt.vasd.text[2] = 0x16;
break;
case 1:
pkt.vpkt.vasd.text[0] = '@' ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[0] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[1] ^ 0x93;
break;
case 2:
pkt.vpkt.vasd.text[0] = RADIO_ID[2] ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[3] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[4] ^ 0x93;
break;
case 3:
pkt.vpkt.vasd.text[0] = 'A' ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[5] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[6] ^ 0x93;
break;
case 4:
pkt.vpkt.vasd.text[0] = RADIO_ID[7] ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[8] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[9] ^ 0x93;
break;
case 5:
pkt.vpkt.vasd.text[0] = 'B' ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[10] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[11] ^ 0x93;
break;
case 6:
pkt.vpkt.vasd.text[0] = RADIO_ID[12] ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[13] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[14] ^ 0x93;
break;
case 7:
pkt.vpkt.vasd.text[0] = 'C' ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[15] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[16] ^ 0x93;
break;
case 8:
pkt.vpkt.vasd.text[0] = RADIO_ID[17] ^ 0x70;
pkt.vpkt.vasd.text[1] = RADIO_ID[18] ^ 0x4f;
pkt.vpkt.vasd.text[2] = RADIO_ID[19] ^ 0x93;
break;
case 9: // terminal voice packet
pkt.vpkt.ctrl |= 0x40;
pkt.vpkt.vasd.text[0] = 0x70;
pkt.vpkt.vasd.text[1] = 0x4f;
pkt.vpkt.vasd.text[2] = 0x93;
break;
}
sent = sendto(sockDst,pkt.pkt_id, 29, 0, (struct sockaddr *)&toDst, sizeof(toDst));
if (sent != 29) {
printf("%s: ERROR: could not send voice packet %d\n", argv[0], i);
dst_close();
return 1;
}
}
dst_close();
return 0;
}

@ -13,7 +13,9 @@ git clone git://github.com/n7tae/QnetGateway.git
Then look to the MMDVM.README or the BUILDING file for more information.
For details of interesting things QnetGatway can do, see the CONFIGURING file. For example, with QnetGateway, you can execute up to 36 different Linux scripts from you radio. Two scripts are include:
QnetGateway includes a "remote control" program, called `qnremote`. After you build and install the system, type `qnremote` for a prompt on how to use it. Using this and cron, it's possible to setup schedules where you system will automatically link up to a reflector, or subscribe to a Routing Group. For More information, see DTMF+REMOTE.README.
For other details of interesting things QnetGatway can do, see the CONFIGURING file. For example, with QnetGateway, you can execute up to 36 different Linux scripts from you radio. Two scripts are include:
```
YourCall = " HX" will halt your system.

@ -1,150 +0,0 @@
#!/bin/bash
# This script finds files in the /tmp directory
# The files have a name like x_mod_DTMF_NOTIFY, where x is one of 0 1 2
# 0=A module,
# 1=B module,
# 2=C module
# The contents of these files can be as follows:
# Example: 73 will unlink local module
# Example: #02102 will link local module to XRF021 B
# Example: D00126 will link local module to DCS001 Z
# Example: *01601 will link local module to REF016 A
# Example: 99 will report status of the link
# We set this to spaces, it will be set later
LUSER=" "
# The G2 INTERNAL IP/Port
G2_INT_IP=127.0.0.1
G2_INT_PORT=19000
# This is the callsign of your Gateway, set it correctly
G2=
cd /tmp
echo started at `date`
while [ 1 ]
do
for i in `ls ?_mod_DTMF_NOTIFY 2>/dev/null`
do
echo found file $i at `date`
x=${i:0:1}
if [ "$x" = "0" ] ; then
LOCAL_BAND=A
elif [ "$x" = "1" ] ; then
LOCAL_BAND=B
elif [ "$x" = "2" ] ; then
LOCAL_BAND=C
else
LOCAL_BAND=garbage
fi
if [[ "$LOCAL_BAND" == "garbage" ]]
then
echo garbage value for local band
else
CMD=`head -n 1 $i 2>/dev/null`
LUSER=`tail -n 1 $i 2>/dev/null`
echo "... with these contents: " $CMD " " $LUSER
if [ "$CMD" = "73" ] ; then
echo Unlinking local band $LOCAL_BAND requested by $LUSER
/usr/local/bin/qnlinktest ${G2_INT_IP} ${G2_INT_PORT} "" $G2 ${LOCAL_BAND} 20 1 "$LUSER" " U" >/dev/null 2>&1
echo
elif [ "$CMD" = "99" ] ; then
echo Link Status on local band $LOCAL_BAND requested by $LUSER
/usr/local/bin/qnlinktest ${G2_INT_IP} ${G2_INT_PORT} "" $G2 ${LOCAL_BAND} 20 1 "$LUSER" " I" >/dev/null 2>&1
echo
else
LEN=${#CMD}
if [ "$LEN" = "6" ] ; then
PFX=${CMD:0:1}
REMOTE_NODE=${CMD:1:3}
REMOTE_BAND=${CMD:4:2}
if [ "$REMOTE_BAND" = "01" ] ; then
REMOTE_BAND=A
elif [ "$REMOTE_BAND" = "02" ] ; then
REMOTE_BAND=B
elif [ "$REMOTE_BAND" = "03" ] ; then
REMOTE_BAND=C
elif [ "$REMOTE_BAND" = "04" ] ; then
REMOTE_BAND=D
elif [ "$REMOTE_BAND" = "05" ] ; then
REMOTE_BAND=E
elif [ "$REMOTE_BAND" = "06" ] ; then
REMOTE_BAND=F
elif [ "$REMOTE_BAND" = "07" ] ; then
REMOTE_BAND=G
elif [ "$REMOTE_BAND" = "08" ] ; then
REMOTE_BAND=H
elif [ "$REMOTE_BAND" = "09" ] ; then
REMOTE_BAND=I
elif [ "$REMOTE_BAND" = "10" ] ; then
REMOTE_BAND=J
elif [ "$REMOTE_BAND" = "11" ] ; then
REMOTE_BAND=K
elif [ "$REMOTE_BAND" = "12" ] ; then
REMOTE_BAND=L
elif [ "$REMOTE_BAND" = "13" ] ; then
REMOTE_BAND=M
elif [ "$REMOTE_BAND" = "14" ] ; then
REMOTE_BAND=N
elif [ "$REMOTE_BAND" = "15" ] ; then
REMOTE_BAND=O
elif [ "$REMOTE_BAND" = "16" ] ; then
REMOTE_BAND=P
elif [ "$REMOTE_BAND" = "17" ] ; then
REMOTE_BAND=Q
elif [ "$REMOTE_BAND" = "18" ] ; then
REMOTE_BAND=R
elif [ "$REMOTE_BAND" = "19" ] ; then
REMOTE_BAND=S
elif [ "$REMOTE_BAND" = "20" ] ; then
REMOTE_BAND=T
elif [ "$REMOTE_BAND" = "21" ] ; then
REMOTE_BAND=U
elif [ "$REMOTE_BAND" = "22" ] ; then
REMOTE_BAND=V
elif [ "$REMOTE_BAND" = "23" ] ; then
REMOTE_BAND=W
elif [ "$REMOTE_BAND" = "24" ] ; then
REMOTE_BAND=X
elif [ "$REMOTE_BAND" = "25" ] ; then
REMOTE_BAND=Y
elif [ "$REMOTE_BAND" = "26" ] ; then
REMOTE_BAND=Z
else
REMOTE_BAND=Z
fi
if [ "$PFX" = "#" ] ; then
RMT=XRF
elif [ "$PFX" = "D" ] ; then
RMT=DCS
elif [ "$PFX" = "*" ] ; then
RMT=REF
else
RMT=garbage
fi
if [[ "$RMT" == "garbage" ]]
then
echo garbage value in prefix
else
echo linking local band $LOCAL_BAND to remote node ${RMT}${REMOTE_NODE} $REMOTE_BAND requested by $LUSER
/usr/local/bin/qnlinktest ${G2_INT_IP} ${G2_INT_PORT} "" $G2 ${LOCAL_BAND} 20 1 "$LUSER" ${RMT}${REMOTE_NODE}${REMOTE_BAND}L >/dev/null 2>&1
echo
fi
fi
fi
fi
rm -f $i
done
sleep 3
done
exit 0

@ -0,0 +1,134 @@
#!/bin/bash
# Copyright (C) 2011 by Scott Lawson KI4LKF
# Copyright (C) 2018 by Thomas A. Early N7TAE
#
# This script finds files in the /tmp directory
# The files have a name like x_mod_DTMF_NOTIFY, where x is one of A B or C, the local module
# The contents of these files can be as follows:
# Example: # will unlink local module, " U"
# Example: B75703 will link local module to XRF757 C
# Example: D00617 will link local module to DCS006 Q
# Example: *00103 will link local module to REF001 C
# Example: 0 or 00 will report status of the link, " I"
# We set this to spaces, it will be set later
LUSER=" "
cd /tmp
echo started at `date`
while [[ 1 ]]
do
for i in `ls ?_mod_DTMF_NOTIFY 2>/dev/null`
do
echo found file $i at `date`
LOCAL_BAND=${i:0:1}
if [[ "$LOCAL_BAND" = "A" ]] || [[ "$LOCAL_BAND" = "B" ]] || [[ "$LOCAL_BAND" = "C" ]] ; then
CMD=`head -n 1 $i 2>/dev/null`
LUSER=`tail -n 1 $i 2>/dev/null`
echo "... with these contents: " $CMD " " $LUSER
if [[ "$CMD" = "#" ]] ; then
echo Unlinking local band $LOCAL_BAND requested by $LUSER
qnremote ${LOCAL_BAND} "$LUSER" U >/dev/null 2>&1
echo
elif [[ "$CMD" = "0" ]] || [[ "$CMD" = "00" ]] ; then
echo Link Status on local band $LOCAL_BAND requested by $LUSER
qnremote ${LOCAL_BAND} "$LUSER" I >/dev/null 2>&1
echo
elif [[ "$CMD" = "**" ]] ; then
echo Load Hosts on local band $LOCAL_BAND requested by $LUSER
qnremote ${LOCAL_BAND} "$LUSER" L >/dev/null 2>&1
else
LEN=${#CMD}
if [[ "$LEN" = "6" ]] ; then
PFX=${CMD:0:1}
REMOTE_NODE=${CMD:1:3}
REMOTE_BAND=${CMD:4:2}
if [[ "$REMOTE_BAND" = "01" ]] ; then
REMOTE_BAND=A
elif [[ "$REMOTE_BAND" = "02" ]] ; then
REMOTE_BAND=B
elif [[ "$REMOTE_BAND" = "03" ]] ; then
REMOTE_BAND=C
elif [[ "$REMOTE_BAND" = "04" ]] ; then
REMOTE_BAND=D
elif [[ "$REMOTE_BAND" = "05" ]] ; then
REMOTE_BAND=E
elif [[ "$REMOTE_BAND" = "06" ]] ; then
REMOTE_BAND=F
elif [[ "$REMOTE_BAND" = "07" ]] ; then
REMOTE_BAND=G
elif [[ "$REMOTE_BAND" = "08" ]] ; then
REMOTE_BAND=H
elif [[ "$REMOTE_BAND" = "09" ]] ; then
REMOTE_BAND=I
elif [[ "$REMOTE_BAND" = "10" ]] ; then
REMOTE_BAND=J
elif [[ "$REMOTE_BAND" = "11" ]] ; then
REMOTE_BAND=K
elif [[ "$REMOTE_BAND" = "12" ]] ; then
REMOTE_BAND=L
elif [[ "$REMOTE_BAND" = "13" ]] ; then
REMOTE_BAND=M
elif [[ "$REMOTE_BAND" = "14" ]] ; then
REMOTE_BAND=N
elif [[ "$REMOTE_BAND" = "15" ]] ; then
REMOTE_BAND=O
elif [[ "$REMOTE_BAND" = "16" ]] ; then
REMOTE_BAND=P
elif [[ "$REMOTE_BAND" = "17" ]] ; then
REMOTE_BAND=Q
elif [[ "$REMOTE_BAND" = "18" ]] ; then
REMOTE_BAND=R
elif [[ "$REMOTE_BAND" = "19" ]] ; then
REMOTE_BAND=S
elif [[ "$REMOTE_BAND" = "20" ]] ; then
REMOTE_BAND=T
elif [[ "$REMOTE_BAND" = "21" ]] ; then
REMOTE_BAND=U
elif [[ "$REMOTE_BAND" = "22" ]] ; then
REMOTE_BAND=V
elif [[ "$REMOTE_BAND" = "23" ]] ; then
REMOTE_BAND=W
elif [[ "$REMOTE_BAND" = "24" ]] ; then
REMOTE_BAND=X
elif [[ "$REMOTE_BAND" = "25" ]] ; then
REMOTE_BAND=Y
elif [[ "$REMOTE_BAND" = "26" ]] ; then
REMOTE_BAND=Z
else
REMOTE_BAND=Z
fi
if [[ "$PFX" = "B" ]] ; then
RMT=XRF
elif [[ "$PFX" = "D" ]] ; then
RMT=DCS
elif [[ "$PFX" = "*" ]] ; then
RMT=REF
else
RMT=garbage
fi
if [[ "$RMT" == "garbage" ]] ; then
echo bad value in prefix
else
echo linking local band $LOCAL_BAND to remote node ${RMT}${REMOTE_NODE} $REMOTE_BAND requested by $LUSER
qnremote ${LOCAL_BAND} "$LUSER" ${RMT}${REMOTE_NODE}${REMOTE_BAND}L >/dev/null 2>&1
echo
fi
fi
fi
else
echo "Local band '${LOCAL_BAND}' is bad"
fi
rm -f $i
done
sleep 2
done
exit 0

@ -1,29 +1,14 @@
#/bin/bash
#!/bin/bash
# Get the big list from Ramesh (VA3UV) and extract the DCS, DStar and XReflectors only.
# Put XREF reflectors on port 20001 so they will use DPlus linking!
#
# 73
#
# Tom, n7tae (at) arrl (dot) net
wget ftp://dschost1.w6kd.com/DExtra_Hosts.txt || wget ftp://dschost2.w6kd.com/DExtra_Hosts.txt
wget ftp://dschost1.w6kd.com/DPlus_Hosts.txt || wget ftp://dschost2.w6kd.com/DPlus_Hosts.txt
wget ftp://dschost1.w6kd.com/DCS_Hosts.txt || wget ftp://dschost2.w6kd.com/DCS_Hosts.txt
if [ -e gwys.txt ]; then
mv -f gwys.txt gwys.txt.orig
fi
/bin/rm -f gwys.txt
rm -f gwys.va2uv.txt
wget -nv -O gwys.va3uv.txt http://www.va3uv.com/gwys.txt
if [ -e gwys.va3uv.txt ]; then
echo "# from www.va3uv.com on `date`" > gwys.txt
echo "Got `awk '$1~/^REF/{print $1, $2, $3}' gwys.va3uv.txt | tee -a gwys.txt | wc -l` REF reflectors"
echo "Got `awk '$1~/^XRF/{print $1, $2, $3}' gwys.va3uv.txt | tee -a gwys.txt | wc -l` XRF reflectors"
echo "Got `awk '$1~/^DCS/{print $1, $2, $3}' gwys.va3uv.txt | tee -a gwys.txt | wc -l` DCS reflectors"
else
echo "Could not get gateways list from www.va3uv.com!"
if [ -e gwys.txt.orig ]; then
mv -f gwys.txt.orig gwys.txt
fi
fi
echo "# Downloaded from dschost1.w6kd.com `date`" > gwys.txt
awk '$1 ~ /^REF/ { printf "%s %s 20001\n", $1, $2 }' DPlus_Hosts.txt >> gwys.txt
awk '$1 ~ /^XRF/ { printf "%s %s 30001\n", $1, $2 }' DExtra_Hosts.txt >> gwys.txt
awk '$1 ~ /^DCS/ { printf "%s %s 30051\n", $1, $2 }' DCS_Hosts.txt >> gwys.txt
/bin/rm -f D{Extra,Plus,DSC}_Hosts.txt

@ -1,10 +1,11 @@
[Unit]
Description=QnetDTMFS
Description=QnetDTMF
After=systemd-user-session.service
[Service]
Type=simple
ExecStart=/usr/local/bin/proc_qnlinktest
ExecStart=/usr/local/bin/qndtmf
Restart=always
[Install]
WantedBy=multi-user.target

@ -1,5 +1,5 @@
// version strings must be 55 characters or less!
#define IRCDDB_VERSION "linux-qngateway-6.0.1"
#define IRCDDB_VERSION "linux-qngateway-6.1.0"
#define LINK_VERSION "5.1.2"
#define DVAP_VERSION "linux-qndvap-5.1.1"
#define DVRPTR_VERSION "linux-qndvrptr-5.1.0"

Loading…
Cancel
Save

Powered by TurnKey Linux.