Skip to content

Commit 65d8d26

Browse files
committed
More complete monitoring messages to AGW client app.
1 parent c15903e commit 65d8d26

File tree

3 files changed

+171
-50
lines changed

3 files changed

+171
-50
lines changed

src/server.c

Lines changed: 156 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// This file is part of Dire Wolf, an amateur radio packet TNC.
33
//
4-
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
4+
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2020 John Langner, WB2OSZ
55
//
66
// This program is free software: you can redistribute it and/or modify
77
// it under the terms of the GNU General Public License as published by
@@ -45,9 +45,9 @@
4545
* 'k' Ask to start receiving RAW AX25 frames.
4646
*
4747
* 'm' Ask to start receiving Monitor AX25 frames.
48+
* Enables sending of U, I, S, and T messages to client app.
4849
*
4950
* 'V' Transmit UI data frame.
50-
* Generate audio for transmission.
5151
*
5252
* 'H' Report recently heard stations. Not implemented yet.
5353
*
@@ -89,7 +89,16 @@
8989
* 'K' Received AX.25 frame in raw format.
9090
* (Enabled with 'k' command.)
9191
*
92-
* 'U' Received AX.25 frame in monitor format.
92+
* 'U' Received AX.25 "UI" frames in monitor format.
93+
* (Enabled with 'm' command.)
94+
*
95+
* 'I' Received AX.25 "I" frames in monitor format. (new in 1.6)
96+
* (Enabled with 'm' command.)
97+
*
98+
* 'S' Received AX.25 "S" and "U" (other than UI) frames in monitor format. (new in 1.6)
99+
* (Enabled with 'm' command.)
100+
*
101+
* 'T' Own Transmitted AX.25 frames in monitor format. (new in 1.6)
93102
* (Enabled with 'm' command.)
94103
*
95104
* 'y' Outstanding frames waiting on a Port (new in 1.2)
@@ -768,10 +777,13 @@ static THREAD_F connect_listen_thread (void *arg)
768777
*
769778
* There are two different formats:
770779
* RAW - the original received frame.
771-
* MONITOR - just the information part.
780+
* MONITOR - human readable monitoring format.
772781
*
773782
*--------------------------------------------------------------------*/
774783

784+
static void mon_addrs (int chan, packet_t pp, char *result, int result_size);
785+
static char mon_desc (packet_t pp, char *result, int result_size);
786+
775787

776788
void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int flen)
777789
{
@@ -781,15 +793,11 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
781793
} agwpe_msg;
782794

783795
int err;
784-
int info_len;
785-
unsigned char *pinfo;
786-
int client;
787-
788796

789797
/*
790798
* RAW format
791799
*/
792-
for (client=0; client<MAX_NET_CLIENTS; client++) {
800+
for (int client=0; client<MAX_NET_CLIENTS; client++) {
793801

794802
if (enable_send_raw_to_client[client] && client_sock[client] > 0){
795803

@@ -839,32 +847,37 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
839847
}
840848
}
841849

850+
// Application might want more human readable format.
842851

843-
/* MONITOR format - only for UI frames. */
852+
server_send_monitored (chan, pp, 0);
844853

845-
for (client=0; client<MAX_NET_CLIENTS; client++) {
846-
847-
if (enable_send_monitor_to_client[client] && client_sock[client] > 0
848-
&& ax25_get_control(pp) == AX25_UI_FRAME){
854+
} /* end server_send_rec_packet */
849855

850-
time_t clock;
851-
struct tm *tm;
852-
int num_digi;
853856

854-
clock = time(NULL);
855-
tm = localtime(&clock); // TODO: should use localtime_r
856857

857-
memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
858+
void server_send_monitored (int chan, packet_t pp, int own_xmit)
859+
{
860+
/*
861+
* MONITOR format - 'I' for information frames.
862+
* 'U' for unnumbered information.
863+
* 'S' for supervisory and other unnumbered.
864+
*/
865+
struct {
866+
struct agwpe_s hdr;
867+
char data[1+AX25_MAX_PACKET_LEN];
868+
} agwpe_msg;
858869

859-
agwpe_msg.hdr.portx = chan;
870+
int err;
860871

861-
agwpe_msg.hdr.datakind = 'U';
872+
for (int client=0; client<MAX_NET_CLIENTS; client++) {
862873

863-
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
874+
if (enable_send_monitor_to_client[client] && client_sock[client] > 0) {
864875

865-
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
876+
memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
866877

867-
info_len = ax25_get_info (pp, &pinfo);
878+
agwpe_msg.hdr.portx = chan; // datakind is added later.
879+
ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
880+
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
868881

869882
/* http://uz7ho.org.ua/includes/agwpeapi.htm#_Toc500723812 */
870883

@@ -883,34 +896,34 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
883896
// AGWPE:
884897
// [AGWE-IN] 1:Fm ZL4FOX-8 To Q7P2U2 Via WIDE3-3 [08:32:14]`I0*l V>/"98}[:Barts Tracker 3.83V X
885898

886-
num_digi = ax25_get_num_repeaters(pp);
899+
// Format the channel and addresses, with leading and trailing space.
887900

888-
if (num_digi > 0) {
901+
mon_addrs (chan, pp, (char*)(agwpe_msg.data), sizeof(agwpe_msg.data));
889902

890-
char via[AX25_MAX_REPEATERS*(AX25_MAX_ADDR_LEN+1)];
891-
char stemp[AX25_MAX_ADDR_LEN+1];
892-
int j;
903+
// Add the description with <... >
893904

894-
ax25_get_addr_with_ssid (pp, AX25_REPEATER_1, via);
895-
for (j = 1; j < num_digi; j++) {
896-
ax25_get_addr_with_ssid (pp, AX25_REPEATER_1 + j, stemp);
897-
strlcat (via, ",", sizeof(via));
898-
strlcat (via, stemp, sizeof(via));
899-
}
900-
901-
snprintf (agwpe_msg.data, sizeof(agwpe_msg.data), " %d:Fm %s To %s Via %s <UI pid=%02X Len=%d >[%02d:%02d:%02d]\r%s\r\r",
902-
chan+1, agwpe_msg.hdr.call_from, agwpe_msg.hdr.call_to, via,
903-
ax25_get_pid(pp), info_len,
904-
tm->tm_hour, tm->tm_min, tm->tm_sec,
905-
pinfo);
905+
char desc[80];
906+
agwpe_msg.hdr.datakind = mon_desc (pp, desc, sizeof(desc));
907+
if (own_xmit) {
908+
agwpe_msg.hdr.datakind = 'T';
906909
}
907-
else {
910+
strlcat ((char*)(agwpe_msg.data), desc, sizeof(agwpe_msg.data));
911+
912+
// Timestamp with [...]\r
913+
914+
time_t clock = time(NULL);
915+
struct tm *tm = localtime(&clock); // TODO: use localtime_r ?
916+
char ts[32];
917+
snprintf (ts, sizeof(ts), "[%02d:%02d:%02d]\r", tm->tm_hour, tm->tm_min, tm->tm_sec);
918+
strlcat ((char*)(agwpe_msg.data), ts, sizeof(agwpe_msg.data));
908919

909-
snprintf (agwpe_msg.data, sizeof(agwpe_msg.data), " %d:Fm %s To %s <UI pid=%02X Len=%d >[%02d:%02d:%02d]\r%s\r\r",
910-
chan+1, agwpe_msg.hdr.call_from, agwpe_msg.hdr.call_to,
911-
ax25_get_pid(pp), info_len,
912-
tm->tm_hour, tm->tm_min, tm->tm_sec,
913-
pinfo);
920+
// Information if any with \r\r.
921+
922+
unsigned char *pinfo = NULL;
923+
int info_len = ax25_get_info (pp, &pinfo);
924+
if (info_len > 0 && pinfo != NULL) {
925+
strlcat ((char*)(agwpe_msg.data), (char*)pinfo, sizeof(agwpe_msg.data));
926+
strlcat ((char*)(agwpe_msg.data), "\r", sizeof(agwpe_msg.data));
914927
}
915928

916929
agwpe_msg.hdr.data_len_NETLE = host2netle(strlen(agwpe_msg.data) + 1) /* +1 to include terminating null */ ;
@@ -944,9 +957,103 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
944957
}
945958
}
946959

947-
} /* server_send_rec_packet */
960+
} /* server_send_monitored */
961+
962+
963+
// Next two are broken out in case they can be reused elsewhere.
964+
965+
// Format addresses in AGWPR monitoring format such as:
966+
// 1:Fm ZL4FOX-8 To Q7P2U2 Via WIDE3-3
967+
968+
static void mon_addrs (int chan, packet_t pp, char *result, int result_size)
969+
{
970+
char src[AX25_MAX_ADDR_LEN];
971+
char dst[AX25_MAX_ADDR_LEN];
972+
973+
ax25_get_addr_with_ssid (pp, AX25_SOURCE, src);
974+
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, dst);
975+
int num_digi = ax25_get_num_repeaters(pp);
976+
977+
if (num_digi > 0) {
978+
979+
char via[AX25_MAX_REPEATERS*(AX25_MAX_ADDR_LEN+1)];
980+
char stemp[AX25_MAX_ADDR_LEN+1];
981+
int j;
982+
983+
ax25_get_addr_with_ssid (pp, AX25_REPEATER_1, via);
984+
for (j = 1; j < num_digi; j++) {
985+
ax25_get_addr_with_ssid (pp, AX25_REPEATER_1 + j, stemp);
986+
strlcat (via, ",", sizeof(via));
987+
strlcat (via, stemp, sizeof(via));
988+
}
989+
snprintf (result, result_size, " %d:Fm %s To %s Via %s ",
990+
chan+1, src, dst, via);
991+
}
992+
else {
993+
snprintf (result, result_size, " %d:Fm %s To %s ",
994+
chan+1, src, dst);
995+
}
996+
}
948997

949998

999+
// Generate frame description in AGWPE monitoring format such as
1000+
// <UI pid=F0 Len=123 >
1001+
// <I R1 S3 pid=F0 Len=123 >
1002+
// <RR P1 R5 >
1003+
//
1004+
// Returns:
1005+
// 'I' for information frame.
1006+
// 'U' for unnumbered information frame.
1007+
// 'S' for supervisory and other unnumbered frames.
1008+
1009+
static char mon_desc (packet_t pp, char *result, int result_size)
1010+
{
1011+
cmdres_t cr; // command/response.
1012+
char ignore[80]; // direwolf description. not used here.
1013+
int pf; // poll/final bit.
1014+
int ns; // N(S) Send sequence number.
1015+
int nr; // N(R) Received sequence number.
1016+
char pf_text[4]; // P or F depending on whether command or response.
1017+
1018+
ax25_frame_type_t ftype = ax25_frame_type (pp, &cr, ignore, &pf, &nr, &ns);
1019+
1020+
switch (cr) {
1021+
case cr_cmd: strcpy(pf_text, "P"); break; // P only: I, SABME, SABM, DISC
1022+
case cr_res: strcpy(pf_text, "F"); break; // F only: DM, UA, FRMR
1023+
// Either: RR, RNR, REJ, SREJ, UI, XID, TEST
1024+
1025+
default: strcpy(pf_text, "PF"); break; // Not AX.25 version >= 2.0
1026+
// APRS is often sloppy about this but it
1027+
// is essential for connected mode.
1028+
}
1029+
1030+
unsigned char *pinfo = NULL; // I, UI, XID, SREJ, TEST can have information part.
1031+
int info_len = ax25_get_info (pp, &pinfo);
1032+
1033+
switch (ftype) {
1034+
1035+
case frame_type_I: snprintf (result, result_size, "<I S%d R%d pid=0x%02X Len=%d %s=%d >", ns, nr, ax25_get_pid(pp), info_len, pf_text, pf); return ('I');
1036+
1037+
case frame_type_U_UI: snprintf (result, result_size, "<UI pid=%02X Len=%d %s=%d >", ax25_get_pid(pp), info_len, pf_text, pf); return ('U'); break;
1038+
1039+
case frame_type_S_RR: snprintf (result, result_size, "<RR R%d %s=%d >", nr, pf_text, pf); return ('S'); break;
1040+
case frame_type_S_RNR: snprintf (result, result_size, "<RNR R%d %s=%d >", nr, pf_text, pf); return ('S'); break;
1041+
case frame_type_S_REJ: snprintf (result, result_size, "<REJ R%d %s=%d >", nr, pf_text, pf); return ('S'); break;
1042+
case frame_type_S_SREJ: snprintf (result, result_size, "<SREJ R%d %s=%d Len=%d >", nr, pf_text, pf, info_len); return ('S'); break;
1043+
1044+
case frame_type_U_SABME: snprintf (result, result_size, "<SABME %s=%d >", pf_text, pf); return ('S'); break;
1045+
case frame_type_U_SABM: snprintf (result, result_size, "<SABM %s=%d >", pf_text, pf); return ('S'); break;
1046+
case frame_type_U_DISC: snprintf (result, result_size, "<DISC %s=%d >", pf_text, pf); return ('S'); break;
1047+
case frame_type_U_DM: snprintf (result, result_size, "<DM %s=%d >", pf_text, pf); return ('S'); break;
1048+
case frame_type_U_UA: snprintf (result, result_size, "<UA %s=%d >", pf_text, pf); return ('S'); break;
1049+
case frame_type_U_FRMR: snprintf (result, result_size, "<FRMR %s=%d >", pf_text, pf); return ('S'); break;
1050+
case frame_type_U_XID: snprintf (result, result_size, "<XID %s=%d Len=%d >", pf_text, pf, info_len); return ('S'); break;
1051+
case frame_type_U_TEST: snprintf (result, result_size, "<TEST %s=%d Len=%d >", pf_text, pf, info_len); return ('S'); break;
1052+
default:
1053+
case frame_type_U: snprintf (result, result_size, "<U other??? >"); return ('S'); break;
1054+
}
1055+
}
1056+
9501057

9511058
/*-------------------------------------------------------------------
9521059
*

src/server.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ void server_init (struct audio_s *audio_config_p, struct misc_config_s *misc_con
1515

1616
void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int flen);
1717

18+
void server_send_monitored (int chan, packet_t pp, int own_xmit);
19+
1820
int server_callsign_registered_by_client (char *callsign);
1921

2022

src/xmit.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
#include "dtmf.h"
7777
#include "xid.h"
7878
#include "dlq.h"
79-
79+
#include "server.h"
8080

8181

8282
/*
@@ -1002,7 +1002,14 @@ static int send_one_frame (int c, int p, packet_t pp)
10021002
ax25_format_addrs (pp, stemp);
10031003
info_len = ax25_get_info (pp, &pinfo);
10041004
text_color_set(DW_COLOR_XMIT);
1005+
#if 0
1006+
dw_printf ("[%d%c%s%s] ", c,
1007+
p==TQ_PRIO_0_HI ? 'H' : 'L',
1008+
save_audio_config_p->fx25_xmit_enable ? "F" : "",
1009+
ts);
1010+
#else
10051011
dw_printf ("[%d%c%s] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L', ts);
1012+
#endif
10061013
dw_printf ("%s", stemp); /* stations followed by : */
10071014

10081015
/* Demystify non-APRS. Use same format for received frames in direwolf.c. */
@@ -1068,6 +1075,11 @@ static int send_one_frame (int c, int p, packet_t pp)
10681075
}
10691076

10701077
nb = hdlc_send_frame (c, fbuf, flen, send_invalid_fcs2, save_audio_config_p->fx25_xmit_enable);
1078+
1079+
// Optionally send confirmation to AGW client app if monitoring enabled.
1080+
1081+
server_send_monitored (c, pp, 1);
1082+
10711083
return (nb);
10721084

10731085
} /* end send_one_frame */

0 commit comments

Comments
 (0)