Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
248 lines (155 sloc) 8.87 KB

alt text

APRS is a protocol for widely spreading messages over an ad-hoc radio network while avoiding redundancy and network congestion.

F# for APRS

A system for sending APRS messages built in F#, because functional programming and static typing make everything better.

Mac and Linux users: You too can work on this code. Install the .NET Core SDK for your system and you can do all the things. I recommend installing Visual Studio Code with the Ionide plugin for development.

A work in progress.

Prior Art

Here is a similar system using a Kantronics packet radio setup that functions like a BBS with keyboard-to-keyboard communications.

Packet Radio

The architecture


TODO draw a diagram



See the project files, but here are the highlights.

  • .NET Core SDK v2.2 and above
  • Argu for the CLI
  • Expecto for unit tests

Future enhancements will include a Fable-based, Elmish, progressive web app and a Saturn based web server.


The design calls for 3 main parts:

  • A service that runs on the APRS server (work in progress).
    • This service picks up new APRS messages from Dire Wolf. The messages are written in TNC2MON format to a designated folder by the DireWolf kissutil.
  • A CLI that can be used to write TNC2MON format frames.
    • They can be written to a folder monitored by the kissutil. When the kissutil detects a new file DireWolf will process the frames and transmit.
    • Presently only produces TNC2MON formatted messages with Lat/Lon Position Report without Timestamp, and a plain text message
  • A progressive web app that can be used to compose APRS packets that will be used by the kissutil. (not started)
    • The service will serve the web app.

How to setup and run

First, make sure you have .NET Core SDK 2.2 or above installed.

Currently, there is only a CLI that can be used to create a TNC2MON formatted KISS frame suitable for the Dire Wolf kissutil, but a progressive web app (in Fable) is planned.

The CLI can produce a frame with a simple message or a Lat/Lon position report without timestamp as per the APRS 1.01 specification.

After cloning this repo you can restore the dependencies, run the migrations, run the tests, or run the CLI with dotnet.

Run the migrations

dotnet run -p src/faprs.migrations

This should create two tables.

Run the CLI and see the possible commands

From the root project folder (the folder that was created when you cloned this repo)

dotnet run --project src/faprs.cli/ -- --help

This will restore dependencies, compile the code, and run the CLI (please be patient).

You should see the help output looking like this:

USAGE: faprs [--help] --sender <sender> --destination <destination> [--path <path>] [--custommessage <msg>] [--savefilepath <save>] [<subcommand> [<options>]]


    --positionreport, --rpt <rpt>
                          Position Reports require a Latitude and Longitude. See Position Report usage for more.

    Use 'faprs <subcommand> --help' for additional information.


    --sender, -s <sender> Your Call Sign
    --destination, -d <destination>
                          To whom is this intended? This could also be a an application from the To Calls list
    --path <path>         Only option is WIDE1-1
    --custommessage, --msg <msg>
                          Unformatted message. Anything you want but cuts off at 63 chars. in length
    --savefilepath, --save-to <save>
                          Send output to a file in this location to be used by Dire Wolf's kissutil
    --help                display this list of options.

There are also sub-commands for the position report. You can get help for those too.

dotnet run --project src/faprs.cli/ -- --rpt --help

You should see some helpful stuff like this.

USAGE: faprs --positionreport [--help] latitude <latitude> <hemisphere> longitude <longitude> <hemisphere> [symbol <symbol>] [comment <comment>]


    latitude <latitude> <hemisphere>
                          Your current latitude in this format 36.106964 N
    longitude <longitude> <hemisphere>
                          Your current longitude in this format 112.112999 E
    symbol <symbol>       Optional. Default is House (-). If you want to use House, do not use the symbol argument because dashes do not parse.
    comment <comment>     Optional. What do you want to say? <comment> must be 43 characters or fewer.
    --help                display this list of options.

Create a TNC2MON formatted frame with position report

dotnet run --project src/faprs.cli/ -- --save-to XMIT --sender KG7SIO-7 --destination APDW15 --path WIDE1-1 --rpt latitude 36.106964 longitude -112.112999 symbol b comment "Join Oro Valley Amateur Radio Club"

This will create a TNC2MON formatted frame with a lat/lon position report that looks like this:

KG7SIO>APDW15:WIDE1-1:=36.106964N/112.112999WbJoin Oro Valley Amateur Radio Club.

The CLI will save it to the folder (and path) specified in --save-to. In this case the XMIT folder (if you have one) in your present working directory.

Let's break this down:

  • Who is sending this packet?
    • KG7SIO
  • The destination in this case is the Dire Wolf v1.5 TOCALL as specified in APRS 1.1.. The destination field can be overridden to indicate the sending application.
    • APDW15
  • Your position is 36.106964 degrees N and 112.112999 degrees W
  • Your APRS symbol is b for bicycle
  • Your comment is Join Oro Valley Amateur Radio Club

Create a TNC2MON formatted frame with unformatted message (string)

dotnet run --project src/faprs.cli/ -- --save-to XMIT --sender KG7SIO-7 --destination APDW15 --path WIDE1-1 --msg "Join Oro Valley Amateur Radio Club"

This will create a TNC2MON formatted frame with a custom message that looks like this:

KG7SIO>APDW15,WIDE1-1:Join Oro Valley Amateur Radio Club

The CLI will save it to the folder (and path) specified in --save-to. In this case the XMIT folder (if you have one) in your present working directory.

Developers and contributors

Contributors welcome. Please follow the F# Style Guide and open source contributors guide.

How to get started

  1. Clone this repo
  2. Run dotnet build or run the tests like below under Run the tests


There is a DOCKERFILE if you are so inclined.

Run service: dotnet run -p src/faprs.service or dotnet watch -p src/faprs.service/ run

Run the tests

dotnet run -p src/faprs.tests -f netcoreapp2.2

This will restore dependencies, compile all projects, and run tests.

Run the tests while changing code (dotnet watch)

dotnet watch -p src/faprs.tests run -f netcoreapp2.2

The tests will re-run every time you save changes, including adding more tests.

Deploy to a Raspberry PI


Working with Dire Wolf and the kissutil

Follow the Dire Wolf user guide to install Dire Wolf on your system. Follow the user guide to configure and start Dire Wolf.

Start the kissutil specifying the read and write folder

kissutil -o REC -f XMIT

-o specifies the folder to which Dire Wolf will write the received APRS messages.

-f specifies the folder from which Dire Wolf will read the messages FAPRS will send.

User FAPRS to send a message through kissutil

Write a Position Report without Timestamp to the XMIT folder.

dotnet run --project src/faprs.cli/ -- --save-to XMIT --sender KG7SIO --destination APDW15 --path WIDE1-1 --msg "Join Oro Valley Amateur Radio Club"

DireWolf tips

Debugging tip: Use the direwolf "-d n" command line option to print the KISS frames in hexadecimal so we can see what is being sent.

Run the web project

faprs.service provides a web interface to enter messages you want to send over APRS and to see messages received over APRS.

You can run it with dotnet run and dotnet watch.

Run with re-loading after changes.

dotnet watch -p src/faprs.service/ run

Run once

dotnet run -p src/faprs.service/
You can’t perform that action at this time.