mirror of https://github.com/wb2osz/direwolf.git
Use tocalls.yaml rather than tocalls.txt which is no longer maintained.
This commit is contained in:
parent
d679e06846
commit
46f31d4453
|
@ -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 ##
|
||||
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
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
|
@ -33,6 +33,7 @@ list(APPEND direwolf_SOURCES
|
|||
beacon.c
|
||||
config.c
|
||||
decode_aprs.c
|
||||
deviceid.c
|
||||
dedupe.c
|
||||
demod_9600.c
|
||||
demod_afsk.c
|
||||
|
@ -171,6 +172,7 @@ endif()
|
|||
# decode_aprs
|
||||
list(APPEND decode_aprs_SOURCES
|
||||
decode_aprs.c
|
||||
deviceid.c
|
||||
ais.c
|
||||
kiss_frame.c
|
||||
ax25_pad.c
|
||||
|
@ -355,6 +357,7 @@ list(APPEND atest_SOURCES
|
|||
ax25_pad.c
|
||||
ax25_pad2.c
|
||||
decode_aprs.c
|
||||
deviceid.c
|
||||
dwgpsnmea.c
|
||||
dwgps.c
|
||||
dwgpsd.c
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017, 2022 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017, 2022, 2023 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -56,7 +56,7 @@
|
|||
#include "decode_aprs.h"
|
||||
#include "telemetry.h"
|
||||
#include "ais.h"
|
||||
|
||||
#include "deviceid.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
@ -124,7 +124,6 @@ static double get_longitude_9 (char *p, int quiet);
|
|||
static time_t get_timestamp (decode_aprs_t *A, char *p);
|
||||
static int get_maidenhead (decode_aprs_t *A, char *p);
|
||||
static int data_extension_comment (decode_aprs_t *A, char *pdext);
|
||||
static void decode_tocall (decode_aprs_t *A, char *dest);
|
||||
//static void get_symbol (decode_aprs_t *A, char dti, char *src, char *dest);
|
||||
static void process_comment (decode_aprs_t *A, char *pstart, int clen);
|
||||
|
||||
|
@ -292,7 +291,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, char *third_party_sr
|
|||
}
|
||||
|
||||
/*
|
||||
* Application might be in the destination field for most message types.
|
||||
* Device/Application is in the destination field for most packet types.
|
||||
* MIC-E format has part of location in the destination field.
|
||||
*/
|
||||
|
||||
|
@ -303,7 +302,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, char *third_party_sr
|
|||
break;
|
||||
|
||||
default:
|
||||
decode_tocall (A, A->g_dest);
|
||||
deviceid_decode_dest (A->g_dest, A->g_mfr, sizeof(A->g_mfr));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1392,7 +1391,6 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
int cust_msg = 0;
|
||||
const char *std_text[8] = {"Emergency", "Priority", "Special", "Committed", "Returning", "In Service", "En Route", "Off Duty" };
|
||||
const char *cust_text[8] = {"Emergency", "Custom-6", "Custom-5", "Custom-4", "Custom-3", "Custom-2", "Custom-1", "Custom-0" };
|
||||
unsigned char *pfirst, *plast;
|
||||
|
||||
strlcpy (A->g_data_type_desc, "MIC-E", sizeof(A->g_data_type_desc));
|
||||
|
||||
|
@ -1622,111 +1620,32 @@ 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. 3 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 && 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; }
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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 ( ! isdigit91(trimmed[0]) || ! isdigit91(trimmed[1]) || ! isdigit91(trimmed[2]))
|
||||
{
|
||||
if ( ! A->g_quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1736,12 +1655,13 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
A->g_altitude_ft = G_UNKNOWN;
|
||||
}
|
||||
|
||||
pfirst += 4;
|
||||
process_comment (A, mcomment+4, strlen(mcomment) - 4);
|
||||
return;
|
||||
}
|
||||
|
||||
process_comment (A, (char*)pfirst, (int)(plast - pfirst) + 1);
|
||||
process_comment (A, mcomment, strlen(mcomment));
|
||||
|
||||
}
|
||||
} // end aprs_mic_e
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
|
@ -4251,221 +4171,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 +4218,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 +4248,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 +4417,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 +4777,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 +4895,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 +5041,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,660 @@
|
|||
//
|
||||
// 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);
|
||||
|
||||
|
||||
// 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++) {
|
||||
dw_printf ("Trying %s\n", search_locations[n]);
|
||||
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), //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;
|
||||
|
@ -985,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) {
|
||||
|
|
|
@ -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