From c4d3aacccbe1097c8cc06f74a1c5f0563de42a6d Mon Sep 17 00:00:00 2001 From: Tom Early Date: Wed, 10 Oct 2018 15:29:13 -0700 Subject: [PATCH] reworked audio_notify and AudioNotifyThread --- QnetGateway.h | 9 -- QnetLink.cpp | 285 ++++++++++++++------------------- QnetLink.h | 4 +- QnetTypeDefs.h | 9 ++ announce/already_linked.dat | Bin 3287 -> 1152 bytes announce/already_unlinked.dat | Bin 3519 -> 1368 bytes announce/connected2network.dat | Bin 0 -> 876 bytes announce/failed_link.dat | Bin 0 -> 996 bytes announce/failed_linked.dat | Bin 3229 -> 0 bytes announce/id.dat | Bin 2997 -> 744 bytes announce/linked.dat | Bin 2707 -> 960 bytes announce/notincache.dat | Bin 0 -> 1728 bytes announce/unlinked.dat | Bin 2997 -> 1080 bytes 13 files changed, 131 insertions(+), 176 deletions(-) create mode 100644 announce/connected2network.dat create mode 100644 announce/failed_link.dat delete mode 100644 announce/failed_linked.dat create mode 100644 announce/notincache.dat diff --git a/QnetGateway.h b/QnetGateway.h index 4cc4d52..757a92c 100644 --- a/QnetGateway.h +++ b/QnetGateway.h @@ -28,15 +28,6 @@ using namespace libconfig; #define CALL_SIZE 8 #define MAX_DTMF_BUF 32 -typedef struct echo_tag { - time_t last_time; - unsigned short streamid; - int fd; - char message[24]; - SDSVT header; - char file[FILENAME_MAX + 1]; -} SECHO; - typedef struct to_remote_g2_tag { unsigned short streamid; struct sockaddr_in toDst4; diff --git a/QnetLink.cpp b/QnetLink.cpp index a0689de..6cd1d04 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -164,7 +164,6 @@ void CQnetLink::RptrAckThread(char *arg) char from_mod = arg[0]; char RADIO_ID[21]; memcpy(RADIO_ID, arg + 1, 21); - time_t tnow = 0; unsigned char silence[12] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xf5 }; struct sigaction act; @@ -180,8 +179,6 @@ void CQnetLink::RptrAckThread(char *arg) return; } - time(&tnow); - short int streamid_raw = Random.NewStreamID(); sleep(delay_before); @@ -1348,7 +1345,7 @@ void CQnetLink::Process() } else if (0==memcmp(buf + 10, "NAK", 3) && to_remote_g2[i].from_mod==buf[8]) { printf("Link module %c to [%s] %c is rejected\n", to_remote_g2[i].from_mod, to_remote_g2[i].to_call, to_remote_g2[i].to_mod); - sprintf(notify_msg, "%c_failed_linked.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); + sprintf(notify_msg, "%c_failed_link.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); audio_notify(notify_msg); to_remote_g2[i].to_call[0] = '\0'; @@ -2214,7 +2211,7 @@ void CQnetLink::Process() } else if (buf[4]==70 && buf[5]==65 && buf[6]==73 && buf[7]==76) { printf("Login failed to call %s mod %c\n", to_remote_g2[i].to_call, to_remote_g2[i].to_mod); - sprintf(notify_msg, "%c_failed_linked.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); + sprintf(notify_msg, "%c_failed_link.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); audio_notify(notify_msg); to_remote_g2[i].to_call[0] = '\0'; @@ -2226,7 +2223,7 @@ void CQnetLink::Process() } else if (buf[4]==66 && buf[5]==85 && buf[6]==83 && buf[7]==89) { printf("Busy or unknown status from call %s mod %c\n", to_remote_g2[i].to_call, to_remote_g2[i].to_mod); - sprintf(notify_msg, "%c_failed_linked.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); + sprintf(notify_msg, "%c_failed_link.dat_FAILED_TO_LINK", to_remote_g2[i].from_mod); audio_notify(notify_msg); to_remote_g2[i].to_call[0] = '\0'; @@ -2818,7 +2815,7 @@ void CQnetLink::Process() to_remote_g2[i].from_mod, to_remote_g2[i].to_call, to_remote_g2[i].to_mod); - sprintf(notify_msg, "%c_failed_linked.dat_UNLINKED", + sprintf(notify_msg, "%c_failed_link.dat_UNLINKED", to_remote_g2[i].from_mod); audio_notify(notify_msg); @@ -3360,8 +3357,7 @@ void CQnetLink::audio_notify(char *msg) if (!announce) return; - short int i = 0; - static char notify_msg[3][64]; + short int i = -1; if (*msg == 'A') i = 0; @@ -3370,202 +3366,161 @@ void CQnetLink::audio_notify(char *msg) else if (*msg == 'C') i = 2; - strcpy(notify_msg[i], msg); + if (i < 0) { + fprintf(stderr, "Improper module in msg '%s'\n", msg); + return; + } + + SECHO edata; + char *p = strstr(msg, ".dat"); + if (NULL == p) { + fprintf(stderr, "Improper AMBE data file in msg '%s'\n", msg); + return; + } + if ('_' == p[4]) { + std::string message(p+5); + message.resize(20, ' '); + strcpy(edata.message, message.c_str()); + for (int i=0; i<20; i++) { + if ('_' == edata.message[i]) + edata.message[i] = ' '; + } + } else { + strcpy(edata.message, "QnetGateway Message "); + } + p[4] = '\0'; + snprintf(edata.file, FILENAME_MAX, "%s/%s", announce_dir.c_str(), msg+2); + + memcpy(edata.header.title, "DSVT", 4); + edata.header.config = 0x10U; + edata.header.flaga[0] = edata.header.flaga[1] = edata.header.flaga[2] = 0x0U; + edata.header.id = 0x20; + edata.header.streamid = Random.NewStreamID(); + edata.header.ctrl = 0x80U; + edata.header.hdr.flag[0] = edata.header.hdr.flag[1] = edata.header.hdr.flag[2] = 0x0U; + memcpy(edata.header.hdr.rpt1, owner.c_str(), CALL_SIZE); + edata.header.hdr.rpt1[7] = msg[0]; + memcpy(edata.header.hdr.rpt2, owner.c_str(), CALL_SIZE); + edata.header.hdr.rpt2[7] = 'G'; + memcpy(edata.header.hdr.urcall, "CQCQCQ ", CALL_SIZE); + memcpy(edata.header.hdr.mycall, owner.c_str(), CALL_SIZE); + memcpy(edata.header.hdr.sfx, "RPTR", 4); + calcPFCS(edata.header.title, 56); + try { - std::async(std::launch::async, &CQnetLink::AudioNotifyThread, this, notify_msg[i]); + std::async(std::launch::async, &CQnetLink::AudioNotifyThread, this, std::ref(edata)); } catch (const std::exception &e) { printf ("Failed to start AudioNotifyThread(). Exception: %s\n", e.what()); } return; } -void CQnetLink::AudioNotifyThread(char *arg) +void CQnetLink::AudioNotifyThread(SECHO &edata) { - char notify_msg[64]; - - strcpy(notify_msg, (char *)arg); - - unsigned short rlen = 0; - size_t nread = 0; - bool useTEXT = false; - short int TEXT_idx = 0; - char RADIO_ID[21]; - char temp_file[FILENAME_MAX + 1]; - FILE *fp = NULL; - char mod; - char *p = NULL; - u_int16_t streamid_raw = 0; - time_t tnow = 0; struct sigaction act; - - /* example: A_linked.dat_LINKED_TO_XRF005_A */ - /* example: A_unlinked.dat */ - /* example: A_failed_linked.dat */ - act.sa_handler = sigCatch; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; if (sigaction(SIGTERM, &act, 0) != 0) { - printf("sigaction-TERM failed, error=%d\n", errno); + fprintf(stderr, "sigaction-TERM failed, error=%d\n", errno); return; } if (sigaction(SIGINT, &act, 0) != 0) { - printf("sigaction-INT failed, error=%d\n", errno); + fprintf(stderr, "sigaction-INT failed, error=%d\n", errno); return; } - memset(RADIO_ID, ' ', 20); - RADIO_ID[20] = '\0'; - - mod = notify_msg[0]; + char mod = edata.header.hdr.rpt1[7]; if ((mod != 'A') && (mod != 'B') && (mod != 'C')) { - printf("Invalid module %c in %s\n", mod, notify_msg); - return; - } - - p = strstr(notify_msg, ".dat"); - if (!p) { - printf("Incorrect filename in %s\n", notify_msg); + fprintf(stderr, "Invalid module %c in %s\n", mod, edata.file); return; } - if (p[4] == '_') { - useTEXT = true; - memcpy(RADIO_ID, p + 5, (strlen(p + 5) > 20)?20:strlen(p + 5)); - for (TEXT_idx = 0; TEXT_idx < 20; TEXT_idx++) { - RADIO_ID[TEXT_idx] = toupper(RADIO_ID[TEXT_idx]); - if (RADIO_ID[TEXT_idx] == '_') - RADIO_ID[TEXT_idx] = ' '; - } - TEXT_idx = 0; - p[4] = '\0'; - } else - useTEXT = false; - sleep(delay_before); - memset(temp_file, '\0', sizeof(temp_file)); - snprintf(temp_file, FILENAME_MAX, "%s/%s", announce_dir.c_str(), notify_msg + 2); - printf("sending File:[%s], mod:[%c], RADIO_ID=[%s]\n", temp_file, mod, RADIO_ID); + printf("sending File:[%s], mod:[%c], RADIO_ID=[%s]\n", edata.file, mod, edata.message); - fp = fopen(temp_file, "rb"); - if (!fp) { - printf("Failed to open file %s for reading\n", temp_file); + struct stat sbuf; + if (stat(edata.file, &sbuf)) { + fprintf(stderr, "can't stat %s\n", edata.file); return; } - /* stupid DVTOOL + 4 byte num_of_records */ - unsigned char dstar_buf[10]; - nread = fread(dstar_buf, 10, 1, fp); - if (nread != 1) { - printf("Cant read first 10 bytes from %s\n", temp_file); - fclose(fp); - return; - } - if (memcmp(dstar_buf, "DVTOOL", 6) != 0) { - printf("DVTOOL keyword not found in %s\n", temp_file); - fclose(fp); + if (sbuf.st_size % 9) + printf("Warning %s file size is %ld (not a multiple of 9)!\n", edata.file, sbuf.st_size); + int ambeblocks = (int)sbuf.st_size / 9; + + + FILE *fp = fopen(edata.file, "rb"); + if (!fp) { + fprintf(stderr, "Failed to open file %s for reading\n", edata.file); return; } - time(&tnow); + sendto(rptr_sock, edata.header.title, 56, 0, (struct sockaddr *)&toLocalg2, sizeof(struct sockaddr_in)); - while (keep_running) { - /* 2 byte length */ - nread = fread(&rlen, 2, 1, fp); - if (nread != 1) - break; + edata.header.config = 0x20U; - if (rlen == 56) - streamid_raw = Random.NewStreamID(); - else if (rlen == 27) - ; - else { - printf("Not 56-byte and not 27-byte in %s\n", temp_file); - break; - } + for (int i=0; i2^O_|& zGrX)#&FPeFm>bjD@@J)vIV-fU#$`^e7sAL0=J8 z1K9~tx~attc%NC+L%d(BmTg*T0IP}54X%v@+6=f%Qapd{u09cEDOajxFW7Q|CHM|^ zP(yu#IUg zJ3u-Ej+lw9xbY>JV{S?v;v&Fp3e?g)cI9`yHafQ%*mC%u0wWa zU5jCx&*B7nmw5Mtc_>|PtOd{W412fliwHnFebp}xaT@;V3k+<&oH>lSfBa({n4vj! zG3c;eofK^H67;kQg?lvM=t8frL>Fq?(0&h!nqQQ-?MXwC+^OH#G0 zh*b@KP`LWi=^d4S7P#x9jx?P}Q-yM+d$#V^-OOj_gN<7h)y_}nwg!S{o21#KHte_vnwbJGvtlnB#;Iq7VZ5VEJ! znCoc)2|EU$J}B^unV;oTOdP<85lJ z=#;3?J)aTG@d-U+znZ{Uid8RW>#>4va=CA(vy#JAqn$>dWrpRFPRtd9jjzX&f`oj# zaWLglo`6|%7>DlJ*ob9|%)tqs;QlYMCFMa!n`hvzsqQtYHFano*p$-pN^{d{69GKP z!I9U5WWNu;9$qiPV$F~L|@20f{W)I zb!L~?Kpl5C)uKpw%nkk5yIuw{RG&;}(VbLr_djsMX{Bf;7b-)@k>~&3H3jw`%;*l+ ziHgu|e0V3ZkS#TA_5fS9#E)!@jijc6mnf9>-jUmf(B36@e*3LaZ*?#@vuAg^mOr7w GgZ~3_Gf)Zu literal 3287 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 diff --git a/announce/connected2network.dat b/announce/connected2network.dat new file mode 100644 index 0000000000000000000000000000000000000000..74277cd1331f4be482502e634c4a985796f82293 GIT binary patch literal 876 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 Tqq=@U(A;-q=dXz2&==uQ0+e&^a1>u!!ki^yA7 zIwW^Sqbs(na8c6>b{Um2u8y0RokrNHXa4)#_rCvppNG#PjgB%x%srm=v-vFCgpd(Z z6U?rY@>wL+K@J`R#U#~>!Tf={b1y(}f-m2iPEF zlfqHBZYubV6Ee5u--FSE)4WXQDAucDI`|B2z2k+G`K^oK^E>Nu#O{|S4Q#PLr&r50 zO*nAvjspQ-qUjfdgJ?1?xy=k6@~+odpM^ zRyIZZ`mCVTmGaKw~{$` z$|2wNbx4@hyH;d^`M(dxsPO_xK3LVpBn>34)Z4@M&~n5zHgB~w3vvMoJ)h!PEq4b; za~6M2BQ*6AIEnKR^P}pq=Sy&b_-4Tuo|R-Atc-7Y!WRf{bHTAzTbgtIin0dqB5ylz z$XOxX2j?u0ZT2OjLwCWe)IGnA6kOCP@XTP-pX;Jupc64zXCKf?G&Et5%K*ecjI0cTW4T3}eZ)MPMg N5ee`5Y?GG&{tpq%bLjv8 literal 2997 zcmaLZeNfYN90%~RjXl7g$9W4(X>Jjc@p3~?Y733ovkqCmkk0UnTNIq*LEIUPB_LXi8c!)vZh<^Bo&*fI5P}6XIgUTP&-m?+-R*Vn@6*29y$=hb zdA#Eo%kw(saFigLfte>E7#pn9Zn5RF=#Z#r1VI8f-$R2Vp1u$yEM#BIkst(#43Can zUw7I_B3ns}RI*>5D&USx^1XLFi#Af8R;?3xs#Tf1%g-Vfl>}%jV(6K*0OC-IT1*gf zlO_Sgqn0^G4SvHj0NN@xlW71F(C+>6F@f_d(40h6QZH*WaKT|oQeJ?{L*(fK%}GWj z&FV{5wql1$e2d(zY{hu%)#tB&&mVQmjc_;Y^btN4*A;v73<#}^; zTJ8oQ(^Me~{M+RKwi7_s&y^LXm+Ld<$^m4ThUey*(l0uW0qF3LPd0nez2oFA05L<^ zc{w>HdM^fa!OWR~9bSR6C8vNS_SYDrM~k4f+8IDxF`9I(r9OgM2q3=PF(&AI zK-=1cbKcVBn2BZp3HsRVoHL^SOA`PR_0QKgkyM0nZ>^5w7kEHnX#=^4^jmVJA?=mK=XT5mllkgV_ac0mLc$kHz1n;ba^D@io(g;2T9w;eP;VJEMGeFyqo!C!sH!U=ZewlDWbRXe-1! zW$zDC=I>0M0EQ(Q4xR0h%(YE-14z~xl9$%JgibpFw5vzYt{og$N`mIJmmQj}@a%KD zod6^$#m1F#$FAb*(65ZDWJzUC%-rq(AW72vM~i>`cE zUTG?Twl(_QY2S>!__i59Lc1%<_~LX{uMj}u6%VyJ>z*j)I)Efep;xDF{JDtF0396jZCFyCav=jiM(rf)qq(EYM|}WfHoQdmj!3{8E&|A!l4$N? zjOWIC0c3Yj)c0+EPxZJ5pu=Y6nS+W8W~&N77Yr@&l~+b`%dK=UOXU%A!C`S|x4$aY z=z)M8OwnC0(^+X!w%b)6!giI1D5d*rNAKIe2d$R0wNK!LEFH{J3awNgJH=)}+Y2Nu m9n5+`qin7gJRwU5v!0}(C2HBnRt}!NT{8S>Mc;TVtNkB9LYCwJ diff --git a/announce/linked.dat b/announce/linked.dat index 21047f80812d65c44e30956582a5bf5e82ebfdb5..af56abd6bd41dd017005db67b3fa30a8ccb3cb78 100644 GIT binary patch literal 960 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 literal 0 HcmV?d00001 diff --git a/announce/unlinked.dat b/announce/unlinked.dat index b2151dcc012e5101835d3c1193e88289bfe15362..6f2396f799b69d467ee45db76cff671c44b30491 100644 GIT binary patch literal 1080 zcmW;Le^AnA90zdCsZ(!?BL<|7%dO>)sn`xRx7eX=6U-WOP7xDDQ=GJkOpxn~ZO-O8 zW>P}NU^z?4^qg~OWk{}N_@k+L;S4C*&7IDs5Qo~L%zeK7_qxx0?s=Z~^L(BPZrbp0 z0o8}p*~hEkM*jYF0kv@tPtjAsO*1{OgKyMV)7x@F#W`T>!|h?iOY+hfFw*{E%7nXC z=>;C~e#hox9&>#KCW>$`KETX|Nx>m?N!tR4R#r>EiRM_Ek`~7^fp7FkYUBF`1LMI4 z_8&=9d{gNvxQS|{)~v7@8Ze3T&EM|zm}ltvk-7Z#ssqKOLbOMHV)=B5cJLrLkuZ60 zgHU>M6KuHG(hySA`nUqz{C2&!`n;3z0XXRDRQ(g*x+;J0K$87(-;`>+7<}?Sd(XN} zmC_E`@$A{Ex#aU4C;EP7_& zEpYadL&_`@f1wB8(pY10g8M4;Y|P!kqq@qNTt3()iQ1pw(eYLb_-47UEpy3z`wV2y z?6|auB|lm~_Yy}eY~B^x99r-iZ!vD`u8c(VP3I@XdvNC7Ppsh029eqNTJp~YV8M~y zwY`<$;bmY>9!qgmV!xgVj-ycs$S&fEePE=vY*b?H!tVgDq!yZ)FHg^izz++^Mwcn6 z903Ot>=)e`)x=tG!xJOLwUek~gA<8%u5PkD&H%=nZJ!-^sg;L1Q8kq7>{gbb4r0GT zKn73a)ZqBcaH#Vy`5elmm)DUCtBd_mAJB}Ddw1#|D8Sujhjx|kCAtD`I_f|kPx1R1 z;P#rIbQ_`lb!f))f6sNwwb5J9Tr*LYrKbNco>s*JA9iRM@;tOtk?~wn^4i(X>Jjc@p3~?Y733ovkqCmkk0UnTNIq*LEIUPB_LXi8c!)vZh<^Bo&*fI5P}6XIgUTP&-m?+-R*Vn@6*29y$=hb zdA#Eo%kw(saFigLfte>E7#pn9Zn5RF=#Z#r1VI8f-$R2Vp1u$yEM#BIkst(#43Can zUw7I_B3ns}RI*>5D&USx^1XLFi#Af8R;?3xs#Tf1%g-Vfl>}%jV(6K*0OC-IT1*gf zlO_Sgqn0^G4SvHj0NN@xlW71F(C+>6F@f_d(40h6QZH*WaKT|oQeJ?{L*(fK%}GWj z&FV{5wql1$e2d(zY{hu%)#tB&&mVQmjc_;Y^btN4*A;v73<#}^; zTJ8oQ(^Me~{M+RKwi7_s&y^LXm+Ld<$^m4ThUey*(l0uW0qF3LPd0nez2oFA05L<^ zc{w>HdM^fa!OWR~9bSR6C8vNS_SYDrM~k4f+8IDxF`9I(r9OgM2q3=PF(&AI zK-=1cbKcVBn2BZp3HsRVoHL^SOA`PR_0QKgkyM0nZ>^5w7kEHnX#=^4^jmVJA?=mK=XT5mllkgV_ac0mLc$kHz1n;ba^D@io(g;2T9w;eP;VJEMGeFyqo!C!sH!U=ZewlDWbRXe-1! zW$zDC=I>0M0EQ(Q4xR0h%(YE-14z~xl9$%JgibpFw5vzYt{og$N`mIJmmQj}@a%KD zod6^$#m1F#$FAb*(65ZDWJzUC%-rq(AW72vM~i>`cE zUTG?Twl(_QY2S>!__i59Lc1%<_~LX{uMj}u6%VyJ>z*j)I)Efep;xDF{JDtF0396jZCFyCav=jiM(rf)qq(EYM|}WfHoQdmj!3{8E&|A!l4$N? zjOWIC0c3Yj)c0+EPxZJ5pu=Y6nS+W8W~&N77Yr@&l~+b`%dK=UOXU%A!C`S|x4$aY z=z)M8OwnC0(^+X!w%b)6!giI1D5d*rNAKIe2d$R0wNK!LEFH{J3awNgJH=)}+Y2Nu m9n5+`qin7gJRwU5v!0}(C2HBnRt}!NT{8S>Mc;TVtNkB9LYCwJ