Skip to content

mobilinkd/libaprsroute

 
 

Repository files navigation

libaprsroute

C++ header only standalone APRS routing library.

This library can be used to implement a digipeater.

Automatic Packet Reporting System (APRS) is a system for real-time digital data communication over ham radio.

See more info at http://www.aprs.org/ and https://groups.io/g/APRS.

Build Status

Examples

Decoding a packet:

packet p;
try_decode_packet("N0CALL>APRS,WIDE2-2:data", p);

assert(p.from == "N0CALL");
assert(p.to == "APRS");
assert(p.data == "data");
assert(p.path.size() == 1);
assert(p.path[0] == "WIDE2-2");

Decoding a packet using constructors:

packet p = "N0CALL>APRS,WIDE2-2:data";
assert(p == "N0CALL>APRS,WIDE2-2:data");

Routing a packet:

router_settings digi { "DIGI", {}, { "WIDE1" } };
routing_result result;

packet p = "N0CALL>APRS,WIDE1-3:data";

try_route_packet(p, digi, result);

assert(result.state == routing_state::routed);
assert(to_string(result.routed_packet) == "N0CALL>APRS,DIGI*,WIDE1-2:data");

Routing diagnostics:

router_settings digi { "DIGI", {}, { "WIDE1", "WIDE2" }, routing_option::none, true };
routing_result result;

packet p = { "N0CALL", "APRS", { "WIDE1-2" }, "data"};

try_route_packet(p, digi, result);

// N0CALL>APRS,WIDE1-2:data
//             ~~~~~~~
//             12 19 - Packet address decremented
//
// N0CALL>APRS,DIGI,WIDE1-1:data
//             ~~~~
//             12 16 - Packet address inserted
//
// N0CALL>APRS,DIGI,WIDE1-1:data
//             ~~~~
//             12 16 - Packet address marked as 'set'

assert(result.actions.size() == 3);

assert(result.actions[0].address == "WIDE1-1");
assert(result.actions[0].target == applies_to::path);
assert(result.actions[0].type == routing_action::decrement);
assert(result.actions[0].start == 12);
assert(result.actions[0].end == 19);
assert(result.actions[0].index == 0);

assert(result.actions[1].address == "DIGI");
assert(result.actions[1].target == applies_to::path);
assert(result.actions[1].type == routing_action::insert);
assert(result.actions[1].start == 12);
assert(result.actions[1].end == 16);
assert(result.actions[1].index == 0);

assert(result.actions[2].address == "DIGI");
assert(result.actions[2].target == applies_to::path);
assert(result.actions[2].type == routing_action::set);
assert(result.actions[2].start == 12);
assert(result.actions[2].end == 16);
assert(result.actions[2].index == 0);

Print routing diagnostics using to_string:

router_settings digi { "DIGI", {}, { "WIDE1", "WIDE2" }, routing_option::none, /*enable_diagnostics*/ true };
routing_result result;

packet p = { "N0CALL", "APRS", { "WIDE1-2" }, "data"};

try_route_packet(p, digi, result);

std::string diag_string = to_string(result);

std::cout << diag_string << std::endl;

// Prints the following to stdout:

/*
   Packet address decremented:
   
   N0CALL>APRS,WIDE1-1:data
               ~~~~~~~
   
   Packet address inserted:
   
   N0CALL>APRS,DIGI,WIDE1-1:data
               ~~~~
   
   Packet address marked as 'set':
   
   N0CALL>APRS,DIGI*,WIDE1-1:data
               ~~~~~
*/

Print routing diagnostics using format:

routing_result result;

routing_diagnostic_display diag = format(result);

for (auto& e : diag.entries)
{
    fmt::print(fg(fmt::color::blue_violet), "note: ");
    fmt::print("{}\n", e.message);
    fmt::print(fg(fmt::color::gray), "{:4}{}\n", "", e.packet_string);
    fmt::print(fg(fmt::color::lime_green), "{:4}{}\n", "", e.highlight_string);
}

Address parsing:

Parsing a WIDE alias

address s;
std::string path = "WIDE2-1*";

try_parse_address(path, s);

assert(s.mark == true); // *
assert(s.n == 2); // 2-1
assert(s.N == 1); // 2-1
assert(s.text == "WIDE");
assert(s.kind == address_kind::wide);

Parsing a callsign

address s;
std::string path = "N0CALL-10*";

try_parse_address(path, s);

assert(s.mark == true); // *
assert(s.ssid == 10); // 10
assert(s.text == "N0CALL");

Other examples can be found in the tests directory.

Features

  • Packet decoding
  • Address parsing, encoding and decomposition
    • Can parse WIDE aliases, and decode n, N, or the used flag
    • Can parse callsigns, and decode ssid, or the used flag
  • Explicit routing
    • Supports preemptive routing: front, truncate and drop
    • Supports any arbitrary aliases, ex: WIDE2-2 can be used for explicit routing as an address "WIDE2" with callsign "2"
    • Supports optional router address substitution
  • n-N routing
    • Supports any arbitrary aliases, ex: FOOBAR2-2 can be used
    • Supports optional completed alias substitution
    • Trap excessive hops
  • Diagnostics: every routing action is surfaced as a diagnostic
    • Routed packets can be fully restored using the routing actions alone
    • Intelligent post-routing decisions can be made using the routing actions
    • Routing actions can be printed as a ready string using to_string, or customized with format

Goals

  • Modularity. This library is reusable, composable and standalone. It is written without any coupling to command line parsing code, configuration parsing code, memory management infrastructure, logging, or thread management. This makes it easy to integrate in any project in an unintrusive way. This library has no dependencies, only relying on the C++ standard library.
  • Diagnostics. This library generates extensive diagnostics as part of its core routing API, which allow for clean detailed diagnostics and logging, without an actual dependency on stdout or a dependency on a logging library.
  • Testability. This library has a comprehensive set of tests to ensure quality and correctness. The library has been written with testability in mind.
  • Documentation. Democratize APRS. The documentation in the code, combined with a comprehensive set of tests, can be used for learning and understanding of how the APRS network routing works.
  • Cross Platform. The library works on Linux, Windows or OSX systems. And has been tested with an MSVC, Clang and GCC compiler.

Testing

The tests directory contain a comprehensive sets of tests. tests/tests.cpp contains tests written using the Google Test framework.

A test asset file routes.json contains various routing scenarios. This test asset is stored in a structured format, which can be read by humans or programs, and can be used to study APRS routing, or used for standalone digipeater testing.

Use the tests as examples of how to use the library.

Development

The test project can be opened in Visual Studio or VSCode. And it will work out of the box if the dependencies are installed.

Install the CMake and C++ extensions in VSCode, or the Native Desktop workload inside Visual Studio (if using Visual Studio).

On Linux systems, install the dependencies listed in install_dependencies.sh, which include a compiler, the CMake build system, and a native build system like make. Example for Debian systems: apt-get install -y gcc g++ clang make cmake ninja-build.

Integration with CMake

As this is a header only library, you can simple download the header and use it:

file(DOWNLOAD https://raw.githubusercontent.com/iontodirel/libaprsroute/main/aprsroute.hpp ${CMAKE_SOURCE_DIR}/external/aprsroute.hpp)

Include the header in your source file:

#include "external/aprsroute.hpp"

Samples

There are a few samples provided in the examples directory.

The android_basic sample shows how to integrate the library in an Android application. The sample was generated using Android Studio.

About

APRS routing library

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 97.6%
  • CMake 1.7%
  • Other 0.7%