diff --git a/.github/workflows/codeql-analysis-python.yml b/.github/workflows/codeql-analysis-python.yml
new file mode 100644
index 0000000..a47a8f8
--- /dev/null
+++ b/.github/workflows/codeql-analysis-python.yml
@@ -0,0 +1,64 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL - Python"
+
+on:
+ push:
+ branches: [ dev ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ dev ]
+ schedule:
+ - cron: '25 8 * * 4'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'python' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ setup-python-dependencies: true
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v3
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 7134f21..a86300f 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -9,7 +9,7 @@
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
-name: "CodeQL"
+name: "CodeQL - CPP"
on:
push:
@@ -32,19 +32,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: [ 'cpp', 'python' ]
+ language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
+ setup-python-dependencies: true
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
@@ -53,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v1
+ uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -70,4 +71,4 @@ jobs:
make test
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@v3
diff --git a/.gitignore b/.gitignore
index 659c845..b917a7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,5 +109,5 @@ $RECYCLE.BIN/
*.dSYM
# cmake
-build/
+build*/
tmp/
\ No newline at end of file
diff --git a/CHANGES.md b/CHANGES.md
index 4b78ca1..0903e9e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,12 @@
# Revision History #
+## Version 1.8 -- Development Version
+
+### New Features: ###
+
+- [http://www.aprs.org/aprs11/tocalls.txt](http://www.aprs.org/aprs11/tocalls.txt) has been abandoned since the end of 2021. [https://github.com/aprsorg/aprs-deviceid](https://github.com/aprsorg/aprs-deviceid) is now considered to be the authoritative source of truth for the vendor/model encoding.
+
## Version 1.7 -- October 2023 ##
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 20aa28f..966fbaf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,10 +1,10 @@
-cmake_minimum_required(VERSION 3.1.0)
+cmake_minimum_required(VERSION 3.5.0)
project(direwolf)
# configure version
set(direwolf_VERSION_MAJOR "1")
-set(direwolf_VERSION_MINOR "7")
+set(direwolf_VERSION_MINOR "8")
set(direwolf_VERSION_PATCH "0")
set(direwolf_VERSION_SUFFIX "Development")
@@ -320,6 +320,14 @@ else()
set(HAMLIB_LIBRARIES "")
endif()
+find_package(gpiod)
+if(GPIOD_FOUND)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_GPIOD")
+else()
+ set(GPIOD_INCLUDE_DIRS "")
+ set(GPIOD_LIBRARIES "")
+endif()
+
if(LINUX)
find_package(ALSA REQUIRED)
if(ALSA_FOUND)
diff --git a/cmake/include/uninstall.cmake.in b/cmake/include/uninstall.cmake.in
index 2037e36..8ddc56a 100644
--- a/cmake/include/uninstall.cmake.in
+++ b/cmake/include/uninstall.cmake.in
@@ -7,10 +7,10 @@ string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
- exec_program(
- "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ execute_process(
+ COMMAND "@CMAKE_COMMAND@" -E remove "$ENV{DESTDIR}${file}"
OUTPUT_VARIABLE rm_out
- RETURN_VALUE rm_retval
+ RESULT_VARIABLE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
diff --git a/cmake/modules/FindCompiler.cmake b/cmake/modules/FindCompiler.cmake
index fe036e4..91e1b89 100644
--- a/cmake/modules/FindCompiler.cmake
+++ b/cmake/modules/FindCompiler.cmake
@@ -5,9 +5,9 @@ elseif(NOT DEFINED C_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(C_GCC 1)
elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(C_MSVC 1)
- if(MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS_EQUAL 1929)
+ if(MSVC_VERSION GREATER 1919 AND MSVC_VERSION LESS 1926)
set(VS2019 ON)
- elseif(MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS_EQUAL 1919)
+ elseif(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919)
set(VS2017 ON)
elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910)
set(VS2015 ON)
diff --git a/cmake/modules/Findgpiod.cmake b/cmake/modules/Findgpiod.cmake
new file mode 100644
index 0000000..bf5be30
--- /dev/null
+++ b/cmake/modules/Findgpiod.cmake
@@ -0,0 +1,23 @@
+# - Try to find libgpiod
+# Once done this will define
+# GPIOD_FOUND - System has libgpiod
+# GPIOD_INCLUDE_DIRS - The libgpiod include directories
+# GPIOD_LIBRARIES - The libraries needed to use libgpiod
+# GPIOD_DEFINITIONS - Compiler switches required for using libgpiod
+
+find_package(PkgConfig)
+pkg_check_modules(PC_GPIOD QUIET gpiod)
+
+find_path(GPIOD_INCLUDE_DIR gpiod.h)
+find_library(GPIOD_LIBRARY NAMES gpiod)
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set GPIOD_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(gpiod DEFAULT_MSG
+ GPIOD_LIBRARY GPIOD_INCLUDE_DIR)
+
+mark_as_advanced(GPIOD_INCLUDE_DIR GPIOD_LIBRARY)
+
+set(GPIOD_LIBRARIES ${GPIOD_LIBRARY})
+set(GPIOD_INCLUDE_DIRS ${GPIOD_INCLUDE_DIR})
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index 7972cc2..11a82a4 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -16,7 +16,7 @@
#
# The destination field is often used to identify the manufacturer/model.
# These are not hardcoded into Dire Wolf. Instead they are read from
-# a file called tocalls.txt at application start up time.
+# a file called tocalls.yaml at application start up time.
#
# The original permanent symbols are built in but the "new" symbols,
# using overlays, are often updated. These are also read from files.
@@ -25,17 +25,17 @@
include(ExternalProject)
-set(TOCALLS_TXT "tocalls.txt")
+set(TOCALLS_YAML "tocalls.yaml")
set(SYMBOLS-NEW_TXT "symbols-new.txt")
set(SYMBOLSX_TXT "symbolsX.txt")
set(CUSTOM_BINARY_DATA_DIR "${CMAKE_BINARY_DIR}/data")
# we can also move to a separate cmake file and use file(download)
# see conf/install_conf.cmake as example
-file(COPY "${CUSTOM_DATA_DIR}/${TOCALLS_TXT}" DESTINATION "${CUSTOM_BINARY_DATA_DIR}")
+file(COPY "${CUSTOM_DATA_DIR}/${TOCALLS_YAML}" DESTINATION "${CUSTOM_BINARY_DATA_DIR}")
file(COPY "${CUSTOM_DATA_DIR}/${SYMBOLS-NEW_TXT}" DESTINATION "${CUSTOM_BINARY_DATA_DIR}")
file(COPY "${CUSTOM_DATA_DIR}/${SYMBOLSX_TXT}" DESTINATION "${CUSTOM_BINARY_DATA_DIR}")
-install(FILES "${CUSTOM_BINARY_DATA_DIR}/${TOCALLS_TXT}" DESTINATION ${INSTALL_DATA_DIR})
+install(FILES "${CUSTOM_BINARY_DATA_DIR}/${TOCALLS_YAML}" DESTINATION ${INSTALL_DATA_DIR})
install(FILES "${CUSTOM_BINARY_DATA_DIR}/${SYMBOLS-NEW_TXT}" DESTINATION ${INSTALL_DATA_DIR})
install(FILES "${CUSTOM_BINARY_DATA_DIR}/${SYMBOLSX_TXT}" DESTINATION ${INSTALL_DATA_DIR})
diff --git a/data/README.txt b/data/README.txt
new file mode 100644
index 0000000..9d4da43
--- /dev/null
+++ b/data/README.txt
@@ -0,0 +1,18 @@
+
+tocalls.yaml contains the encoding for the device/system/software
+identifier which created the packet.
+Knowing what generated the packet is very useful for troubleshooting.
+TNCs, digipeaters, and IGates must not change this.
+
+For MIC-E format, well... it's complicated.
+See Understanding-APRS-Packets.pdf. Too long to repeat here.
+
+For all other packet types, the AX.25 destination, or "tocall" field
+contains a code for what generated the packet.
+This is of the form AP????. For example, APDW18 for direwolf 1.8.
+
+The database of identifiers is currently maintained by Hessu, OH7LZB.
+
+You can update your local copy by running:
+
+wget https://raw.githubusercontent.com/aprsorg/aprs-deviceid/main/tocalls.yaml
diff --git a/data/tocalls.txt b/data/tocalls.txt
deleted file mode 100644
index 169c986..0000000
--- a/data/tocalls.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-
-APRS TO-CALL VERSION NUMBERS 14 Dec 2021
----------------------------------------------------------------------
- WB4APR
-
-
-07 Jun 23 Added APK005 for Kenwood TH-D75
-14 Dec 21 Added APATAR ATA-R APRS Digipeater by TA7W/OH2UDS and TA6AEU
-26 Sep 21 Added APRRDZ EPS32 https://github.com/dl9rdz/rdz_ttgo_sonde
-18 Sep 21 Added APCSS for AMSAT Cubesat Simulator https://cubesatsim.org
-16 Sep 21 Added APY05D for Yaesu FT5D series
-04 Sep 21 APLOxx LoRa KISS TNC/Tracker https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS
-24 Aug 21 Added APLSxx SARIMESH http://www.sarimesh.net
-22 Aug 21 Added APE2Ax for VA3NNW's Email-2-APRS ap
-30 Jun 21 Added APCNxx for carNET by DG5OAW
-14 Jun 21 Added APN2xx for NOSaprs JNOS 2.0 - VE4KLM
-24 Apr 21 Added APMPAD for DF1JSL's WXBot clone and extension
-20 Apr 21 Added APLCxx for APRScube by DL3DCW
-19 Apr 21 Added APVMxx for DRCC-DVM Voice (Digital Radio China Club)
-13 Apr 21 Added APIxxx for all Dstar ICOMS (APRS via DPRS)
-23 MAr 20 Added APW9xx For 9A9Y Weather Tracker
-16 Feb 21 Added API970 for I com 9700
-
-2020 Added APHBLx,APIZCI,APLGxx,APLTxx,APNVxx,APY300,APESPG,APESPW
- APGDTx,APOSWx,APOSBx,APBT62,APCLUB,APMQxx
-2019 Added APTPNx,APJ8xx,APBSDx,APNKMX,APAT51,APMGxx,APTCMA,
- APATxx,APQTHx,APLIGx
-2018 added APRARX,APELKx,APGBLN,APBKxx,APERSx,APTCHE
-2017 Added APHWxx,APDVxx,APPICO,APBMxx,APP6xx,APTAxx,APOCSG,APCSMS,
- APPMxx,APOFF,APDTMF,APRSON,APDIGI,APSAT,APTBxx,APIExx,
- APSFxx
-2016 added APYSxx,APINxx,APNICx,APTKPT,APK004,APFPRS,APCDS0,APDNOx
-2015 Added APSTPO,APAND1,APDRxx,APZ247,APHTxx,APMTxx,APZMAJ
- APB2MF,APR2MF,APAVT5
-
-
-
-
-In APRS, the AX.25 Destination address is not used for packet
-routing as is normally done in AX.25. So APRS uses it for two
-things. The initial APxxxx is used as a group identifier to make
-APRS packets instanantly recognizable on shared channels. Most
-applicaitons ignore all non APRS packets. The remaining 4 xxxx
-bytes of the field are available to indicate the software version
-number or application. The following applications have requested
-a TOCALL number series:
-
-Authors with similar alphabetic requirements are encouraged to share
-their address space with other software. Work out agreements amongst
-yourselves and keep me informed.
-
-
-
-
- APn 3rd digit is a number
- AP1WWX TAPR T-238+ WX station
- AP1MAJ Martyn M1MAJ DeLorme inReach Tracker
- AP4Rxy APRS4R software interface
- APnnnD Painter Engineering uSmartDigi D-Gate DSTAR Gateway
- APnnnU Painter Engineering uSmartDigi Digipeater
- APA APAFxx AFilter.
- APAGxx AGATE
- APAGWx SV2AGW's AGWtracker
- APALxx Alinco DR-620/635 internal TNC digis. "Hachi" ,JF1AJE
- APAXxx AFilterX.
- APAHxx AHub
- APAND1 APRSdroid (pre-release) http://aprsdroid.org/
- APAMxx Altus Metrum GPS trackers
- APATAR ATA-R APRS Digipeater by TA7W/OH2UDS and TA6AEU
- APAT8x for Anytone. 81 for 878 HT
- APAT51 for Anytone AT-D578UV APRS mobile radio
- APAVT5 SainSonic AP510 which is a 1watt tracker
- APAWxx AGWPE
- APB APBxxx Beacons or Rabbit TCPIP micros?
- APB2MF DL2MF - MF2APRS Radiosonde for balloons
- APBLxx BigRedBee BeeLine
- APBLO MOdel Rocketry K7RKT
- APBKxx PY5BK Bravo Tracker in Brazil
- APBPQx John G8BPQ Digipeater/IGate
- APBMxx BrandMeister DMR Server for R3ABM
- APBSDx HamBSD https://hambsd.org/
- APBT62 BTech DMR 6x2
- APC APCxxx Cellular applications
- APCBBx VE7UDP Blackberry Applications
- APCDS0 Leon Lessing ZS6LMG's cell tracker
- APCLEY EYTraker GPRS/GSM tracker by ZS6EY
- APCLEZ Telit EZ10 GSM application ZS6CEY
- APCLUB Brazil APRS network
- APCLWX EYWeather GPRS/GSM WX station by ZS6EY
- APCNxx for carNET by DG5OAW
- APCSMS for Cosmos (used for sending commands @USNA)
- APCSS for AMSAT cubesats https://cubesatsim.org
- APCWP8 John GM7HHB, WinphoneAPRS
- APCYxx Cybiko applications
- APD APD4xx UP4DAR platform
- APDDxx DV-RPTR Modem and Control Center Software
- APDFxx Automatic DF units
- APDGxx D-Star Gateways by G4KLX ircDDB
- APDHxx WinDV (DUTCH*Star DV Node for Windows)
- APDInn DIXPRS - Bela, HA5DI
- APDIGI Used by PSAT2 to indicate the digi is ON
- APDIGI digi ON for PSAT2 and QIKCOM-2
- APDKxx KI4LKF g2_ircddb Dstar gateway software
- APDNOx APRSduino by DO3SWW
- APDOxx ON8JL Standalone DStar Node
- APDPRS D-Star originated posits
- APDRxx APRSdroid Android App http://aprsdroid.org/
- APDSXX SP9UOB for dsDigi and ds-tracker
- APDTxx APRStouch Tone (DTMF)
- APDTMF digi off mode on QIKCOM2 and DTMF ON
- APDUxx U2APRS by JA7UDE
- APDVxx OE6PLD's SSTV with APRS status exchange
- APDWxx DireWolf, WB2OSZ
- APE APExxx Telemetry devices
- APE2Ax VA3NNW's Email-2-APRS ap
- APECAN Pecan Pico APRS Balloon Tracker
- APELKx WB8ELK balloons
- APERXQ Experimental tracker by PE1RXQ
- APERSx Runner tracking by Jason,KG7YKZ
- APESPG ESP SmartBeacon APRS-IS Client
- APESPW ESP Weather Station APRS-IS Client
- APF APFxxx Firenet
- APFGxx Flood Gage (KP4DJT)
- APFIxx for APRS.FI OH7LZB, Hessu
- APFPRS for FreeDV by Jeroen PE1RXQ
- APG APGxxx Gates, etc
- APGOxx for AA3NJ PDA application
- APGBLN for NW5W's GoBalloon
- APGDTx for VK4FAST's Graphic Data Terminal
- APH APHKxx for LA1BR tracker/digipeater
- APHAXn SM2APRS by PY2UEP
- APHBLx for DMR Gateway by Eric - KF7EEL
- APHTxx HMTracker by IU0AAC
- APHWxx for use in "HamWAN
- API API282 for ICOM IC-2820
- API31 for ICOM ID-31
- API410 for ICOM ID-4100
- API51 for ICOM ID-51
- API510 for ICOM ID-5100
- API710 for ICOM IC-7100
- API80 for ICOM IC-80
- API880 for ICOM ID-880
- API910 for ICOM IC-9100
- API92 for ICOM IC-92
- API970 for ICOM 9700
- APICQx for ICQ
- APICxx HA9MCQ's Pic IGate
- APIExx W7KMV's PiAPRS system
- APINxx PinPoint by AB0WV
- APIZCI hymTR IZCI Tracker by TA7W/OH2UDS and TA6AEU
- APJ APJ8xx Jordan / KN4CRD JS8Call application
- APJAxx JavAPRS
- APJExx JeAPRS
- APJIxx jAPRSIgate
- APJSxx javAPRSSrvr
- APJYnn KA2DDO Yet another APRS system
- APK APK0xx Kenwood TH-D7's
- APK003 Kenwood TH-D72
- APK004 Kenwood TH-D74
- APK005 Kenwood TH-D75
- APK1xx Kenwood D700's
- APK102 Kenwood D710
- APKRAM KRAMstuff.com - Mark. G7LEU
- APL APLCxx APRScube by DL3DCW
- APLGxx LoRa Gateway/Digipeater OE5BPA
- APLIGx LightAPRS - TA2MUN and TA9OHC
- APLOxx LoRa KISS TNC/Tracker
- APLQRU Charlie - QRU Server
- APLMxx WA0TQG transceiver controller
- APLSxx SARIMESH ( http://www.sarimesh.net )
- APLTxx LoRa Tracker - OE5BPA
- APM APMxxx MacAPRS,
- APMGxx PiCrumbs and MiniGate - Alex, AB0TJ
- APMIxx SQ3PLX http://microsat.com.pl/
- APMPAD DF1JSL's WXBot clone and extension
- APMQxx Ham Radio of Things WB2OSZ
- APMTxx LZ1PPL for tracker
- APN APNxxx Network nodes, digis, etc
- APN2xx NOSaprs for JNOS 2.0 - VE4KLM
- APN3xx Kantronics KPC-3 rom versions
- APN9xx Kantronics KPC-9612 Roms
- APNAxx WB6ZSU's APRServe
- APNDxx DIGI_NED
- APNICx SQ5EKU http://sq5eku.blogspot.com/
- APNK01 Kenwood D700 (APK101) type
- APNK80 KAM version 8.0
- APNKMP KAM+
- APNKMX KAM-XL
- APNMxx MJF TNC roms
- APNPxx Paccom TNC roms
- APNTxx SV2AGW's TNT tnc as a digi
- APNUxx UIdigi
- APNVxx SQ8L's VP digi and Nodes
- APNXxx TNC-X (K6DBG)
- APNWxx SQ3FYK.com WX/Digi and SQ3PLX http://microsat.com.pl/
- APO APRSpoint
- APOFF Used by PSAT and PSAT2 to indicate the digi is OFF
- APOLUx for OSCAR satellites for AMSAT-LU by LU9DO
- APOAxx OpenAPRS - Greg Carter
- APOCSG For N0AGI's APRS to POCSAG project
- APOD1w Open Track with 1 wire WX
- APOSBx openSPOT3 by HA2NON at sharkrf.com
- APOSWx openSPOT2
- APOTxx Open Track
- APOU2k Open Track for Ultimeter
- APOZxx www.KissOZ.dk Tracker. OZ1EKD and OZ7HVO
- APP APP6xx for APRSlib
- APPICx DB1NTO' PicoAPRS
- APPMxx DL1MX's RTL-SDR pytohon Igate
- APPTxx KetaiTracker by JF6LZE, Takeki (msg capable)
- APQ APQxxx Earthquake data
- APQTHx W8WJB's QTH.app
- APR APR8xx APRSdos versions 800+
- APR2MF DL2MF - MF2APRS Radiosonde WX reporting
- APRARX VK5QI's radiosonde tracking
- APRDxx APRSdata, APRSdr
- APRGxx aprsg igate software, OH2GVE
- APRHH2 HamHud 2
- APRKxx APRStk
- APRNOW W5GGW ipad application
- APRRTx RPC electronics
- APRS Generic, (obsolete. Digis should use APNxxx instead)
- APRSON Used by PSAT to indicate the DIGI is ON
- APRXxx >40 APRSmax
- APRXxx <39 for OH2MQK's igate
- APRTLM used in MIM's and Mic-lites, etc
- APRtfc APRStraffic
- APRSTx APRStt (Touch tone)
- APS APSxxx APRS+SA, etc
- APSARx ZL4FOX's SARTRACK
- APSAT digi ON for QIKCOM-1
- APSCxx aprsc APRS-IS core server (OH7LZB, OH2MQK)
- APSFxx F5OPV embedded devices - was APZ40
- APSK63 APRS Messenger -over-PSK63
- APSK25 APRS Messenger GMSK-250
- APSMSx Paul Dufresne's SMSGTE - SMS Gateway
- APSTMx for W7QO's Balloon trackers
- APSTPO for N0AGI Satellite Tracking and Operations
- APT APT2xx Tiny Track II
- APT3xx Tiny Track III
- APTAxx K4ATM's tiny track
- APTBxx TinyAPRS by BG5HHP Was APTAxx till Sep 2017
- APTCHE PU3IKE in Brazil TcheTracker/Tcheduino
- APTCMA CAPI tracker - PU1CMA Brazil
- APTIGR TigerTrack
- APTKPT TrackPoint N0LP
- APTPNx TARPN Packet Node Tracker by KN4ORB http://tarpn.net/
- APTTxx Tiny Track
- APTWxx Byons WXTrac
- APTVxx for ATV/APRN and SSTV applications
- APU APU1xx UIview 16 bit applications
- APU2xx UIview 32 bit apps
- APU3xx UIview terminal program
- APUDRx NW Digital Radio's UDR (APRS/Dstar)
- APV APVxxx Voice over Internet applications
- APVMxx DRCC-DVM Digital Voice (Digital Radio China Club)
- APVRxx for IRLP
- APVLxx for I-LINK
- APVExx for ECHO link
- APW APWxxx WinAPRS, etc
- APW9xx 9A9Y Weather Tracker
- APWAxx APRSISCE Android version
- APWSxx DF4IAN's WS2300 WX station
- APWMxx APRSISCE KJ4ERJ
- APWWxx APRSISCE win32 version
- APX APXnnn Xastir
- APXRnn Xrouter
- APY APYxxx Yaesu Radios
- APY008 Yaesu VX-8 series
- APY01D Yaesu FT1D series
- APY02D Yaesu FT2D series
- APY03D Yaesu FT3D series
- APY05D Yaesu FT5D series
- APY100 Yaesu FTM-100D series
- APY300 Yaesu FTM-300D series
- APY350 Yaesu FTM-350 series
- APY400 Yaesu FTM-400D series
- APZ APZxxx Experimental
- APZ200 old versions of JNOS
- APZ247 for UPRS NR0Q
- APZ0xx Xastir (old versions. See APX)
- APZMAJ Martyn M1MAJ DeLorme inReach Tracker
- APZMDM github/codec2_talkie - product code not registered
- APZMDR for HaMDR trackers - hessu * hes.iki.fi]
- APZPAD Smart Palm
- APZTKP TrackPoint, Nick N0LP (Balloon tracking)(depricated)
- APZWIT MAP27 radio (Mountain Rescue) EI7IG
- APZWKR GM1WKR NetSked application
-
-
-
-
-
-
-REGISTERED TOCALL ALTNETS:
---------------------------
-
-ALTNETS are uses of the AX-25 tocall to distinguish specialized
-traffic that may be flowing on the APRS-IS, but that are not intended
-to be part of normal APRS distribution to all normal APRS software
-operating in normal (default) modes. Proper APRS software that
-honors this design are supposed to IGNORE all ALTNETS unless the
-particular operator has selected an ALTNET to monitor for.
-
-An example is when testing; an author may want to transmit objects
-all over his map for on-air testing, but does not want these to
-clutter everyone's maps or databases. He could use the ALTNET of
-"TEST" and client APRS software that respects the ALTNET concept
-should ignore these packets.
-
-An ALTNET is defined to be ANY AX.25 TOCALL that is NOT one of the
-normal APRS TOCALL's. The normal TOCALL's that APRS is supposed to
-process are: ALL, BEACON, CQ, QST, GPSxxx and of course APxxxx.
-
-The following is a list of ALTNETS that may be of interest to other
-users. This list is by no means complete, since ANY combination of
-characters other than APxxxx are considered an ALTNET. But this list
-can give consisntecy to ALTNETS that may be using the global APRS-IS
-and need some special recognition. Here are some ideas:
-
-
-
- SATERN - Salvation Army Altnet
- AFMARS - Airforce Mars
- AMARS - Army Mars
-
\ No newline at end of file
diff --git a/data/tocalls.yaml b/data/tocalls.yaml
new file mode 100644
index 0000000..0df0478
--- /dev/null
+++ b/data/tocalls.yaml
@@ -0,0 +1,1637 @@
+#
+# This is a machine-readable index of APRS device and software
+# identification strings. For easy manual editing and validation, the
+# master file is in YAML format. A conversion tool and pre-converted
+# versions in XML and JSON are also provided for environments where those
+# are more convenient to parse.
+#
+# This list is maintained by Hessu, OH7LZB, for the aprs.fi service.
+# It is licensed under the CC BY-SA 2.0 license, so you're free to use
+# it in any of your applications. For free. Just mention the source
+# somewhere in the small print.
+# http://creativecommons.org/licenses/by-sa/2.0/
+#
+
+---
+
+#
+# English shown names and descriptions for device classes
+#
+classes:
+ - class: wx
+ shown: Weather station
+ description: Dedicated weather station
+
+ - class: tracker
+ shown: Tracker
+ description: Tracker device
+
+ - class: rig
+ shown: Rig
+ description: Mobile or desktop radio
+
+ - class: ht
+ shown: HT
+ description: Hand-held radio
+
+ - class: app
+ shown: Mobile app
+ description: Mobile phone or tablet app
+
+ - class: software
+ shown: Software
+ description: Desktop software
+
+ - class: digi
+ shown: Digipeater
+ description: Digipeater software
+
+ - class: igate
+ shown: iGate
+ description: iGate software
+
+ - class: dstar
+ shown: D-Star
+ description: D-Star radio
+
+ - class: satellite
+ shown: Satellite
+ description: Satellite-based station
+
+ - class: service
+ shown: Service
+ description: Software running as a web service
+
+#
+# mic-e device identifier index for new-style 2-character device
+# suffixes. The first prefix byte indicates messaging capability.
+#
+mice:
+ - suffix: "_ "
+ vendor: Yaesu
+ model: VX-8
+ class: ht
+
+ - suffix: "_\""
+ vendor: Yaesu
+ model: FTM-350
+ class: rig
+
+ - suffix: "_#"
+ vendor: Yaesu
+ model: VX-8G
+ class: ht
+
+ - suffix: "_$"
+ vendor: Yaesu
+ model: FT1D
+ class: ht
+
+ - suffix: "_("
+ vendor: Yaesu
+ model: FT2D
+ class: ht
+
+ - suffix: "_0"
+ vendor: Yaesu
+ model: FT3D
+ class: ht
+
+ - suffix: "_3"
+ vendor: Yaesu
+ model: FT5D
+ class: ht
+
+ - suffix: "_1"
+ vendor: Yaesu
+ model: FTM-300D
+ class: rig
+
+ - suffix: "_2"
+ vendor: Yaesu
+ model: FTM-200D
+ class: rig
+
+ - suffix: "_4"
+ vendor: Yaesu
+ model: FTM-500D
+ class: rig
+
+ - suffix: "_)"
+ vendor: Yaesu
+ model: FTM-100D
+ class: rig
+
+ - suffix: "_%"
+ vendor: Yaesu
+ model: FTM-400DR
+ class: rig
+
+ - suffix: "(5"
+ vendor: Anytone
+ model: D578UV
+ class: ht
+
+ - suffix: "(8"
+ vendor: Anytone
+ model: D878UV
+ class: ht
+
+ - suffix: "|3"
+ vendor: Byonics
+ model: TinyTrak3
+ class: tracker
+
+ - suffix: "|4"
+ vendor: Byonics
+ model: TinyTrak4
+ class: tracker
+
+ - suffix: "^v"
+ vendor: HinzTec
+ model: anyfrog
+
+ - suffix: "*v"
+ vendor: KissOZ
+ model: Tracker
+ class: tracker
+
+ - suffix: ":2"
+ vendor: SQ8L
+ model: VP-Tracker
+ class: tracker
+
+#
+# mic-e legacy devices, with an unique comment suffix and prefix
+#
+
+micelegacy:
+ - prefix: ">"
+ vendor: Kenwood
+ model: TH-D7A
+ class: ht
+ features:
+ - messaging
+
+ - prefix: ">"
+ suffix: "="
+ vendor: Kenwood
+ model: TH-D72
+ class: ht
+ features:
+ - messaging
+
+ - prefix: ">"
+ suffix: "^"
+ vendor: Kenwood
+ model: TH-D74
+ class: ht
+ features:
+ - messaging
+
+ - prefix: ">"
+ suffix: "&"
+ vendor: Kenwood
+ model: TH-D75
+ class: ht
+ features:
+ - messaging
+
+ - prefix: "]"
+ vendor: Kenwood
+ model: TM-D700
+ class: rig
+ features:
+ - messaging
+
+ - prefix: "]"
+ suffix: "="
+ vendor: Kenwood
+ model: TM-D710
+ class: rig
+ features:
+ - messaging
+
+#
+# TOCALL index
+#
+tocalls:
+ - tocall: AP1WWX
+ vendor: TAPR
+ model: T-238+
+ class: wx
+
+ - tocall: AP4R??
+ vendor: Open Source
+ model: APRS4R
+ class: software
+
+ - tocall: APAEP1
+ vendor: Paraguay Space Agency (AEP)
+ model: "EIRUAPRSDIGIS&FV1"
+ class: satellite
+
+ - tocall: APAF??
+ model: AFilter
+
+ - tocall: APAG??
+ model: AGate
+
+ - tocall: APAGW
+ vendor: SV2AGW
+ model: AGWtracker
+ class: software
+ os: Windows
+
+ - tocall: APAGW?
+ vendor: SV2AGW
+ model: AGWtracker
+ class: software
+ os: Windows
+
+ - tocall: APAH??
+ model: AHub
+
+ - tocall: APAIOR
+ vendor: J. Angelo Racoma DU2XXR/N2RAC
+ model: APRSPH net bot based on Ioreth
+ class: service
+ os: linux
+ contact: info@aprsph.net
+ features:
+ - messaging
+
+ - tocall: APAM??
+ vendor: Altus Metrum
+ model: AltOS
+ class: tracker
+
+ - tocall: APAND?
+ vendor: Open Source
+ model: APRSdroid
+ os: Android
+ class: app
+
+ - tocall: APAR??
+ vendor: Øyvind, LA7ECA
+ model: Arctic Tracker
+ class: tracker
+ os: embedded
+
+ - tocall: APAT51
+ vendor: Anytone
+ model: AT-D578
+ class: rig
+
+ - tocall: APAT81
+ vendor: Anytone
+ model: AT-D878
+ class: ht
+
+ - tocall: APAT??
+ vendor: Anytone
+
+ - tocall: APATAR
+ vendor: TA7W/OH2UDS Baris Dinc and TA6AEU
+ model: ATA-R APRS Digipeater
+ class: digi
+
+ - tocall: APAVT5
+ vendor: SainSonic
+ model: AP510
+ class: tracker
+
+ - tocall: APAW??
+ vendor: SV2AGW
+ model: AGWPE
+ class: software
+ os: Windows
+
+ - tocall: APAX??
+ model: AFilterX
+
+ - tocall: APB2MF
+ vendor: Mike, DL2MF
+ model: MF2APRS Radiosonde tracking tool
+ class: software
+ os: Windows
+
+ - tocall: APBK??
+ vendor: PY5BK
+ model: Bravo Tracker
+ class: tracker
+
+ - tocall: APBL??
+ vendor: BigRedBee
+ model: BeeLine GPS
+ class: tracker
+
+ - tocall: APBM??
+ vendor: R3ABM
+ model: BrandMeister DMR
+
+ - tocall: APBPQ?
+ vendor: John Wiseman, G8BPQ
+ model: BPQ32
+ class: software
+ os: Windows
+
+ - tocall: APBSD?
+ vendor: hambsd.org
+ model: HamBSD
+
+ - tocall: APBT62
+ vendor: BTech
+ model: DMR 6x2
+
+ - tocall: APC???
+ vendor: Rob Wittner, KZ5RW
+ model: APRS/CE
+ class: app
+
+ - tocall: APCDS0
+ vendor: ZS6LMG
+ model: cell tracker
+ class: tracker
+
+ - tocall: APCLEY
+ vendor: ZS6EY
+ model: EYTraker
+ class: tracker
+
+ - tocall: APCLEZ
+ vendor: ZS6EY
+ model: Telit EZ10 GSM application
+ class: tracker
+
+ - tocall: APCLUB
+ model: Brazil APRS network
+
+ - tocall: APCLWX
+ vendor: ZS6EY
+ model: EYWeather
+ class: wx
+
+ - tocall: APCN??
+ vendor: DG5OAW
+ model: carNET
+
+ - tocall: APCSMS
+ vendor: USNA
+ model: Cosmos
+
+ - tocall: APCSS
+ vendor: AMSAT
+ model: CubeSatSim CubeSat Simulator
+
+ - tocall: APCTLK
+ vendor: Open Source
+ model: Codec2Talkie
+ class: app
+
+ - tocall: APCWP8
+ vendor: GM7HHB
+ model: WinphoneAPRS
+ class: app
+
+ - tocall: APD5T?
+ vendor: Geoffrey, F4FXL
+ model: Open Source DStarGateway
+ class: dstar
+ contact: f4fxl@dstargateway.digital
+
+ - tocall: APDF??
+ model: Automatic DF units
+
+ - tocall: APDG??
+ vendor: Jonathan, G4KLX
+ model: ircDDB Gateway
+ class: dstar
+
+ - tocall: APDI??
+ vendor: Bela, HA5DI
+ model: DIXPRS
+ class: software
+
+ - tocall: APDNO?
+ vendor: DO3SWW
+ model: APRSduino
+ class: tracker
+ os: embedded
+
+ - tocall: APDPRS
+ vendor: unknown
+ model: D-Star APDPRS
+ class: dstar
+
+ - tocall: APDR??
+ vendor: Open Source
+ model: APRSdroid
+ os: Android
+ class: app
+
+ - tocall: APDS??
+ vendor: SP9UOB
+ model: dsDIGI
+ os: embedded
+
+ - tocall: APDST?
+ vendor: SP9UOB
+ model: dsTracker
+ os: embedded
+
+ - tocall: APDT??
+ vendor: unknown
+ model: APRStouch Tone (DTMF)
+
+ - tocall: APDU??
+ vendor: JA7UDE
+ model: U2APRS
+ class: app
+ os: Android
+
+ - tocall: APDV??
+ vendor: OE6PLD
+ model: SSTV with APRS
+ class: software
+
+ - tocall: APDW??
+ vendor: WB2OSZ
+ model: DireWolf
+
+ - tocall: APDnnn
+ vendor: Open Source
+ model: aprsd
+ class: software
+ os: Linux/Unix
+
+ - tocall: APE2A?
+ vendor: NoseyNick, VA3NNW
+ model: Email-2-APRS gateway
+ class: software
+ os: Linux/Unix
+
+ - tocall: APE???
+ model: Telemetry devices
+
+ - tocall: APECAN
+ vendor: KT5TK/DL7AD
+ model: Pecan Pico APRS Balloon Tracker
+ class: tracker
+
+ - tocall: APELK?
+ vendor: WB8ELK
+ model: Balloon tracker
+ class: tracker
+
+ - tocall: APEML?
+ vendor: Leszek, SP9MLI
+ model: SP9MLI for WX, Telemetry
+ class: software
+ contact: sp9mli@gmail.com
+
+ - tocall: APEP??
+ vendor: Patrick EGLOFF, TK5EP
+ model: LoRa WX station
+ class: wx
+ os: embedded
+ contact: pegloff@gmail.com
+
+ - tocall: APERS?
+ vendor: Jason, KG7YKZ
+ model: Runner tracking
+ class: tracker
+
+ - tocall: APERXQ
+ vendor: PE1RXQ
+ model: PE1RXQ APRS Tracker
+ class: tracker
+
+ - tocall: APESP?
+ vendor: LY3PH
+ model: APRS-ESP
+ os: embedded
+
+ - tocall: APFG??
+ vendor: KP4DJT
+ model: Flood Gage
+ class: software
+
+ - tocall: APFI??
+ vendor: aprs.fi
+ class: app
+
+ - tocall: APFII?
+ model: iPhone/iPad app
+ vendor: aprs.fi
+ os: ios
+ class: app
+
+ - tocall: APGBLN
+ vendor: NW5W
+ model: GoBalloon
+ class: tracker
+
+ - tocall: APGO??
+ vendor: AA3NJ
+ model: APRS-Go
+ class: app
+
+ - tocall: APHAX?
+ vendor: PY2UEP
+ model: SM2APRS SondeMonitor
+ class: software
+ os: Windows
+
+ - tocall: APHBL?
+ vendor: KF7EEL
+ model: HBLink D-APRS Gateway
+ class: software
+
+ - tocall: APHH?
+ vendor: Steven D. Bragg, KA9MVA
+ model: HamHud
+ class: tracker
+
+ - tocall: APHK??
+ vendor: LA1BR
+ model: Digipeater/tracker
+
+ - tocall: APHMEY
+ vendor: Tapio Heiskanen, OH2TH
+ model: APRS-IS Client for Athom Homey
+ contact: oh2th@iki.fi
+
+ - tocall: APHPIA
+ vendor: HP3ICC
+ model: Arduino APRS
+
+ - tocall: APHPIB
+ vendor: HP3ICC
+ model: Python APRS Beacon
+
+ - tocall: APHPIW
+ vendor: HP3ICC
+ model: Python APRS WX
+
+ - tocall: APHRM?
+ vendor: Giovanni, IW1CGW
+ model: Meteo
+ class: wx
+ contact: iw1cgw@libero.it
+
+ - tocall: APHRT?
+ vendor: Giovanni, IW1CGW
+ model: Telemetry
+ contact: iw1cgw@libero.it
+
+ - tocall: APHT??
+ vendor: IU0AAC
+ model: HMTracker
+ class: tracker
+
+ - tocall: APHW??
+ vendor: HamWAN
+
+ - tocall: API282
+ vendor: Icom
+ model: IC-2820
+ class: dstar
+
+ - tocall: API31
+ vendor: Icom
+ model: IC-31
+ class: dstar
+
+ - tocall: API410
+ vendor: Icom
+ model: IC-4100
+ class: dstar
+
+ - tocall: API51
+ vendor: Icom
+ model: IC-51
+ class: dstar
+
+ - tocall: API510
+ vendor: Icom
+ model: IC-5100
+ class: dstar
+
+ - tocall: API710
+ vendor: Icom
+ model: IC-7100
+ class: dstar
+
+ - tocall: API80
+ vendor: Icom
+ model: IC-80
+ class: dstar
+
+ - tocall: API880
+ vendor: Icom
+ model: IC-880
+ class: dstar
+
+ - tocall: API910
+ vendor: Icom
+ model: IC-9100
+ class: dstar
+
+ - tocall: API92
+ vendor: Icom
+ model: IC-92
+ class: dstar
+
+ - tocall: API970
+ vendor: Icom
+ model: IC-9700
+ class: dstar
+
+ - tocall: API???
+ vendor: Icom
+ model: unknown
+ class: dstar
+
+ - tocall: APIC??
+ vendor: HA9MCQ
+ model: PICiGATE
+
+ - tocall: APIE??
+ vendor: W7KMV
+ model: PiAPRS
+
+ - tocall: APIN??
+ vendor: AB0WV
+ model: PinPoint
+
+ - tocall: APIZCI
+ vendor: TA7W/OH2UDS and TA6AEU
+ model: hymTR IZCI Tracker
+ class: tracker
+ os: embedded
+
+ - tocall: APJ8??
+ vendor: KN4CRD
+ model: JS8Call
+ class: software
+
+ - tocall: APJA??
+ vendor: K4HG & AE5PL
+ model: JavAPRS
+
+ - tocall: APJE??
+ vendor: Gregg Wonderly, W5GGW
+ model: JeAPRS
+
+ - tocall: APJI??
+ vendor: Peter Loveall, AE5PL
+ model: jAPRSIgate
+ class: software
+
+ - tocall: APJID2
+ vendor: Peter Loveall, AE5PL
+ model: D-Star APJID2
+ class: dstar
+
+ - tocall: APJS??
+ vendor: Peter Loveall, AE5PL
+ model: javAPRSSrvr
+
+ - tocall: APJY??
+ vendor: KA2DDO
+ model: YAAC
+ class: software
+
+ - tocall: APK003
+ vendor: Kenwood
+ model: TH-D72
+ class: ht
+
+ - tocall: APK004
+ vendor: Kenwood
+ model: TH-D74
+ class: ht
+
+ - tocall: APK005
+ vendor: Kenwood
+ model: TH-D75
+ class: ht
+
+ - tocall: APK0??
+ vendor: Kenwood
+ model: TH-D7
+ class: ht
+
+ - tocall: APK1??
+ vendor: Kenwood
+ model: TM-D700
+ class: rig
+
+ - tocall: APKHTW
+ vendor: Kip, W3SN
+ model: Tempest Weather Bridge
+ class: wx
+ os: embedded
+ contact: w3sn@moxracing.33mail.com
+
+ - tocall: APKRAM
+ vendor: kramstuff.com
+ model: Ham Tracker
+ class: app
+ os: ios
+
+ - tocall: APLC??
+ vendor: DL3DCW
+ model: APRScube
+
+ - tocall: APLDG?
+ vendor: Eddie, 9W2LWK
+ model: LoRAIGate
+ class: igate
+ os: embedded
+ contact: 9w2lwk@gmail.com
+
+ - tocall: APLDH?
+ vendor: Eddie, 9W2LWK
+ model: LoraTracker
+ class: tracker
+ os: embedded
+ contact: 9w2lwk@gmail.com
+
+ - tocall: APLDI?
+ vendor: David, OK2DDS
+ model: LoRa IGate/Digipeater
+ class: digi
+
+ - tocall: APLDM?
+ vendor: David, OK2DDS
+ model: LoRa Meteostation
+ class: wx
+
+ - tocall: APLETK
+ vendor: DL5TKL
+ model: T-Echo
+ class: tracker
+ os: embedded
+ contact: cfr34k-git@tkolb.de
+
+ - tocall: APLFG?
+ vendor: Gabor, HG3FUG
+ model: LoRa WX station
+ class: wx
+ os: embedded
+ contact: hg3fug@fazi.hu
+
+ - tocall: APLFM?
+ vendor: DO1MA
+ model: FemtoAPRS
+ class: tracker
+ os: embedded
+
+ - tocall: APLG??
+ vendor: OE5BPA
+ model: LoRa Gateway/Digipeater
+ class: digi
+
+ - tocall: APLHI?
+ vendor: Giovanni, IW1CGW
+ model: LoRa IGate/Digipeater/Telemetry
+ class: digi
+ contact: iw1cgw@libero.it
+
+ - tocall: APLHM?
+ vendor: Giovanni, IW1CGW
+ model: LoRa Meteostation
+ class: wx
+ contact: iw1cgw@libero.it
+
+ - tocall: APLIG?
+ vendor: TA2MUN/TA9OHC
+ model: LightAPRS Tracker
+ class: tracker
+
+ - tocall: APLM??
+ vendor: WA0TQG
+ class: software
+
+ - tocall: APLO??
+ vendor: SQ9MDD
+ model: LoRa KISS TNC/Tracker
+ class: tracker
+
+ - tocall: APLP0?
+ vendor: SQ9P
+ model: fajne digi
+ class: digi
+ os: embedded
+ contact: sq9p.peter@gmail.com
+
+ - tocall: APLP1?
+ vendor: SQ9P
+ model: LORA/FSK/AFSK fajny tracker
+ class: tracker
+ os: embedded
+ contact: sq9p.peter@gmail.com
+
+ - tocall: APLRG?
+ vendor: Ricardo, CA2RXU
+ model: ESP32 LoRa iGate
+ class: igate
+ os: embedded
+ contact: richonguzman@gmail.com
+
+ - tocall: APLRT?
+ vendor: Ricardo, CA2RXU
+ model: ESP32 LoRa Tracker
+ class: tracker
+ os: embedded
+ contact: richonguzman@gmail.com
+
+ - tocall: APLS??
+ vendor: SARIMESH
+ model: SARIMESH
+ class: software
+
+ - tocall: APLT??
+ vendor: OE5BPA
+ model: LoRa Tracker
+ class: tracker
+
+ - tocall: APLU0?
+ vendor: SP9UP
+ model: ESP32/SX12xx LoRa iGate / Digi
+ class: digi
+ os: embedded
+ contact: wajdzik.m@gmail.com
+
+ - tocall: APLU1?
+ vendor: SP9UP
+ model: ESP32/SX12xx LoRa Tracker
+ class: tracker
+ os: embedded
+ contact: wajdzik.m@gmail.com
+
+ - tocall: APMAIL
+ vendor: Mike, NA7Q
+ model: APRS Mailbox
+ class: service
+ contact: mike.ph4@gmail.com
+
+ - tocall: APMG??
+ vendor: Alex, AB0TJ
+ model: PiCrumbs and MiniGate
+ class: software
+
+ - tocall: APMI01
+ vendor: Microsat
+ os: embedded
+ model: WX3in1
+
+ - tocall: APMI02
+ vendor: Microsat
+ os: embedded
+ model: WXEth
+
+ - tocall: APMI03
+ vendor: Microsat
+ os: embedded
+ model: PLXDigi
+
+ - tocall: APMI04
+ vendor: Microsat
+ os: embedded
+ model: WX3in1 Mini
+
+ - tocall: APMI05
+ vendor: Microsat
+ os: embedded
+ model: PLXTracker
+
+ - tocall: APMI06
+ vendor: Microsat
+ os: embedded
+ model: WX3in1 Plus 2.0
+
+ - tocall: APMI??
+ vendor: Microsat
+ os: embedded
+
+ - tocall: APMON?
+ vendor: Amon Schumann, DL9AS
+ model: APRS Balloon Tracker
+ class: tracker
+ os: embedded
+
+ - tocall: APMPAD
+ vendor: DF1JSL
+ model: Multi-Purpose APRS Daemon
+ class: service
+ contact: joerg.schultze.lutter@gmail.com
+ features:
+ - messaging
+
+ - tocall: APMQ??
+ vendor: WB2OSZ
+ model: Ham Radio of Things
+
+ - tocall: APMT??
+ vendor: LZ1PPL
+ model: Micro APRS Tracker
+ class: tracker
+
+ - tocall: APN102
+ vendor: Gregg Wonderly, W5GGW
+ model: APRSNow
+ class: app
+ os: ipad
+
+ - tocall: APN2??
+ vendor: VE4KLM
+ model: NOSaprs for JNOS 2.0
+
+ - tocall: APN3??
+ vendor: Kantronics
+ model: KPC-3
+
+ - tocall: APN9??
+ vendor: Kantronics
+ model: KPC-9612
+
+ - tocall: APNCM
+ vendor: Keith Kaiser, WA0TJT
+ model: Net Control Manager
+ class: software
+ os: browser
+ contact: wa0tjt@gmail.com
+
+ - tocall: APND??
+ vendor: PE1MEW
+ model: DIGI_NED
+
+ - tocall: APNIC4
+ vendor: SQ5EKU
+ model: BidaTrak
+ class: tracker
+ os: embedded
+
+ - tocall: APNJS?
+ vendor: Julien Sansonnens, HB9HRD
+ model: Web messaging service
+ class: service
+ contact: julien.owls@gmail.com
+ features:
+ - messaging
+
+ - tocall: APNK01
+ vendor: Kenwood
+ model: TM-D700
+ class: rig
+ features:
+ - messaging
+
+ - tocall: APNK80
+ vendor: Kantronics
+ model: KAM
+
+ - tocall: APNKMP
+ vendor: Kantronics
+ model: KAM+
+
+ - tocall: APNKMX
+ vendor: Kantronics
+ model: KAM-XL
+
+ - tocall: APNM??
+ vendor: MFJ
+ model: TNC
+
+ - tocall: APNP??
+ vendor: PacComm
+ model: TNC
+
+ - tocall: APNT??
+ vendor: SV2AGW
+ model: TNT TNC as a digipeater
+ class: digi
+
+ - tocall: APNU??
+ vendor: IW3FQG
+ model: UIdigi
+ class: digi
+
+ - tocall: APNV0?
+ vendor: SQ8L
+ model: VP-Digi
+ os: embedded
+ class: digi
+
+ - tocall: APNV1?
+ vendor: SQ8L
+ model: VP-Node
+ os: embedded
+
+ - tocall: APNV2?
+ vendor: SQ8L
+ model: VP-Tracker
+ class: tracker
+
+ - tocall: APNV??
+ vendor: SQ8L
+
+ - tocall: APNW??
+ vendor: SQ3FYK
+ model: WX3in1
+ os: embedded
+
+ - tocall: APNX??
+ vendor: K6DBG
+ model: TNC-X
+
+ - tocall: APOA??
+ vendor: OpenAPRS
+ model: app
+ class: app
+ os: ios
+
+ - tocall: APOCSG
+ vendor: N0AGI
+ model: POCSAG
+
+ - tocall: APODOT
+ vendor: Mike, NA7Q
+ model: Oregon Department of Transportion Traffic Alerts
+ class: service
+
+ - tocall: APOG7?
+ vendor: OpenGD77
+ model: OpenGD77
+ os: embedded
+ contact: Roger VK3KYY/G4KYF
+
+ - tocall: APOLU?
+ vendor: AMSAT-LU
+ model: Oscar
+ class: satellite
+
+ - tocall: APOPYT
+ vendor: Mike, NA7Q
+ model: NA7Q Messenger
+ class: software
+ contact: mike.ph4@gmail.com
+
+ - tocall: APOSAT
+ vendor: Mike, NA7Q
+ model: Open Source Satellite Gateway
+ class: service
+ contact: mike.ph4@gmail.com
+
+ - tocall: APOSMS
+ vendor: Mike, NA7Q
+ model: Open Source SMS Gateway
+ class: service
+ contact: mike.ph4@gmail.com
+ features:
+ - messaging
+
+ - tocall: APOT??
+ vendor: Argent Data Systems
+ model: OpenTracker
+ class: tracker
+
+ - tocall: APOVU?
+ vendor: K J Somaiya Institute
+ model: BeliefSat
+
+ - tocall: APOZ??
+ vendor: OZ1EKD, OZ7HVO
+ model: KissOZ
+ class: tracker
+
+ - tocall: APP6??
+ model: APRSlib
+
+ - tocall: APPCO?
+ vendor: RadCommSoft, LLC
+ model: PicoAPRSTracker
+ class: tracker
+ os: embedded
+ contact: ab4mw@radcommsoft.com
+
+ - tocall: APPIC?
+ vendor: DB1NTO
+ model: PicoAPRS
+ class: tracker
+
+ - tocall: APPM??
+ vendor: DL1MX
+ model: rtl-sdr Python iGate
+ class: software
+
+ - tocall: APPRIS
+ vendor: DF1JSL
+ model: Apprise APRS plugin
+ class: service
+ contact: joerg.schultze.lutter@gmail.com
+ features:
+ - messaging
+
+ - tocall: APPS??
+ vendor: Øyvind, LA7ECA (for the Norwegian Radio Relay League)
+ model: Polaric Server
+ class: software
+ os: Linux
+
+ - tocall: APPT??
+ vendor: JF6LZE
+ model: KetaiTracker
+ class: tracker
+
+ - tocall: APQTH?
+ vendor: Weston Bustraan, W8WJB
+ model: QTH.app
+ class: software
+ os: macOS
+ features:
+ - messaging
+
+ - tocall: APR2MF
+ vendor: Mike, DL2MF
+ model: MF2wxAPRS Tinkerforge gateway
+ class: wx
+ os: Windows
+
+ - tocall: APR8??
+ vendor: Bob Bruninga, WB4APR
+ model: APRSdos
+ class: software
+
+ - tocall: APRARX
+ vendor: Open Source
+ model: radiosonde_auto_rx
+ class: software
+ os: Linux/Unix
+
+ - tocall: APRFG?
+ vendor: RF.Guru
+ contact: info@rf.guru
+
+ - tocall: APRFGB
+ vendor: RF.Guru
+ model: APRS LoRa Pager
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGD
+ vendor: RF.Guru
+ model: APRS Digipeater
+ class: digi
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGH
+ vendor: RF.Guru
+ model: Hotspot
+ class: rig
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGI
+ vendor: RF.Guru
+ model: LoRa APRS iGate
+ class: igate
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGL
+ vendor: RF.Guru
+ model: Lora APRS Digipeater
+ class: digi
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGM
+ vendor: RF.Guru
+ model: Mobile Radio
+ class: rig
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGP
+ vendor: RF.Guru
+ model: Portable Radio
+ class: ht
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGR
+ vendor: RF.Guru
+ model: Repeater
+ class: rig
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGT
+ vendor: RF.Guru
+ model: LoRa APRS Tracker
+ class: tracker
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRFGW
+ vendor: RF.Guru
+ model: LoRa APRS Weather Station
+ class: wx
+ os: embedded
+ contact: info@rf.guru
+
+ - tocall: APRG??
+ vendor: OH2GVE
+ model: aprsg
+ class: software
+ os: Linux/Unix
+
+ - tocall: APRHH?
+ vendor: Steven D. Bragg, KA9MVA
+ model: HamHud
+ class: tracker
+
+ - tocall: APRNOW
+ vendor: Gregg Wonderly, W5GGW
+ model: APRSNow
+ class: app
+ os: ipad
+
+ - tocall: APRPR?
+ vendor: Robert DM4RW, Peter DL6MAA
+ model: Teensy RPR TNC
+ class: tracker
+ os: embedded
+ contact: dm4rw@skywaves.de
+
+ - tocall: APRRDZ
+ model: rdzTTGOsonde
+ vendor: DL9RDZ
+ class: tracker
+
+ - tocall: APRRF?
+ vendor: Jean-Francois Huet F1EVM
+ model: Tracker for RRF
+ class: tracker
+ os: embedded
+ contact: f1evm@f1evm.fr
+ features:
+ - messaging
+
+ - tocall: APRRT?
+ vendor: RPC Electronics
+ model: RTrak
+ class: tracker
+
+ - tocall: APRS
+ vendor: Unknown
+ model: Unknown
+
+ - tocall: APRX??
+ vendor: Kenneth W. Finnegan, W6KWF
+ model: Aprx
+ class: igate
+ os: Linux/Unix
+
+ - tocall: APS???
+ vendor: Brent Hildebrand, KH2Z
+ model: APRS+SA
+ class: software
+
+ - tocall: APSAR
+ vendor: ZL4FOX
+ model: SARTrack
+ class: software
+ os: Windows
+
+ - tocall: APSC??
+ vendor: OH2MQK, OH7LZB
+ model: aprsc
+ class: software
+
+ - tocall: APSF??
+ vendor: F5OPV, SFCP_LABS
+ model: embedded APRS devices
+ os: embedded
+
+ - tocall: APSFLG
+ vendor: F5OPV, SFCP_LABS
+ model: LoRa/APRS Gateway
+ class: digi
+ os: embedded
+
+ - tocall: APSFRP
+ vendor: F5OPV, SFCP_LABS
+ model: VHF/UHF Repeater
+ os: embedded
+
+ - tocall: APSFTL
+ vendor: F5OPV, SFCP_LABS
+ model: LoRa/APRS Telemetry Reporter
+ os: embedded
+
+ - tocall: APSFWX
+ vendor: F5OPV, SFCP_LABS
+ model: embedded Weather Station
+ class: wx
+ os: embedded
+
+ - tocall: APSK63
+ vendor: Chris Moulding, G4HYG
+ model: APRS Messenger
+ class: software
+ os: Windows
+
+ - tocall: APSMS?
+ vendor: Paul Dufresne
+ model: SMS gateway
+ class: software
+
+ - tocall: APSRF?
+ vendor: SoftRF
+ model: Ham Edition
+ class: tracker
+ os: embedded
+
+ - tocall: APSTM?
+ vendor: W7QO
+ model: Balloon tracker
+ class: tracker
+
+ - tocall: APSTPO
+ vendor: N0AGI
+ model: Satellite Tracking and Operations
+ class: software
+
+ - tocall: APT2??
+ vendor: Byonics
+ model: TinyTrak2
+ class: tracker
+
+ - tocall: APT3??
+ vendor: Byonics
+ model: TinyTrak3
+ class: tracker
+
+ - tocall: APT4??
+ vendor: Byonics
+ model: TinyTrak4
+ class: tracker
+
+ - tocall: APTB??
+ vendor: BG5HHP
+ model: TinyAPRS
+
+ - tocall: APTCHE
+ vendor: PU3IKE
+ model: TcheTracker, Tcheduino
+ class: tracker
+
+ - tocall: APTCMA
+ vendor: Cleber, PU1CMA
+ model: CAPI Tracker
+ class: tracker
+
+ - tocall: APTEMP
+ vendor: KL7AF
+ model: APRS-Tempest Weather Gateway
+ class: wx
+ os: Linux/Unix
+ contact: kl7af@foghaven.net
+
+ - tocall: APTHUR
+ model: APRSThursday weekly event mapbot daemon
+ contact: harihend1973@gmail.com
+ vendor: YD0BCX
+ class: service
+ os: linux/unix
+ features:
+ - messaging
+
+ - tocall: APTKJ?
+ vendor: W9JAJ
+ model: ATTiny APRS Tracker
+ os: embedded
+
+ - tocall: APTLVC
+ vendor: TA5LVC
+ model: TR80 APRS Tracker
+ class: tracker
+
+ - tocall: APTNG?
+ vendor: Filip YU1TTN
+ model: Tango Tracker
+ class: tracker
+
+ - tocall: APTPN?
+ vendor: KN4ORB
+ model: TARPN Packet Node Tracker
+ class: tracker
+
+ - tocall: APTR??
+ vendor: Motorola
+ model: MotoTRBO
+
+ - tocall: APTT*
+ vendor: Byonics
+ model: TinyTrak
+ class: tracker
+
+ - tocall: APTW??
+ vendor: Byonics
+ model: WXTrak
+ class: wx
+
+ - tocall: APU1??
+ vendor: Roger Barker, G4IDE
+ model: UI-View16
+ class: software
+ os: Windows
+
+ - tocall: APU2*
+ vendor: Roger Barker, G4IDE
+ model: UI-View32
+ class: software
+ os: Windows
+
+ - tocall: APUDR?
+ vendor: NW Digital Radio
+ model: UDR
+
+ - tocall: APVE??
+ vendor: unknown
+ model: EchoLink
+
+ - tocall: APVM??
+ vendor: Digital Radio China Club
+ model: DRCC-DVM
+ class: igate
+
+ - tocall: APVR??
+ vendor: unknown
+ model: IRLP
+
+ - tocall: APW9??
+ vendor: Mile Strk, 9A9Y
+ model: WX Katarina
+ class: wx
+ os: embedded
+ features:
+ - messaging
+
+ - tocall: APWA??
+ vendor: KJ4ERJ
+ model: APRSISCE
+ class: software
+ os: Android
+
+ - tocall: APWEE?
+ vendor: Tom Keffer and Matthew Wall
+ model: WeeWX Weather Software
+ class: software
+ os: Linux/Unix
+
+ - tocall: APWM??
+ vendor: KJ4ERJ
+ model: APRSISCE
+ class: software
+ os: Windows Mobile
+ features:
+ - messaging
+ - item-in-msg
+
+ - tocall: APWW??
+ vendor: KJ4ERJ
+ model: APRSIS32
+ class: software
+ os: Windows
+ features:
+ - messaging
+ - item-in-msg
+
+ - tocall: APWnnn
+ vendor: Sproul Brothers
+ model: WinAPRS
+ class: software
+ os: Windows
+
+ - tocall: APX???
+ vendor: Open Source
+ model: Xastir
+ class: software
+ os: Linux/Unix
+
+ - tocall: APXR??
+ vendor: G8PZT
+ model: Xrouter
+
+ - tocall: APY01D
+ vendor: Yaesu
+ model: FT1D
+ class: ht
+
+ - tocall: APY02D
+ vendor: Yaesu
+ model: FT2D
+ class: ht
+
+ - tocall: APY05D
+ vendor: Yaesu
+ model: FT5D
+ class: ht
+
+ - tocall: APY200
+ vendor: Yaesu
+ model: FTM-200D
+ class: rig
+
+ - tocall: APY300
+ vendor: Yaesu
+ model: FTM-300D
+ class: rig
+
+ - tocall: APY400
+ vendor: Yaesu
+ model: FTM-400
+ class: rig
+
+ - tocall: APY500
+ vendor: Yaesu
+ model: FTM-500D
+ class: rig
+
+ - tocall: APYS??
+ vendor: W2GMD
+ model: Python APRS
+ class: software
+
+ - tocall: "APZ*"
+ vendor: Unknown
+ model: Experimental
+
+ - tocall: APZ18
+ vendor: IW3FQG
+ model: UIdigi
+ class: digi
+
+ - tocall: APZ186
+ vendor: IW3FQG
+ model: UIdigi
+ class: digi
+
+ - tocall: APZ19
+ vendor: IW3FQG
+ model: UIdigi
+ class: digi
+
+ - tocall: APZ247
+ model: UPRS
+ vendor: NR0Q
+
+ - tocall: APZG??
+ vendor: OH2GVE
+ model: aprsg
+ class: software
+ os: Linux/Unix
+
+ - tocall: APZMAJ
+ vendor: M1MAJ
+ model: DeLorme inReach Tracker
+
+ - tocall: APZMDR
+ vendor: Open Source
+ model: HaMDR
+ class: tracker
+ os: embedded
+
+ - tocall: APZTKP
+ vendor: Nick Hanks, N0LP
+ model: TrackPoint
+ class: tracker
+ os: embedded
+
+ - tocall: APZWKR
+ vendor: GM1WKR
+ model: NetSked
+ class: software
+
+ - tocall: APnnnD
+ vendor: Painter Engineering
+ model: uSmartDigi D-Gate
+ class: dstar
+
+ - tocall: APnnnU
+ vendor: Painter Engineering
+ model: uSmartDigi Digipeater
+ class: digi
+
+ - tocall: PSKAPR
+ vendor: Open Source
+ model: PSKmail
+ class: software
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7a05ecc..d159e3f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,6 +10,7 @@ include_directories(
${PORTAUDIO_INCLUDE_DIRS}
${SNDIO_INCLUDE_DIRS}
${CUSTOM_GEOTRANZ_DIR}
+ ${GPIOD_INCLUDE_DIRS}
)
if(WIN32 OR CYGWIN)
@@ -38,6 +39,7 @@ list(APPEND direwolf_SOURCES
beacon.c
config.c
decode_aprs.c
+ deviceid.c
dedupe.c
demod_9600.c
demod_afsk.c
@@ -162,6 +164,7 @@ target_link_libraries(direwolf
${ALSA_LIBRARIES}
${UDEV_LIBRARIES}
${PORTAUDIO_LIBRARIES}
+ ${GPIOD_LIBRARIES}
${SNDIO_LIBRARIES}
${AVAHI_LIBRARIES}
)
@@ -176,6 +179,7 @@ endif()
# decode_aprs
list(APPEND decode_aprs_SOURCES
decode_aprs.c
+ deviceid.c
ais.c
kiss_frame.c
ax25_pad.c
@@ -360,6 +364,7 @@ list(APPEND atest_SOURCES
ax25_pad.c
ax25_pad2.c
decode_aprs.c
+ deviceid.c
dwgpsnmea.c
dwgps.c
dwgpsd.c
diff --git a/src/audio.h b/src/audio.h
index cb5ca94..4fc0570 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -28,7 +28,8 @@
enum ptt_method_e {
PTT_METHOD_NONE, /* VOX or no transmit. */
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
- PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */
+ PTT_METHOD_GPIO, /* General purpose I/O using sysfs, deprecated after 2020, Linux only. */
+ PTT_METHOD_GPIOD, /* General purpose I/O, using libgpiod, Linux only. */
PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */
PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */
@@ -74,16 +75,23 @@ struct audio_s {
/* Properties of the sound device. */
- int defined; /* Was device defined? */
- /* First one defaults to yes. */
+ int defined; /* Was device defined? 0=no. >0 for yes. */
+ /* First channel defaults to 2 for yes with default config. */
+ /* 1 means it was defined by user. */
+
+ int copy_from; /* >=0 means copy contents from another audio device. */
+ /* In this case we don't have device names, below. */
+ /* Num channels, samples/sec, and bit/sample are copied from */
+ /* original device and can't be changed. */
+ /* -1 for normal case. */
char adevice_in[80]; /* Name of the audio input device (or file?). */
- /* TODO: Can be "-" to read from stdin. */
+ /* Can be udp:nnn for UDP or "-" to read from stdin. */
char adevice_out[80]; /* Name of the audio output device (or file?). */
int num_channels; /* Should be 1 for mono or 2 for stereo. */
- int samples_per_sec; /* Audio sampling rate. Typically 11025, 22050, or 44100. */
+ int samples_per_sec; /* Audio sampling rate. Typically 11025, 22050, 44100, or 48000. */
int bits_per_sample; /* 8 (unsigned char) or 16 (signed short). */
} adev[MAX_ADEVS];
@@ -304,6 +312,7 @@ struct audio_s {
/* the case for CubieBoard where it was longer. */
/* This is filled in by ptt_init so we don't have to */
/* recalculate it each time we access it. */
+ /* Also GPIO chip name for GPIOD method. Looks like 'gpiochip4' */
/* This could probably be collapsed into ptt_device instead of being separate. */
diff --git a/src/ax25_link.c b/src/ax25_link.c
index 3043a04..98d6c45 100644
--- a/src/ax25_link.c
+++ b/src/ax25_link.c
@@ -4642,6 +4642,8 @@ static void dm_frame (ax25_dlsm_t *S, int f)
if (f == 1) {
text_color_set(DW_COLOR_INFO);
dw_printf ("%s doesn't understand AX.25 v2.2. Trying v2.0 ...\n", S->addrs[PEERCALL]);
+ dw_printf ("You can avoid this failed attempt and speed up the\n");
+ dw_printf ("process by putting \"V20 %s\" in the configuration file.\n", S->addrs[PEERCALL]);
INIT_T1V_SRT;
@@ -4930,6 +4932,8 @@ static void frmr_frame (ax25_dlsm_t *S)
text_color_set(DW_COLOR_INFO);
dw_printf ("%s doesn't understand AX.25 v2.2. Trying v2.0 ...\n", S->addrs[PEERCALL]);
+ dw_printf ("You can avoid this failed attempt and speed up the\n");
+ dw_printf ("process by putting \"V20 %s\" in the configuration file.\n", S->addrs[PEERCALL]);
INIT_T1V_SRT;
diff --git a/src/ax25_pad.c b/src/ax25_pad.c
index 0f07580..4a52638 100644
--- a/src/ax25_pad.c
+++ b/src/ax25_pad.c
@@ -2579,6 +2579,59 @@ int ax25_get_c2 (packet_t this_p)
}
+/*------------------------------------------------------------------
+ *
+ * Function: ax25_set_pid
+ *
+ * Purpose: Set protocol ID in packet.
+ *
+ * Inputs: this_p - pointer to packet object.
+ *
+ * pid - usually 0xF0 for APRS or 0xCF for NET/ROM.
+ *
+ * AX.25: "The Protocol Identifier (PID) field appears in information
+ * frames (I and UI) only. It identifies which kind of
+ * Layer 3 protocol, if any, is in use."
+ *
+ *------------------------------------------------------------------*/
+
+void ax25_set_pid (packet_t this_p, int pid)
+{
+ assert (this_p->magic1 == MAGIC);
+ assert (this_p->magic2 == MAGIC);
+
+ // Some applications set this to 0 which is an error.
+ // Change 0 to 0xF0 meaning no layer 3 protocol.
+
+ if (pid == 0) {
+ pid = AX25_PID_NO_LAYER_3;
+ }
+
+ // Sanity check: is it I or UI frame?
+
+ if (this_p->frame_len == 0) return;
+
+ ax25_frame_type_t frame_type;
+ cmdres_t cr; // command or response.
+ char description[64];
+ int pf; // Poll/Final.
+ int nr, ns; // Sequence numbers.
+
+ frame_type = ax25_frame_type (this_p, &cr, description, &pf, &nr, &ns);
+
+ if (frame_type != frame_type_I && frame_type != frame_type_U_UI) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("ax25_set_pid(0x%2x): Packet type is not I or UI.\n", pid);
+ return;
+ }
+
+ // TODO: handle 2 control byte case.
+ if (this_p->num_addr >= 2) {
+ this_p->frame_data[ax25_get_pid_offset(this_p)] = pid;
+ }
+}
+
+
/*------------------------------------------------------------------
*
* Function: ax25_get_pid
diff --git a/src/ax25_pad.h b/src/ax25_pad.h
index cdb84c6..6d3d5cb 100644
--- a/src/ax25_pad.h
+++ b/src/ax25_pad.h
@@ -66,6 +66,7 @@
#define AX25_UI_FRAME 3 /* Control field value. */
#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */
+#define AX25_PID_NETROM 0xcf /* protocol ID used for NET/ROM */
#define AX25_PID_SEGMENTATION_FRAGMENT 0x08
#define AX25_PID_ESCAPE_CHARACTER 0xff
@@ -427,6 +428,7 @@ extern int ax25_is_null_frame (packet_t this_p);
extern int ax25_get_control (packet_t this_p);
extern int ax25_get_c2 (packet_t this_p);
+extern void ax25_set_pid (packet_t this_p, int pid);
extern int ax25_get_pid (packet_t this_p);
extern int ax25_get_frame_len (packet_t this_p);
diff --git a/src/config.c b/src/config.c
index 1ad6c08..de8d74d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
-// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2021 John Langner, WB2OSZ
+// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2021, 2023 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -755,12 +755,13 @@ void config_init (char *fname, struct audio_s *p_audio_config,
strlcpy (p_audio_config->adev[adevice].adevice_out, DEFAULT_ADEVICE, sizeof(p_audio_config->adev[adevice].adevice_out));
p_audio_config->adev[adevice].defined = 0;
+ p_audio_config->adev[adevice].copy_from = -1;
p_audio_config->adev[adevice].num_channels = DEFAULT_NUM_CHANNELS; /* -2 stereo */
p_audio_config->adev[adevice].samples_per_sec = DEFAULT_SAMPLES_PER_SEC; /* -r option */
p_audio_config->adev[adevice].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; /* -8 option for 8 instead of 16 bits */
}
- p_audio_config->adev[0].defined = 1;
+ p_audio_config->adev[0].defined = 2; // 2 means it was done by default and not the user's config file.
for (channel=0; channelmaxframe_extended = AX25_K_MAXFRAME_EXTENDED_DEFAULT; /* Max frames to send before ACK. mod 128 "Window" size. */
- p_misc_config->maxv22 = AX25_N2_RETRY_DEFAULT / 3; /* Max SABME before falling back to SABM. */
- p_misc_config->v20_addrs = NULL; /* Go directly to v2.0 for stations listed. */
+ p_misc_config->maxv22 = AX25_N2_RETRY_DEFAULT / 3; /* Send SABME this many times before falling back to SABM. */
+ p_misc_config->v20_addrs = NULL; /* Go directly to v2.0 for stations listed */
+ /* without trying v2.2 first. */
p_misc_config->v20_count = 0;
p_misc_config->noxid_addrs = NULL; /* Don't send XID to these stations. */
+ /* Might work with a partial v2.2 implementation */
+ /* on the other end. */
p_misc_config->noxid_count = 0;
/*
@@ -1012,7 +1016,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
* ADEVICE plughw:1,0 -- same for in and out.
* ADEVICE plughw:2,0 plughw:3,0 -- different in/out for a channel or channel pair.
* ADEVICE1 udp:7355 default -- from Software defined radio (SDR) via UDP.
- *
+ *
+ * New in 1.8: Ability to map to another audio device.
+ * This allows multiple modems (i.e. data speeds) on the same audio interface.
+ *
+ * ADEVICEn = n -- Copy from different already defined channel.
*/
/* Note that ALSA name can contain comma such as hw:1,0 */
@@ -1040,17 +1048,42 @@ void config_init (char *fname, struct audio_s *p_audio_config,
exit(EXIT_FAILURE);
}
+ // Do not allow same adevice to be defined more than once.
+ // Overriding the default for adevice 0 is ok.
+ // In that case definded was 2. That's why we check for 1, not just non-zero.
+
+ if (p_audio_config->adev[adevice].defined == 1) { // 1 means defined by user.
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file: ADEVICE%d can't be defined more than once. Line %d.\n", adevice, line);
+ continue;
+ }
+
p_audio_config->adev[adevice].defined = 1;
-
- /* First channel of device is valid. */
- p_audio_config->chan_medium[ADEVFIRSTCHAN(adevice)] = MEDIUM_RADIO;
- strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
- strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
+ // New case for release 1.8.
- t = split(NULL,0);
- if (t != NULL) {
+ if (strcmp(t, "=") == 0) {
+ t = split(NULL,0);
+ if (t != NULL) {
+
+ }
+
+///////// to be continued.... FIXME
+
+ }
+ else {
+ /* First channel of device is valid. */
+ // This might be changed to UDP or STDIN when the device name is examined.
+ p_audio_config->chan_medium[ADEVFIRSTCHAN(adevice)] = MEDIUM_RADIO;
+
+ strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
+
+ t = split(NULL,0);
+ if (t != NULL) {
+ // Different audio devices for receive and transmit.
+ strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
+ }
}
}
@@ -1809,6 +1842,45 @@ void config_init (char *fname, struct audio_s *p_audio_config,
}
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIO;
#endif
+ }
+ else if (strcasecmp(t, "GPIOD") == 0) {
+#if __WIN32__
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: %s with GPIOD is only available on Linux.\n", line, otname);
+#else
+#if defined(USE_GPIOD)
+ t = split(NULL,0);
+ if (t == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Config file line %d: Missing GPIO chip name for %s.\n", line, otname);
+ dw_printf ("Use the \"gpioinfo\" command to get a list of gpio chip names and corresponding I/O lines.\n");
+ continue;
+ }
+ strlcpy(p_audio_config->achan[channel].octrl[ot].out_gpio_name, t,
+ sizeof(p_audio_config->achan[channel].octrl[ot].out_gpio_name));
+
+ t = split(NULL,0);
+ if (t == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("Config file line %d: Missing GPIO number for %s.\n", line, otname);
+ continue;
+ }
+
+ if (*t == '-') {
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t+1);
+ p_audio_config->achan[channel].octrl[ot].ptt_invert = 1;
+ }
+ else {
+ p_audio_config->achan[channel].octrl[ot].out_gpio_num = atoi(t);
+ p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
+ }
+ p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_GPIOD;
+#else
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Application was not built with optional support for GPIOD.\n");
+ dw_printf ("Install packages gpiod and libgpiod-dev, remove 'build' subdirectory, then rebuild.\n");
+#endif /* USE_GPIOD*/
+#endif /* __WIN32__ */
}
else if (strcasecmp(t, "LPT") == 0) {
@@ -2132,6 +2204,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
/*
* DWAIT n - Extra delay for receiver squelch. n = 10 mS units.
+ *
+ * Why did I do this? Just add more to TXDELAY.
+ * Now undocumented in User Guide. Might disappear someday.
*/
else if (strcasecmp(t, "DWAIT") == 0) {
@@ -2167,14 +2242,20 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue;
}
n = atoi(t);
- if (n >= 0 && n <= 255) {
+ if (n >= 5 && n < 50) {
+ // 0 = User has no clue. This would be no delay.
+ // 10 = Default.
+ // 50 = Half second. User might think it is mSec and use 100.
p_audio_config->achan[channel].slottime = n;
}
else {
p_audio_config->achan[channel].slottime = DEFAULT_SLOTTIME;
text_color_set(DW_COLOR_ERROR);
- dw_printf ("Line %d: Invalid delay time for persist algorithm. Using %d.\n",
+ dw_printf ("Line %d: Invalid delay time for persist algorithm. Using default %d.\n",
line, p_audio_config->achan[channel].slottime);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default?\n");
}
}
@@ -2191,14 +2272,17 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue;
}
n = atoi(t);
- if (n >= 0 && n <= 255) {
+ if (n >= 5 && n <= 250) {
p_audio_config->achan[channel].persist = n;
}
else {
p_audio_config->achan[channel].persist = DEFAULT_PERSIST;
text_color_set(DW_COLOR_ERROR);
- dw_printf ("Line %d: Invalid probability for persist algorithm. Using %d.\n",
+ dw_printf ("Line %d: Invalid probability for persist algorithm. Using default %d.\n",
line, p_audio_config->achan[channel].persist);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default?\n");
}
}
@@ -2216,6 +2300,23 @@ void config_init (char *fname, struct audio_s *p_audio_config,
}
n = atoi(t);
if (n >= 0 && n <= 255) {
+ text_color_set(DW_COLOR_ERROR);
+ if (n < 10) {
+ dw_printf ("Line %d: Setting TXDELAY this small is a REALLY BAD idea if you want other stations to hear you.\n",
+ line);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default rather than reducing reliability?\n");
+ }
+ else if (n >= 100) {
+ dw_printf ("Line %d: Keeping with tradition, going back to the 1980s, TXDELAY is in 10 millisecond units.\n",
+ line);
+ dw_printf ("Line %d: The value %d would be %.3f seconds which seems rather excessive. Are you sure you want that?\n",
+ line, n, (double)n * 10. / 1000.);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default?\n");
+ }
p_audio_config->achan[channel].txdelay = n;
}
else {
@@ -2240,12 +2341,28 @@ void config_init (char *fname, struct audio_s *p_audio_config,
}
n = atoi(t);
if (n >= 0 && n <= 255) {
+ if (n < 5) {
+ dw_printf ("Line %d: Setting TXTAIL that small is a REALLY BAD idea if you want other stations to hear you.\n",
+ line);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default rather than reducing reliability?\n");
+ }
+ else if (n >= 50) {
+ dw_printf ("Line %d: Keeping with tradition, going back to the 1980s, TXTAIL is in 10 millisecond units.\n",
+ line);
+ dw_printf ("Line %d: The value %d would be %.3f seconds which seems rather excessive. Are you sure you want that?\n",
+ line, n, (double)n * 10. / 1000.);
+ dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n");
+ dw_printf ("section, to understand what this means.\n");
+ dw_printf ("Why don't you just use the default?\n");
+ }
p_audio_config->achan[channel].txtail = n;
}
else {
p_audio_config->achan[channel].txtail = DEFAULT_TXTAIL;
text_color_set(DW_COLOR_ERROR);
- dw_printf ("Line %d: Invalid time for transmit timing. Using %d.\n",
+ dw_printf ("Line %d: Invalid time for transmit timing. Using %d.\n",
line, p_audio_config->achan[channel].txtail);
}
}
@@ -2794,7 +2911,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
dw_printf ("Config file: FILTER IG ... on line %d.\n", line);
dw_printf ("Warning! Don't mess with IS>RF filtering unless you are an expert and have an unusual situation.\n");
dw_printf ("Warning! The default is fine for nearly all situations.\n");
- dw_printf ("Warning! Be sure to read carefully and understand Successful-APRS-Gateway-Operation.pdf .\n");
+ dw_printf ("Warning! Be sure to read carefully and understand \"Successful-APRS-Gateway-Operation.pdf\" .\n");
dw_printf ("Warning! If you insist, be sure to add \" | i/180 \" so you don't break messaging.\n");
}
else {
@@ -2834,7 +2951,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
dw_printf ("Warning! Don't mess with RF>IS filtering unless you are an expert and have an unusual situation.\n");
dw_printf ("Warning! Expected behavior is for everything to go from RF to IS.\n");
dw_printf ("Warning! The default is fine for nearly all situations.\n");
- dw_printf ("Warning! Be sure to read carefully and understand Successful-APRS-Gateway-Operation.pdf .\n");
+ dw_printf ("Warning! Be sure to read carefully and understand \"Successful-APRS-Gateway-Operation.pdf\" .\n");
}
else {
to_chan = isdigit(*t) ? atoi(t) : -999;
@@ -4470,6 +4587,13 @@ void config_init (char *fname, struct audio_s *p_audio_config,
if (t != NULL && strlen(t) > 0) {
p_igate_config->t2_filter = strdup (t);
+
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Line %d: Warning - IGFILTER is a rarely needed expert level feature.\n", line);
+ dw_printf ("If you don't have a special situation and a good understanding of\n");
+ dw_printf ("how this works, you probably should not be messing with it.\n");
+ dw_printf ("The default behavior is appropriate for most situations.\n");
+ dw_printf ("Please read \"Successful-APRS-IGate-Operation.pdf\".\n");
}
}
diff --git a/src/decode_aprs.c b/src/decode_aprs.c
index ab93327..08534f7 100644
--- a/src/decode_aprs.c
+++ b/src/decode_aprs.c
@@ -1,7 +1,7 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
-// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017, 2022 John Langner, WB2OSZ
+// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017, 2022, 2023 John Langner, WB2OSZ
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
#include "decode_aprs.h"
#include "telemetry.h"
#include "ais.h"
-
+#include "deviceid.h"
#define TRUE 1
#define FALSE 0
@@ -124,7 +124,6 @@ static double get_longitude_9 (char *p, int quiet);
static time_t get_timestamp (decode_aprs_t *A, char *p);
static int get_maidenhead (decode_aprs_t *A, char *p);
static int data_extension_comment (decode_aprs_t *A, char *pdext);
-static void decode_tocall (decode_aprs_t *A, char *dest);
//static void get_symbol (decode_aprs_t *A, char dti, char *src, char *dest);
static void process_comment (decode_aprs_t *A, char *pstart, int clen);
@@ -292,7 +291,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, char *third_party_sr
}
/*
- * Application might be in the destination field for most message types.
+ * Device/Application is in the destination field for most packet types.
* MIC-E format has part of location in the destination field.
*/
@@ -303,7 +302,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, char *third_party_sr
break;
default:
- decode_tocall (A, A->g_dest);
+ deviceid_decode_dest (A->g_dest, A->g_mfr, sizeof(A->g_mfr));
break;
}
@@ -1392,7 +1391,6 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
int cust_msg = 0;
const char *std_text[8] = {"Emergency", "Priority", "Special", "Committed", "Returning", "In Service", "En Route", "Off Duty" };
const char *cust_text[8] = {"Emergency", "Custom-6", "Custom-5", "Custom-4", "Custom-3", "Custom-2", "Custom-1", "Custom-0" };
- unsigned char *pfirst, *plast;
strlcpy (A->g_data_type_desc, "MIC-E", sizeof(A->g_data_type_desc));
@@ -1622,126 +1620,43 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
A->g_course = n;
+// The rest is a comment which can have other information cryptically embedded.
+// Remove any trailing CR, which I would argue, violates the protocol spec.
+// It is essential to keep trailing spaces. e.g. VX-8 suffix is "_ "
+
+ char mcomment[256];
+ strlcpy (mcomment, info + sizeof(struct aprs_mic_e_s), sizeof(mcomment));
+ if (mcomment[strlen(mcomment)-1] == '\r') {
+ mcomment[strlen(mcomment)-1] = '\0';
+ }
+
/* Now try to pick out manufacturer and other optional items. */
/* The telemetry field, in the original spec, is no longer used. */
-
- strlcpy (A->g_mfr, "Unknown manufacturer", sizeof(A->g_mfr));
- pfirst = info + sizeof(struct aprs_mic_e_s);
- plast = info + ilen - 1;
-
-/* Carriage return character at the end is not mentioned in spec. */
-/* Remove if found because it messes up extraction of manufacturer. */
-/* Don't drop trailing space because that is used for Yaesu VX-8. */
-/* As I recall, the IGate function trims trailing spaces. */
-/* That would be bad for this particular model. Maybe I'm mistaken? */
+ char trimmed[256]; // Comment with vendor/model removed.
+ deviceid_decode_mice (mcomment, trimmed, sizeof(trimmed), A->g_mfr, sizeof(A->g_mfr));
- if (*plast == '\r') plast--;
-#define isT(c) ((c) == ' ' || (c) == '>' || (c) == ']' || (c) == '`' || (c) == '\'')
+// Possible altitude at beginning of remaining comment.
+// Three base 91 characters followed by }
-// Last Updated Dec. 2021
-// This does not change very often but I'm wondering if we could parse
-// http://www.aprs.org/aprs12/mic-e-types.txt similar to how we use tocalls.txt.
+ if (strlen(trimmed) >=4 &&
+ isdigit91(trimmed[0]) &&
+ isdigit91(trimmed[1]) &&
+ isdigit91(trimmed[2]) &&
+ trimmed[3] == '}') {
-// TODO: Use https://github.com/aprsorg/aprs-deviceid rather than hardcoding.
+ A->g_altitude_ft = DW_METERS_TO_FEET((trimmed[0]-33)*91*91 + (trimmed[1]-33)*91 + (trimmed[2]-33) - 10000);
- if (isT(*pfirst)) {
-
-// "legacy" formats.
-
- if (*pfirst == ' ' ) { strlcpy (A->g_mfr, "Original MIC-E", sizeof(A->g_mfr)); pfirst++; }
-
- else if (*pfirst == '>' && *plast == '=') { strlcpy (A->g_mfr, "Kenwood TH-D72", sizeof(A->g_mfr)); pfirst++; plast--; }
- else if (*pfirst == '>' && *plast == '^') { strlcpy (A->g_mfr, "Kenwood TH-D74", sizeof(A->g_mfr)); pfirst++; plast--; }
- else if (*pfirst == '>' && *plast == '&') { strlcpy (A->g_mfr, "Kenwood TH-D75", sizeof(A->g_mfr)); pfirst++; plast--; }
- else if (*pfirst == '>' ) { strlcpy (A->g_mfr, "Kenwood TH-D7A", sizeof(A->g_mfr)); pfirst++; }
-
- else if (*pfirst == ']' && *plast == '=') { strlcpy (A->g_mfr, "Kenwood TM-D710", sizeof(A->g_mfr)); pfirst++; plast--; }
- else if (*pfirst == ']' ) { strlcpy (A->g_mfr, "Kenwood TM-D700", sizeof(A->g_mfr)); pfirst++; }
-
-// ` should be used for message capable devices.
-
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == ' ') { strlcpy (A->g_mfr, "Yaesu VX-8", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '"') { strlcpy (A->g_mfr, "Yaesu FTM-350", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '#') { strlcpy (A->g_mfr, "Yaesu VX-8G", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '$') { strlcpy (A->g_mfr, "Yaesu FT1D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '%') { strlcpy (A->g_mfr, "Yaesu FTM-400DR", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == ')') { strlcpy (A->g_mfr, "Yaesu FTM-100D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '(') { strlcpy (A->g_mfr, "Yaesu FT2D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '0') { strlcpy (A->g_mfr, "Yaesu FT3D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '3') { strlcpy (A->g_mfr, "Yaesu FT5D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '1') { strlcpy (A->g_mfr, "Yaesu FTM-300D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' && *(plast-1) == '_' && *plast == '5') { strlcpy (A->g_mfr, "Yaesu FTM-500D", sizeof(A->g_mfr)); pfirst++; plast-=2; }
-
- else if (*pfirst == '`' && *(plast-1) == ' ' && *plast == 'X') { strlcpy (A->g_mfr, "AP510", sizeof(A->g_mfr)); pfirst++; plast-=2; }
-
- else if (*pfirst == '`' && *(plast-1) == '(' && *plast == '5') { strlcpy (A->g_mfr, "Anytone D578UV", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '`' ) { strlcpy (A->g_mfr, "Generic Mic-Emsg", sizeof(A->g_mfr)); pfirst++; }
-
-// ' should be used for trackers (not message capable).
-
- else if (*pfirst == '\'' && *(plast-1) == '(' && *plast == '5') { strlcpy (A->g_mfr, "Anytone D578UV", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '\'' && *(plast-1) == '(' && *plast == '8') { strlcpy (A->g_mfr, "Anytone D878UV", sizeof(A->g_mfr)); pfirst++; plast-=2; }
-
- else if (*pfirst == '\'' && *(plast-1) == '|' && *plast == '3') { strlcpy (A->g_mfr, "Byonics TinyTrack3", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '\'' && *(plast-1) == '|' && *plast == '4') { strlcpy (A->g_mfr, "Byonics TinyTrack4", sizeof(A->g_mfr)); pfirst++; plast-=2; }
-
- else if (*pfirst == '\'' && *(plast-1) == ':' && *plast == '4') { strlcpy (A->g_mfr, "SCS GmbH & Co. P4dragon DR-7400 modems", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if (*pfirst == '\'' && *(plast-1) == ':' && *plast == '8') { strlcpy (A->g_mfr, "SCS GmbH & Co. P4dragon DR-7800 modems", sizeof(A->g_mfr)); pfirst++; plast-=2; }
-
- else if (*pfirst == '\'' ) { strlcpy (A->g_mfr, "Generic McTrackr", sizeof(A->g_mfr)); pfirst++; }
-
- else if ( *(plast-1) == '\\' ) { strlcpy (A->g_mfr, "Hamhud ?", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if ( *(plast-1) == '/' ) { strlcpy (A->g_mfr, "Argent ?", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if ( *(plast-1) == '^' ) { strlcpy (A->g_mfr, "HinzTec anyfrog", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if ( *(plast-1) == '*' ) { strlcpy (A->g_mfr, "APOZxx www.KissOZ.dk Tracker. OZ1EKD and OZ7HVO", sizeof(A->g_mfr)); pfirst++; plast-=2; }
- else if ( *(plast-1) == '~' ) { strlcpy (A->g_mfr, "Unknown OTHER", sizeof(A->g_mfr)); pfirst++; plast-=2; }
+ process_comment (A, trimmed+4, strlen(trimmed) - 4);
+ return;
}
-/*
- * An optional altitude is next.
- * It is three base-91 digits followed by "}".
- * The TM-D710A might have encoding bug. This was observed:
- *
- * KJ4ETP-9>SUUP9Q,KE4OTZ-3,WIDE1*,WIDE2-1,qAR,KI4HDU-2:`oV$n6:>/]"7&}162.475MHz clintserman@gmail=
- * N 35 50.9100, W 083 58.0800, 25 MPH, course 230, alt 945 ft, 162.475MHz
- *
- * KJ4ETP-9>SUUP6Y,GRNTOP-3*,WIDE2-1,qAR,KI4HDU-2:`oU~nT >/]<0x9a>xt}162.475MHz clintserman@gmail=
- * Invalid character in MIC-E altitude. Must be in range of '!' to '{'.
- * N 35 50.6900, W 083 57.9800, 29 MPH, course 204, alt 3280843 ft, 162.475MHz
- *
- * KJ4ETP-9>SUUP6Y,N4NEQ-3,K4EGA-1,WIDE2*,qAS,N5CWH-1:`oU~nT >/]?xt}162.475MHz clintserman@gmail=
- * N 35 50.6900, W 083 57.9800, 29 MPH, course 204, alt 808497 ft, 162.475MHz
- *
- * KJ4ETP-9>SUUP2W,KE4OTZ-3,WIDE1*,WIDE2-1,qAR,KI4HDU-2:`oV2o"J>/]"7)}162.475MHz clintserman@gmail=
- * N 35 50.2700, W 083 58.2200, 35 MPH, course 246, alt 955 ft, 162.475MHz
- *
- * Note the <0x9a> which is outside of the 7-bit ASCII range. Clearly very wrong.
- */
+ process_comment (A, trimmed, strlen(trimmed));
- if (plast > pfirst && pfirst[3] == '}') {
-
- A->g_altitude_ft = DW_METERS_TO_FEET((pfirst[0]-33)*91*91 + (pfirst[1]-33)*91 + (pfirst[2]-33) - 10000);
-
- if ( ! isdigit91(pfirst[0]) || ! isdigit91(pfirst[1]) || ! isdigit91(pfirst[2]))
- {
- if ( ! A->g_quiet) {
- text_color_set(DW_COLOR_ERROR);
- dw_printf("Invalid character in MIC-E altitude. Must be in range of '!' to '{'.\n");
- dw_printf("Bogus altitude of %.0f changed to unknown.\n", A->g_altitude_ft);
- }
- A->g_altitude_ft = G_UNKNOWN;
- }
-
- pfirst += 4;
- }
-
- process_comment (A, (char*)pfirst, (int)(plast - pfirst) + 1);
-
-}
+} // end aprs_mic_e
/*------------------------------------------------------------------
@@ -4251,221 +4166,6 @@ static int data_extension_comment (decode_aprs_t *A, char *pdext)
}
-/*------------------------------------------------------------------
- *
- * Function: decode_tocall
- *
- * Purpose: Extract application from the destination.
- *
- * Inputs: dest - Destination address.
- * Don't care if SSID is present or not.
- *
- * Outputs: A->g_mfr
- *
- * Description: For maximum flexibility, we will read the
- * data file at run time rather than compiling it in.
- *
- * For the most recent version, download from:
- *
- * http://www.aprs.org/aprs11/tocalls.txt
- *
- * Windows version: File must be in current working directory.
- *
- * Linux version: Search order is current working directory then
- * /usr/local/share/direwolf
- * /usr/share/direwolf/tocalls.txt
- *
- * Mac: Like Linux and then
- * /opt/local/share/direwolf
- *
- *------------------------------------------------------------------*/
-
-// If I was more ambitious, this would dynamically allocate enough
-// storage based on the file contents. Just stick in a constant for
-// now. This takes an insignificant amount of space and
-// I don't anticipate tocalls.txt growing that quickly.
-// Version 1.4 - add message if too small instead of silently ignoring the rest.
-
-// Dec. 2016 tocalls.txt has 153 destination addresses.
-
-#define MAX_TOCALLS 250
-
-static struct tocalls_s {
- unsigned char len;
- char prefix[7];
- char *description;
-} tocalls[MAX_TOCALLS];
-
-static int num_tocalls = 0;
-
-// Make sure the array is null terminated.
-// If search order is changed, do the same in symbols.c for consistency.
-
-static const char *search_locations[] = {
- (const char *) "tocalls.txt", // CWD
- (const char *) "data/tocalls.txt", // Windows with CMake
- (const char *) "../data/tocalls.txt", // ?
-#ifndef __WIN32__
- (const char *) "/usr/local/share/direwolf/tocalls.txt",
- (const char *) "/usr/share/direwolf/tocalls.txt",
-#endif
-#if __APPLE__
- // https://groups.yahoo.com/neo/groups/direwolf_packet/conversations/messages/2458
- // Adding the /opt/local tree since macports typically installs there. Users might want their
- // INSTALLDIR (see Makefile.macosx) to mirror that. If so, then we need to search the /opt/local
- // path as well.
- (const char *) "/opt/local/share/direwolf/tocalls.txt",
-#endif
- (const char *) NULL // Important - Indicates end of list.
-};
-
-static int tocall_cmp (const void *px, const void *py)
-{
- const struct tocalls_s *x = (struct tocalls_s *)px;
- const struct tocalls_s *y = (struct tocalls_s *)py;
-
- if (x->len != y->len) return (y->len - x->len);
- return (strcmp(x->prefix, y->prefix));
-}
-
-static void decode_tocall (decode_aprs_t *A, char *dest)
-{
- FILE *fp = 0;
- int n = 0;
- static int first_time = 1;
- char stuff[100];
- char *p = NULL;
- char *r = NULL;
-
- //dw_printf("debug: decode_tocall(\"%s\")\n", dest);
-
-/*
- * Extract the calls and descriptions from the file.
- *
- * Use only lines with exactly these formats:
- *
- * APN Network nodes, digis, etc
- * APWWxx APRSISCE win32 version
- * | | |
- * 00000000001111111111
- * 01234567890123456789...
- *
- * Matching will be with only leading upper case and digits.
- */
-
-// TODO: Look for this in multiple locations.
-// For example, if application was installed in /usr/local/bin,
-// we might want to put this in /usr/local/share/aprs
-
-// If search strategy changes, be sure to keep symbols_init in sync.
-
- if (first_time) {
-
- n = 0;
- fp = NULL;
- do {
- if(search_locations[n] == NULL) break;
- fp = fopen(search_locations[n++], "r");
- } while (fp == NULL);
-
- if (fp != NULL) {
-
- while (fgets(stuff, sizeof(stuff), fp) != NULL && num_tocalls < MAX_TOCALLS) {
-
- p = stuff + strlen(stuff) - 1;
- while (p >= stuff && (*p == '\r' || *p == '\n')) {
- *p-- = '\0';
- }
-
- // dw_printf("debug: %s\n", stuff);
-
- if (stuff[0] == ' ' &&
- stuff[4] == ' ' &&
- stuff[5] == ' ' &&
- stuff[6] == 'A' &&
- stuff[7] == 'P' &&
- stuff[12] == ' ' &&
- stuff[13] == ' ' ) {
-
- p = stuff + 6;
- r = tocalls[num_tocalls].prefix;
- while (isupper((int)(*p)) || isdigit((int)(*p))) {
- *r++ = *p++;
- }
- *r = '\0';
- if (strlen(tocalls[num_tocalls].prefix) > 2) {
- tocalls[num_tocalls].description = strdup(stuff+14);
- tocalls[num_tocalls].len = strlen(tocalls[num_tocalls].prefix);
- // dw_printf("debug %d: %d '%s' -> '%s'\n", num_tocalls, tocalls[num_tocalls].len, tocalls[num_tocalls].prefix, tocalls[num_tocalls].description);
-
- num_tocalls++;
- }
- }
- else if (stuff[0] == ' ' &&
- stuff[1] == 'A' &&
- stuff[2] == 'P' &&
- isupper((int)(stuff[3])) &&
- stuff[4] == ' ' &&
- stuff[5] == ' ' &&
- stuff[6] == ' ' &&
- stuff[12] == ' ' &&
- stuff[13] == ' ' ) {
-
- p = stuff + 1;
- r = tocalls[num_tocalls].prefix;
- while (isupper((int)(*p)) || isdigit((int)(*p))) {
- *r++ = *p++;
- }
- *r = '\0';
- if (strlen(tocalls[num_tocalls].prefix) > 2) {
- tocalls[num_tocalls].description = strdup(stuff+14);
- tocalls[num_tocalls].len = strlen(tocalls[num_tocalls].prefix);
- // dw_printf("debug %d: %d '%s' -> '%s'\n", num_tocalls, tocalls[num_tocalls].len, tocalls[num_tocalls].prefix, tocalls[num_tocalls].description);
-
- num_tocalls++;
- }
- }
- if (num_tocalls == MAX_TOCALLS) { // oops. might have discarded some.
- text_color_set(DW_COLOR_ERROR);
- dw_printf("MAX_TOCALLS needs to be larger than %d to handle contents of 'tocalls.txt'.\n", MAX_TOCALLS);
- }
- }
- fclose(fp);
-
-/*
- * Sort by decreasing length so the search will go
- * from most specific to least specific.
- * Example: APY350 or APY008 would match those specific
- * models before getting to the more generic APY.
- */
-
- qsort (tocalls, num_tocalls, sizeof(struct tocalls_s), tocall_cmp);
-
- }
- else {
- if ( ! A->g_quiet) {
- text_color_set(DW_COLOR_ERROR);
- dw_printf("Warning: Could not open 'tocalls.txt'.\n");
- dw_printf("System types in the destination field will not be decoded.\n");
- }
- }
-
- first_time = 0;
-
- //for (n=0; n '%s'\n", n, tocalls[n].len, tocalls[n].prefix, tocalls[n].description);
- //}
- }
-
-
- for (n=0; ng_mfr, tocalls[n].description, sizeof(A->g_mfr));
- return;
- }
- }
-
-} /* end decode_tocall */
@@ -4513,7 +4213,7 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
* clen - Length of comment or -1 to take it all.
*
* Outputs: A->g_telemetry - Base 91 telemetry |ss1122|
- * A->g_altitude_ft - from /A=123456
+ * A->g_altitude_ft - from /A=123456 or /A=-12345
* A->g_lat - Might be adjusted from !DAO!
* A->g_lon - Might be adjusted from !DAO!
* A->g_aprstt_loc - Private extension to !DAO!
@@ -4543,6 +4243,10 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
* Protocol reference, end of chapter 6.
*
* /A=123456 Altitude
+ * /A=-12345 Enhancement - There are many places on the earth's
+ * surface but the APRS spec has no provision for negative
+ * numbers. I propose having 5 digits for a consistent
+ * field width. 6 would be excessive.
*
* What can appear in a comment?
*
@@ -4708,7 +4412,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
dw_printf("%s:%d: %s\n", __FILE__, __LINE__, emsg);
}
- e = regcomp (&alt_re, "/A=[0-9][0-9][0-9][0-9][0-9][0-9]", REG_EXTENDED);
+ e = regcomp (&alt_re, "/A=[0-9-][0-9][0-9][0-9][0-9][0-9]", REG_EXTENDED);
if (e) {
regerror (e, &alt_re, emsg, sizeof(emsg));
dw_printf("%s:%d: %s\n", __FILE__, __LINE__, emsg);
@@ -5068,7 +4772,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
}
/*
- * Altitude in feet. /A=123456
+ * Altitude in feet. /A=123456 or /A=-12345
*/
if (regexec (&alt_re, A->g_comment, MAXMATCH, match, 0) == 0)
@@ -5186,7 +4890,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
*
* Function: main
*
- * Purpose: Main program for standalone test program.
+ * Purpose: Main program for standalone application to parse and explain APRS packets.
*
* Inputs: stdin for raw data to decode.
* This is in the usual display format either from
@@ -5332,6 +5036,7 @@ int main (int argc, char *argv[])
// If you don't like the text colors, use 0 instead of 1 here.
text_color_init(1);
text_color_set(DW_COLOR_INFO);
+ deviceid_init();
while (fgets(stuff, sizeof(stuff), stdin) != NULL)
{
diff --git a/src/deviceid.c b/src/deviceid.c
new file mode 100644
index 0000000..de910e5
--- /dev/null
+++ b/src/deviceid.c
@@ -0,0 +1,668 @@
+//
+// This file is part of Dire Wolf, an amateur radio packet TNC.
+//
+// Copyright (C) 2023 John Langner, WB2OSZ
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+
+/*------------------------------------------------------------------
+ *
+ * File: deviceid.c
+ *
+ * Purpose: Determine the device identifier from the destination field,
+ * or from prefix/suffix for MIC-E format.
+ *
+ * Description: Orginally this used the tocalls.txt file and was part of decode_aprs.c.
+ * For release 1.8, we use tocalls.yaml and this is split into a separate file.
+ *
+ *------------------------------------------------------------------*/
+
+//#define TEST 1 // Standalone test. $ gcc -DTEST deviceid.c && ./a.out
+
+
+#if TEST
+#define HAVE_STRLCPY 1 // prevent defining in direwolf.h
+#define HAVE_STRLCAT 1
+#endif
+
+#include "direwolf.h"
+
+#include
+#include
+#include
+#include
+
+#include "deviceid.h"
+#include "textcolor.h"
+
+
+static void unquote (int line, char *pin, char *pout);
+static int tocall_cmp (const void *px, const void *py);
+static int mice_cmp (const void *px, const void *py);
+
+/*------------------------------------------------------------------
+ *
+ * Function: main
+ *
+ * Purpose: A little self-test used during development.
+ *
+ * Description: Read the yaml file. Decipher a few typical values.
+ *
+ *------------------------------------------------------------------*/
+
+#if TEST
+// So we don't need to link with any other files.
+#define dw_printf printf
+void text_color_set(dw_color_t) { return; }
+void strlcpy(char *dst, char *src, size_t dlen) {
+ strcpy (dst, src);
+}
+void strlcat(char *dst, char *src, size_t dlen) {
+ strcat (dst, src);
+}
+
+
+int main (int argc, char *argv[])
+{
+ char device[80];
+ char comment_out[80];
+
+ deviceid_init ();
+
+ dw_printf ("\n");
+ dw_printf ("Testing ...\n");
+
+// MIC-E Legacy (really Kenwood).
+
+ deviceid_decode_mice (">Comment", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Kenwood TH-D7A") == 0);
+
+ deviceid_decode_mice (">Comment^", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Kenwood TH-D74") == 0);
+
+ deviceid_decode_mice ("]Comment", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Kenwood TM-D700") == 0);
+
+ deviceid_decode_mice ("]Comment=", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Kenwood TM-D710") == 0);
+
+ deviceid_decode_mice ("]\"4V}=", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "\"4V}") == 0);
+ assert (strcmp(device, "Kenwood TM-D710") == 0);
+
+
+// Modern MIC-E.
+
+ deviceid_decode_mice ("`Comment_\"", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Yaesu FTM-350") == 0);
+
+ deviceid_decode_mice ("`Comment_ ", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Yaesu VX-8") == 0);
+
+ deviceid_decode_mice ("'Comment|3", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "Byonics TinyTrak3") == 0);
+
+ deviceid_decode_mice ("Comment", comment_out, sizeof(comment_out), device, sizeof(device));
+ dw_printf ("%s %s\n", comment_out, device);
+ assert (strcmp(comment_out, "Comment") == 0);
+ assert (strcmp(device, "UNKNOWN vendor/model") == 0);
+
+
+// Tocall
+
+ deviceid_decode_dest ("APDW18", device, sizeof(device));
+ dw_printf ("%s\n", device);
+ assert (strcmp(device, "WB2OSZ DireWolf") == 0);
+
+ deviceid_decode_dest ("APD123", device, sizeof(device));
+ dw_printf ("%s\n", device);
+ assert (strcmp(device, "Open Source aprsd") == 0);
+
+ // null for Vendor.
+ deviceid_decode_dest ("APAX", device, sizeof(device));
+ dw_printf ("%s\n", device);
+ assert (strcmp(device, "AFilterX") == 0);
+
+ deviceid_decode_dest ("APA123", device, sizeof(device));
+ dw_printf ("%s\n", device);
+ assert (strcmp(device, "UNKNOWN vendor/model") == 0);
+
+ dw_printf ("\n");
+ dw_printf ("Success!\n");
+
+ exit (EXIT_SUCCESS);
+}
+
+#endif // TEST
+
+
+
+// Structures to hold mapping from encoded form to vendor and model.
+// The .yaml file has two separate sections for MIC-E but they can
+// both be handled as a single more general case.
+
+struct mice {
+ char prefix[4]; // The legacy form has 1 prefix character.
+ // The newer form has none. (more accurately ` or ')
+ char suffix[4]; // The legacy form has 0 or 1.
+ // The newer form has 2.
+ char *vendor;
+ char *model;
+};
+
+struct tocalls {
+ char tocall[8]; // Up to 6 characters. Some may have wildcards at the end.
+ // Most often they are trailing "??" or "?" or "???" in one case.
+ // Sometimes there is trailing "nnn". Does that imply digits only?
+ // Sometimes we see a trailing "*". Is "*" different than "?"?
+ // There are a couple bizzare cases like APnnnD which can
+ // create an ambigious situation. APMPAD, APRFGD, APY0[125]D.
+ // Screw them if they can't follow the rules. I'm not putting in a special case.
+ char *vendor;
+ char *model;
+};
+
+
+static struct mice *pmice = NULL; // Pointer to array.
+static int mice_count = 0; // Number of allocated elements.
+static int mice_index = -1; // Current index for filling in.
+
+static struct tocalls *ptocalls = NULL; // Pointer to array.
+static int tocalls_count = 0; // Number of allocated elements.
+static int tocalls_index = -1; // Current index for filling in.
+
+
+
+
+/*------------------------------------------------------------------
+ *
+ * Function: deviceid_init
+ *
+ * Purpose: Called once at startup to read the tocalls.yaml file which was obtained from
+ * https://github.com/aprsorg/aprs-deviceid .
+ *
+ * Inputs: tocalls.yaml with OS specific directory search list.
+ *
+ * Outputs: static variables listed above.
+ *
+ * Description: For maximum flexibility, we will read the
+ * data file at run time rather than compiling it in.
+ *
+ *------------------------------------------------------------------*/
+
+// Make sure the array is null terminated.
+// If search order is changed, do the same in symbols.c for consistency.
+// fopen is perfectly happy with / in file path when running on Windows.
+
+static const char *search_locations[] = {
+ (const char *) "tocalls.yaml", // Current working directory
+ (const char *) "data/tocalls.yaml", // Windows with CMake
+ (const char *) "../data/tocalls.yaml", // Source tree
+#ifndef __WIN32__
+ (const char *) "/usr/local/share/direwolf/tocalls.yaml",
+ (const char *) "/usr/share/direwolf/tocalls.yaml",
+#endif
+#if __APPLE__
+ // https://groups.yahoo.com/neo/groups/direwolf_packet/conversations/messages/2458
+ // Adding the /opt/local tree since macports typically installs there. Users might want their
+ // INSTALLDIR (see Makefile.macosx) to mirror that. If so, then we need to search the /opt/local
+ // path as well.
+ (const char *) "/opt/local/share/direwolf/tocalls.yaml",
+#endif
+ (const char *) NULL // Important - Indicates end of list.
+};
+
+
+void deviceid_init(void)
+{
+ FILE *fp = NULL;
+ for (int n = 0; search_locations[n] != NULL && fp == NULL; n++) {
+#if TEST
+ text_color_set(DW_COLOR_INFO);
+ dw_printf ("Trying %s\n", search_locations[n]);
+#endif
+ fp = fopen(search_locations[n], "r");
+#if TEST
+ if (fp != NULL) {
+ dw_printf ("Opened %s\n", search_locations[n]);
+ }
+#endif
+ };
+
+ if (fp == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("Could not open any of these file locations:\n");
+ for (int n = 0; search_locations[n] != NULL; n++) {
+ dw_printf (" %s\n", search_locations[n]);
+ }
+ dw_printf("It won't be possible to extract device identifiers from packets.\n");
+ return;
+ };
+
+// Read file first time to get number of items.
+// Allocate required space.
+// Rewind.
+// Read file second time to gather data.
+
+ enum { no_section, mice_section, tocalls_section} section = no_section;
+ char stuff[80];
+
+ for (int pass = 1; pass <=2; pass++) {
+ int line = 0; // Line number within file.
+
+ while (fgets(stuff, sizeof(stuff), fp)) {
+ line++;
+
+ // Remove trailing CR/LF or spaces.
+ char *p = stuff + strlen(stuff) - 1;
+ while (p >= (char*)stuff && (*p == '\r' || *p == '\n' || *p == ' ')) {
+ *p-- = '\0';
+ }
+
+ // Ignore comment lines.
+ if (stuff[0] == '#') {
+ continue;
+ }
+
+#if TEST
+ //dw_printf ("%d: %s\n", line, stuff);
+#endif
+ // This is not very robust; everything better be in exactly the right format.
+
+ if (strncmp(stuff, "mice:", strlen("mice:")) == 0) {
+ section = mice_section;
+#if TEST
+ dw_printf ("Pass %d, line %d, MIC-E section\n", pass, line);
+#endif
+ }
+ else if (strncmp(stuff, "micelegacy:", strlen("micelegacy:")) == 0) {
+ section = mice_section; // treat both same.
+#if TEST
+ dw_printf ("Pass %d, line %d, Legacy MIC-E section\n", pass, line);
+#endif
+ }
+ else if (strncmp(stuff, "tocalls:", strlen("tocalls:")) == 0) {
+ section = tocalls_section;
+#if TEST
+ dw_printf ("Pass %d, line %d, TOCALLS section\n", pass, line);
+#endif
+ }
+
+ // The first property of an item is preceded by " - ".
+
+ if (pass == 1 && strncmp(stuff, " - ", 3) == 0) {
+ switch (section) {
+ case no_section: break;
+ case mice_section: mice_count++; break;
+ case tocalls_section: tocalls_count++; break;
+ }
+ }
+
+ if (pass == 2) {
+ switch (section) {
+ case no_section:
+ break;
+
+ case mice_section:
+ if (strncmp(stuff, " - ", 3) == 0) {
+ mice_index++;
+ assert (mice_index >= 0 && mice_index < mice_count);
+ }
+ if (strncmp(stuff+3, "prefix: ", strlen("prefix: ")) == 0) {
+ unquote (line, stuff+3+8, pmice[mice_index].prefix);
+ }
+ else if (strncmp(stuff+3, "suffix: ", strlen("suffix: ")) == 0) {
+ unquote (line, stuff+3+8, pmice[mice_index].suffix);
+ }
+ else if (strncmp(stuff+3, "vendor: ", strlen("vendor: ")) == 0) {
+ pmice[mice_index].vendor = strdup(stuff+3+8);
+ }
+ else if (strncmp(stuff+3, "model: ", strlen("model: ")) == 0) {
+ pmice[mice_index].model = strdup(stuff+3+7);
+ }
+ break;
+
+ case tocalls_section:
+ if (strncmp(stuff, " - ", 3) == 0) {
+ tocalls_index++;
+ assert (tocalls_index >= 0 && tocalls_index < tocalls_count);
+ }
+ if (strncmp(stuff+3, "tocall: ", strlen("tocall: ")) == 0) {
+ // Remove trailing wildcard characters ? * n
+ char *r = stuff + strlen(stuff) - 1;
+ while (r >= (char*)stuff && (*r == '?' || *r == '*' || *r == 'n')) {
+ *r-- = '\0';
+ }
+
+ strlcpy (ptocalls[tocalls_index].tocall, stuff+3+8, sizeof(ptocalls[tocalls_index].tocall));
+
+ // Remove trailing CR/LF or spaces.
+ char *p = stuff + strlen(stuff) - 1;
+ while (p >= (char*)stuff && (*p == '\r' || *p == '\n' || *p == ' ')) {
+ *p-- = '\0';
+ }
+ }
+ else if (strncmp(stuff+3, "vendor: ", strlen("vendor: ")) == 0) {
+ ptocalls[tocalls_index].vendor = strdup(stuff+3+8);
+ }
+ else if (strncmp(stuff+3, "model: ", strlen("model: ")) == 0) {
+ ptocalls[tocalls_index].model = strdup(stuff+3+7);
+ }
+ break;
+ }
+ }
+ } // while(fgets
+
+ if (pass == 1) {
+#if TEST
+ dw_printf ("deviceid sizes %d %d\n", mice_count, tocalls_count);
+#endif
+ pmice = calloc(sizeof(struct mice), mice_count);
+ ptocalls = calloc(sizeof(struct tocalls), tocalls_count);
+
+ rewind (fp);
+ section = no_section;
+ }
+ } // for pass = 1 or 2
+
+ fclose (fp);
+
+ assert (mice_index == mice_count - 1);
+ assert (tocalls_index == tocalls_count - 1);
+
+
+// MIC-E Legacy needs to be sorted so those with suffix come first.
+
+ qsort (pmice, mice_count, sizeof(struct mice), mice_cmp);
+
+
+// Sort tocalls by decreasing length so the search will go from most specific to least specific.
+// Example: APY350 or APY008 would match those specific models before getting to the more generic APY.
+
+ qsort (ptocalls, tocalls_count, sizeof(struct tocalls), tocall_cmp);
+
+
+#if TEST
+ dw_printf ("MIC-E:\n");
+ for (int i = 0; i < mice_count; i++) {
+ dw_printf ("%s %s %s\n", pmice[i].suffix, pmice[i].vendor, pmice[i].model);
+ }
+ dw_printf ("TOCALLS:\n");
+ for (int i = 0; i < tocalls_count; i++) {
+ dw_printf ("%s %s %s\n", ptocalls[i].tocall, ptocalls[i].vendor, ptocalls[i].model);
+ }
+#endif
+
+ return;
+
+} // end deviceid_init
+
+
+/*------------------------------------------------------------------
+ *
+ * Function: unquote
+ *
+ * Purpose: Remove surrounding quotes and undo any escapes.
+ *
+ * Inputs: line - File line number for error message.
+ *
+ * in - String with quotes. Might contain \ escapes.
+ *
+ * Outputs: out - Quotes and escapes removed.
+ * Limited to 2 characters to avoid buffer overflow.
+ *
+ * Examples: in out
+ * "_#" _#
+ * "_\"" _"
+ * "=" =
+ *
+ *------------------------------------------------------------------*/
+
+static void unquote (int line, char *pin, char *pout)
+{
+ int count = 0;
+
+ *pout = '\0';
+ if (*pin != '"') {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("Missing leading \" for %s on line %d.\n", pin, line);
+ return;
+ }
+
+ pin++;
+ while (*pin != '\0' && *pin != '\"' && count < 2) {
+ if (*pin == '\\') {
+ pin++;
+ }
+ *pout++ = *pin++;
+ count++;
+ }
+ *pout = '\0';
+
+ if (*pin != '"') {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("Missing trailing \" or string too long on line %d.\n", line);
+ return;
+ }
+}
+
+// Used to sort the tocalls by length.
+// When length is equal, alphabetically.
+
+static int tocall_cmp (const void *px, const void *py)
+{
+ const struct tocalls *x = (struct tocalls *)px;
+ const struct tocalls *y = (struct tocalls *)py;
+
+ if (strlen(x->tocall) != strlen(y->tocall)) {
+ return (strlen(y->tocall) - strlen(x->tocall));
+ }
+ return (strcmp(x->tocall, y->tocall));
+}
+
+// Used to sort the suffixes by length.
+// Longer at the top.
+// Example check for >xxx^ before >xxx .
+
+static int mice_cmp (const void *px, const void *py)
+{
+ const struct mice *x = (struct mice *)px;
+ const struct mice *y = (struct mice *)py;
+
+ return (strlen(y->suffix) - strlen(x->suffix));
+}
+
+
+
+
+
+/*------------------------------------------------------------------
+ *
+ * Function: deviceid_decode_dest
+ *
+ * Purpose: Find vendor/model for destination address of form APxxxx.
+ *
+ * Inputs: dest - Destination address. No SSID.
+ *
+ * device_size - Amount of space available for result to avoid buffer overflow.
+ *
+ * Outputs: device - Vendor and model.
+ *
+ * Description: With the exception of MIC-E format, we expect to find the vendor/model in the
+ * AX.25 destination field. The form should be APxxxx.
+ *
+ * Search the list looking for the maximum length match.
+ * For example,
+ * APXR = Xrouter
+ * APX = Xastir
+ *
+ *------------------------------------------------------------------*/
+
+void deviceid_decode_dest (char *dest, char *device, size_t device_size)
+{
+ *device = '\0';
+
+ if (ptocalls == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("deviceid_decode_dest called without any deviceid data.\n");
+ return;
+ }
+
+ for (int n = 0; n < tocalls_count; n++) {
+ if (strncmp(dest, ptocalls[n].tocall, strlen(ptocalls[n].tocall)) == 0) {
+
+ if (ptocalls[n].vendor != NULL) {
+ strlcpy (device, ptocalls[n].vendor, device_size);
+ }
+
+ if (ptocalls[n].vendor != NULL && ptocalls[n].model != NULL) {
+ strlcat (device, " ", device_size);
+ }
+
+ if (ptocalls[n].model != NULL) {
+ strlcat (device, ptocalls[n].model, device_size);
+ }
+ return;
+ }
+ }
+
+ strlcpy (device, "UNKNOWN vendor/model", device_size);
+
+} // end deviceid_decode_dest
+
+
+/*------------------------------------------------------------------
+ *
+ * Function: deviceid_decode_mice
+ *
+ * Purpose: Find vendor/model for MIC-E comment.
+ *
+ * Inputs: comment - MIC-E comment that might have vendor/model encoded as
+ * a prefix and/or suffix.
+ *
+ * trimmed_size - Amount of space available for result to avoid buffer overflow.
+ *
+ * device_size - Amount of space available for result to avoid buffer overflow.
+ *
+ * Outputs: trimmed - Final comment with device vendor/model removed.
+ *
+ * device - Vendor and model.
+ *
+ * Description: This has a tortured history.
+ *
+ * The Kenwood TH-D7A put ">" at the beginning of the comment.
+ * The Kenwood TM-D700 put "]" at the beginning of the comment.
+ * Later Kenwood models also added a single suffix character
+ * using a character very unlikely to appear at the end of a comment.
+ *
+ * The later convention, used by everyone else, is to have a prefix of ` or '
+ * and a suffix of two characters. The suffix characters need to be
+ * something very unlikely to be found at the end of a comment.
+ *
+ * A receiving device is expected to remove those extra characters
+ * before displaying the comment.
+ *
+ * References: http://www.aprs.org/aprs12/mic-e-types.txt
+ * http://www.aprs.org/aprs12/mic-e-examples.txt
+ *
+ *------------------------------------------------------------------*/
+
+// The strncmp documentation doesn't mention behavior if length is zero.
+// Do our own just to be safe.
+
+static inline int strncmp_z (char *a, char *b, size_t len)
+{
+ int result = 0;
+ if (len > 0) {
+ result = strncmp(a, b, len);
+ }
+ //dw_printf ("Comparing '%s' and '%s' len %d result %d\n", a, b, len, result);
+ return result;
+}
+
+void deviceid_decode_mice (char *comment, char *trimmed, size_t trimmed_size, char *device, size_t device_size)
+{
+ *device = '\0';
+
+ if (ptocalls == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf("deviceid_decode_mice called without any deviceid data.\n");
+ return;
+ }
+
+
+// The Legacy format has an explicit prefix in the table.
+// For others, it must be ` or ' to indicate whether messaging capable.
+
+ for (int n = 0; n < mice_count; n++) {
+ if ((strlen(pmice[n].prefix) != 0 && // Legacy
+ strncmp_z(comment, // prefix from table
+ pmice[n].prefix,
+ strlen(pmice[n].prefix)) == 0 &&
+ strncmp_z(comment + strlen(comment) - strlen(pmice[n].suffix), // possible suffix
+ pmice[n].suffix,
+ strlen(pmice[n].suffix)) == 0) ||
+
+ (strlen(pmice[n].prefix) == 0 && // Later
+ (comment[0] == '`' || comment[0] == '\'') && // prefix ` or '
+ strncmp_z(comment + strlen(comment) - strlen(pmice[n].suffix), // suffix
+ pmice[n].suffix,
+ strlen(pmice[n].suffix)) == 0) ) {
+
+ if (pmice[n].vendor != NULL) {
+ strlcpy (device, pmice[n].vendor, device_size);
+ }
+
+ if (pmice[n].vendor != NULL && pmice[n].model != NULL) {
+ strlcat (device, " ", device_size);
+ }
+
+ if (pmice[n].model != NULL) {
+ strlcat (device, pmice[n].model, device_size);
+ }
+
+ // Remove any prefix/suffix and return what remains.
+
+ strlcpy (trimmed, comment + 1, trimmed_size);
+ trimmed[strlen(comment) - 1 - strlen(pmice[n].suffix)] = '\0';
+
+ return;
+ }
+ }
+
+
+// Not found.
+
+ strlcpy (device, "UNKNOWN vendor/model", device_size);
+
+} // end deviceid_decode_mice
+
+// end deviceid.c
diff --git a/src/deviceid.h b/src/deviceid.h
new file mode 100644
index 0000000..d7a1b30
--- /dev/null
+++ b/src/deviceid.h
@@ -0,0 +1,6 @@
+
+// deviceid.h
+
+void deviceid_init(void);
+void deviceid_decode_dest (char *dest, char *device, size_t device_size);
+void deviceid_decode_mice (char *comment, char *trimmed, size_t trimmed_size, char *device, size_t device_size);
diff --git a/src/direwolf.c b/src/direwolf.c
index e23aecb..2dfa58d 100644
--- a/src/direwolf.c
+++ b/src/direwolf.c
@@ -129,6 +129,7 @@
#include "dwsock.h"
#include "dns_sd_dw.h"
#include "dlq.h" // for fec_type_t definition.
+#include "deviceid.h"
//static int idx_decoded = 0;
@@ -186,7 +187,7 @@ static int d_u_opt = 0; /* "-d u" command line option to print UTF-8 also in h
static int d_p_opt = 0; /* "-d p" option for dumping packets over radio. */
static int q_h_opt = 0; /* "-q h" Quiet, suppress the "heard" line with audio level. */
-static int q_d_opt = 0; /* "-q d" Quiet, suppress the printing of decoded of APRS packets. */
+static int q_d_opt = 0; /* "-q d" Quiet, suppress the printing of description of APRS packets. */
static int A_opt_ais_to_obj = 0; /* "-A" Convert received AIS to APRS "Object Report." */
@@ -302,24 +303,27 @@ int main (int argc, char *argv[])
text_color_init(t_opt);
text_color_set(DW_COLOR_INFO);
//dw_printf ("Dire Wolf version %d.%d (%s) BETA TEST 7\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
- //dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "G", __DATE__);
- dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
+ dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "A", __DATE__);
+ //dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
-#if defined(ENABLE_GPSD) || defined(USE_HAMLIB) || defined(USE_CM108) || USE_AVAHI_CLIENT || USE_MACOS_DNSSD
+#if defined(ENABLE_GPSD) || defined(USE_HAMLIB) || defined(USE_CM108) || USE_AVAHI_CLIENT || USE_MACOS_DNSSD || USE_GPIOD
dw_printf ("Includes optional support for: ");
-#if defined(ENABLE_GPSD)
+ #if defined(ENABLE_GPSD)
dw_printf (" gpsd");
-#endif
-#if defined(USE_HAMLIB)
+ #endif
+ #if defined(USE_HAMLIB)
dw_printf (" hamlib");
-#endif
-#if defined(USE_CM108)
+ #endif
+ #if defined(USE_CM108)
dw_printf (" cm108-ptt");
-#endif
-#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD)
+ #endif
+ #if defined(USE_GPIOD)
+ dw_printf (" libgpiod");
+ #endif
+ #if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD)
dw_printf (" dns-sd");
-#endif
+ #endif
dw_printf ("\n");
#endif
@@ -982,6 +986,7 @@ int main (int argc, char *argv[])
* Files not supported at this time.
* Can always "cat" the file and pipe it into stdin.
*/
+ deviceid_init();
err = audio_open (&audio_config);
if (err < 0) {
@@ -1708,7 +1713,7 @@ static void usage (char **argv)
dw_printf (" d d = APRStt (DTMF to APRS object translation).\n");
dw_printf (" -q Quiet (suppress output) options:\n");
dw_printf (" h h = Heard line with the audio level.\n");
- dw_printf (" d d = Decoding of APRS packets.\n");
+ dw_printf (" d d = Description of APRS packets.\n");
dw_printf (" x x = Silence FX.25 information.\n");
dw_printf (" -t n Text colors. 0=disabled. 1=default. 2,3,4,... alternatives.\n");
dw_printf (" Use 9 to test compatibility with your terminal.\n");
diff --git a/src/ptt.c b/src/ptt.c
index 5187f1d..af74662 100644
--- a/src/ptt.c
+++ b/src/ptt.c
@@ -162,6 +162,10 @@
#include
#endif
+#ifdef USE_GPIOD
+#include
+#endif
+
/* So we can have more common code for fd. */
typedef int HANDLE;
#define INVALID_HANDLE_VALUE (-1)
@@ -468,6 +472,20 @@ void export_gpio(int ch, int ot, int invert, int direction)
text_color_set(DW_COLOR_ERROR);
dw_printf ("Error writing \"%s\" to %s, errno=%d\n", stemp, gpio_export_path, e);
dw_printf ("%s\n", strerror(e));
+
+ if (e == 22) {
+ // It appears that error 22 occurs when sysfs gpio is not available.
+ // (See https://github.com/wb2osz/direwolf/issues/503)
+ //
+ // The solution might be to use the new gpiod approach.
+
+ dw_printf ("It looks like gpio with sysfs is not supported on this operating system.\n");
+ dw_printf ("Rather than the following form, in the configuration file,\n");
+ dw_printf (" PTT GPIO %s\n", stemp);
+ dw_printf ("try using gpiod form instead. e.g.\n");
+ dw_printf (" PTT GPIOD gpiochip0 %s\n", stemp);
+ dw_printf ("You can get a list of gpio chip names and corresponding I/O lines with \"gpioinfo\" command.\n");
+ }
exit (1);
}
}
@@ -634,6 +652,31 @@ void export_gpio(int ch, int ot, int invert, int direction)
get_access_to_gpio (gpio_value_path);
}
+#if defined(USE_GPIOD)
+int gpiod_probe(const char *chip_name, int line_number)
+{
+ struct gpiod_chip *chip;
+ chip = gpiod_chip_open_by_name(chip_name);
+ if (chip == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Can't open GPIOD chip %s.\n", chip_name);
+ return -1;
+ }
+
+ struct gpiod_line *line;
+ line = gpiod_chip_get_line(chip, line_number);
+ if (line == NULL) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Can't get GPIOD line %d.\n", line_number);
+ return -1;
+ }
+ if (ptt_debug_level >= 2) {
+ text_color_set(DW_COLOR_DEBUG);
+ dw_printf("GPIOD probe OK. Chip: %s line: %d\n", chip_name, line_number);
+ }
+ return 0;
+}
+#endif /* USE_GPIOD */
#endif /* not __WIN32__ */
@@ -650,7 +693,8 @@ void export_gpio(int ch, int ot, int invert, int direction)
* ptt_method Method for PTT signal.
* PTT_METHOD_NONE - not configured. Could be using VOX.
* PTT_METHOD_SERIAL - serial (com) port.
- * PTT_METHOD_GPIO - general purpose I/O.
+ * PTT_METHOD_GPIO - general purpose I/O (sysfs).
+ * PTT_METHOD_GPIOD - general purpose I/O (libgpiod).
* PTT_METHOD_LPT - Parallel printer port.
* PTT_METHOD_HAMLIB - HAMLib rig control.
* PTT_METHOD_CM108 - GPIO pins of CM108 etc. USB Audio.
@@ -729,12 +773,13 @@ void ptt_init (struct audio_s *audio_config_p)
if (ptt_debug_level >= 2) {
text_color_set(DW_COLOR_DEBUG);
- dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
+ dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, name=%s, gpio=%d, lpt_bit=%d, invert=%d\n",
ch,
otnames[ot],
audio_config_p->achan[ch].octrl[ot].ptt_method,
audio_config_p->achan[ch].octrl[ot].ptt_device,
audio_config_p->achan[ch].octrl[ot].ptt_line,
+ audio_config_p->achan[ch].octrl[ot].out_gpio_name,
audio_config_p->achan[ch].octrl[ot].out_gpio_num,
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
audio_config_p->achan[ch].octrl[ot].ptt_invert);
@@ -880,7 +925,28 @@ void ptt_init (struct audio_s *audio_config_p)
if (using_gpio) {
get_access_to_gpio ("/sys/class/gpio/export");
}
-
+#if defined(USE_GPIOD)
+ // GPIOD
+ for (ch = 0; ch < MAX_CHANS; ch++) {
+ if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
+ for (int ot = 0; ot < NUM_OCTYPES; ot++) {
+ if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
+ const char *chip_name = audio_config_p->achan[ch].octrl[ot].out_gpio_name;
+ int line_number = audio_config_p->achan[ch].octrl[ot].out_gpio_num;
+ int rc = gpiod_probe(chip_name, line_number);
+ if (rc < 0) {
+ text_color_set(DW_COLOR_ERROR);
+ dw_printf ("Disable PTT for channel %d\n", ch);
+ audio_config_p->achan[ch].octrl[ot].ptt_method = PTT_METHOD_NONE;
+ } else {
+ // Set initial state off ptt_set will invert output signal if appropriate.
+ ptt_set (ot, ch, 0);
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_GPIOD */
/*
* We should now be able to create the device nodes for
* the pins we want to use.
@@ -1123,7 +1189,27 @@ void ptt_init (struct audio_s *audio_config_p)
if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
if(audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_NONE) {
text_color_set(DW_COLOR_INFO);
- dw_printf ("Note: PTT not configured for channel %d. (Ignore this if using VOX.)\n", ch);
+ dw_printf ("\n");
+ dw_printf ("Note: PTT not configured for channel %d. (OK if using VOX.)\n", ch);
+ dw_printf ("When using VOX, ensure that it adds very little delay (e.g. 10-20) milliseconds\n");
+ dw_printf ("between the time that transmit audio ends and PTT is deactivated.\n");
+ dw_printf ("For example, if using a SignaLink USB, turn the DLY control all the\n");
+ dw_printf ("way counter clockwise.\n");
+ dw_printf ("\n");
+ dw_printf ("Using VOX built in to the radio is a VERY BAD idea. This is intended\n");
+ dw_printf ("for voice operation, with gaps in the sound, and typically has a delay of about a\n");
+ dw_printf ("half second between the time the audio stops and the transmitter is turned off.\n");
+ dw_printf ("When using APRS your transmiter will be sending a quiet carrier for\n");
+ dw_printf ("about a half second after your packet ends. This may interfere with the\n");
+ dw_printf ("the next station to transmit. This is being inconsiderate.\n");
+ dw_printf ("\n");
+ dw_printf ("If you are trying to use VOX with connected mode packet, expect\n");
+ dw_printf ("frustration and disappointment. Connected mode involves rapid responses\n");
+ dw_printf ("which you will probably miss because your transmitter is still on when\n");
+ dw_printf ("the response is being transmitted.\n");
+ dw_printf ("\n");
+ dw_printf ("Read the User Guide 'Transmit Timing' section for more details.\n");
+ dw_printf ("\n");
}
}
}
@@ -1298,6 +1384,18 @@ void ptt_set (int ot, int chan, int ptt_signal)
close (fd);
}
+
+#if defined(USE_GPIOD)
+ if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
+ const char *chip = save_audio_config_p->achan[chan].octrl[ot].out_gpio_name;
+ int line = save_audio_config_p->achan[chan].octrl[ot].out_gpio_num;
+ int rc = gpiod_ctxless_set_value(chip, line, ptt, false, "direwolf", NULL, NULL);
+ if (ptt_debug_level >= 1) {
+ text_color_set(DW_COLOR_DEBUG);
+ dw_printf("PTT_METHOD_GPIOD chip: %s line: %d ptt: %d rc: %d\n", chip, line, ptt, rc);
+ }
+ }
+#endif /* USE_GPIOD */
#endif
/*
diff --git a/src/server.c b/src/server.c
index 6b41af2..2cc108b 100644
--- a/src/server.c
+++ b/src/server.c
@@ -379,7 +379,7 @@ static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int
case 'C': strlcpy (datakind, "AX.25 Connection Received", sizeof(datakind)); break;
case 'D': strlcpy (datakind, "Connected AX.25 Data", sizeof(datakind)); break;
case 'd': strlcpy (datakind, "Disconnected", sizeof(datakind)); break;
- case 'M': strlcpy (datakind, "Monitored Connected Information", sizeof(datakind)); break;
+ case 'I': strlcpy (datakind, "Monitored Connected Information", sizeof(datakind)); break;
case 'S': strlcpy (datakind, "Monitored Supervisory Information", sizeof(datakind)); break;
case 'U': strlcpy (datakind, "Monitored Unproto Information", sizeof(datakind)); break;
case 'T': strlcpy (datakind, "Monitoring Own Information", sizeof(datakind)); break;
@@ -820,7 +820,7 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
/* Stick in extra byte for the "TNC" to use. */
- agwpe_msg.data[0] = 0;
+ agwpe_msg.data[0] = chan << 4; // Was 0. Fixed in 1.8.
memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
if (debug_client) {
@@ -1559,6 +1559,7 @@ static THREAD_F cmd_listen_thread (void *arg)
case MEDIUM_RADIO:
{
+ // Misleading if using stdin or udp.
char stemp[100];
int a = ACHAN2ADEV(j);
// If I was really ambitious, some description could be provided.
@@ -1593,12 +1594,7 @@ static THREAD_F cmd_listen_thread (void *arg)
break;
default:
- {
- // could elaborate with hostname, etc.
- char stemp[100];
- snprintf (stemp, sizeof(stemp), "Port%d INVALID CHANNEL;", j+1);
- strlcat (reply.info, stemp, sizeof(reply.info));
- }
+ ; // Only list valid channels.
break;
} // switch
@@ -1721,6 +1717,7 @@ static THREAD_F cmd_listen_thread (void *arg)
packet_t pp;
+ int pid = cmd.hdr.pid;
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
strlcat (stemp, ">", sizeof(stemp));
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
@@ -1734,33 +1731,41 @@ static THREAD_F cmd_listen_thread (void *arg)
strlcat (stemp, p, sizeof(stemp));
p += 10;
}
+ // At this point, p now points to info part after digipeaters.
+
+ // Issue 527: NET/ROM routing broadcasts are binary info so we can't treat as string.
+ // Originally, I just appended the information part.
+ // That was fine until NET/ROM, with binary data, came along.
+ // Now we set the information field after creating the packet object.
+
strlcat (stemp, ":", sizeof(stemp));
- strlcat (stemp, p, sizeof(stemp));
+ strlcat (stemp, " ", sizeof(stemp));
//text_color_set(DW_COLOR_DEBUG);
//dw_printf ("Transmit '%s'\n", stemp);
pp = ax25_from_text (stemp, 1);
-
if (pp == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Failed to create frame from AGW 'V' message.\n");
+ break;
}
- else {
- /* This goes into the low priority queue because it is an original. */
+ ax25_set_info (pp, (unsigned char*)p, data_len - ndigi * 10);
+ // Issue 527: NET/ROM routing broadcasts use PID 0xCF which was not preserved here.
+ ax25_set_pid (pp, pid);
- /* Note that the protocol has no way to set the "has been used" */
- /* bits in the digipeater fields. */
+ /* This goes into the low priority queue because it is an original. */
- /* This explains why the digipeating option is grayed out in */
- /* xastir when using the AGW interface. */
- /* The current version uses only the 'V' message, not 'K' for transmitting. */
+ /* Note that the protocol has no way to set the "has been used" */
+ /* bits in the digipeater fields. */
- tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
+ /* This explains why the digipeating option is grayed out in */
+ /* xastir when using the AGW interface. */
+ /* The current version uses only the 'V' message, not 'K' for transmitting. */
- }
+ tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
}
break;
@@ -1784,11 +1789,17 @@ static THREAD_F cmd_listen_thread (void *arg)
// 00=Port 1
// 16=Port 2
//
- // I don't know what that means; we already a port number in the header.
+ // The seems to be redundant; we already a port number in the header.
// Anyhow, the original code here added one to cmd.data to get the
// first byte of the frame. Unfortunately, it did not subtract one from
// cmd.hdr.data_len so we ended up sending an extra byte.
+ // TODO: Right now I just use the port (channel) number in the header.
+ // What if the second one is inconsistent?
+ // - Continue to ignore port number at beginning of data?
+ // - Use second one instead?
+ // - Error message if a mismatch?
+
memset (&alevel, 0xff, sizeof(alevel));
pp = ax25_from_frame ((unsigned char *)cmd.data+1, data_len - 1, alevel);
@@ -1888,7 +1899,7 @@ static THREAD_F cmd_listen_thread (void *arg)
unsigned char num_digi; /* Expect to be in range 1 to 7. Why not up to 8? */
char dcall[7][10];
}
-#if 1
+
// October 2017. gcc ??? complained:
// warning: dereferencing pointer 'v' does break strict-aliasing rules
// Try adding this attribute to get rid of the warning.
@@ -1896,7 +1907,6 @@ static THREAD_F cmd_listen_thread (void *arg)
// Let me know. Maybe we could put in a compiler version check here.
__attribute__((__may_alias__))
-#endif
*v = (struct via_info *)cmd.data;
char callsigns[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
@@ -2005,19 +2015,7 @@ static THREAD_F cmd_listen_thread (void *arg)
{
int pid = cmd.hdr.pid;
- (void)(pid);
- /* The AGW protocol spec says, */
- /* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
-
- /* BUG: In theory, the AX.25 PID octet should be set from this. */
- /* All examples seen (above) have 0. */
- /* The AX.25 protocol spec doesn't list 0 as a valid value. */
- /* We always send 0xf0, meaning no layer 3. */
- /* Maybe we should have an ax25_set_pid function for cases when */
- /* it is neither 0 nor 0xf0. */
-
char stemp[AX25_MAX_PACKET_LEN];
- packet_t pp;
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
strlcat (stemp, ">", sizeof(stemp));
@@ -2025,21 +2023,29 @@ static THREAD_F cmd_listen_thread (void *arg)
cmd.data[data_len] = '\0';
+ // Issue 527: NET/ROM routing broadcasts are binary info so we can't treat as string.
+ // Originally, I just appended the information part as a text string.
+ // That was fine until NET/ROM, with binary data, came along.
+ // Now we set the information field after creating the packet object.
+
strlcat (stemp, ":", sizeof(stemp));
- strlcat (stemp, cmd.data, sizeof(stemp));
+ strlcat (stemp, " ", sizeof(stemp));
//text_color_set(DW_COLOR_DEBUG);
//dw_printf ("Transmit '%s'\n", stemp);
- pp = ax25_from_text (stemp, 1);
+ packet_t pp = ax25_from_text (stemp, 1);
if (pp == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Failed to create frame from AGW 'M' message.\n");
}
- else {
- tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
- }
+
+ ax25_set_info (pp, (unsigned char*)cmd.data, data_len);
+ // Issue 527: NET/ROM routing broadcasts use PID 0xCF which was not preserved here.
+ ax25_set_pid (pp, pid);
+
+ tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
}
break;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 91e06a2..da732ac 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -147,6 +147,7 @@ list(APPEND dtest_SOURCES
${CUSTOM_SRC_DIR}/tq.c
${CUSTOM_SRC_DIR}/textcolor.c
${CUSTOM_SRC_DIR}/decode_aprs.c
+ ${CUSTOM_SRC_DIR}/deviceid.c
${CUSTOM_SRC_DIR}/dwgpsnmea.c
${CUSTOM_SRC_DIR}/dwgps.c
${CUSTOM_SRC_DIR}/dwgpsd.c
@@ -232,6 +233,7 @@ list(APPEND pftest_SOURCES
${CUSTOM_SRC_DIR}/textcolor.c
${CUSTOM_SRC_DIR}/fcs_calc.c
${CUSTOM_SRC_DIR}/decode_aprs.c
+ ${CUSTOM_SRC_DIR}/deviceid.c
${CUSTOM_SRC_DIR}/dwgpsnmea.c
${CUSTOM_SRC_DIR}/dwgps.c
${CUSTOM_SRC_DIR}/dwgpsd.c
@@ -522,6 +524,7 @@ if(OPTIONAL_TEST)
${CUSTOM_SRC_DIR}/pfilter.c
${CUSTOM_SRC_DIR}/telemetry.c
${CUSTOM_SRC_DIR}/decode_aprs.c
+ ${CUSTOM_SRC_DIR}/deviceid.c.c
${CUSTOM_SRC_DIR}/dwgpsnmea.c
${CUSTOM_SRC_DIR}/dwgps.c
${CUSTOM_SRC_DIR}/dwgpsd.c
@@ -574,6 +577,7 @@ if(OPTIONAL_TEST)
${CUSTOM_SRC_DIR}/fcs_calc.c
${CUSTOM_SRC_DIR}/ax25_pad.c
${CUSTOM_SRC_DIR}/decode_aprs.c
+ ${CUSTOM_SRC_DIR}/deviceid.c
${CUSTOM_SRC_DIR}/dwgpsnmea.c
${CUSTOM_SRC_DIR}/dwgps.c
${CUSTOM_SRC_DIR}/dwgpsd.c