Giter VIP home page Giter VIP logo

aprssharp's Introduction

APRS# (APRSsharp)

APRS# - Modern APRS software for the amateur radio community

About APRS

The Automatic Packet Reporting System is a digital wireless network designed and run by amateur (ham) radio operators around the world. Introduced in 1980, it is an ad-hoc, multi-hop, distributed network through which packets are transmitted and retransmitted between nodes to increase range. Data transmitted through APRS includes positional information, personal messages, weather station readings, search and rescue locations, and more. APRS packets are encoded and decoded by amateur radio devices, specialized hardware or software, or a combination.

APRS# Project

The protocol has been in use since its introduction in the 1980s (see the site by the original creator here) and has seen various incarnations of encode/decode/visualize software. This project exists to eventually become a modern user interface for sending, receiving, and visualizing APRS digital packets in a straight-forward manner.

This project is provided as open source and developed by the community for the community.

Further Documentation

See supplemental documentation for APRS# constituent projects:

Contributions

Please see the code of conduct and contributing document for details on contributing to this project.

Development

Dependencies

The target is .NET 6.0 for development.

Building

Warnings are treated as errors in the release build (as in CI builds) but are left as warnings in local development. To verify your code is warning-free, you can run dotnet build -c Release to get the release build behavior.

Generating / Publishing console application binary file

To generate the console application binary, go to the APRSsharp folder (AprsSharp\src\APRSsharp) and run the command dotnet publish -c Release to generate the console application. The resulting binary will be placed in bin\Release\net6.0\win-x86\publish. Alternatively, use dotnet publish -c Release -o <outputfolder> to specify the output directory.

Nuget Packages and Release

All packages are versioned together for now via a field in Directory.Build.props. This means if one package gets a new version, they all do. While this is not exactly ideal, this is currently used to manage inter-dependencies during early development.

Maintainers should ensure the version has been updated before creating a new GitHub release. Creating a release will publish nuget packages to Nuget.org list.

Running the project/application binary file

To run the generated console application binary, go to the APRSsharp folder (src\AprsSharp\src\APRSsharp).

Run the command dotnet run which will run AprsSharp with default parameters. You can run the console app with command line arguments. Examples of flags used with the arguments.

Callsign argument as {dotnet run -- --callsign with --callsign/-c/--cgn}. Password as {dotnet run -- --password with --password/-p/--pwd/--pass}. Server name as {dotnet run -- --server with --server or -s or --svr}. Filter arguments as {dotnet run -- --filter and --filter or -f}.

For example dotnet run -- -c "arg" --pwd "args" --server "args" -f "args".

You can specify different combinations of the commandline flags. Either use 0, 1, 2, 3 or all the flags combination of flags.

For missing flags, the console application will use the default arguments.

To gracefully terminate the application, press the command Q or q. This will exit the application after the last packet is received.

To force terminate the application, press the command Ctrl + c

aprssharp's People

Contributors

cbielstein avatar eddywine avatar martelro avatar dk-obrien avatar

Stargazers

 avatar Tommaso Giachi avatar Scott Fernandez avatar Tom M0LTE avatar Robert Chipperfield avatar  avatar Witold Karaś avatar Gerad Munsch avatar  avatar Kez avatar Christopher Zenzel avatar  avatar

Watchers

James Cloos avatar Shawn Stoddard avatar  avatar  avatar  avatar  avatar  avatar

aprssharp's Issues

Consider removal of NMEA types

Description

The APRS 1.01 spec describes raw GPS NMEA types. However, it's unclear to me at this moment if that is ever transmitted over the air in an unencoded way.

Given that this project is not desired to communicate directly with GPS devices at this time, we can consider removing the currently-unused NMEA code. This includes

  • NmeaType.cs
  • Relevant converter in EnumConversionExtensions.cs
  • NmeaTypeUnitTests.cs

Consider using regex for packet decode parsing

Description

Currently, packet decode uses substring, charAt, indexOf, and other string methods to handle parsing packets. This can likely be more concisely written using regex.

This issue is to consider if this is true and, if it is, make the switch in code.

Acceptance Criteria

  • Decide if regex can be more efficient or more maintainable in code. Document decision in the comments of this issue.
  • If the switch to regex should be made, implement the changes
  • Ensure all tests are still passing

PositionInfo does not handle position without timestamp and with messaging

Description

PositionInfo cannot decode a position report without timestamp and without messaging.

This should be a simple issue of updating the regex to accept either of the two "without timestamp" type characters, then refactoring code just like the "with timestamp" code directly beneath it (all of the "without timestamp" decode is the same except for if messaging is supported or not.)

Acceptance Criteria

  • PositionInfo can handle decode of position report without timestamp and without messaging
  • And encode as well
  • Add unit tests

Add GitHub Action to build and test code

GitHub Actions provide an automated way to run builds, tests, and other tasks when actions are taken in GitHub. We should add an Action workflow to build and test this code when: a push to main happens, on PR open, or PR update. There are existing Actions that may keep us from re-inventing the wheel. Discuss with @CBielstein if need be.

Likely should happen after #7 to ease the build and test commands.

For this issue to be complete:

  • A GitHub Action titled build or something similar should be added
  • A status badge for the action should be added to the readme
  • The action should successfully run for pushes or PRs to main

Packet decode does not handle Meteor Scatter beam information

Description

Currently, Meteor Scatter beam information is not decoded as part of packet decode. This should be corrected according to the APRS spec.

Acceptance Criteria

  • Meteor Scatter beam data is correctly decoded
  • Any test skips or TODOs in the code with this issue are resolved and removed
  • Additional test coverage as appropriate

Enable static analysis and linting

Static code analysis and linting are important for reducing bugs and increasing code maintainability.

For this task to be done, the following items should be done for all projects (yes, even tests). It's okay to tackle this in multiple PRs (one per project) to minimize PR size, if desired.

  • Set C# version to 8.0
  • Enable nullable references
  • Enable StyleCop
  • Enable FxCop
  • Project build should succeed (indicating successful analysis with no issues)

Consolidate FindCorrectYear, FindCorrectDayMonthAndYear, FindCorrectYearAndMonth

Timestamp has three methods that appear to do very similar work. Can they be consolidated somehow? Perhaps using optional parameters, etc. Those methods are FindCorrectYear, FindCorrectDayMonthAndYear, and FindCorrectYearAndMonth.

FindCorrectYear also does some weird...while(true) catch loop. Investigate if that can be replaced with a cleaner approach.

Maidenhead gridsquare locator logic appears to not be correct

Description

When testing latest changes (#93) against real packets, it appears that the full 6-char gridsquare locator is in accurate. I'm getting the following interpretations.

5017.57N/00404.80E_ (JO20AH) which maps 50.1757N, 004.0480E to JO20ah. However, the coordinates don't appear to be in the box in various online tools. One tool indicated such coordinates should be in JO20ae.

Similar with a decode on 5050.28NT00420.23E& to JO20EU.

Acceptance Criteria

  • Investigate if 6-char gridsquare encoding is inaccurate or if these other websites (or my current understanding) is wrong
  • Find the bug and fix it!
  • Write tests to validate the fix

Ensure compliance with package licenses

Find a way to comply with any packages' licenses that require disclosures (e.g. GPL licenses) and document it.

Then either open an issue to follow up with the disclosures for specific packages or just do it as part of this PR as an example.

A great change for this would be to take #26 first so that all packages can be consolidated in to a single file. This would allow that file to be monitored for changes via a GitHub Action and to ensure that a corresponding disclosure file has been modified as well.

Packet.GetDataType does not support complex data types

Description

While many APRS packet types are determined by their first character alone, some are more complex and can have ! or _ further in to the packet to change the type. Currently, the code responsible for detecting this (Packet.GetDataType) does not take these advanced considerations in to account and only uses the first character.

This should be corrected based on the APRS spec.

Acceptance Criteria

  • Handles weather type packets (which can have _ somewhere further in the packet to indicate weather)
  • Any reference to this issue are resolved in the code, either by remove test skips or handling caveats called out in comments
  • Tests added for other cases from APRS spec

Move to .NET 5 or 6 for newer features

Description

Issues #81 and #27 require .NET 5 or higher to complete. Consider moving to .NET 5 or greater for this project to take advantage.

Acceptance Criteria

Build moves to .NET 5 or higher.

Creating a console application

The created application should accept a string representing a packet and calls the APRS parser for decoding
It should also decode different types of packets and display them and in case of an incorrect packet, should display the appropriate message

Unnest nested types

Description

Several places in code have nested types. Examples of this include Packet.Type and Timestamp.Type. These files are hundreds of lines long and unnesting these types (e.g. to PacketType and TimestampType) would help break up long files and clarify the difference between a field on a packet and a type of packet.

Acceptance Criteria

  • Locate nested types in the code
  • Move them in to separate files
  • Ensure tests pass
  • Justify not unnesting in this issue or in the PR comments as appropriate

AprsParser can decode TNC2 packets

Description

APRS-IS sends packets in TNC2 format (source 1, source 2). Currently Packet.cs does not handle this encoding, so we cannot display human readable packets.

For this issue

  • introduce a new method on Packet to decode from TNC2 packets
  • add properties for the originating call sign and the packet's path, which are encoded in TNC2 information.

An example of such a method:

public void DecodeTnc2(string encodedPacket)
{
    // Decode TNC2 information
        // e.g. Callsign (sender)
        // Path
    DecodeInformationField(/* information field */);
}

NOTE: Not all packet types can be decoded by AprsParser at this point in time, so choose your test packets wisely. Consider building test packets based on those already covered in tests in PacketInformationFieldUnitTests.cs to avoid personal data from "real" packets being put in our repository...and to ensure you're using an information field that should decode.

Acceptance Criteria:

  • TNC2 fields (callsign, path) are decoded on to the Packet object
  • Information field is passed to DecodeInformationField for decode
  • Unit tests of new TNC2 decode functionality

Consider refactor of Packet.cs to pull out smaller classes

Description

Packet.cs is extremely long and has a lot of potential to refactor out smaller pieces of code. Logic around handling specific fields can and should be abstracted out of the Packet class. This would make development and testing much easier and perhaps make the file less intimidating to new developers.

Examples of opportunity here include basically all of the Handle... or Decode... methods in to various types: InformationField, MaidenheadGrid, etc.

Acceptance Criteria

  • Find potential refactors
  • Evaluate and make decisions on if refactors should be applied (be prepared to justify decision in PR or in this issue discussion)
  • Send PR with appropriate code changes

Enforce disallowed comment characters across all types

Description

Currently, only StatusInfo and MaidenheadBeaconInfo correctly enforce disallowed characters in an ARPS message comment (| or ~). This should be consistent across all packets which support a comment.

Acceptance Criteria

  • Check user-specified comments for disallowed characters across all packet types (consider not enforcing for decoded packets, just for sending)
  • Find a way to reduce duplication.

APRS# Can Connect to a TNC via TCP/IP

Description

With modern software TNCs such as direwolf, TCP/IP connects are support to allow the TNC and client applications to run on the same machine without a hardware serial connection.

APRS# should support such a TCP/IP connect to a TNC through the TncInterface abstraction.

Acceptance Criteria

  • APRS# can connect to KISS TNCs via TCP/IP
  • Manual integration testing against a software TNC such as direwolf may suffice where TCP testing is difficult.

Use `Assert.Throws` for tests expecting an exception

Several tests are using an outdated model of ensuring an exception is thrown. An example is in APaRSerUnitTests.PositionUnitTests.DecodeLatitudeOutOfRange (test/APaRSerUnitTests/PositionUnitTests.cs) where a model of try, catch and return, then throw an exception after the catch is used. This should instead be written with Assert.Throws for a more clean test model.

`AprsIsConnection` should have a way to terminate receiving

Description

AprsIsConnection currently can Receive() but there is no way to stop receiving and responsibly clean up the system resources (namely, the TCP port). We should implement a call on AprsIsConnection to terminate receiving.

Implementation Suggestions

A simple way to do this would be to change the while(true) in the Receive method to use a private class property boolean. That should be set to true at the beginning of Receive and then we could add a new method called StopReceiving() or something similar to set that to false. Then the next loop will terminate the loop and end the Receive task.

Acceptance Criteria

  • Add a StopReceiving() or similar call to AprsIsConnection to stop the running of Receive() and release the active TCP connection
  • Add tests

Update APRS parser from .NET Framework 4.5 to .NET Standard

The APRS parsing code was originally implemented for .NET Framework 4.5 as a portable class library. We should move this in to the future with .NET Standard, which is the much more modern (and much easier) model for cross platform libraries.

Honestly, the fastest way to do this is probably to just delete the .csproj file and create a new one with dotnet new classlib from within the directory. Likely want 2.1 instead of 2.0, so change that if appropriate inside the .csproj after creating. For the unit tests, do a similar process but dotnet new xunit

For this issue to be done:

  • APRS parser project should target .NET Standard 2.1
  • APRS parser unit test project should target netcoreapp3.1 (this is the .NET Core 3.1 runtime target)
  • Building each project should succeed (dotnet build in each directory modified here)
  • Running tests should succeed (dotnet test in the directory with the unit test project)

AprsIsConnection should expose authentication status

Description

AprsIsConnection is gaining the ability to expose if it's logged in with #98, but it should ideally also expose if it is authorized.

For this story, we should change the LoggedIn Boolean to be an enum with states along the lines of NotLoggedIn, Unverified and Verified.

Any CLI code or tests should be updated appropriately.

For reference, the login response message appears to follow the pattern:

# logresp <callsign> <verified|unverified>, server <serverCallsign>

Read more on here: http://www.aprs-is.net/ServerDesign.aspx

Acceptance Criteria

  • Change LoggedIn boolean to a tri-state enum status reflecting if the client is not logged in, logged in but unverified, or logged in and verified.
  • Update CLI code, if necessary
  • Add tests

Add ability to filter APRS-IS messages

Description

The APRS-IS specifies a way that clients can filter packets which they receive. This is called server side filtering and is discussed in the Connecting to APRS-IS documentation. The commands themselves are described in Server-side Filter Commands documentation.

APRS# should take advantage of this functionality to filter packets as specified by the user. This should be done through a command line parameter, so it will build on top of the work done in #62.

Although we may want to consider adding fancier shortcuts for these filters later, for now, let's just take a raw filter string as a parameter based on the format defined in Server-side Filter Commands.

Usage should look like this to receive all packets sent by N0CALL: aprssharp --filter b/N0CALL. This should work for any filters which can be constructed on the filter commands page.

Implementation guidance

The good news about server-side filtering is that it's implemented on the server, so this should be relatively straight forward on the client. Accept the string given by the user and pass it straight to the server.

The only difficult part here is validating user input. If the server gives detailed errors on invalid filter strings, reuse that and find a way to show it to the user. Perhaps a new event from AprsIsConnection for warnings/errors rather than packets could be good. If the server does NOT show a warning or error on an invalid filter but instead never returns packets or perhaps ignores the filter and returns all packets, we should work to implement at least a basic check. Perhaps a simple regex match can tell us if the filter is at least close and we can print an error if not.

Acceptance Criteria

  • Add a parameter to pass a filter string to the APRS-IS server and begin filtering on that string. This should just be accepting a string and passing it through to the server.
  • On the help page (e.g. aprssharp --help), include the link to the APRS-IS page on filter commands for reference: http://aprs-is.net/javAPRSFilter.aspx
  • Consider a way of validating user input. Try an invalid filter string with a server and see what happens. If the server rejects it, we should find a way to pass that message back to the user and quit. If it doesn't reject it, perhaps we should do a basic check to ensure the command fits a regex or something.
  • Add tests to ensure the filter is passed to the server appropriately
  • Add tests for any validation to ensure all cases in the filter commands document are allowed

Handle parsing of symbol/icon information

Description

Currently, symbols are just kept as the table ID and symbol character on a position. Design a way to move that to some sort of enum or something for the icon being reported. e.g. "Person" or "Jeep" or whatever.

The Position object is probably the correct spot for that information to be encoded and decoded. If that's the case, it may be desirable to remove the public property of table and symbol and just expose the enum. That's up to the implementer and reviewers.

Acceptance Criteria

  • Add enum for APRS icons
  • Hook up encode/decode logic in the Position class
  • Expose on the Position class through a new property
  • Consider removing the table and symbol char properties as those are encoding details that most callers won't necessarily care about
  • Add tests!

Rename old APaRSer code

The APRS parser was originally written as a standalone library and titled APaRSer, as a play on APRS and the word parser. Let's rename it to something professional.

For this issue:

  • Rename APaRSer project to AprsParser or something similar
  • Move namespace of various classes (APRS, AX.25, etc. classes) to AprsSharp.Parsers or something equally appropriate
  • Update references in tests
  • Update project name, class names, and namespaces in tests to reflect new changes in the source code

Add maidenhead precision logic to `Position`

Description

Position class currently does not have an automatic encoding of gridsquare to be the correct specificity. This can be a problem if a 4-char gridsquare is decoded and then attempted to encode later. This would add additional precision (which may not be very accurate) to the location.

Another example is decoding from a lat/long coordinate with ambiguity.

Consider using the ambiguity value in encodes and decodes.

Acceptance Criteria

  • Maidenhead gridsquare decode and encode results in the same precision of gridsquare
  • Maidenhead encode does not result in a more precise location than geocoord with ambiguity

Enable C# 10 for const string interpolation

Description

C# 10 supports string interpolation for constants. This would be helpful in places like the regex file at src\AprsParser\RegexStrings.cs.

Acceptance Criteria

  • C# 10 language support is enabled
  • CA1802 is enabled
  • Strings in regex file are made constant

Switch user interface to use command line flags/parameters

Description

Currently, APRS# prompts the user to optionally enter username and password, using default values if the user chooses to not enter any commands. While this is clear, it's a bit verbose and difficult for a user to call in a command line scripting scenario. The number of optional parameters will also grow as APRS# supports an increasing number of scenarios and configurations (user filters, sources, log files, etc.).

Because of this, many command line applications use parameters or flags. This would allow us to change our flow from:

> aprssharp
"Enter callsign:"
> N0CALL
"Enter password:"
> -1
"Begin receiving..."

to a single invocation:

> aprssharp --callsign N0CALL --password -1
"Begin receiving..."

where excluding either of those parameters could use the default value we have already been using.

It may also be nice to have the "short" version of the parameters, though this is less necessary. For example:

> aprsshar -c N0CALL -p -1
"Begin receiving..."

Eventually, this framework will expand to support receiving from different sources such as a hardware connector (that is a "TNC"), maybe decoding from a file or string passed om the command line or even sending via a TNC connection. Not to be implemented now but should be kept in mind for the future.

Implementation Notes

Though it's possible to do this by manually parsing the args string array in public static main(string[] args), we likely want to approach this in a more sustainable way. There are several libraries already around and I'm sure many of them would do the trick nicely.

One in particular that looks interesting is under development by the .NET folks already and is called System.CommandLine (GitHub repo, nuget.org listing). Since they support .NET Standard 2.0, we should be good to use them. It might be a good place to start investigating as it may become the new standard going forward. If there is a reason it won't work or that we should use something else, we should discuss and make a decision from there.

Acceptance Criteria

To consider this issue complete the following items must be completed and checked in:

  • Add code to set up the following commands
    • Some way to show help. The usual methods are one or all of --help, -h, -?. If it isn't too difficult, maybe all three. It should print out a description of APRS# with a link to our repository and a description of each of the commands added after this.
    • --callsign (and maybe -c) to specify a callsign with which to register to the server (same as we are doing now with callsign, just a new way of fetching it)
    • --password (and maybe -p) to specify a password (maybe this should fail if --callsign isn't set)
  • The command line should show appropriate errors if the values are incorrect (for example, I add --callsign but don't specify a callsign) or if the combination of parameters is incorrect (e.g. --password without --callsign) or missing (calling just aprssharp should show the help page and exit).
  • Add tests and ensure they're passing
  • Remove the current Console.WriteLine method of asking the user for input

Nice to have but not required:

  • Ability to specify which APRS-IS server to use. Might be nice. --server and a URL could be nice.

Switch from method overloads to optional parameters

Description

Some methods (at least one) in this codebase use method overloading to allow for varying parameters for different scenarios. Method overloads lead to duplicated documentation and extra lines of code for call-through code. Find overloaded methods and consider each case for a refactor to use optional parameters.

One example is Packet.EncodeInformationField.

Acceptance Criteria

  • As many method overloads as possible have been refactored to use optional parameters.
  • Implementer is able to speak to why any method overloads remain during code review.

AprsSharp can display decoded APRS-IS packets

Description

Currently, AprsSharp command line app prints out raw TNC2-encoded APRS packets. This is not very intuitive for the reader as most humans are not familiar with TNC2 and APRS encodings.

For this issue:

  • Use the functionality introduced by #79 to decode packets and raise a new packet received event
  • Printing out relevant fields

Since different APRS packet types have different relevant fields, there may be some work here to decide which fields are relevant. It's also okay to take an easy approach and refine later e.g printing all fields or printing specific common fields (e.g. callsign, comment, timestamp?, etc.).

Acceptance Criteria

  • New event in AprsIsConnection for receiving a packet which passes a decoded APRS packet
  • Update the AprsIsConnection unit tests to mock TcpConnection to return a valid packet string and assert an event is raised with the proper decoded packet
  • Human-readable decoded packet information is printed out in AprsSharp command line application

Handle Status report without maidenhead

Description

Status reports can come with or without a maidenhead gridsquare locator (position). Currently, APRS# can encode and decode status reports with the maidenhead locator but cannot handle without.

This is currently handled in Packet.cs but will be moved to StatusInfo.cs as part of the #77 refactor.

Acceptance Criteria

  • Decode status report without maidenhead
  • Encode status report without maidenhead
  • Unit tests

Add top-level solution file

Having a bunch of projects in the repository will get old to build and test. A .NET solution can be used to build and run tests on all projects at once. Create a new solution file with dotnet new sln at the top level of the directory. Use dotnet sln add to add existing projects to the solution file.

For this issue to be done:

  • Create AprsSharp.sln
  • Add all current projects to the solution
  • dotnet build and dotnet test from the root directory should succeed (and run tests for test comand)

Packet decode does not handle altitude data

Description

Currently, altitude information is not decoded as part of packet decode. This should be corrected according to the APRS spec.

Acceptance Criteria

  • Altitude data is correctly decoded
  • Any test skips or TODOs in the code with this issue are resolved and removed
  • Additional test coverage as appropriate

Rename old "KissIt" project and namespace to more professional name

The old KISS TNC protocol library was written under the name KissIt as a joke. Let's rename that to something more appropriate.

For this ticket, do the following:

  • Update KissIt project name to KissTnc
  • Update class names as appropriate
  • Update namespaces to AprsSharp.Protocols, AprsSharp.DataSources or something appropriate for this and other hardware/software interfaces for receiving and sending packets
  • Update references in test project to point to new project
  • Update test project name, class name, and namespaces along similar lines.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.