Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

acarsdec next? :-) #117

Open
wants to merge 142 commits into
base: master
Choose a base branch
from
Open

acarsdec next? :-) #117

wants to merge 142 commits into from

Conversation

f00b4r0
Copy link

@f00b4r0 f00b4r0 commented Aug 18, 2024

Hi,

This large PR proposes what could be acarsdec 4.x

It'll be too long to document each commit separately (that's what the commit log is for anyway, I tried to use meaningful commit messages) so I'll focus on main changes:

This PR includes #116, #107, #106 and bits of #111, in more or less reworked form. It fixes #112, #76 and presumably #100 (through inclusion of #107).

The bulk of this PR consists of:

  • a large code cleanup and refactor, reducing the number of duplicated (sometimes with slight unnecessary variations) code, deleting dead code and removing unnecessary bandaids; hence deleting more lines than are added (despite adding several header files and comment blocks). The net result is improved memory footprint and CPU usage.
  • improving error checking and reporting
  • improving signal handling and exit cleanup
  • improving build system: all optional libraries are now autodetected (including libasound for ALSA support), the system-wide libcJSON is used instead of embedding a local copy and it builds fine on Linux and macOS (cannot test Windows but I don't expect changes there from previous situation)
  • enabling an unlimited number of ACARS channels to be decoded simultaneously (within available bandwidth and CPU power). This also means that acarsdec now uses just as much memory it needs for the number of channels actually decoded, no more, no less.
  • allowing all supported inputs to be built in the same executable (no more "cmake -Drtl=ON") which, together with the removal of the unconditional -march=native compilation flag (which can be added back on cmake invocation, as detailed in README), should make acarsdec packageable by distributions if necessary
  • allowing all supported output types to be used concurrently and repeatedly, which means it's now possible to display full text will sending JSON (or anything else) via UDP to several feed collectors and updating an MQTT broker at the same time
  • improving performance-critical common code which translates into e.g. the CPU usage of the SoapySDR backend being all but divided by 4, so that the overhead of using Soapy instead of native backend is now quite negligible
  • implementing multichannel raw audio input, at multiple sample rates (partly addresses Adding standard input option #109, supersedes Add option to decode raw audio data from STDIN #110).
  • and more 😁

Oh yes and now there's also a bit of statistics collection and reporting available via a simple StatsD-compatible interface. It's loosely based on how dumpvdl2 reports its own statistics. This helps to e.g. keep track of the performance of the SDR dongle, or to find which ACARS channels are the busiest.

The code reorganization (building all supported input backends together) and the ability to use multiple output combinations prompted me to change quite drastically how command line options are processed. This means in particular that from this point forward, acarsdec is no longer compatible with previous command line parameters (another reason for increasing the version major number, if all the above changes weren't enough already 😉):

  • inputs now use unambiguous long options (e.g. --rtlsdr instead of -r or --airspy instead of -s, loosely based on dumpvdl2), yet their argument remains unchanged: migration is easy.
  • outputs are defined using --output FORMAT:DESTINATION:PARAMETERS allowing mix and match of output formats and destinations (e.g. it's now possible to log planeplotter format to file, or send full text via UDP). This is detailed in the README and the supported formats and destinations can be listed via acarsdec --output help.
  • That aside I tried to keep carried-over short options unchanged.
  • A side effect of the reorganization is that all options - including frequencies - can be provided in any order. In other words, you can specify options after frequencies and even between frequencies if you so fancy.

I tried to revamp the help text (shown with acarsdec -h) to make everything as clear as possible, as well as correctly handling the cases where not all optional libraries were available at build time.

Finally the things I didn't touch (beyond code cleanup) at this stage are:

  • output formats syntax (for obvious backward compatibility reasons): I've been testing "acarsdec 4.0" feeding JSON to airframes.io with no problem.
  • Airspy SDR backend, which does things rather differently than the other 3 (beyond the filter tweak, that is) for reasons I'm not completely clear about: I'd like to make changes but I'd like to get some feedback from the author before I do (e.g. why is it operating entirely on real numbers instead of complex ones, which as far as I can tell the airspy driver can provide?). So the performance of this backend should be essentially unchanged as it doesn't use the new optimized common code.
  • MSK demodulator
  • ACARS decoder

The latter two I might revisit later as I see some room for improvement (I'd like to add a noisefloor measurement among other things), but I thought that a 100-commit PR was a nice round number for a start 😅

I have tried to add some meaningful documentation where applicable, I'm by no means an SDR expert so I hope I didn't write any blunder. Should probably still be better than nothing 😊

Sucessfully built: everything except the sdrplay backend (I don't have the required dependencies)

Tested:

  • rtlsdr input
  • soapysdr input (both rtlsdr and network modules)
  • sndfile input
  • file output
  • udp output
  • mqtt output
  • all output formats
  • statsd reporting

Needs testing:

  • sdrplay input
  • airspy input
  • ALSA input

(though I shouldn't have brought any functional changes to the latter two)

Tests performed on macOS x86_64, Linux x86_64 and armhf.

I think that sums it up. I'm happy to help maintain acarsdec in the future, if that can help 😊

I hope all of this is useful.

BuildTools and others added 30 commits July 11, 2024 19:56
- avoid special-casing IPv6 (AF_UNSPEC already handles it)
- avoid keeping multiple copies of the Rawaddr parameter
- avoid redundant (and useless) error checks
- avoid redundant checks in Netout*()
- avoid running strlen() over buffer when snprintf() is guaranteed to
  return the buffer size
- avoid duplicating the prepared JSON buffer, send it natively instead
  (tested working with airframes.io)
- use static buffers for Netoutpp() and Netoutsv() to reduce stack pressure
This fixes the following problem:

Found 3 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000003
  1:  Realtek, RTL2838UHIDIR, SN: 00000002
  2:  Realtek, RTL2838UHIDIR, SN: 00000001

`acarsdec -r 00000002` would select the device with serial 00000001
`acarsdec -r 00000001` would select the device with serial 00000002

This patch disambiguates explicit serials by skipping matching device ID
number when the passed argument is exactly 8 characters long, like a
fully qualified serial.

This patch is designed to be as short a diff as possible while preserving
existing behaviour for all but 8-character long arguments.
- move common global variables out of #define scope
- exit with an error if more than one input is selected
- reformat the usage help text
- rename rtlMult -> rateMult (in line with soapy)
- adjust rtl and soapy gain routines to work with floats

cmake -Drtl=ON -Dsoapy=ON -Dairspy=ON works and builds
This reverts commit 22f0c81.

Does this solve an actual problem? dumpvdl2 doesn't have similar code.
This runs an extraneous thread and uses nonportable pthread API.
-Drtl=ON now builds on macOS
Does this solve an actual problem? Neither dumpvdl2 nor common examples
have similar code. This runs an extraneous thread and uses nonportable
pthread API. -Dsoapy=ON now builds on macOS

Additionally:
- add some error checking
- retry on SOAPY_SDR_OVERFLOW (previous code wouldn't work either without it)
- gracefully retry on zero-reads
- don't free in buffer while read() may still be in-flight
- remove unnecessary global variables

PS: this needs so much more work :/
- No functional change.
- Some unused vars have been removed.
- No functional change.
- Some unused vars have been removed.
- Simplify the logic (use the median value of min and max frequency)
- Switch all Fc/minFc/maxFc references to unsigned int

This also "fixes" the following warning:
warning: taking the absolute value of unsigned type 'unsigned int' has no effect [-Wabsolute-value]
First pass at cleaning the mess, using Linux kernel clang-format rules
(without ColumnLimit) and a handful of manual adjustements.

No code change.
don't explicitly zero R initializers (zeroing is implicit)
allows decoding an arbitrary number of channels, limited only by CPU
and memory.

channels.Fr is now unsigned int, adjust casts accordingly until further
cleanup.
Remove malloc() casts.
No code change.
find it through pkg-config since we're already using that for libacars
and make it a hard dependency for now.
We no longer need the various -D<radio>=On since we can build them all
simultaneously. Instead, print an informative message when the
corresponding library is or isn't found.
also make MQTT support depend on it.
This commit enables the use of multiple concurrent outputs, using the
following syntax:

acarsdec --output format:destination:parameters [--output ...]

Where "format" is one of:
- "oneline" for single line text decoding
- "full" for full text decoding
- "monitor" for live decoding
- "pp" for PlanePlotter
- "native" for Acarsdec native format
With CJSON support enabled:
- "json" for JSON output
- "routejson" for flight route output in JSON format

and "destination" is one of:
- "file" for file (including stdout) output
- "udp" for network output over UDP
With MQTT support enabled:
- "mqtt" for MQTT output

Not all combinations of format and destination are valid, acarsdec will
complain if an invalid combination is chosen.

params are described in respective source file (TODO: update usage())

Fixes: TLeconte#76
No functional change
this is completely redundant with the check in blk_thread() and adds
extra processing time in the sample processing path.
This reduces memory pressure and cache trashing and speeds up execution.
outputmsg() no longers allocates memory unnecessarily and operates on
the data passed on from acars blk_thread(), which it only modifies once
(nul-termination at suffix position - necessary as cJSON doesn't have
primitives to limit string length).
This is faster, especially considering that the source will typically be
all-but-last non-nulls.
msg is zeroed on initialization
Use memcpy() instead of for loops and entirely skip parsing if text_len
is too short. Avoids redundant tests.
This speeds up execution by not trying each if() in sequence and makes
the function operation clearer. Using immediate returns instead of a
function pointer and single return point allows aggressive auto-inlining
'bs' is only used once locally in outputmsg()
use explicit size relationships for null-terminated copies
'msn_seq' is only used once locally in outputmsg()
Move one member outside of #ifdef since it's a standard type and this
makes packing deterministic.
use sf_readf_float() and close input file on exit
This partly addresses TLeconte#109
until a proper raw IQ input is added, and replaces
TLeconte#110 as a more generic
implementation

use '--sndfile <file>' as previously for all containers supported by
libsndfile.
use '--sndfile <file>,subtype=<N>' for raw audio processing with <N>
being a supported subtype value as specified in sndfile.h. Optionally,
'channels=<M>,endian=<end>' can be added to decode <M> channels (default
1 if not specified) using <end> endianness, where <end> is one of 'big',
'little' or 'cpu' (default 'cpu' if not specified).
use '-m' to change the multiplier from the default '1'
GCC is apparently not as smart as clang to identify uninitialized uses

Fixes: d6b48ae
@f00b4r0 f00b4r0 changed the title acarsdec 4.0? :-) acarsdec next? :-) Sep 26, 2024
@fredclausen
Copy link
Contributor

Thank you so much for this. I maintain a docker container that originally was running TLeconte's acarsdec, and I've switched to using your version 4.0/4.1 for my users. It works wonderfully, and I appreciate your work on this.

@f00b4r0
Copy link
Author

f00b4r0 commented Jan 12, 2025

Thank you so much for this. I maintain a docker container that originally was running TLeconte's acarsdec, and I've switched to using your version 4.0/4.1 for my users. It works wonderfully, and I appreciate your work on this.

Thanks for the feedback, much appreciated. I have a few more improvements brewing but have left them on the backburner especially considering there was zero feedback here. This gives new motivation to complete that work 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

library not found for -lacars-2 - MacOS
3 participants