From f9753ec74797c9b21789df39cb39e0ef165580ca Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 23 Apr 2018 11:52:58 -0700 Subject: [PATCH 01/15] reworked remote control --- .gitignore | 2 +- Makefile | 37 +- QnetLinkTest.cpp | 383 ---------------- QnetRemote.cpp | 409 ++++++++++++++++++ proc_qnlinktest => qndtmf.sh | 0 system/{qnlinktest.service => qndtmf.service} | 4 +- 6 files changed, 432 insertions(+), 403 deletions(-) delete mode 100644 QnetLinkTest.cpp create mode 100644 QnetRemote.cpp rename proc_qnlinktest => qndtmf.sh (100%) rename system/{qnlinktest.service => qndtmf.service} (62%) diff --git a/.gitignore b/.gitignore index 9247c19..371a509 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,6 @@ qndvap qndvrptr qnlink qngateway -qnlinktest +qnremote qnlinktestaudio qnrelay diff --git a/Makefile b/Makefile index 8931a45..7148aaa 100644 --- a/Makefile +++ b/Makefile @@ -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 : QnetDTMF + /bin/cp -f QnetDTMF $(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 @@ -254,10 +259,8 @@ uninstalldvrptr : 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 + systemctl stop qndtmf.service + systemctl disable qndtmf.service + /bin/rm -f $(SYSDIR)/qndtmf.service systemctl daemon-reload + /bin/rm -f $(BINDIR)/qndtmf diff --git a/QnetLinkTest.cpp b/QnetLinkTest.cpp deleted file mode 100644 index f875113..0000000 --- a/QnetLinkTest.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#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 \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; -} diff --git a/QnetRemote.cpp b/QnetRemote.cpp new file mode 100644 index 0000000..988afa6 --- /dev/null +++ b/QnetRemote.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 (lmax) { + 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 \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 = (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); + 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); + memcpy(pkt.vpkt.hdr.nm, "QNET", 4); + + 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; +} diff --git a/proc_qnlinktest b/qndtmf.sh similarity index 100% rename from proc_qnlinktest rename to qndtmf.sh diff --git a/system/qnlinktest.service b/system/qndtmf.service similarity index 62% rename from system/qnlinktest.service rename to system/qndtmf.service index 2e3d890..9998d55 100644 --- a/system/qnlinktest.service +++ b/system/qndtmf.service @@ -1,10 +1,10 @@ [Unit] -Description=QnetDTMFS +Description=QnetDTMF After=systemd-user-session.service [Service] Type=simple -ExecStart=/usr/local/bin/proc_qnlinktest +ExecStart=/usr/local/bin/qndtmf [Install] WantedBy=multi-user.target From 344f67d7524a945294b75cc84bdea858344b7bfa Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 23 Apr 2018 13:37:25 -0700 Subject: [PATCH 02/15] debug printfs --- QnetRemote.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/QnetRemote.cpp b/QnetRemote.cpp index 988afa6..159afbf 100644 --- a/QnetRemote.cpp +++ b/QnetRemote.cpp @@ -306,22 +306,27 @@ int main(int argc, char *argv[]) pkt.vpkt.snd_term_id = 0x02; else pkt.vpkt.snd_term_id = 0x00; - streamid_raw = (short)(::rand() & 0xFFFF); + 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); + std::string gateway(REPEATER + 'G'); + printf("gateway = '%s'\n", gateway.c_str()); + memcpy(pkt.vpkt.hdr.r2, gateway.c_str(), 8); + std::string repeater(REPEATER + module); + printf("module = '%s'\n", repeater.c_str()); + memcpy(pkt.vpkt.hdr.r1, repeater.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); - memcpy(pkt.vpkt.hdr.nm, "QNET", 4); + printf("header dump: '%.36s'\n", pkt.vpkt.hdr.r2); calcPFCS(pkt.pkt_id); // send the header From 151406304a3dc3dde9baf60d509fd31f449344d6 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 23 Apr 2018 14:00:40 -0700 Subject: [PATCH 03/15] resize() syntax error! --- QnetRemote.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/QnetRemote.cpp b/QnetRemote.cpp index 159afbf..37a99e1 100644 --- a/QnetRemote.cpp +++ b/QnetRemote.cpp @@ -280,7 +280,7 @@ int main(int argc, char *argv[]) std::string RADIO_ID("QnetRemote "); RADIO_ID.append(VERSION); - RADIO_ID.resize(' ', 20); + RADIO_ID.resize(20, ' '); time(&tNow); srand(tNow + getpid()); @@ -311,20 +311,20 @@ int main(int argc, char *argv[]) pkt.vpkt.ctrl = 0x80; pkt.vpkt.hdr.flag[0] = pkt.vpkt.hdr.flag[1] = pkt.vpkt.hdr.flag[2] = 0x00; - REPEATER.resize(' ', 7); + REPEATER.resize(7, ' '); std::string gateway(REPEATER + 'G'); printf("gateway = '%s'\n", gateway.c_str()); memcpy(pkt.vpkt.hdr.r2, gateway.c_str(), 8); std::string repeater(REPEATER + module); printf("module = '%s'\n", repeater.c_str()); memcpy(pkt.vpkt.hdr.r1, repeater.c_str(), 8); - mycall.resize(' ', 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); + yourcall.resize(8, ' '); memcpy(pkt.vpkt.hdr.ur, yourcall.c_str(), 8); printf("header dump: '%.36s'\n", pkt.vpkt.hdr.r2); From 7742ead6d9efa76128c3fb2acab867629c59e202 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 23 Apr 2018 14:13:08 -0700 Subject: [PATCH 04/15] got it! cleanup --- QnetRemote.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/QnetRemote.cpp b/QnetRemote.cpp index 37a99e1..f8e4455 100644 --- a/QnetRemote.cpp +++ b/QnetRemote.cpp @@ -312,12 +312,8 @@ int main(int argc, char *argv[]) pkt.vpkt.hdr.flag[0] = pkt.vpkt.hdr.flag[1] = pkt.vpkt.hdr.flag[2] = 0x00; REPEATER.resize(7, ' '); - std::string gateway(REPEATER + 'G'); - printf("gateway = '%s'\n", gateway.c_str()); - memcpy(pkt.vpkt.hdr.r2, gateway.c_str(), 8); - std::string repeater(REPEATER + module); - printf("module = '%s'\n", repeater.c_str()); - memcpy(pkt.vpkt.hdr.r1, repeater.c_str(), 8); + 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); @@ -326,7 +322,6 @@ int main(int argc, char *argv[]) else yourcall.resize(8, ' '); memcpy(pkt.vpkt.hdr.ur, yourcall.c_str(), 8); - printf("header dump: '%.36s'\n", pkt.vpkt.hdr.r2); calcPFCS(pkt.pkt_id); // send the header From c7f758d7ead99357c8c98e26eae2e18e11ac7483 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 23 Apr 2018 16:09:40 -0700 Subject: [PATCH 05/15] DTMF --- DTMF+REMOTE.README | 54 +++++++++++++++++++++++++++++++++++++++++++ Makefile | 6 ++--- README.md | 4 +++- qndtmf.sh | 26 +++++++++------------ system/qndtmf.service | 1 + 5 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 DTMF+REMOTE.README diff --git a/DTMF+REMOTE.README b/DTMF+REMOTE.README new file mode 100644 index 0000000..24c9a7a --- /dev/null +++ b/DTMF+REMOTE.README @@ -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 +"#75703" would 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 +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". + diff --git a/Makefile b/Makefile index 7148aaa..f4d6c29 100644 --- a/Makefile +++ b/Makefile @@ -146,8 +146,8 @@ installdvrptr : qngateway qnlink qndvrptr systemctl daemon-reload systemctl start qndvrptr.service -installdtmf : QnetDTMF - /bin/cp -f QnetDTMF $(BINDIR) +installdtmf : qndtmf + /bin/cp -f qndtmf $(BINDIR) /bin/cp -f system/qndtmf.service $(SYSDIR) systemctl enable qndtmf.service systemctl daemon-reload @@ -258,7 +258,7 @@ uninstalldvrptr : /bin/rm -f $(BINDIR)/qndvrptr systemctl daemon-reload -uninstalldtmfs: +uninstalldtmfs : systemctl stop qndtmf.service systemctl disable qndtmf.service /bin/rm -f $(SYSDIR)/qndtmf.service diff --git a/README.md b/README.md index 3226118..c479291 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/qndtmf.sh b/qndtmf.sh index 9cd31c7..64932b9 100755 --- a/qndtmf.sh +++ b/qndtmf.sh @@ -1,28 +1,24 @@ #!/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 0 1 2 -# 0=A module, -# 1=B module, +# 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: #75703 will link local module to XRF757 C +# Example: D00617 will link local module to DCS006 Q +# Example: *00101 will link local module to REF001 C # 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` @@ -51,11 +47,11 @@ do 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 + qnremote ${LOCAL_BAND} "$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 + qnremote ${LOCAL_BAND} "$LUSER" I >/dev/null 2>&1 echo else LEN=${#CMD} @@ -135,7 +131,7 @@ do 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 + qnremote ${LOCAL_BAND} "$LUSER" ${RMT}${REMOTE_NODE}${REMOTE_BAND}L >/dev/null 2>&1 echo fi fi diff --git a/system/qndtmf.service b/system/qndtmf.service index 9998d55..3d5dbbb 100644 --- a/system/qndtmf.service +++ b/system/qndtmf.service @@ -5,6 +5,7 @@ After=systemd-user-session.service [Service] Type=simple ExecStart=/usr/local/bin/qndtmf +Restart=always [Install] WantedBy=multi-user.target From e9ea455772235e493bd3e7e21449dc28a64410c4 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 10:13:24 -0700 Subject: [PATCH 06/15] more dtmf debug output --- MMDVM.README | 2 +- QnetGateway.cpp | 8 ++++++-- QnetLink.cpp | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/MMDVM.README b/MMDVM.README index b1221a7..f9718c2 100644 --- a/MMDVM.README +++ b/MMDVM.README @@ -21,7 +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: cat /cpu/info | 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 diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 9487057..8416724 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -1552,7 +1552,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) @@ -1560,6 +1560,9 @@ void CQnetGateway::process() band_txt[i].num_bit_errors += ber_errs; band_txt[i].num_dv_frames++; + if (bool_dtmf_debug) + printf("ber_data = %X %X %X, ber_data[0] & 0xffc = %X\n", + ber_data[0], ber_data[1], ber_data[2], ber_data[0] & 0xffc); if ((ber_data[0] & 0x0ffc) == 0xfc0) { dtmf_digit = (ber_data[0] & 0x03) | ((ber_data[2] & 0x60) >> 3); if (dtmf_counter[i] > 0) { @@ -1576,7 +1579,8 @@ void CQnetGateway::process() dtmf_buf_count[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; diff --git a/QnetLink.cpp b/QnetLink.cpp index 241c14c..660e4cd 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -176,7 +176,7 @@ static regex_t preg; const char* G2_html = "" "" "" "
" - "REPEATER G2_IRCDDB Gateway v3.09+" + "REPEATER QnetGateway v1.0+" "
"; @@ -2901,7 +2901,7 @@ static void runit() dcs_buf[59] = (ref_2_dcs[i].dcs_rptr_seq >> 8) & 0xff; dcs_buf[60] = (ref_2_dcs[i].dcs_rptr_seq >> 16) & 0xff; - ref_2_dcs[i].dcs_rptr_seq ++; + ref_2_dcs[i].dcs_rptr_seq++; dcs_buf[61] = 0x01; dcs_buf[62] = 0x00; From 6d2d45329905167aa47f011a8712a1d218880b9a Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 10:14:53 -0700 Subject: [PATCH 07/15] Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f4d6c29..8f2b2d0 100644 --- a/Makefile +++ b/Makefile @@ -258,7 +258,7 @@ uninstalldvrptr : /bin/rm -f $(BINDIR)/qndvrptr systemctl daemon-reload -uninstalldtmfs : +uninstalldtmf : systemctl stop qndtmf.service systemctl disable qndtmf.service /bin/rm -f $(SYSDIR)/qndtmf.service From 5d0000efd22ab6eac518bd08d02c0ee5cdd813c2 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 10:45:38 -0700 Subject: [PATCH 08/15] different dtmf logs --- QnetGateway.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 8416724..a0384b1 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -1560,9 +1560,6 @@ void CQnetGateway::process() band_txt[i].num_bit_errors += ber_errs; band_txt[i].num_dv_frames++; - if (bool_dtmf_debug) - printf("ber_data = %X %X %X, ber_data[0] & 0xffc = %X\n", - ber_data[0], ber_data[1], ber_data[2], ber_data[0] & 0xffc); if ((ber_data[0] & 0x0ffc) == 0xfc0) { dtmf_digit = (ber_data[0] & 0x03) | ((ber_data[2] & 0x60) >> 3); if (dtmf_counter[i] > 0) { @@ -1570,13 +1567,17 @@ void CQnetGateway::process() dtmf_counter[i] = 0; } dtmf_last_frame[i] = dtmf_digit; - dtmf_counter[i] ++; + dtmf_counter[i]++; + if (bool_dtmf_debug) + printf("got a dtmf digit = %d and counter is %d\n", dtmf_digit, dtmf_counter[i]); if ((dtmf_counter[i] == 5) && (dtmf_digit >= 0) && (dtmf_digit <= 15)) { if (dtmf_buf_count[i] < MAX_DTMF_BUF) { const char *dtmf_chars = "147*2580369#ABCD"; dtmf_buf[i][ dtmf_buf_count[i] ] = dtmf_chars[dtmf_digit]; - dtmf_buf_count[i] ++; + 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 }; From de4d229d7224c38963681d40a3bdd1343713fa7c Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 11:03:30 -0700 Subject: [PATCH 09/15] different dtmf logs --- QnetGateway.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/QnetGateway.cpp b/QnetGateway.cpp index a0384b1..d010a32 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -1563,13 +1563,14 @@ 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; } dtmf_last_frame[i] = dtmf_digit; dtmf_counter[i]++; - if (bool_dtmf_debug) - printf("got a dtmf digit = %d and counter is %d\n", dtmf_digit, dtmf_counter[i]); if ((dtmf_counter[i] == 5) && (dtmf_digit >= 0) && (dtmf_digit <= 15)) { if (dtmf_buf_count[i] < MAX_DTMF_BUF) { From 6525cccde5127bd27a0d06fee0eadec3e5c9b81f Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 11:13:20 -0700 Subject: [PATCH 10/15] different dtmf logs --- QnetGateway.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/QnetGateway.cpp b/QnetGateway.cpp index d010a32..25f03e3 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -1006,6 +1006,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 +1517,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; From acdcef542e1a5492254cdfd712593566fcd2c62b Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 11:23:35 -0700 Subject: [PATCH 11/15] moved dtmf declarations --- QnetGateway.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/QnetGateway.cpp b/QnetGateway.cpp index 25f03e3..e6d738c 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -623,6 +623,12 @@ void CQnetGateway::process() std::future 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) From cb36c9eda22f1270ddcc882b9e9f7780d566fa45 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 17:31:05 -0700 Subject: [PATCH 12/15] new qndtmf.sh and reflist.sh --- qndtmf.sh | 232 +++++++++++++++++++++++++---------------------------- reflist.sh | 35 +++----- 2 files changed, 120 insertions(+), 147 deletions(-) diff --git a/qndtmf.sh b/qndtmf.sh index 64932b9..cce2194 100755 --- a/qndtmf.sh +++ b/qndtmf.sh @@ -4,17 +4,14 @@ # 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 0 1 2 -# 0=A module, -# 1=B module, -# 2=C module +# 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: 73 will unlink local module -# Example: #75703 will link local module to XRF757 C +# Example: # will unlink local module +# Example: B75703 will link local module to XRF757 C # Example: D00617 will link local module to DCS006 Q -# Example: *00101 will link local module to REF001 C -# Example: 99 will report status of the link +# Example: *00103 will link local module to REF001 C +# Example: 0 or 00 will report status of the link # We set this to spaces, it will be set later LUSER=" " @@ -22,124 +19,115 @@ LUSER=" " cd /tmp echo started at `date` -while [ 1 ] +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 + for i in `ls ?_mod_DTMF_NOTIFY 2>/dev/null` + do + echo found file $i at `date` + LOCAL_BAND=${i:0:1} + if [[ "$x" != "A" ]] & [[ "$x" != "B" ]] && [[ "$x" != "C" ]] ; 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" = "#" ]] ; 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 [[ "$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 - qnremote ${LOCAL_BAND} "$LUSER" U >/dev/null 2>&1 - echo - elif [ "$CMD" = "99" ] ; then - echo Link Status on local band $LOCAL_BAND requested by $LUSER - qnremote ${LOCAL_BAND} "$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 [ "$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 [ "$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 - qnremote ${LOCAL_BAND} "$LUSER" ${RMT}${REMOTE_NODE}${REMOTE_BAND}L >/dev/null 2>&1 - echo - fi - fi - fi - fi - rm -f $i - done - sleep 3 + 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 + qnremote ${LOCAL_BAND} "$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 diff --git a/reflist.sh b/reflist.sh index 65946f8..aa50572 100755 --- a/reflist.sh +++ b/reflist.sh @@ -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 From d51d3e4e7ea23fce16b281cf145293ecb93aeafd Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 17:52:14 -0700 Subject: [PATCH 13/15] fixes to qndtmf.sh --- qndtmf.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qndtmf.sh b/qndtmf.sh index cce2194..a125d24 100755 --- a/qndtmf.sh +++ b/qndtmf.sh @@ -25,9 +25,7 @@ do do echo found file $i at `date` LOCAL_BAND=${i:0:1} - if [[ "$x" != "A" ]] & [[ "$x" != "B" ]] && [[ "$x" != "C" ]] ; then - echo garbage value for local band - else + 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 @@ -116,7 +114,7 @@ do fi if [[ "$RMT" == "garbage" ]] ; then - echo garbage value in prefix + 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 @@ -124,6 +122,8 @@ do fi fi fi + else + echo "Local band '${LOCAL_BAND}' is bad" fi rm -f $i done From b69e877e3d1a905f26510344a588007379e56ce9 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 17:54:05 -0700 Subject: [PATCH 14/15] fixes to qndtmf.sh --- qndtmf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qndtmf.sh b/qndtmf.sh index a125d24..3200d4e 100755 --- a/qndtmf.sh +++ b/qndtmf.sh @@ -25,7 +25,7 @@ do do echo found file $i at `date` LOCAL_BAND=${i:0:1} - if [[ "$LOCAL_BAND" = "A" ]] & [[ "$LOCAL_BAND" = "B" ]] && [[ "$LOCAL_BAND" = "C" ]] ; then + 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 From ef2939b52262193d4eb8b6eeb9196d7b86b88fda Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 24 Apr 2018 18:57:50 -0700 Subject: [PATCH 15/15] DTMF enabled! --- DTMF+REMOTE.README | 4 ++-- MMDVM.README | 8 +++++++- qndtmf.sh | 6 +++--- versions.h | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/DTMF+REMOTE.README b/DTMF+REMOTE.README index 24c9a7a..3b27b49 100644 --- a/DTMF+REMOTE.README +++ b/DTMF+REMOTE.README @@ -2,7 +2,7 @@ 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 -"#75703" would link you to XRF757 C. +"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 @@ -18,7 +18,7 @@ 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 ######### 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: diff --git a/MMDVM.README b/MMDVM.README index f9718c2..cf434a1 100644 --- a/MMDVM.README +++ b/MMDVM.README @@ -87,4 +87,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... diff --git a/qndtmf.sh b/qndtmf.sh index 3200d4e..129ddfe 100755 --- a/qndtmf.sh +++ b/qndtmf.sh @@ -7,11 +7,11 @@ # 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 +# 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 +# Example: 0 or 00 will report status of the link, " I" # We set this to spaces, it will be set later LUSER=" " @@ -127,7 +127,7 @@ do fi rm -f $i done - sleep 3 + sleep 2 done exit 0 diff --git a/versions.h b/versions.h index e0fb391..9f9f84d 100644 --- a/versions.h +++ b/versions.h @@ -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"