Direwolf measures a per-frame signal metric — audio level rec(mark/space)
plus the retry/FEC decode level — but only emits it to stdout and the
APRS-only CSV log, never over the AGWPE monitor API. This adds an opt-in,
backwards-compatible way for an AGWPE client to receive it in-band.
A client enables the feature with a new 'q' command; the server replies
with a 'q' frame carrying "ExtSig=1". For clients that opted in, the
per-frame metrics are packed into the four otherwise-zero user_reserved
header bytes of 'U'/'S'/'I' monitor frames:
user_reserved[0] = rec (0..255)
user_reserved[1] = mark (0..255; 0xFF = N/A for non-AFSK)
user_reserved[2] = space (0..255; 0xFF = N/A)
user_reserved[3] = retries (0 = clean copy)
Backwards compatibility is structural: the bytes are written only in the
copy sent to a client that sent 'q', after the header is zeroed, so any
client that does not opt in — every stock AGWPE client — receives
byte-identical frames. A stock Direwolf ignores the unknown 'q' command,
so a client requesting the extension against stock never sees the ACK and
leaves the feature off.
alevel and the retry count are threaded from app_process_rec_packet
through server_send_rec_packet into server_send_monitored. Own
transmitted ('T') frames and synthetic packets (AIS objects, APRStt) pass
a rec = -1 sentinel, which suppresses the reserved-byte write.
The Morse table contains two conflicting definitions for '-':
1. "-...-" on L101 (henceforth "3dit")
2. "-....-" on L108 ("4dit")
The order of the list meant that 3dit was used as it came first.
However it also used 3dit for `=` (L107).
Multiple sources, most notably the International Telecommunication Union
Recommendation for Morse code (ITU-R;
https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1677-1-200910-I!!PDF-E.pdf),
use 4dit for `-`, and I found nobody else using 3dit.
As such, especially given the conflicting definitions, I think 3dit is
an error, and this commit removes it.
Two unconditional DW_COLOR_DEBUG / dw_printf("DEBUG: ...") statements
were left in aprs_general_query() with TODO comments marking them for
removal. They printed on every General Query packet regardless of any
debug flag, adding noise to normal operation.
Removes both blocks (query type at line 2649 and footprint coordinates
at line 2726) and their associated TODO comments.
* Fix -T precedence so it does not clobber a future config-file timestamp setting
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Add TIMESTAMP config file directive
Adds a config-file equivalent for the -T command-line option, so
timestamps can be enabled when launching Direwolf from a supervisor
that cannot pass CLI arguments (e.g. Winlink Express). Closes#625.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Document TIMESTAMP config directive in sample config and changelog
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Address final-review minor findings for TIMESTAMP directive
- man/direwolf.1: mention the TIMESTAMP config directive alongside -T,
matching the -h help text.
- config.c: warn (rather than silently truncate) when a TIMESTAMP
format string exceeds the 40-byte field.
- dtime_now.c: harden timestamp_user_format() against strftime()
returning 0 on overflow, whose buffer contents are unspecified per
the C standard. Pre-existing gap also reachable via -T; fixed here
since this change adds a second entry point to the same code path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
The bad_tone_re pattern matched numbers like 100, 67, 77, 123 when they
appeared in a comment, warning that they look like CTCSS tones in
non-standard format. The trailing boundary group ($|[^0-9.]) also
matched '%', so a comment like "Battery voltage 100%" triggered a
spurious warning.
Exclude '%' from the trailing boundary: ($|[^0-9.%]). This means
"100%", "67%", etc. no longer match the pattern, while standalone
numeric values that genuinely look like misformatted tones still do.
Addresses the TODO at decode_aprs.c line 4941.
gmtime(3) returns a pointer to a static internal buffer shared across
all threads. In a multi-threaded decoder, concurrent calls to
get_timestamp() could race on that buffer, corrupting decoded timestamps.
gmtime_r(3) takes a caller-supplied struct tm buffer, eliminating the
race. It is already used consistently elsewhere in the codebase
(log.c, waypoint.c, encode_aprs.c, beacon.c) and the portability shim
that makes it available on all platforms is in direwolf.h.
Add a null-return guard as the FIXME comment requested.
Fixes the FIXME at decode_aprs.c line 4041.
An AGWPE client request for Heard Stations ('H' frame) requires that
data for the most recent 20 heard callsigns be returned. Much of the
data for this was already being collected, and displayed with the
'-d m' command line option, but was not available via AGWPE.
The following changes have been made to support requests for Heard
Stations:
* Last heard times are now saved on a per-channel basis, since the
AGWPE request specifies the channel for which data is being
requested. The most recently heard time on any channel is still
available using the 'chan' value, reflecting the channel on which
the callsign was most recently heard.
* First heard times are saved in addition to last heard times.
* Two new functions, mheard_latest_for_channel and mheard_latest_for_is,
are exposed from the mheard code, for use by the AGWPE server code.
These two functions parallel the separation between the existing
mheard_save_rf and mheard_save_is functions.
* The AGWPE server responds to 'H' frame requests by constructing and
returning 20 'H' frame responses (including blank responses if fewer
stations have been heard). The responses include both the text and
binary forms of the first and last heard times, as described in the
AGWPE spec.
* Macros are used to wrap the platform differences for qsort_r /
qsort_s, needed to sort heard times on a per-channel basis.
Tested on Linux Mint 22.1, macOS Sequoia 15.6.1, and Windows 10.
* Add new build config for Direwolf with Hamlib on Windows
In parallel with the existing 64-bit Windows build, these changes add
a new matrix config for the same build but including Hamlib as part of
the build and package distribution. The resultant package zip file has
"-hamlib" appended to the name to distinguish it from the standard
Windows build.
Installing Hamlib as a build dependency using a package manager isn't
a viable option on Windows. Instead, we interrogate the GitHub release
assets to find the latest 4.x release of Hamlib, download and expand
the zip file for that release, and provide the path to the directory
for CMake configuration.
* Fix WIndows build errors
* Include Hamlib license-related files in Windows Hamlib zip