mirror of https://github.com/wb2osz/direwolf.git
Sync Mac CM108 changes with latest dev branch
This commit is contained in:
commit
8ae7de98fc
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -109,5 +109,5 @@ $RECYCLE.BIN/
|
|||
*.dSYM
|
||||
|
||||
# cmake
|
||||
build/
|
||||
build*/
|
||||
tmp/
|
|
@ -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 ##
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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})
|
|
@ -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})
|
||||
|
|
|
@ -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
|
326
data/tocalls.txt
326
data/tocalls.txt
|
@ -1,326 +0,0 @@
|
|||
<title>
|
||||
APRS TO-CALL VERSION NUMBERS 14 Dec 2021
|
||||
---------------------------------------------------------------------
|
||||
WB4APR
|
||||
</title>
|
||||
<version_notes>
|
||||
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
|
||||
|
||||
</version_notes>
|
||||
<description>
|
||||
|
||||
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.
|
||||
|
||||
</description>
|
||||
<tocalls>
|
||||
|
||||
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
|
||||
</tocalls>
|
||||
<notes>
|
||||
|
||||
</notes>
|
||||
<altnets>
|
||||
|
||||
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:
|
||||
</altnets>
|
||||
<altnet_list>
|
||||
|
||||
SATERN - Salvation Army Altnet
|
||||
AFMARS - Airforce Mars
|
||||
AMARS - Army Mars
|
||||
</altnet_list>
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
19
src/audio.h
19
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. */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
162
src/config.c
162
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; channel<MAX_CHANS; channel++) {
|
||||
int ot, it;
|
||||
|
@ -925,10 +926,13 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
p_misc_config->maxframe_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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <Knox,TN> 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 <Knox,TN> 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 <Knox,TN> 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 <Knox,TN> 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<num_tocalls; n++) {
|
||||
// dw_printf("sorted %d: %d '%s' -> '%s'\n", n, tocalls[n].len, tocalls[n].prefix, tocalls[n].description);
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
for (n=0; n<num_tocalls; n++) {
|
||||
if (strncmp(dest, tocalls[n].prefix, tocalls[n].len) == 0) {
|
||||
strlcpy (A->g_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)
|
||||
{
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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
|
|
@ -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);
|
|
@ -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");
|
||||
|
|
106
src/ptt.c
106
src/ptt.c
|
@ -162,6 +162,10 @@
|
|||
#include <hamlib/rig.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_GPIOD
|
||||
#include <gpiod.h>
|
||||
#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
|
||||
|
||||
/*
|
||||
|
|
84
src/server.c
84
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue