Browse Source

Initial import

master
maze 1 year ago
parent
commit
b9ef634852
29 changed files with 2400 additions and 0 deletions
  1. +3
    -0
      .gitignore
  2. BIN
      .vscode/.browse.c_cpp.db
  3. BIN
      .vscode/.browse.c_cpp.db-shm
  4. BIN
      .vscode/.browse.c_cpp.db-wal
  5. +216
    -0
      .vscode/c_cpp_properties.json
  6. +7
    -0
      .vscode/extensions.json
  7. +32
    -0
      .vscode/launch.json
  8. +6
    -0
      .vscode/settings.json
  9. +39
    -0
      include/README
  10. +20
    -0
      lib/AX25/include/AX25.h
  11. +54
    -0
      lib/AX25/include/AX25/Address.h
  12. +31
    -0
      lib/AX25/include/AX25/Buffer.h
  13. +72
    -0
      lib/AX25/include/AX25/Link.h
  14. +30
    -0
      lib/AX25/include/AX25/Message.h
  15. +41
    -0
      lib/AX25/include/AX25/Port.h
  16. +40
    -0
      lib/AX25/include/AX25/Port/UDP.h
  17. +64
    -0
      lib/AX25/include/AX25/Types.h
  18. +140
    -0
      lib/AX25/src/Address.cpp
  19. +91
    -0
      lib/AX25/src/Buffer.cpp
  20. +52
    -0
      lib/AX25/src/CRC.cpp
  21. +815
    -0
      lib/AX25/src/Link.cpp
  22. +45
    -0
      lib/AX25/src/Message.cpp
  23. +57
    -0
      lib/AX25/src/Port.cpp
  24. +160
    -0
      lib/AX25/src/Port/UDP.cpp
  25. +46
    -0
      lib/README
  26. +15
    -0
      platformio.ini
  27. +164
    -0
      src/Timing.h
  28. +107
    -0
      src/main.cpp
  29. +53
    -0
      stack.py

+ 3
- 0
.gitignore View File

@ -32,3 +32,6 @@
*.out
*.app
.pio
.pioenvs
.piolibdeps

BIN
.vscode/.browse.c_cpp.db View File


BIN
.vscode/.browse.c_cpp.db-shm View File


BIN
.vscode/.browse.c_cpp.db-wal View File


+ 216
- 0
.vscode/c_cpp_properties.json View File

@ -0,0 +1,216 @@
{
"configurations": [
{
"name": "!!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags"
},
{
"name": "Mac",
"macFrameworkPath": [],
"includePath": [
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/config",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_trace",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_update",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/asio",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bootloader_support",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bt",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/coap",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/console",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/driver",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-tls",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_adc_cal",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_event",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_client",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_server",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_https_ota",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_ringbuf",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ethernet",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/expat",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fatfs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freemodbus",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freertos",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/heap",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/idf_test",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/jsmn",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/json",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/libsodium",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/log",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/lwip",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mbedtls",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mdns",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/micro-ecc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mqtt",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/newlib",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nghttp",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nvs_flash",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/openssl",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protobuf-c",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protocomm",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/pthread",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/sdmmc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/smartconfig_ack",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/soc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spi_flash",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spiffs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcp_transport",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcpip_adapter",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ulp",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/vfs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wear_levelling",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wifi_provisioning",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wpa_supplicant",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/xtensa-debug-module",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32-camera",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-face",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/cores/esp32",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/variants/wesp32",
"/Users/wijnand/Work/mcu/esp32/tnc/lib/AX25",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/FS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SD/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Update/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src",
"/Users/wijnand/.platformio/packages/tool-unity",
"/Users/wijnand/Work/mcu/esp32/tnc/include",
"/Users/wijnand/Work/mcu/esp32/tnc/src",
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "${workspaceRoot}/.vscode/.browse.c_cpp.db",
"path": [
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/config",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_trace",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_update",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/asio",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bootloader_support",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bt",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/coap",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/console",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/driver",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-tls",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_adc_cal",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_event",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_client",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_server",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_https_ota",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_ringbuf",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ethernet",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/expat",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fatfs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freemodbus",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freertos",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/heap",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/idf_test",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/jsmn",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/json",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/libsodium",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/log",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/lwip",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mbedtls",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mdns",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/micro-ecc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mqtt",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/newlib",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nghttp",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nvs_flash",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/openssl",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protobuf-c",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protocomm",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/pthread",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/sdmmc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/smartconfig_ack",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/soc",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spi_flash",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spiffs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcp_transport",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcpip_adapter",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ulp",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/vfs",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wear_levelling",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wifi_provisioning",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wpa_supplicant",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/xtensa-debug-module",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32-camera",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-face",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/cores/esp32",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/variants/wesp32",
"/Users/wijnand/Work/mcu/esp32/tnc/lib/AX25",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/FS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SD/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Update/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src",
"/Users/wijnand/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src",
"/Users/wijnand/.platformio/packages/tool-unity",
"/Users/wijnand/Work/mcu/esp32/tnc/include",
"/Users/wijnand/Work/mcu/esp32/tnc/src",
""
]
},
"defines": [
"PLATFORMIO=30607",
"ARDUINO_WESP32",
"ESP32",
"ESP_PLATFORM",
"F_CPU=240000000L",
"HAVE_CONFIG_H",
"MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"",
"ARDUINO=10805",
"ARDUINO_ARCH_ESP32",
"ARDUINO_VARIANT=\"wesp32\"",
"ARDUINO_BOARD=\"Silicognition wESP32\"",
""
],
"intelliSenseMode": "clang-x64",
"cStandard": "c99",
"cppStandard": "c++11",
"compilerPath": "\"/Users/wijnand/.platformio/packages/toolchain-xtensa32/bin/xtensa-esp32-elf-gcc\" -mlongcalls"
}
],
"version": 4
}

+ 7
- 0
.vscode/extensions.json View File

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

+ 32
- 0
.vscode/launch.json View File

@ -0,0 +1,32 @@
// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY
// PIO Unified Debugger
//
// Documentation: https://docs.platformio.org/page/plus/debugging.html
// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html
{
"version": "0.2.0",
"configurations": [
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug",
"executable": "/Users/wijnand/Work/mcu/esp32/tnc/.pioenvs/wesp32/firmware.elf",
"toolchainBinDir": "/Users/wijnand/.platformio/packages/toolchain-xtensa32/bin",
"preLaunchTask": {
"type": "PlatformIO",
"task": "Pre-Debug"
},
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "/Users/wijnand/Work/mcu/esp32/tnc/.pioenvs/wesp32/firmware.elf",
"toolchainBinDir": "/Users/wijnand/.platformio/packages/toolchain-xtensa32/bin",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

+ 6
- 0
.vscode/settings.json View File

@ -0,0 +1,6 @@
{
"terminal.integrated.env.osx": {
"PATH": "/Users/wijnand/.platformio/penv/bin:/Users/wijnand/.platformio/penv:/Users/wijnand/.rvm/gems/ruby-2.4.1/bin:/Users/wijnand/.rvm/gems/ruby-2.4.1@global/bin:/Users/wijnand/.rvm/rubies/ruby-2.4.1/bin:/usr/local/opt/qt/bin:/Users/wijnand/perl5/bin:/Users/wijnand/Work/sdk/esp32/xtensa-esp32-elf/bin:/usr/local/opt/ruby/bin:/Library/Frameworks/Python.framework/Versions/3.4/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/Library/TeX/texbin:/usr/local/MacGPG2/bin:/opt/X11/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Applications/Wireshark.app/Contents/MacOS:/usr/local/share/python:/usr/local/sbin:/usr/X11/bin:/Users/wijnand/bin:/Users/wijnand/gopath/bin:/Users/wijnand/.rvm/bin",
"PLATFORMIO_CALLER": "vscode"
}
}

+ 39
- 0
include/README View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

+ 20
- 0
lib/AX25/include/AX25.h View File

@ -0,0 +1,20 @@
#pragma once
#include <functional>
#include <Arduino.h>
#include <Udp.h>
#include "AX25/Types.h"
#include "AX25/Address.h"
#include "AX25/Message.h"
#include "AX25/Buffer.h"
#include "AX25/Link.h"
#include "AX25/Port.h"
namespace AX25
{
uint16_t calc_fcs(const uint8_t *buffer, size_t length);
const char *pid_name(uint8_t pid);
} // namespace AX25

+ 54
- 0
lib/AX25/include/AX25/Address.h View File

@ -0,0 +1,54 @@
#pragma once
namespace AX25
{
typedef struct Address
{
char call[7];
Address();
Address(const char *callsign);
void fromASCII(const char *callsign);
char *toASCII(char *buffer);
int compare(struct Address const &rhs);
bool operator==(struct Address const &rhs) { return compare(rhs) == 0; }
bool operator!=(struct Address const &rhs) { return compare(rhs) != 0; }
bool operator<(struct Address const &rhs) { return compare(rhs) < 0; }
bool operator<=(struct Address const &rhs) { return compare(rhs) <= 0; }
bool operator>=(struct Address const &rhs) { return compare(rhs) >= 0; }
bool operator>(struct Address const &rhs) { return compare(rhs) > 0; }
} Address;
typedef struct Path
{
Address calls[AX25_MAX_DIGIS];
bool repeated[AX25_MAX_DIGIS];
uint8_t hops;
int8_t last;
int compare(Path const &rhs);
bool operator==(Path const &rhs) { return compare(rhs) == 0; }
bool operator!=(Path const &rhs) { return compare(rhs) != 0; }
bool operator<(Path const &rhs) { return compare(rhs) < 0; }
bool operator<=(Path const &rhs) { return compare(rhs) <= 0; }
bool operator>=(Path const &rhs) { return compare(rhs) >= 0; }
bool operator>(Path const &rhs) { return compare(rhs) > 0; }
void invert(Path &out);
} Path;
typedef struct Route
{
Address call;
struct route *next;
int refcount;
Path path;
} Route;
extern const Address broadcast;
extern const Address default_address;
extern const Address null_address;
} // namespace AX25

+ 31
- 0
lib/AX25/include/AX25/Buffer.h View File

@ -0,0 +1,31 @@
#pragma once
#include "AX25/Types.h"
namespace AX25
{
typedef struct Buffer : public Stream
{
uint8_t *data;
size_t alloc;
size_t length;
size_t cursor;
Buffer(size_t alloc);
~Buffer();
void reset();
int available();
int read();
int peek();
void flush();
size_t write(uint8_t c);
size_t write(const uint8_t *buffer, size_t length);
uint8_t *reserve(size_t size);
size_t readFrom(FrameStream &stream);
size_t writeTo(FrameStream &stream);
} Buffer;
} // namespace AX25

+ 72
- 0
lib/AX25/include/AX25/Link.h View File

@ -0,0 +1,72 @@
#pragma once
#include <Arduino.h>
#include "AX25/Address.h"
#include "AX25/Buffer.h"
#include "AX25/Types.h"
#include "AX25/Message.h"
namespace AX25
{
typedef enum LinkState
{
AX25_DISCONNECTED = 0,
AX25_WAIT_CONNECT,
AX25_WAIT_DISCONNECT,
AX25_CONNECTED,
AX25_RECOVERY
} LinkState;
class Port;
class Link
{
public:
Address src, dst;
Path path;
bool is_digi;
uint8_t vr; // received sequence
uint8_t vs; // sent sequence
uint8_t va; // acknowledged sequence
uint8_t window;
LinkState state;
Modulus modulus;
Port &port;
Buffer rx, tx;
Link(Port &port);
~Link();
bool sendControl(FrameType type, bool poll, bool response = false, bool invert = true);
void encodeControl(FrameType type, bool poll, bool response = false, bool invert = false);
void decode();
void dumpTo(Stream *stream);
void sendText(String text);
void sendText(const char *buffer);
void send(Message &);
protected:
size_t decodeAddresses(bool *response);
FrameType decodeType(size_t *offset, int *ns, int *nr, bool *pf);
void decodeI(size_t offset, int ns, int nr, bool pf);
void decodeSABM(bool pf, bool extended = false);
void decodeDISC(bool pf);
void decodeUA(bool pf);
void decodeDM(bool pf);
void decodeFRMR(bool pf);
void decodeUI(size_t offset, bool pf);
void decodeXID(bool pf);
void decodeTEST(bool pf);
void decodeRR(bool pf, bool rejected = false);
void decodeREJ(bool pf);
void decodeSREJ(bool pf);
void encodeHeader(bool response = false, bool invert = false);
bool validateNR(int nr);
private:
Stream *dump;
};
} // namespace AX25

+ 30
- 0
lib/AX25/include/AX25/Message.h View File

@ -0,0 +1,30 @@
#pragma once
#include <vector>
#include "AX25/Address.h"
#include "AX25/Types.h"
namespace AX25
{
class Link;
typedef struct Message
{
Address source;
Address target;
std::vector<Address> path;
std::vector<bool> repeated;
FrameType type;
uint16_t control;
uint8_t pid;
const uint8_t * buffer;
size_t length;
void invert(Message &);
bool reply(Link *, const char *);
bool reply(Link *, String const &);
} Message;
} // namespace AX25

+ 41
- 0
lib/AX25/include/AX25/Port.h View File

@ -0,0 +1,41 @@
#pragma once
#include <functional>
#include <Arduino.h>
#include <Udp.h>
#include "AX25/Types.h"
#include "AX25/Link.h"
#include "AX25/Message.h"
namespace AX25
{
class Port : public FrameStream
{
public:
virtual ~Port() = default;
void onConnect(std::function<bool(Port *, Link *)> cb);
bool doConnect(Link *link);
void onDisconnect(std::function<void(Port *, Link *)> cb);
void doDisconnect(Link *link);
void onText(std::function<void(Port *, Link *, const char *, size_t)> cb);
void doText(Link *link, const char *text, size_t length);
void onBroadcast(std::function<void(Port *, Link *, const char *, size_t)> cb);
void doBroadcast(Link *link, const char *text, size_t length);
virtual void dumpTo(Stream *stream) = 0;
virtual size_t writeFrame(const uint8_t *buffer, size_t length) = 0;
size_t writeFrame(Buffer &buffer);
virtual void sendBeacon(Address &addr, const char *beacon) = 0;
virtual void sendMessage(Message &) = 0;
protected:
std::function<bool(Port *, Link *)> connect_cb;
std::function<void(Port *, Link *)> disconnect_cb;
std::function<void(Port *, Link *, const char *, size_t)> text_cb;
std::function<void(Port *, Link *, const char *, size_t)> broadcast_cb;
};
} // namespace AX25

+ 40
- 0
lib/AX25/include/AX25/Port/UDP.h View File

@ -0,0 +1,40 @@
#pragma once
#include <Udp.h>
#include "AX25/Port.h"
namespace AX25
{
class UDPPort : public Port
{
public:
UDPPort(const char *callsign, UDP &udp);
~UDPPort();
bool begin(uint16_t port = 93);
void loop();
int available();
void flush();
int peek();
int read();
int read(unsigned char *buffer, size_t length);
int availableFrame();
size_t readFrame(uint8_t *buffer, size_t length);
size_t write(uint8_t c);
size_t write(const uint8_t *buffer, size_t length);
size_t writeFrame(const uint8_t *buffer, size_t length);
void dumpTo(Stream *stream);
void sendBeacon(Address &addr, const char *beacon);
private:
UDP &udp;
Address call;
Link *link;
bool started = false;
IPAddress peer;
uint16_t peer_port;
};
} // namespace AX25

+ 64
- 0
lib/AX25/include/AX25/Types.h View File

@ -0,0 +1,64 @@
#pragma once
#include <Arduino.h>
#define AX25_MAX_DIGIS 8
#define AX25_EXTENSION_BIT 0x01
#define AX25_COMMAND_BIT 0x80
#define AX25_REPEATED_BIT 0x80
#define AX25_SSID_UNUSED_BITS 0x60
#define AX25_ESSID_UNUSED_BITS 0x20
#define AX25_MAX_BUFFER 256
#define AX25_MAX_RX_BUFFER (AX25_MAX_BUFFER)
#define AX25_MAX_TX_BUFFER (AX25_MAX_BUFFER)
#if !defined(AX25_DEBUG)
#define AX25_DEBUG Serial
#endif
namespace AX25
{
typedef enum Modulus
{
AX25_MODULUS = 8,
AX25_EXTENDED_MODULUS = 128
} Modulus;
typedef enum FrameType
{
/* I-frame */
AX25_I = 0,
/* S-frame */
AX25_S_RR,
AX25_S_RNR,
AX25_S_REJ,
AX25_S_SREJ,
/* U-frame */
AX25_U,
AX25_U_SABME,
AX25_U_SABM,
AX25_U_DISC,
AX25_U_DM,
AX25_U_UA,
AX25_U_FRMR,
AX25_U_UI,
AX25_U_XID,
AX25_U_TEST,
/* Invalid */
AX25_INVALID = 0x100
} FrameType;
// FrameStreams can read and write whole HLDC frames.
class FrameStream
{
public:
virtual int availableFrame() = 0;
virtual size_t readFrame(uint8_t *buffer, size_t length) = 0;
virtual size_t writeFrame(const uint8_t *buffer, size_t length) = 0;
};
} // namespace AX25

+ 140
- 0
lib/AX25/src/Address.cpp View File

@ -0,0 +1,140 @@
#include "AX25.h"
namespace AX25
{
const Address broadcast("QST");
const Address default_address("ESP32");
const Address null_address("");
Address::Address()
{
memcpy(call, null_address.call, sizeof(call));
}
Address::Address(const char *callsign)
{
fromASCII(callsign);
}
void Address::fromASCII(const char *callsign)
{
const char *s;
int i;
for (i = 0, s = callsign; i < 6; i++)
{
if (*s != 0x00 && *s != '-')
{
call[i] = *s++;
}
else
{
call[i] = ' ';
}
call[i] <<= 1;
call[i] &= 0xfe;
}
if (*s++ == 0x00)
{
call[6] = 0x00;
return;
}
call[6] = *s++ - '0';
if (*s != 0x00)
{
call[6] *= 10;
call[6] += *s++ - '0';
}
call[6] <<= 1;
call[6] &= 0x1e;
}
static char wildcard[] = "*";
char *Address::toASCII(char *buffer)
{
char c, *s;
uint8_t i;
for (i = 0, s = buffer; i < 6; i++)
{
c = (call[i] >> 1) & 0x7f;
if (c != ' ') *s++ = c;
}
if (((call[6] >> 1) & 0x0f))
{
*s++ = '-';
if ((i = (call[6] >> 1) & 0x0f) > 9)
{
*s++ = '1';
i -= 10;
}
*s++ = i + '0';
}
*s++ = 0x00;
if (*buffer == 0x00 || *buffer == '-')
return wildcard; /* "*" */
return buffer;
}
int Address::compare(Address const &rhs)
{
uint8_t i;
int d;
for (i = 0; i < 6; i++)
{
// Call sign characters without repeater bits.
if ((d = (int)(call[i] & 0xfe) - (int)(rhs.call[i] & 0xfe)) != 0)
return d;
}
// SSID without control.
return ((int)(call[6] & 0x1e) - (int)(rhs.call[6] & 0x1e));
}
int Path::compare(const Path &rhs)
{
uint8_t i;
int d;
if ((d = (int)hops - (int)rhs.hops) != 0)
return d;
if ((d = (int)last - (int)rhs.last) != 0)
return d;
for (i = 0; i < hops; i++)
{
if ((d = calls[i].compare(rhs.calls[i])) != 0)
return d;
}
return 0;
}
void Path::invert(Path &out)
{
uint8_t i;
out.hops = hops;
out.last = hops - last - 2;
for (i = 0; i < hops; i++)
{
out.calls[i] = calls[hops - i - 1];
if ((out.repeated[i] = (i <= last)))
out.calls[i].call[6] |= AX25_REPEATED_BIT;
else
out.calls[i].call[6] &= ~AX25_REPEATED_BIT;
}
}
} // namespace AX25

+ 91
- 0
lib/AX25/src/Buffer.cpp View File

@ -0,0 +1,91 @@
#include <cstring>
#include "AX25.h"
namespace AX25 {
Buffer::Buffer(size_t alloc)
: data(new uint8_t[alloc]), alloc(alloc), length(0)
{
}
Buffer::~Buffer()
{
delete data;
}
int Buffer::available()
{
return length - cursor;
}
int Buffer::read()
{
return data[cursor++];
}
int Buffer::peek()
{
return data[cursor];
}
void Buffer::flush()
{
}
size_t Buffer::write(uint8_t c)
{
if (length < alloc)
{
data[length] = c;
length++;
return 1;
}
return 0;
}
size_t Buffer::write(const uint8_t *buffer, size_t size)
{
if (length + size > alloc)
{
size = alloc - length;
}
if (size > 0)
{
std::memcpy(data + length, buffer, size);
length += size;
}
return size;
}
void Buffer::reset()
{
std::memset(data, 0, length);
length = 0;
cursor = 0;
}
size_t Buffer::readFrom(FrameStream &stream)
{
size_t remaining = alloc - length, read;
if ((read = stream.readFrame(data + length, remaining)) > 0)
length += read;
return read;
}
uint8_t *Buffer::reserve(size_t size)
{
uint8_t *out;
assert(length + size <= alloc);
out = data + length;
length += size;
return out;
}
size_t Buffer::writeTo(FrameStream &stream)
{
AX25_DEBUG.printf("[d] write %d bytes from buffer to stream\n", length);
if (length == 0) return 0;
return stream.writeFrame(data, length);
}
} // namespace AX25

+ 52
- 0
lib/AX25/src/CRC.cpp View File

@ -0,0 +1,52 @@
#include "AX25.h"
namespace AX25 {
static const unsigned short crc_ccitt_table[256] =
{
// from http://www.ietf.org/rfc/rfc1549.txt
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
uint16_t calc_fcs(const uint8_t *buffer, size_t length)
{
uint16_t crc = 0xffff;
for (size_t i = 0; i < length; i++)
{
crc = ((crc) >> 8) ^ crc_ccitt_table[((crc) ^ buffer[i]) & 0xff];
}
return crc ^ 0xffff;
}
} // namespace AX25

+ 815
- 0
lib/AX25/src/Link.cpp View File

@ -0,0 +1,815 @@
#include <cstring>
#include "AX25.h"
#define UPDATE_STATE(new_state) \
do \
{ \
AX25_DEBUG.printf("[i] state %d->%d (in %s:%d)\n", state, new_state, __FILE__, __LINE__); \
state = new_state; \
} while (0)
namespace AX25
{
Link::Link(Port &port)
: state(AX25_DISCONNECTED), modulus(AX25_MODULUS), port(port), rx(AX25_MAX_RX_BUFFER), tx(AX25_MAX_TX_BUFFER), dump(nullptr)
{
vr = 0;
vs = 0;
va = 0;
}
Link::~Link()
{
}
bool Link::sendControl(FrameType type, bool poll, bool response, bool invert)
{
tx.reset();
encodeControl(type, poll, response, invert);
return tx.writeTo(port) > 0;
}
void Link::decode()
{
int ns, nr;
bool pf;
FrameType type;
bool response;
size_t offset = 0;
char cmd = ' ';
if (!(offset = decodeAddresses(&response)))
return;
if (dump)
{
char call[10];
src.toASCII(call);
dump->printf("fm %s ", call);
dst.toASCII(call);
dump->printf("to %s ", call);
if (path.hops > 0)
{
dump->print(F("via"));
for (uint8_t i = 0; i < path.hops; i++)
{
path.calls[i].toASCII(call);
dump->printf(" %s", call);
if (path.repeated[i])
dump->write('*');
}
}
}
type = decodeType(&offset, &ns, &nr, &pf);
if (response)
cmd = (pf ? '-' : 'v');
else
cmd = (pf ? '+' : '^');
switch (type)
{
case AX25_I:
if (dump)
dump->printf("I%02x%c", ns, cmd);
decodeI(offset, ns, nr, pf);
break;
case AX25_U_SABME:
case AX25_U_SABM:
if (dump)
dump->printf("SABM%c", cmd);
decodeSABM(pf, type == AX25_U_SABME);
break;
case AX25_U_DISC:
if (dump)
dump->printf("DISC%c", cmd);
decodeDISC(pf);
break;
case AX25_U_UA:
if (dump)
dump->printf("UA%c", cmd);
decodeUA(pf);
break;
case AX25_U_DM:
if (dump)
dump->printf("DM%c", cmd);
decodeDM(pf);
break;
case AX25_U_FRMR:
if (dump)
dump->printf("FRMR%c", cmd);
decodeFRMR(pf);
break;
case AX25_U_UI:
if (dump)
dump->printf("UI%c", cmd);
decodeUI(offset, pf);
break;
case AX25_U_XID:
if (dump)
dump->printf("XID%c", cmd);
decodeXID(pf);
break;
case AX25_U_TEST:
if (dump)
dump->printf("TEST%c", cmd);
decodeTEST(pf);
break;
case AX25_S_RR:
if (dump)
dump->printf("RR%d%c", nr, cmd);
decodeRR(pf);
break;
case AX25_S_RNR:
if (dump)
dump->printf("RNR%d%c", nr, cmd);
decodeRR(pf, true);
break;
case AX25_S_REJ:
if (dump)
dump->printf("REJ%d%c", nr, cmd);
decodeREJ(pf);
break;
case AX25_S_SREJ:
if (dump)
dump->printf("SREJ%d%c", nr, cmd);
decodeSREJ(pf);
break;
case AX25_U:
case AX25_INVALID:
break;
}
}
size_t Link::decodeAddresses(bool *response)
{
if (rx.length < 14)
return 0;
uint8_t *buffer = rx.data;
size_t length = rx.length;
if (response != nullptr)
{
*response = false;
if (buffer[6] & 0x80)
*response = false;
if (buffer[13] & 0x80)
*response = true;
}
std::memcpy(dst.call, buffer, 7);
buffer += 7;
length -= 7;
std::memcpy(src.call, buffer, 7);
buffer += 7;
length -= 7;
path.last = -1;
path.hops = 0;
while (!(buffer[-1] & 0x01))
{
if (path.hops >= AX25_MAX_DIGIS)
return false;
if (length < 7)
return false;
memcpy(path.calls[path.hops].call, buffer, 7);
if (buffer[6] & 0x80)
{
path.repeated[path.hops] = true;
path.last = path.hops;
}
else
{
path.repeated[path.hops] = false;
}
path.hops = min(path.hops + 1, 1);
buffer += 7;
length -= 7;
}
return rx.length - length;
}
void Link::dumpTo(Stream *stream)
{
dump = stream;
}
void Link::decodeI(size_t offset, int ns, int nr, bool pf)
{
uint8_t pid = rx.data[offset];
if (dump)
dump->printf(" pid=0x%02x(%s) len=%d\n", pid, pid_name(pid), rx.length - offset - 1);
switch (state)
{
case AX25_DISCONNECTED:
case AX25_WAIT_CONNECT:
// ignored
break;
case AX25_WAIT_DISCONNECT:
if (pf)
{
sendControl(AX25_U_DM, true, true);
}
break;
case AX25_CONNECTED:
if (!validateNR(nr))
{
if (modulus == AX25_MODULUS)
sendControl(AX25_U_SABM, true, false);
else
sendControl(AX25_U_SABME, true, false);
UPDATE_STATE(AX25_WAIT_CONNECT);
break;
}
va = nr;
if (ns == vr)
{
vr = (vr + 1) % modulus;
if (pf)
{
sendControl(AX25_S_RR, true, true);
}
}
else
{
if (pf)
{
sendControl(AX25_S_RR, true, true);
}
}
if (pid == 0xf0)
{
offset++;
char *buffer = (char *)rx.data + offset;
size_t length = rx.length - offset;
port.doText(this, buffer, length);
}
break;
case AX25_RECOVERY:
break;
}
}
void Link::decodeSABM(bool pf, bool extended)
{
if (dump)
dump->println();
switch (state)
{
case AX25_DISCONNECTED:
case AX25_WAIT_CONNECT:
modulus = (extended ? AX25_EXTENDED_MODULUS : AX25_MODULUS);
window = 0; // TODO
if (port.doConnect(this))
{
UPDATE_STATE(AX25_CONNECTED);
sendControl(AX25_U_UA, pf, true);
}
else
{
sendControl(AX25_U_DM, pf, true);
}
break;
case AX25_WAIT_DISCONNECT:
sendControl(AX25_U_DM, pf, true);
break;
case AX25_CONNECTED:
case AX25_RECOVERY:
modulus = (extended ? AX25_EXTENDED_MODULUS : AX25_MODULUS);
sendControl(AX25_U_UA, pf, true);
vr = 0;
break;
}
}
void Link::decodeDISC(bool pf)
{
if (dump)
dump->println();
switch (state)
{
case AX25_DISCONNECTED:
sendControl(AX25_U_DM, pf, true);
break;
case AX25_WAIT_CONNECT:
case AX25_WAIT_DISCONNECT:
case AX25_CONNECTED:
port.doDisconnect(this);
sendControl(AX25_U_DM, pf, true);
UPDATE_STATE(AX25_DISCONNECTED);
break;
case AX25_RECOVERY:
sendControl(AX25_U_UA, pf, true);
UPDATE_STATE(AX25_DISCONNECTED);
break;
}
}
void Link::decodeUA(bool pf)
{
if (dump)
dump->println();
switch (state)
{
case AX25_DISCONNECTED:
break;
case AX25_WAIT_CONNECT:
if (pf)
{
vr = 0;
UPDATE_STATE(AX25_CONNECTED);
}
break;
case AX25_WAIT_DISCONNECT:
if (pf)
{
UPDATE_STATE(AX25_DISCONNECTED);
}
break;
case AX25_CONNECTED:
break;
case AX25_RECOVERY:
break;
}
}
void Link::decodeDM(bool pf)
{
if (dump)
dump->println();
switch (state)
{
case AX25_DISCONNECTED:
case AX25_WAIT_CONNECT:
if (pf)
{
if (modulus == AX25_MODULUS)
{
UPDATE_STATE(AX25_DISCONNECTED);
}
else
{
modulus = AX25_MODULUS;
}
}
break;
case AX25_WAIT_DISCONNECT:
if (pf)
{
UPDATE_STATE(AX25_DISCONNECTED);
}
break;
case AX25_CONNECTED:
UPDATE_STATE(AX25_DISCONNECTED);
break;
case AX25_RECOVERY:
UPDATE_STATE(AX25_DISCONNECTED);
break;
}
}
void Link::decodeFRMR(bool pf)
{
if (dump)
dump->println();
}
void Link::decodeUI(size_t offset, bool pf)
{
uint8_t pid = rx.data[offset];
if (dump)
dump->printf(" pid=0x%02x(%s) len=%d\n", pid, pid_name(pid), rx.length - offset - 1);
if (pid == 0xf0)
{
offset++;
char *buffer = (char *)rx.data + offset;
size_t length = rx.length - offset;
port.doBroadcast(this, buffer, length);
}
}
void Link::decodeXID(bool pf)
{
if (dump)
dump->println();
}
void Link::decodeTEST(bool pf)
{
if (dump)
dump->println();
}
void Link::decodeRR(bool pf, bool reject)
{
if (dump)
dump->println();
}
void Link::decodeREJ(bool pf)
{
if (dump)
dump->println();
}
void Link::decodeSREJ(bool pf)
{
if (dump)
dump->println();
}
FrameType Link::decodeType(size_t *offset, int *ns, int *nr, bool *pf)
{
if (rx.length < 15)
return AX25_INVALID;
FrameType type = AX25_INVALID;
uint8_t *frame = rx.data + *offset;
size_t position = *offset + 1;
if ((frame[0] & 0x01) == 0)
{
/* I-frame */
type = AX25_I;
if (modulus == AX25_MODULUS)
{
*ns = (frame[0] >> 1) & 0x07;
*nr = (frame[0] >> 5) & 0x07;
*pf = (frame[0] >> 4) & 0x01;
}
else
{
*ns = (frame[0] >> 1) & 0x7F;
*nr = (frame[1] >> 1) & 0x7F;
*pf = (frame[1]) & 0x01;
position++;
}
}
else if ((frame[0] & 0x03) == 0x01)
{
/* S-frame */
type = (FrameType)((int)AX25_S_RR + ((frame[0] & 0x0c) >> 2));
if (modulus == AX25_MODULUS)
{
*nr = (frame[0] >> 5) & 0x07;
*pf = (frame[0] >> 4) & 0x01;
}
else
{
*nr = (frame[1] >> 1) & 0x7f;
*pf = (frame[1]) & 0x01;
position++;
}
}
else if ((frame[0] & 0x03) == 0x03)
{
/* U-frame */
switch (frame[0] & 0xef)
{
case 0x6f:
type = AX25_U_SABME;
break;
case 0x2f:
type = AX25_U_SABM;
break;
case 0x43:
type = AX25_U_DISC;
break;
case 0x0f:
type = AX25_U_DM;
break;
case 0x63:
type = AX25_U_UA;
break;
case 0x87:
type = AX25_U_FRMR;
break;
case 0x03:
type = AX25_U_UI;
break;
case 0xaf:
type = AX25_U_XID;
break;
case 0xe3:
type = AX25_U_TEST;
break;
default:
return type;
}
if (modulus == AX25_MODULUS)
{
*pf = (frame[0] >> 4) & 0x01;
}
else
{
*pf = (frame[1]) & 0x01;
position++;
}
}
*offset = position;
return type;
}
void Link::encodeHeader(bool response, bool invert)
{
size_t length = sizeof(src.call) * (2 + path.hops);
uint8_t *buffer;
std::memmove(tx.data + length, tx.data, length);
buffer = tx.data;
length = 0;
if (invert)
{
static Path swapped;
char tmp[7];
std::memcpy(tmp, dst.call, 7);
std::memcpy(dst.call, src.call, 7);
std::memcpy(src.call, tmp, 7);
path.invert(swapped);
std::memcpy(&path, &swapped, sizeof(Path));
}
// Target call
std::memcpy(buffer, dst.call, 7);
buffer[6] &= 0x7e;
buffer[6] |= AX25_SSID_UNUSED_BITS;
if (!response)
buffer[6] |= 0x80;
buffer += 7;
length += 7;
// Source call
std::memcpy(buffer, src.call, 7);
buffer[6] &= 0x7e;
buffer[6] &= ~AX25_SSID_UNUSED_BITS;
buffer[6] |= (modulus == AX25_MODULUS ? AX25_SSID_UNUSED_BITS : AX25_ESSID_UNUSED_BITS);
if (response)
buffer[6] |= 0x80;
if (path.hops == 0)
{
buffer[6] |= 0x01;
tx.length += 14;
return;
}
buffer += 7;
length += 7;
for (uint8_t i = 0; i < path.hops; i++)
{
memcpy(buffer, path.calls[i].call, 7);
if (path.repeated[i])
buffer[6] |= 0x80;
else
buffer[6] &= 0x7f;
buffer[6] &= 0xfe;
buffer[6] |= AX25_SSID_UNUSED_BITS;
buffer += 7;
length += 7;
}
buffer[-1] |= 0x01;
tx.length += length;
}
void Link::encodeControl(FrameType type, bool poll, bool response, bool invert)
{
if (type < AX25_S_RR || type > AX25_U_TEST)
return; // Only S- and U-frames
uint8_t *out;
if (modulus == AX25_MODULUS)
{
switch (type)
{
case AX25_S_RR:
case AX25_S_RNR:
case AX25_S_REJ:
case AX25_S_SREJ:
out = tx.reserve(1);
*out = 0x01;
*out |= ((uint8_t)(type - AX25_S_RR)) << 2;
*out |= vr << 5;
break;
default:
out = tx.reserve(1);
switch (type)
{
case AX25_U_SABME:
*out = 0x6f;
break;
case AX25_U_SABM:
*out = 0x2f;
break;
case AX25_U_DISC:
*out = 0x43;
break;
case AX25_U_DM:
*out = 0x0f;
break;
case AX25_U_UA:
*out = 0x63;
break;
case AX25_U_FRMR:
*out = 0x87;
break;
case AX25_U_UI:
*out = 0x03;
break;
case AX25_U_XID:
*out = 0xaf;
break;
case AX25_U_TEST:
*out = 0xe3;
break;
default:
break;
}
break;
}
*out |= (poll ? 0x10 : 0x00);
}
else
{
switch (type)
{
case AX25_S_RR:
case AX25_S_RNR:
case AX25_S_REJ:
case AX25_S_SREJ:
out = tx.reserve(2);
out[0] = 0x01;
out[0] |= (((uint8_t)(type - AX25_S_RR)) << 2);
out[1] = (vr << 5);
out[1] |= (poll ? 0x01 : 0x00);
break;
default:
out = tx.reserve(1);
switch (type)
{
case AX25_U_SABME:
*out = 0x6f;
break;
case AX25_U_SABM:
*out = 0x2f;
break;
case AX25_U_DISC:
*out = 0x43;
break;
case AX25_U_DM: