mirror of https://github.com/wb2osz/direwolf.git
Compare commits
No commits in common. "master" and "1.5-beta2" have entirely different histories.
|
@ -1,162 +0,0 @@
|
|||
name: 'build direwolf'
|
||||
|
||||
on:
|
||||
# permit to manually trigger the CI
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
cmake_flags:
|
||||
description: 'Custom CMAKE flags'
|
||||
required: false
|
||||
push:
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: 'Windows Latest MinGW 64bit',
|
||||
os: windows-latest,
|
||||
cc: 'x86_64-w64-mingw32-gcc',
|
||||
cxx: 'x86_64-w64-mingw32-g++',
|
||||
ar: 'x86_64-w64-mingw32-ar',
|
||||
windres: 'x86_64-w64-mingw32-windres',
|
||||
arch: 'x86_64',
|
||||
build_type: 'Release',
|
||||
cmake_extra_flags: '-G "MinGW Makefiles"'
|
||||
}
|
||||
- {
|
||||
name: 'Windows 2019 MinGW 32bit',
|
||||
os: windows-2019,
|
||||
cc: 'i686-w64-mingw32-gcc',
|
||||
cxx: 'i686-w64-mingw32-g++',
|
||||
ar: 'i686-w64-mingw32-ar',
|
||||
windres: 'i686-w64-mingw32-windres',
|
||||
arch: 'i686',
|
||||
build_type: 'Release',
|
||||
cmake_extra_flags: '-G "MinGW Makefiles"'
|
||||
}
|
||||
- {
|
||||
name: 'macOS latest',
|
||||
os: macos-latest,
|
||||
cc: 'clang',
|
||||
cxx: 'clang++',
|
||||
arch: 'x86_64',
|
||||
build_type: 'Release',
|
||||
cmake_extra_flags: ''
|
||||
}
|
||||
- {
|
||||
name: 'Ubuntu latest Debug',
|
||||
os: ubuntu-latest,
|
||||
cc: 'gcc',
|
||||
cxx: 'g++',
|
||||
arch: 'x86_64',
|
||||
build_type: 'Debug',
|
||||
cmake_extra_flags: ''
|
||||
}
|
||||
- {
|
||||
name: 'Ubuntu 22.04',
|
||||
os: ubuntu-22.04,
|
||||
cc: 'gcc',
|
||||
cxx: 'g++',
|
||||
arch: 'x86_64',
|
||||
build_type: 'Release',
|
||||
cmake_extra_flags: ''
|
||||
}
|
||||
- {
|
||||
name: 'Ubuntu 20.04',
|
||||
os: ubuntu-20.04,
|
||||
cc: 'gcc',
|
||||
cxx: 'g++',
|
||||
arch: 'x86_64',
|
||||
build_type: 'Release',
|
||||
cmake_extra_flags: ''
|
||||
}
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 8
|
||||
- name: dependency
|
||||
shell: bash
|
||||
run: |
|
||||
# this is not perfect but enought for now
|
||||
if [ "$RUNNER_OS" == "Linux" ]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install libasound2-dev libudev-dev libhamlib-dev gpsd
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
# just to simplify I use homebrew but
|
||||
# we can use macports (latest direwolf is already available as port)
|
||||
brew install portaudio hamlib gpsd
|
||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||
# add the folder to PATH
|
||||
echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH
|
||||
fi
|
||||
- name: create build environment
|
||||
run: |
|
||||
cmake -E make_directory ${{github.workspace}}/build
|
||||
- name: configure
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
export CC=${{ matrix.config.cc }}
|
||||
export CXX=${{ matrix.config.cxx }}
|
||||
export AR=${{ matrix.config.ar }}
|
||||
export WINDRES=${{ matrix.config.windres }}
|
||||
fi
|
||||
cmake $GITHUB_WORKSPACE \
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
|
||||
-DCMAKE_C_COMPILER=${{ matrix.config.cc }} \
|
||||
-DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} \
|
||||
-DCMAKE_CXX_FLAGS="-Werror" -DUNITTEST=1 \
|
||||
${{ matrix.config.cmake_extra_flags }} \
|
||||
${{ github.event.inputs.cmake_flags }}
|
||||
- name: build
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
export CC=${{ matrix.config.cc }}
|
||||
export CXX=${{ matrix.config.cxx }}
|
||||
export AR=${{ matrix.config.ar }}
|
||||
export WINDRES=${{ matrix.config.windres }}
|
||||
fi
|
||||
cmake --build . --config ${{ matrix.config.build_type }} \
|
||||
${{ github.event.inputs.cmake_flags }}
|
||||
- name: test
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
ctest -C ${{ matrix.config.build_type }} \
|
||||
--parallel 2 --output-on-failure \
|
||||
${{ github.event.inputs.cmake_flags }}
|
||||
- name: package
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Windows" ] || [ "$RUNNER_OS" == "macOS" ]; then
|
||||
make package
|
||||
fi
|
||||
- name: archive binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: direwolf_${{ matrix.config.os }}_${{ matrix.config.arch }}_${{ github.sha }}
|
||||
path: |
|
||||
${{github.workspace}}/build/direwolf-*.zip
|
||||
${{github.workspace}}/build/direwolf.conf
|
||||
${{github.workspace}}/build/src/*
|
||||
${{github.workspace}}/build/CMakeCache.txt
|
||||
!${{github.workspace}}/build/src/cmake_install.cmake
|
||||
!${{github.workspace}}/build/src/CMakeFiles
|
||||
!${{github.workspace}}/build/src/Makefile
|
|
@ -1,64 +0,0 @@
|
|||
# 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
|
|
@ -1,74 +0,0 @@
|
|||
# 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 - CPP"
|
||||
|
||||
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: [ '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@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
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DUNITTEST=1 ..
|
||||
make
|
||||
make test
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
|
@ -105,9 +105,3 @@ $RECYCLE.BIN/
|
|||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
/use_this_sdk
|
||||
*.dSYM
|
||||
|
||||
# cmake
|
||||
build/
|
||||
tmp/
|
|
@ -3,7 +3,7 @@
|
|||
# $ ls -l /dev/hidraw*
|
||||
# crw------- 1 root root 247, 0 Sep 24 09:40 /dev/hidraw0
|
||||
#
|
||||
# An ordinary user, trying to access it will be denied.
|
||||
# An ordinary user, trying to acccess it will be denied.
|
||||
#
|
||||
# Unnecessarily running applications as root is generally a bad idea because it makes it too easy
|
||||
# to accidentally trash your system. We need to relax the restrictions so ordinary users can use these devices.
|
||||
|
@ -28,9 +28,3 @@ SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d8c", GROUP="audio", MODE="0660"
|
|||
#
|
||||
# Read the User Guide and run the "cm108" application for more information.
|
||||
#
|
||||
|
||||
#
|
||||
# Same thing for the "All In One Cable."
|
||||
#
|
||||
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="7388", GROUP="audio", MODE="0660"
|
135
CHANGES.md
135
CHANGES.md
|
@ -1,141 +1,25 @@
|
|||
|
||||
# Revision History #
|
||||
|
||||
|
||||
## Version 1.7 -- October 2023 ##
|
||||
|
||||
|
||||
### New Documentation: ###
|
||||
|
||||
Additional documentation location to slow down growth of main repository. [https://github.com/wb2osz/direwolf-doc](https://github.com/wb2osz/direwolf-doc) . These are more oriented toward achieving a goal and understanding, as opposed to the User Guide which describes the functionality.
|
||||
|
||||
- ***APRS Digipeaters***
|
||||
|
||||
- ***Internal Packet Routing***
|
||||
|
||||
- ***Radio Interface Guide***
|
||||
|
||||
- ***Successful IGate Operation***
|
||||
|
||||
- ***Understanding APRS Packets***
|
||||
|
||||
|
||||
### New Features: ###
|
||||
|
||||
|
||||
|
||||
- New ICHANNEL configuration option to map a KISS client application channel to APRS-IS. Packets from APRS-IS will be presented to client applications as the specified channel. Packets sent, by client applications, to that channel will go to APRS-IS rather than a radio channel. Details in ***Internal-Packet-Routing.pdf***.
|
||||
|
||||
- New variable speed option for gen_packets. For example, "-v 5,0.1" would generate packets from 5% too slow to 5% too fast with increments of 0.1. Some implementations might have imprecise timing. Use this to test how well TNCs tolerate sloppy timing.
|
||||
|
||||
- Improved Layer 2 Protocol [(IL2P)](https://en.wikipedia.org/wiki/FX.25_Forward_Error_Correction). Compatible with Nino TNC for 1200 and 9600 bps. Use "-I 1" on command line to enable transmit for first channel. For more general case, add to config file (simplified version, see User Guide for more details):
|
||||
|
||||
> After: "CHANNEL 1" (or other channel)
|
||||
>
|
||||
> Add: "IL2PTX 1"
|
||||
|
||||
- Limited support for CM108/CM119 GPIO PTT on Windows.
|
||||
|
||||
- Dire Wolf now advertises itself using DNS Service Discovery. This allows suitable APRS / Packet Radio applications to find a network KISS TNC without knowing the IP address or TCP port. Thanks to Hessu for providing this. Currently available only for Linux and Mac OSX. [Read all about it here.](https://github.com/hessu/aprs-specs/blob/master/TCP-KISS-DNS-SD.md)
|
||||
|
||||
- The transmit calibration tone (-x) command line option now accepts a radio channel number and/or a single letter mode: a = alternate tones, m = mark tone, s = space tone, p = PTT only no sound.
|
||||
|
||||
- The BEACON configuration now recognizes the SOURCE= option. This replaces the AX.25 source address rather than using the MYCALL value for the channel. This is useful for sending more than 5 analog telemetry channels. Use two, or more, source addresses with up to 5 analog channels each.
|
||||
|
||||
- For more flexibility, the FX.25 transmit property can now be set individually by channel, rather than having a global setting for all channels. The -X on the command line applies only to channel 0. For other channels you need to add a new line to the configuration file. You can specify a specific number of parity bytes (16, 32, 64) or 1 to choose automatically based on packet size.
|
||||
|
||||
> After: "CHANNEL 1" (or other channel)
|
||||
>
|
||||
> Add: "FX25TX 1" (or 16 or 32 or 64)
|
||||
|
||||
|
||||
## Version 1.5 -- Beta Test 2 -- February 2018 ##
|
||||
|
||||
### Bugs Fixed: ###
|
||||
|
||||
- The t/m packet filter incorrectly included bulletins. It now allows only "messages" to specific stations. Use of t/m is discouraged. i/180 is the preferred filter for messages to users recently heard locally.
|
||||
|
||||
- Packet filtering now skips over any third party header before classifying packet types.
|
||||
|
||||
- Fixed build for Alpine Linux.
|
||||
|
||||
### Notes: ###
|
||||
|
||||
The Windows binary distribution now uses gcc (MinGW) version 11.3.0.
|
||||
The Windows version is built for both 32 and 64 bit operating systems.
|
||||
Use the 64 bit version if possible; it runs considerably faster.
|
||||
|
||||
## Version 1.6 -- October 2020 ##
|
||||
|
||||
### New Build Procedure: ###
|
||||
- Strange failures when trying to use multiple KISS client applications over TCP. Only Linux was affected.
|
||||
|
||||
|
||||
- Rather than trying to keep a bunch of different platform specific Makefiles in sync, "cmake" is now used for greater portability and easier maintenance. This was contributed by Davide Gerhard.
|
||||
|
||||
- README.md has a quick summary of the process. More details in the ***User Guide***.
|
||||
|
||||
|
||||
### New Features: ###
|
||||
|
||||
|
||||
- "-X" option enables FX.25 transmission. FX.25 reception is always enabled so you don't need to do anything special. "What is FX.25?" you might ask. It is forward error correction (FEC) added in a way that is completely compatible with an ordinary AX.25 frame. See new document ***AX25\_plus\_FEC\_equals\_FX25.pdf*** for details.
|
||||
|
||||
- Receive AIS location data from ships. Enable by using "-B AIS" command line option or "MODEM AIS" in the configuration file. AIS NMEA sentences are encapsulated in APRS user-defined data with a "{DA" prefix. This uses 9600 bps so you need to use wide band audio, not what comes out of the speaker. There is also a "-A" option to generate APRS Object Reports.
|
||||
|
||||
- Receive Emergency Alert System (EAS) Specific Area Message Encoding (SAME). Enable by using "-B EAS" command line option or "MODEM EAS" in the configuration file. EAS SAME messages are encapsulated in APRS user-defined data with a "{DE" prefix. This uses low speed AFSK so speaker output is fine.
|
||||
|
||||
- "-t" option now accepts more values to accommodate inconsistent handling of text color control codes by different terminal emulators. The default, 1, should work with most modern terminal types. If the colors are not right, try "-t 9" to see the result of the different choices and pick the best one. If none of them look right, file a bug report and specify: operating system version (e.g. Raspbian Buster), terminal emulator type and version (e.g. LXTerminal 0.3.2). Include a screen capture.
|
||||
|
||||
|
||||
- "-g" option to force G3RUH mode for lower speeds where a different modem type may be the default.
|
||||
|
||||
- 2400 bps compatibility with MFJ-2400. See ***2400-4800-PSK-for-APRS-Packet-Radio.pdf*** for details
|
||||
|
||||
- "atest -h" will display the frame in hexadecimal for closer inspection.
|
||||
|
||||
- Add support for Multi-GNSS NMEA sentences.
|
||||
|
||||
|
||||
|
||||
### Bugs Fixed: ###
|
||||
|
||||
- Proper counting of frames in transmit queue for AGW protocol 'Y' command.
|
||||
|
||||
|
||||
|
||||
### New Documentation: ###
|
||||
|
||||
- ***AX.25 + FEC = FX.25***
|
||||
|
||||
- ***AIS Reception***
|
||||
|
||||
- ***AX.25 Throughput: Why is 9600 bps Packet Radio only twice as fast as 1200?***
|
||||
|
||||
- [***Ham Radio of Things (HRoT) - IoT over Ham Radio***](https://github.com/wb2osz/hrot)
|
||||
|
||||
- [***EAS SAME to APRS Message Converter***](https://github.com/wb2osz/eas2aprs)
|
||||
|
||||
- [***Dire Wolf PowerPoint Slide Show***](https://github.com/wb2osz/direwolf-presentation)
|
||||
|
||||
### Notes: ###
|
||||
|
||||
The Windows binary distribution now uses gcc (MinGW) version 7.4.0.
|
||||
The Windows version is built for both 32 and 64 bit operating systems.
|
||||
Use the 64 bit version if possible; it runs considerably faster.
|
||||
|
||||
|
||||
|
||||
## Version 1.5 -- September 2018 ##
|
||||
## Version 1.5 -- Beta Test -- January 2018 ##
|
||||
|
||||
|
||||
### New Features: ###
|
||||
|
||||
- PTT using GPIO pin of CM108/CM119 (e.g. DMK URI, RB-USB RIM), Linux only.
|
||||
|
||||
- More efficient error recovery for AX.25 connected mode. Better generation and processing of REJ and SREJ to reduce unnecessary duplicate "**I**" frames.
|
||||
|
||||
- New configuration option, "**V20**", for listing stations known to not understand AX.25 v2.2. This will speed up connection by going right to SABM and not trying SABME first and failing.
|
||||
- More efficient error recovery for AX.25 connected mode. Better generation and processing of REJ and SREJ to reduce unnecessary duplicate I frames.
|
||||
|
||||
- New configuration option, V20, for listing stations known to not understand AX.25 v2.2. This will speed up connection by going right to SABM and not trying SABME first and failing.
|
||||
|
||||
- New "**NOXID**" configuration file option to avoid sending XID command to listed station(s). If other end is a partial v2.2 implementation, which recognizes SABME, but not XID, we would waste a lot of time resending XID many times before giving up. This is less drastic than the "**V20**" option which doesn't even attempt to use v2.2 with listed station(s).
|
||||
|
||||
- New application "**kissutil**" for troubleshooting a KISS TNC or interfacing to an application via files.
|
||||
|
||||
|
@ -161,11 +45,6 @@ Use the 64 bit version if possible; it runs considerably faster.
|
|||
|
||||
- PACLEN configuration item no longer restricts length of received frames.
|
||||
|
||||
- Strange failures when trying to use multiple KISS client applications over TCP. Only Linux was affected.
|
||||
|
||||
- Under certain conditions, outgoing connected mode data would get stuck in a queue and not be transmitted. This could happen if client application sends a burst of data larger than the "window" size (MAXFRAME or EMAXFRAME option).
|
||||
|
||||
|
||||
- Little typographical / spelling errors in messages.
|
||||
|
||||
|
||||
|
@ -176,9 +55,7 @@ Use the 64 bit version if possible; it runs considerably faster.
|
|||
|
||||
- Updates describing cheap SDR frequency inaccuracy and how to compensate for it.
|
||||
|
||||
### Notes: ###
|
||||
|
||||
Windows binary distribution now uses gcc (MinGW) version 6.3.0.
|
||||
|
||||
----------
|
||||
|
||||
|
|
414
CMakeLists.txt
414
CMakeLists.txt
|
@ -1,414 +0,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_PATCH "0")
|
||||
set(direwolf_VERSION_SUFFIX "Development")
|
||||
|
||||
# options
|
||||
# See Issue 297.
|
||||
option(FORCE_SSE "Compile with SSE instruction only" ON)
|
||||
option(FORCE_SSSE3 "Compile with SSSE3 instruction only" OFF)
|
||||
option(FORCE_SSE41 "Compile with SSE4.1 instruction only" OFF)
|
||||
option(OPTIONAL_TEST "Compile optional test (might be broken)" OFF)
|
||||
# UNITTEST option must be after CMAKE_BUILT_TYPE
|
||||
|
||||
# where cmake find custom modules
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
# fix c standard used on the project
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
# Set additional project information
|
||||
set(COMPANY "wb2osz")
|
||||
add_definitions("-DCOMPANY=\"${COMPANY}\"")
|
||||
set(APPLICATION_NAME "Dire Wolf")
|
||||
add_definitions("-DAPPLICATION_NAME=\"${APPLICATION_NAME}\"")
|
||||
set(APPLICATION_MAINTAINER="John Langner, WB2OSZ")
|
||||
set(COPYRIGHT "Copyright (c) 2019 John Langner, WB2OSZ. All rights reserved.")
|
||||
add_definitions("-DCOPYRIGHT=\"${COPYRIGHT}\"")
|
||||
set(IDENTIFIER "com.${COMPANY}.${APPLICATION_NAME}")
|
||||
add_definitions("-DIDENTIFIER=\"${IDENTIFIER}\"")
|
||||
# raspberry as only lxterminal not xterm
|
||||
if(NOT (WIN32 OR CYGWIN))
|
||||
find_program(BINARY_TERMINAL_BIN lxterminal)
|
||||
if(BINARY_TERMINAL_BIN)
|
||||
set(APPLICATION_DESKTOP_EXEC "${BINARY_TERMINAL_BIN} -e ${CMAKE_PROJECT_NAME}")
|
||||
else()
|
||||
set(APPLICATION_DESKTOP_EXEC "xterm -e ${CMAKE_PROJECT_NAME}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Git)
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git/")
|
||||
# we can also use `git describe --tags`
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --short HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res)
|
||||
string(REGEX REPLACE "^v([0-9]+)\.([0-9]+)\.([0-9]+)-" "" git_commit ${out})
|
||||
set(direwolf_VERSION_SUFFIX "-${git_commit}")
|
||||
set(direwolf_VERSION_COMMIT "${git_commit}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# set variables
|
||||
set(direwolf_VERSION "${direwolf_VERSION_MAJOR}.${direwolf_VERSION_MINOR}.${direwolf_VERSION_PATCH}${direwolf_VERSION_SUFFIX}")
|
||||
message(STATUS "${APPLICATION_NAME} Version: ${direwolf_VERSION}")
|
||||
add_definitions("-DIREWOLF_VERSION=\"${direwolf_VERSION}\"")
|
||||
add_definitions("-DMAJOR_VERSION=${direwolf_VERSION_MAJOR}")
|
||||
add_definitions("-DMINOR_VERSION=${direwolf_VERSION_MINOR}")
|
||||
if(direwolf_VERSION_COMMIT)
|
||||
add_definitions("-DEXTRA_VERSION=${direwolf_VERSION_COMMIT}")
|
||||
endif()
|
||||
|
||||
set(CUSTOM_SRC_DIR "${CMAKE_SOURCE_DIR}/src")
|
||||
set(CUSTOM_EXTERNAL_DIR "${CMAKE_SOURCE_DIR}/external")
|
||||
set(CUSTOM_MISC_DIR "${CUSTOM_EXTERNAL_DIR}/misc")
|
||||
set(CUSTOM_REGEX_DIR "${CUSTOM_EXTERNAL_DIR}/regex")
|
||||
set(CUSTOM_HIDAPI_DIR "${CUSTOM_EXTERNAL_DIR}/hidapi")
|
||||
set(CUSTOM_GEOTRANZ_DIR "${CUSTOM_EXTERNAL_DIR}/geotranz")
|
||||
set(CUSTOM_DATA_DIR "${CMAKE_SOURCE_DIR}/data")
|
||||
set(CUSTOM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/scripts")
|
||||
set(CUSTOM_TELEMETRY_DIR "${CUSTOM_SCRIPTS_DIR}/telemetry-toolkit")
|
||||
set(CUSTOM_CONF_DIR "${CMAKE_SOURCE_DIR}/conf")
|
||||
set(CUSTOM_DOC_DIR "${CMAKE_SOURCE_DIR}/doc")
|
||||
set(CUSTOM_MAN_DIR "${CMAKE_SOURCE_DIR}/man")
|
||||
set(CUSTOM_TEST_DIR "${CMAKE_SOURCE_DIR}/test")
|
||||
set(CUSTOM_TEST_SCRIPTS_DIR "${CUSTOM_TEST_DIR}/scripts")
|
||||
set(CUSTOM_SHELL_SHABANG "#!/bin/sh -e")
|
||||
|
||||
# cpack variables
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_STRIP_FILES true)
|
||||
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
# This has architecture of the build machine, not the target platform.
|
||||
# e.g. Comes out as x86_64 when building for i686 target platform.
|
||||
#set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${direwolf_VERSION}_${CMAKE_SYSTEM_PROCESSOR}")
|
||||
# We don't know the target yet so this is set after FindCPUflags.
|
||||
set(CPACK_PACKAGE_CONTACT "https://github.com/wb2osz/direwolf")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Dire Wolf is an AX.25 soundcard TNC, digipeater, APRS IGate, GPS tracker, and APRStt gateway")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_BINARY_DIR};/.git/;.gitignore;menu.yml;.travis.yml;.appveyor.yml;default.nix;.envrc;TODOs.org;/.scripts/")
|
||||
SET(CPACK_PACKAGE_VERSION "${direwolf_VERSION}")
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR "${direwolf_VERSION_MAJOR}")
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR "${direwolf_VERSION_MINOR}")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "${direwolf_VERSION_PATCH}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libasound2,libgps23")
|
||||
|
||||
# if we don't set build_type
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE OR "${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||
endif()
|
||||
message(STATUS "Build type set to: ${CMAKE_BUILD_TYPE}")
|
||||
message("CMake system: ${CMAKE_SYSTEM_NAME}")
|
||||
|
||||
# Unittest should be on for dev builds and off for releases.
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
option(UNITTEST "Build unittest binaries." OFF)
|
||||
else()
|
||||
option(UNITTEST "Build unittest binaries." ON)
|
||||
endif()
|
||||
|
||||
# set compiler
|
||||
include(FindCompiler)
|
||||
|
||||
# find cpu flags (and set compiler)
|
||||
include(FindCPUflags)
|
||||
|
||||
if(${ARCHITECTURE} MATCHES "x86")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${direwolf_VERSION}_i686")
|
||||
else()
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${direwolf_VERSION}_${ARCHITECTURE}")
|
||||
endif()
|
||||
|
||||
# auto include current directory
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# set OS dependent variables
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(LINUX TRUE)
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/cpack/${CMAKE_PROJECT_NAME}.desktop.in"
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.desktop" @ONLY)
|
||||
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(FREEBSD TRUE)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/cpack/${CMAKE_PROJECT_NAME}.desktop.in"
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.desktop" @ONLY)
|
||||
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
set(OPENBSD TRUE)
|
||||
set(HAVE_SNDIO TRUE)
|
||||
|
||||
elseif(APPLE)
|
||||
if("${CMAKE_OSX_DEPLOYMENT_TARGET}" STREQUAL "")
|
||||
message(STATUS "Build for macOS target: local version")
|
||||
else()
|
||||
message(STATUS "Build for macOS target: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif()
|
||||
|
||||
# prepend path to find_*()
|
||||
set(CMAKE_FIND_ROOT_PATH "/opt/local")
|
||||
|
||||
set(CMAKE_MACOSX_RPATH ON)
|
||||
message(STATUS "RPATH support: ${CMAKE_MACOSX_RPATH}")
|
||||
|
||||
# just blindly enable dns-sd
|
||||
set(USE_MACOS_DNSSD ON)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_MACOS_DNSSD")
|
||||
|
||||
elseif (WIN32)
|
||||
if(C_MSVC)
|
||||
if (NOT VS2015 AND NOT VS2017 AND NOT VS2019)
|
||||
message(FATAL_ERROR "You must use Microsoft Visual Studio 2015, 2017 or 2019 as compiler")
|
||||
else()
|
||||
# compile with full multicore
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
set(CUSTOM_SHELL_BIN "")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (C_CLANG OR C_GCC)
|
||||
# _BSD_SOURCE is deprecated we need to use _DEFAULT_SOURCE.
|
||||
#
|
||||
# That works find for more modern compilers but we have issues with:
|
||||
# Centos 7, gcc 4.8.5, glibc 2.17
|
||||
# Centos 6, gcc 4.4.7, glibc 2.12
|
||||
#
|
||||
# CentOS 6 & 7: Without -D_BSD_SOURCE, we get Warning: Implicit declaration of
|
||||
# functions alloca, cfmakeraw, scandir, setlinebuf, strcasecmp, strncasecmp, and strsep.
|
||||
# When a function (like strsep) returns a pointer, the compiler instead assumes a 32 bit
|
||||
# int and sign extends it out to be a 64 bit pointer. Use the pointer and Kaboom!
|
||||
#
|
||||
# CentOS 6: We have additional problem. Without -D_POSIX_C_SOURCE=199309L, we get
|
||||
# implicit declaration of function clock_gettime and the linker can't find it.
|
||||
#
|
||||
# It turns out that -D_GNU_SOURCE can be used instead of both of those. For more information,
|
||||
# see https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
#
|
||||
# Why was this not an issue before? If gcc is used without the -std=c99 option,
|
||||
# it is perfectly happy with clock_gettime, strsep, etc. but with the c99 option, it no longer
|
||||
# recognizes a bunch of commonly used functions. Using _GNU_SOURCE, rather than _DEFAULT_SOURCE
|
||||
# solves the problem for CentOS 6 & 7. This also makes -D_XOPEN_SOURCE= unnecessary.
|
||||
# I hope it doesn't break with newer versions of glibc.
|
||||
#
|
||||
# I also took out -Wextra because it spews out so much noise a serious problem was not noticed.
|
||||
# It might go back in someday when I have more patience to clean up all the warnings.
|
||||
#
|
||||
|
||||
# TODO:
|
||||
# Try error checking -fsanitize=bounds-strict -fsanitize=leak
|
||||
# Requires libubsan and liblsan, respectively.
|
||||
|
||||
###set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wvla -ffast-math -ftree-vectorize -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE ${EXTRA_FLAGS}")
|
||||
if(FREEBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wvla -ffast-math -ftree-vectorize -D_DEFAULT_SOURCE ${EXTRA_FLAGS}")
|
||||
else()
|
||||
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wvla -ffast-math -ftree-vectorize -D_GNU_SOURCE -fsanitize=bounds-strict ${EXTRA_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wvla -ffast-math -ftree-vectorize -D_GNU_SOURCE ${EXTRA_FLAGS}")
|
||||
endif()
|
||||
#
|
||||
#
|
||||
# -lm is needed for functions in math.h
|
||||
if (LINUX)
|
||||
# We have another problem with CentOS 6. clock_gettime() is in librt so we need -lrt.
|
||||
# The clock_* functions were moved into gnu libc for version 2.17.
|
||||
# https://sourceware.org/ml/libc-announce/2012/msg00001.html
|
||||
# If using gnu libc 2.17, or later, the -lrt is no longer needed but doesn't hurt.
|
||||
# I'm making this conditional on LINUX because it is not needed for BSD and MacOSX.
|
||||
link_libraries("-lrt -lm")
|
||||
else()
|
||||
link_libraries("-lm")
|
||||
endif()
|
||||
elseif (C_MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W3 -MP ${EXTRA_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (C_CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ferror-limit=1")
|
||||
elseif (C_GCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmax-errors=1")
|
||||
endif()
|
||||
|
||||
# set installation directories
|
||||
if (WIN32 OR CYGWIN)
|
||||
set(INSTALL_BIN_DIR ".")
|
||||
set(INSTALL_DOC_DIR "doc")
|
||||
set(INSTALL_CONF_DIR ".")
|
||||
set(INSTALL_SCRIPTS_DIR "scripts")
|
||||
set(INSTALL_MAN_DIR "man")
|
||||
set(INSTALL_DATA_DIR "data")
|
||||
else()
|
||||
set(INSTALL_BIN_DIR "bin")
|
||||
set(INSTALL_DOC_DIR "share/doc/${CMAKE_PROJECT_NAME}")
|
||||
set(INSTALL_CONF_DIR "${INSTALL_DOC_DIR}/conf")
|
||||
set(INSTALL_SCRIPTS_DIR "${INSTALL_DOC_DIR}/scripts")
|
||||
if(FREEBSD)
|
||||
set(INSTALL_MAN_DIR "man/man1")
|
||||
else()
|
||||
set(INSTALL_MAN_DIR "share/man/man1")
|
||||
endif()
|
||||
set(INSTALL_DATA_DIR "share/${PROJECT_NAME}")
|
||||
endif(WIN32 OR CYGWIN)
|
||||
|
||||
# requirements
|
||||
|
||||
include(CheckSymbolExists)
|
||||
|
||||
# Some platforms provide their own strlcpy & strlcat. (BSD, MacOSX)
|
||||
# Others don't so we provide our own. (Windows, most, but not all Linux)
|
||||
# Here we detect whether these are provided by the OS and set a symbol
|
||||
# so that:
|
||||
# (1) libgps does not supply its own version.
|
||||
# (2) we know whether we need to supply our own copy.
|
||||
#
|
||||
# This was all working fine until these were added to the gnu c library 2.38.
|
||||
# References:
|
||||
# - https://www.gnu.org/software/libc/sources.html
|
||||
# - https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=NEWS;hb=HEAD
|
||||
#
|
||||
# This test is not detecting them for glibc 2.38 resulting in a conflict.
|
||||
# Why? Are they declared in a different file or in some strange way?
|
||||
#
|
||||
# This is how they are declared in include/string.h:
|
||||
#
|
||||
# extern __typeof (strlcpy) __strlcpy;
|
||||
# libc_hidden_proto (__strlcpy)
|
||||
# extern __typeof (strlcat) __strlcat;
|
||||
# libc_hidden_proto (__strlcat)
|
||||
#
|
||||
# Apparently cmake does not recognize this style.
|
||||
# Keep this here for BSD type systems where it behaves as expected.
|
||||
# We will need to add a hack in direwolf.h to define these if glibc version >= 2.38.
|
||||
|
||||
check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
|
||||
if(HAVE_STRLCPY)
|
||||
add_compile_options(-DHAVE_STRLCPY)
|
||||
endif()
|
||||
check_symbol_exists(strlcat string.h HAVE_STRLCAT)
|
||||
if(HAVE_STRLCAT)
|
||||
add_compile_options(-DHAVE_STRLCAT)
|
||||
endif()
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(GPSD)
|
||||
if(GPSD_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_GPSD")
|
||||
else()
|
||||
set(GPSD_INCLUDE_DIRS "")
|
||||
set(GPSD_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
find_package(hamlib)
|
||||
if(HAMLIB_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_HAMLIB")
|
||||
else()
|
||||
set(HAMLIB_INCLUDE_DIRS "")
|
||||
set(HAMLIB_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
find_package(ALSA REQUIRED)
|
||||
if(ALSA_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_ALSA")
|
||||
endif()
|
||||
|
||||
find_package(udev)
|
||||
if(UDEV_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CM108")
|
||||
endif()
|
||||
|
||||
find_package(Avahi)
|
||||
if(AVAHI_CLIENT_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_AVAHI_CLIENT")
|
||||
endif()
|
||||
|
||||
elseif (HAVE_SNDIO)
|
||||
find_package(sndio REQUIRED)
|
||||
if(SNDIO_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_SNDIO")
|
||||
endif()
|
||||
|
||||
elseif (NOT WIN32 AND NOT CYGWIN)
|
||||
find_package(Portaudio REQUIRED)
|
||||
if(PORTAUDIO_FOUND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_PORTAUDIO")
|
||||
endif()
|
||||
|
||||
else()
|
||||
set(ALSA_INCLUDE_DIRS "")
|
||||
set(ALSA_LIBRARIES "")
|
||||
set(UDEV_INCLUDE_DIRS "")
|
||||
set(UDEV_LIBRARIES "")
|
||||
# Version 1.7 supports CM108/CM119 GPIO PTT for Windows.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CM108")
|
||||
set(PORTAUDIO_INCLUDE_DIRS "")
|
||||
set(PORTAUDIO_LIBRARIES "")
|
||||
set(SNDIO_INCLUDE_DIRS "")
|
||||
set(SNDIO_LIBRARIES "")
|
||||
endif()
|
||||
|
||||
# manage and fetch new data
|
||||
add_subdirectory(data)
|
||||
|
||||
# external libraries
|
||||
add_subdirectory(${CUSTOM_GEOTRANZ_DIR})
|
||||
add_subdirectory(${CUSTOM_REGEX_DIR})
|
||||
add_subdirectory(${CUSTOM_HIDAPI_DIR})
|
||||
add_subdirectory(${CUSTOM_MISC_DIR})
|
||||
|
||||
# direwolf source code and utilities
|
||||
add_subdirectory(src)
|
||||
|
||||
# ctest
|
||||
if(UNITTEST)
|
||||
message(STATUS "Build unit test binaries")
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif(UNITTEST)
|
||||
|
||||
# manage scripts
|
||||
add_subdirectory(scripts)
|
||||
|
||||
# manage config
|
||||
add_subdirectory(conf)
|
||||
|
||||
# install basic docs
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/CHANGES.md DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/external/LICENSE DESTINATION ${INSTALL_DOC_DIR}/external)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(man)
|
||||
|
||||
# install desktop link
|
||||
if (LINUX OR FREEBSD)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.desktop DESTINATION share/applications)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/cpack/${CMAKE_PROJECT_NAME}_icon.png DESTINATION share/pixmaps)
|
||||
endif()
|
||||
|
||||
############ uninstall target ################
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/include/uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P
|
||||
${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake)
|
||||
|
||||
############ packaging ################
|
||||
add_subdirectory(cmake/cpack)
|
50
Makefile
50
Makefile
|
@ -1,36 +1,16 @@
|
|||
# Select proper Makefile for operating system.
|
||||
# The Windows version is built with the help of Cygwin.
|
||||
|
||||
all:
|
||||
@echo "The build procedure has changed in version 1.6."
|
||||
@echo "In general, it now looks like this:"
|
||||
@echo " "
|
||||
@echo "Download the source code:"
|
||||
@echo " "
|
||||
@echo " cd ~"
|
||||
@echo " git clone https://www.github.com/wb2osz/direwolf"
|
||||
@echo " cd direwolf"
|
||||
@echo " "
|
||||
@echo "Optional - Do this to get the latest development version"
|
||||
@echo "rather than the latest stable release."
|
||||
@echo " "
|
||||
@echo " git checkout dev"
|
||||
@echo " "
|
||||
@echo "Build it. There are two new steps not used for earlier releases."
|
||||
@echo " "
|
||||
@echo " mkdir build && cd build"
|
||||
@echo " cmake .."
|
||||
@echo " make -j4"
|
||||
@echo " "
|
||||
@echo "Install:"
|
||||
@echo " "
|
||||
@echo " sudo make install"
|
||||
@echo " make install-conf"
|
||||
@echo " "
|
||||
@echo "You will probably need to install additional applications and"
|
||||
@echo "libraries depending on your operating system."
|
||||
@echo "More details are in the README.md file."
|
||||
@echo " "
|
||||
@echo "Questions?"
|
||||
@echo " "
|
||||
@echo " - Extensive documentation can be found in the 'doc' directory."
|
||||
@echo " - Join the discussion forum here: https://groups.io/g/direwolf"
|
||||
@echo " "
|
||||
# In my case, I see CYGWIN_NT-6.1-WOW so we don't check for
|
||||
# equal to some value. Your mileage my vary.
|
||||
|
||||
win := $(shell uname | grep CYGWIN)
|
||||
dar := $(shell uname | grep Darwin)
|
||||
|
||||
ifneq ($(win),)
|
||||
include Makefile.win
|
||||
else ifeq ($(dar),Darwin)
|
||||
include Makefile.macosx
|
||||
else
|
||||
include Makefile.linux
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,988 @@
|
|||
#
|
||||
# Makefile for Linux version of Dire Wolf.
|
||||
#
|
||||
|
||||
|
||||
|
||||
APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc kissutil cm108
|
||||
|
||||
all : $(APPS) direwolf.desktop direwolf.conf
|
||||
@echo " "
|
||||
@echo "Next step - install with:"
|
||||
@echo " "
|
||||
@echo " sudo make install"
|
||||
@echo " "
|
||||
|
||||
CC := gcc
|
||||
|
||||
# Just for fun, let's see how clang compares to gcc. First install like this:
|
||||
# sudo apt-get update
|
||||
# apt-cache search clang
|
||||
# sudo apt-get install clang-3.5
|
||||
#
|
||||
# CC := clang-3.5
|
||||
|
||||
# _XOPEN_SOURCE=600 and _DEFAULT_SOURCE=1 are needed for glibc >= 2.24.
|
||||
# Explanation here: https://github.com/wb2osz/direwolf/issues/62
|
||||
|
||||
# There are a few source files where it had been necessary to define __USE_XOPEN2KXSI,
|
||||
# __USE_XOPEN, or _POSIX_C_SOURCE. Doesn't seem to be needed after adding this.
|
||||
|
||||
# The first assignment to CFLAGS and LDFLAGS uses +=, rather than :=, so
|
||||
# we will inherit options already set in build environment.
|
||||
# Explanation - https://github.com/wb2osz/direwolf/pull/38
|
||||
|
||||
CFLAGS += -O3 -pthread -Igeotranz -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE=1 -Wall
|
||||
|
||||
# That was fine for a recent Ubuntu and Raspbian Jessie.
|
||||
# However, Raspbian wheezy was then missing declaration for strsep and definition of fd_set.
|
||||
|
||||
CFLAGS += -D_BSD_SOURCE
|
||||
|
||||
LDFLAGS += -lm -lpthread -lrt
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The DSP filters spend a lot of time spinning around in little
|
||||
# loops multiplying and adding arrays of numbers. The Intel "SSE"
|
||||
# instructions, introduced in 1999 with the Pentium III series,
|
||||
# can speed this up considerably.
|
||||
#
|
||||
# SSE2 instructions, added in 2000, don't seem to offer any advantage.
|
||||
#
|
||||
#
|
||||
# Let's take a look at the effect of the compile options.
|
||||
#
|
||||
#
|
||||
# Times are elapsed time to process Track 2 of the TNC test CD.
|
||||
#
|
||||
# i.e. "./atest 02_Track_2.wav"
|
||||
# Default demodulator type is new "E" added for version 1.2.
|
||||
#
|
||||
|
||||
#
|
||||
# ---------- x86 (32 bit) ----------
|
||||
#
|
||||
|
||||
#
|
||||
# gcc 4.6.3 running on Ubuntu 12.04.05.
|
||||
# Intel(R) Celeron(R) CPU 2.53GHz. Appears to have only 32 bit instructions.
|
||||
# Probably from around 2004 or 2005.
|
||||
#
|
||||
# When gcc is generating code for a 32 bit x86 target, it assumes the ancient
|
||||
# i386 processor. This is good for portability but bad for performance.
|
||||
#
|
||||
# The code can run considerably faster by taking advantage of the SSE instructions
|
||||
# available in the Pentium 3 or later.
|
||||
#
|
||||
# seconds options comments
|
||||
# ------ ------- --------
|
||||
# 524
|
||||
# 183 -O2
|
||||
# 182 -O3
|
||||
# 183 -O3 -ffast-math (should be same as -Ofast)
|
||||
# 184 -Ofast
|
||||
# 189 -O3 -ffast-math -march=pentium
|
||||
# 122 -O3 -ffast-math -msse
|
||||
# 122 -O3 -ffast-math -march=pentium -msse
|
||||
# 121 -O3 -ffast-math -march=pentium3 (this implies -msse)
|
||||
# 120 -O3 -ffast-math -march=native
|
||||
#
|
||||
# Note that "-march=native" is essentially the same as "-march=pentium3."
|
||||
#
|
||||
|
||||
# If the compiler is generating code for the i386 target, we can
|
||||
# get much better results by telling it we have at least a Pentium 3.
|
||||
|
||||
arch := $(shell echo | gcc -E -dM - | grep __i386__)
|
||||
ifneq ($(arch),)
|
||||
CFLAGS += -march=pentium3
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# ---------- x86_64 ----------
|
||||
#
|
||||
|
||||
#
|
||||
# gcc 4.8.2 running on Ubuntu 14.04.1.
|
||||
# Intel Core 2 Duo from around 2007 or 2008.
|
||||
#
|
||||
# 64 bit target implies that we have SSE and probably even better vector instructions.
|
||||
#
|
||||
# seconds options comments
|
||||
# ------ ------- --------
|
||||
# 245
|
||||
# 75 -01
|
||||
# 72 -02
|
||||
# 71 -03
|
||||
# 73 -O3 -march=native
|
||||
# 42 -O3 -ffast-math
|
||||
# 42 -Ofast (note below)
|
||||
# 40 -O3 -ffast-math -march=native
|
||||
#
|
||||
#
|
||||
# Note that "-Ofast" is a newer option roughly equivalent to "-O3 -ffast-math".
|
||||
# I use the longer form because it is compatible with older compilers.
|
||||
#
|
||||
# Why don't I don't have "-march=native?"
|
||||
# Older compilers don't recognize "native" as one of the valid options.
|
||||
# One article said it was added with gcc 4.2 but I haven't verified that.
|
||||
#
|
||||
|
||||
# ---------- How does clang compare? - Ubuntu x86_64 ----------
|
||||
#
|
||||
# I keep hearing a lot about "clang." Let's see how it compares with gcc.
|
||||
# Simply use different compiler and keep all options the same.
|
||||
#
|
||||
# test case: atest 02_Track_2.wav
|
||||
#
|
||||
# gcc 4.8.4: 988 packets decoded in 40.503 seconds. 38.3 x realtime
|
||||
# 988 packets decoded in 40.403 seconds. 38.4 x realtime
|
||||
#
|
||||
# clang 3.8.0-2: 988 packets decoded in 77.454 seconds. 20.0 x realtime
|
||||
# 988 packets decoded in 77.232 seconds. 20.1 x realtime
|
||||
#
|
||||
# I'm not impressed. Almost twice as long. Maybe we need to try some other compiler options.
|
||||
# -march=native did not help.
|
||||
# Makefile.macosx, which uses clang, has these:
|
||||
# -fvectorize -fslp-vectorize -fslp-vectorize-aggressive
|
||||
# Those did not help.
|
||||
#
|
||||
|
||||
|
||||
useffast := $(shell gcc --help -v 2>/dev/null | grep ffast-math)
|
||||
ifneq ($(useffast),)
|
||||
CFLAGS += -ffast-math
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# ---------- ARM - Raspberry Pi 1 models ----------
|
||||
#
|
||||
# Raspberry Pi (before RPi model 2), ARM11 (ARMv6 + VFP2)
|
||||
# gcc (Debian 4.6.3-14+rpi1) 4.6.3
|
||||
#
|
||||
#
|
||||
# seconds options comments
|
||||
# ------ ------- ---------
|
||||
# 892 -O3
|
||||
# 887 -O3 -ffast-math
|
||||
# x -O3 -ffast-math -march=native (error: bad value for -march switch)
|
||||
# 887 -O3 -ffast-math -mfpu=vfp
|
||||
# 890 -O3 -ffast-math -march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp
|
||||
#
|
||||
#
|
||||
# The compiler, supplied with Raspbian, is configured with these options which are
|
||||
# good for the pre version 2 models.
|
||||
# --with-arch=armv6 --with-fpu=vfp --with-float=hard
|
||||
#
|
||||
# Run "gcc --help -v 2" and look near the end.
|
||||
#
|
||||
#
|
||||
|
||||
#
|
||||
# ---------- ARM - Raspberry Pi 2 ----------
|
||||
#
|
||||
# Besides the higher clock speed, the Raspberry Pi 2 has the NEON instruction set
|
||||
# which which should make things considerably faster.
|
||||
#
|
||||
#
|
||||
# seconds options comments
|
||||
# ------ ------- ---------
|
||||
# 426 -O3 -ffast-math (already more than twice as fast)
|
||||
# 429 -O3 -mfpu=neon
|
||||
# 419 -O3 -mfpu=neon -funsafe-math-optimizations
|
||||
# 412 -O3 -ffast-math -mfpu=neon
|
||||
# 413 -O3 -ffast-math -mfpu=neon-vfpv4
|
||||
# 430 -O3 -ffast-math -mfpu=neon-vfpv4 -march=armv7-a
|
||||
# 412 -O3 -ffast-math -mfpu=neon-vfpv4 -mtune=arm7
|
||||
# 410 -O3 -ffast-math -mfpu=neon-vfpv4 -funsafe-math-optimizations
|
||||
|
||||
#
|
||||
# gcc -march=armv7-a -mfpu=neon-vfpv4
|
||||
#
|
||||
# I expected the -mfpu=neon option to have a much larger impact.
|
||||
# Adding -march=armv7-a makes it slower!
|
||||
|
||||
#
|
||||
# If you compile with the RPi 2 specific options above and try to run it on the RPi
|
||||
# model B (pre version 2), it will die with "illegal instruction."
|
||||
#
|
||||
# Dire Wolf is known to work on the BeagleBone, CubieBoard2, CHIP, etc.
|
||||
# The best compiler options will depend on the specific type of processor
|
||||
# and the compiler target defaults.
|
||||
#
|
||||
|
||||
neon := $(shell cat /proc/cpuinfo | grep neon)
|
||||
ifneq ($(neon),)
|
||||
CFLAGS += -mfpu=neon
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# You would expect "-march=native" to produce the fastest code.
|
||||
# Why don't I use it here?
|
||||
#
|
||||
# 1. In my benchmarks, above, it has a negligible impact if any at all.
|
||||
# 2. Some older versions of gcc don't recognize "native" as a valid choice.
|
||||
# 3. Results are less portable. Not a consideration if you are
|
||||
# building only for your own use but very important for anyone
|
||||
# redistributing a "binary" version.
|
||||
#
|
||||
# If you are planning to distribute the binary version to other
|
||||
# people (in some ham radio software collection, RPM, or DEB package),
|
||||
# avoid fine tuning it for your particular computer. It could
|
||||
# cause compatibility issues for those with older computers.
|
||||
#
|
||||
|
||||
# ---------- How does clang compare? - ARM - Raspberry Pi 2 ----------
|
||||
#
|
||||
# I keep hearing a lot about "clang." Let's see how it compares with gcc.
|
||||
# Simply use different compiler and keep all options the same.
|
||||
#
|
||||
# test case: atest 02_Track_2.wav
|
||||
#
|
||||
# gcc 4.9.2-10: 988 packets decoded in 353.025 seconds. 4.4 x realtime
|
||||
# 988 packets decoded in 352.752 seconds. 4.4 x realtime
|
||||
#
|
||||
# clang 3.5.0-10: 988 packets decoded in 825.879 seconds. 1.9 x realtime
|
||||
# 988 packets decoded in 831.469 seconds. 1.9 x realtime
|
||||
#
|
||||
# There might be a different set of options which produce faster code
|
||||
# but the initial test doesn't look good. About 2.3 times as slow.
|
||||
|
||||
# If you want to use OSS (for FreeBSD, OpenBSD) instead of
|
||||
# ALSA (for Linux), comment out (or remove) the line below.
|
||||
# TODO: Can we automate this somehow?
|
||||
|
||||
alsa = 1
|
||||
|
||||
ifeq ($(wildcard /usr/include/pthread.h),)
|
||||
$(error /usr/include/pthread.h does not exist. Install it with "sudo apt-get install libc6-dev" or "sudo yum install glibc-headers" )
|
||||
endif
|
||||
|
||||
ifneq ($(alsa),)
|
||||
CFLAGS += -DUSE_ALSA
|
||||
LDFLAGS += -lasound
|
||||
ifeq ($(wildcard /usr/include/alsa/asoundlib.h),)
|
||||
$(error /usr/include/alsa/asoundlib.h does not exist. Install it with "sudo apt-get install libasound2-dev" or "sudo yum install alsa-lib-devel" )
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Enable GPS if header file is present.
|
||||
# Finding libgps.so* is more difficult because it
|
||||
# is in different places on different operating systems.
|
||||
|
||||
enable_gpsd := $(wildcard /usr/include/gps.h)
|
||||
ifneq ($(enable_gpsd),)
|
||||
CFLAGS += -DENABLE_GPSD
|
||||
LDFLAGS += -lgps
|
||||
endif
|
||||
|
||||
|
||||
# Enable hamlib support if header file is present.
|
||||
|
||||
enable_hamlib := $(wildcard /usr/include/hamlib/rig.h /usr/local/include/hamlib/rig.h)
|
||||
ifneq ($(enable_hamlib),)
|
||||
CFLAGS += -DUSE_HAMLIB
|
||||
LDFLAGS += -lhamlib
|
||||
endif
|
||||
|
||||
|
||||
# Should enabling of this feature be strongly encouraged or
|
||||
# is it quite specialized and of interest to a small audience?
|
||||
# If, for some reason, can obtain the libudev-dev package, or
|
||||
# don't want to install it, comment out the next 3 lines.
|
||||
|
||||
#ifeq ($(wildcard /usr/include/libudev.h),)
|
||||
#$(error /usr/include/libudev.h does not exist. Install it with "sudo apt-get install libudev-dev" or "sudo yum install libudev-devel" )
|
||||
#endif
|
||||
|
||||
|
||||
# Enable cm108 PTT support if libudev header file is present.
|
||||
|
||||
enable_cm108 := $(wildcard /usr/include/libudev.h)
|
||||
ifneq ($(enable_cm108),)
|
||||
CFLAGS += -DUSE_CM108
|
||||
LDFLAGS += -ludev
|
||||
endif
|
||||
|
||||
|
||||
# Name of current directory.
|
||||
# Used to generate zip file name for distribution.
|
||||
|
||||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
|
||||
# -------------------------------- Main application -----------------------------------------
|
||||
|
||||
|
||||
|
||||
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_psk.o demod_9600.o hdlc_rec.o \
|
||||
hdlc_rec2.o multi_modem.o rdq.o rrbb.o dlq.o \
|
||||
fcs_calc.o ax25_pad.o ax25_pad2.o xid.o \
|
||||
decode_aprs.o symbols.o server.o kiss.o kissserial.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||
gen_tone.o audio.o audio_stats.o digipeater.o cdigipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
|
||||
ptt.o beacon.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o waypoint.o serial_port.o log.o telemetry.o \
|
||||
dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o mheard.o ax25_link.o cm108.o \
|
||||
misc.a geotranz.a
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
@echo " "
|
||||
ifneq ($(enable_gpsd),)
|
||||
@echo "\t>\tThis includes support for gpsd."
|
||||
else
|
||||
@echo "\t>\tThis does NOT include support for gpsd."
|
||||
endif
|
||||
ifneq ($(enable_hamlib),)
|
||||
@echo "\t>\tThis includes support for hamlib."
|
||||
else
|
||||
@echo "\t>\tThis does NOT include support for hamlib."
|
||||
endif
|
||||
ifneq ($(enable_cm108),)
|
||||
@echo "\t>\tThis includes support for CM108/CM119 PTT."
|
||||
else
|
||||
@echo "\t>\tThis does NOT include support for CM108/CM119 PTT."
|
||||
endif
|
||||
@echo " "
|
||||
|
||||
# Optimization for slow processors.
|
||||
|
||||
demod.o : fsk_fast_filter.h
|
||||
|
||||
demod_afsk.o : fsk_fast_filter.h
|
||||
|
||||
|
||||
fsk_fast_filter.h : gen_fff
|
||||
./gen_fff > fsk_fast_filter.h
|
||||
|
||||
gen_fff : demod_afsk.c dsp.c textcolor.c
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -DGEN_FFF -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff -Z tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff -Z symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff -Z symbolsX.txt~ symbolsX.txt
|
||||
|
||||
|
||||
# ---------------------------------------- Other utilities included ------------------------------
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
# First three use .c rather than .o because they depend on DECAMAIN definition.
|
||||
|
||||
decode_aprs : decode_aprs.c kiss_frame.c ax25_pad.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
tt2text : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
utm2ll : utm2ll.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c morse.c dtmf.c textcolor.c dsp.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
# Unit test for AFSK demodulator
|
||||
|
||||
atest : atest.c demod.o demod_afsk.o demod_psk.o demod_9600.o \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.o ax25_pad.o decode_aprs.o dwgpsnmea.o \
|
||||
dwgps.o dwgpsd.o serial_port.o telemetry.o dtime_now.o latlong.o symbols.o tt_text.o textcolor.o \
|
||||
misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# Talk to a KISS TNC.
|
||||
# Note: kiss_frame.c has conditional compilation on KISSUTIL.
|
||||
|
||||
kissutil : kissutil.c kiss_frame.c ax25_pad.o fcs_calc.o textcolor.o serial_port.o dtime_now.o sock.o misc.a
|
||||
$(CC) $(CFLAGS) -g -DKISSUTIL -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# List USB audio adapters than can use GPIO for PTT.
|
||||
|
||||
cm108 : cm108.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -DCM108_MAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Touch Tone to Speech sample application.
|
||||
|
||||
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# ----------------------------------------- Libraries --------------------------------------------
|
||||
|
||||
# UTM, USNG, MGRS conversions.
|
||||
|
||||
geotranz.a : error_string.o mgrs.o polarst.o tranmerc.o ups.o usng.o utm.o
|
||||
ar -cr $@ $^
|
||||
|
||||
error_string.o : geotranz/error_string.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
mgrs.o : geotranz/mgrs.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
polarst.o : geotranz/polarst.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
tranmerc.o : geotranz/tranmerc.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
ups.o : geotranz/ups.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
usng.o : geotranz/usng.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
utm.o : geotranz/utm.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
|
||||
# Provide our own copy of strlcpy and strlcat because they are not included with Linux.
|
||||
# We don't need the others in that same directory.
|
||||
|
||||
misc.a : strlcpy.o strlcat.o
|
||||
ar -cr $@ $^
|
||||
|
||||
strlcpy.o : misc/strlcpy.c
|
||||
$(CC) $(CFLAGS) -I. -c -o $@ $^
|
||||
|
||||
strlcat.o : misc/strlcat.c
|
||||
$(CC) $(CFLAGS) -I. -c -o $@ $^
|
||||
|
||||
|
||||
|
||||
# ------------------------------------- Installation ----------------------------------
|
||||
|
||||
|
||||
|
||||
# Generate apprpriate sample configuration file for this platform.
|
||||
# Originally, there was one sample for all platforms. It got too cluttered
|
||||
# and confusing saying, this is for windows, and this is for Linux, and this ...
|
||||
# Trying to maintain 3 different versions in parallel is error prone.
|
||||
# We now have a single generic version which can be used to generate
|
||||
# the various platform specific versions.
|
||||
|
||||
# generic.conf should be checked into source control.
|
||||
# direwolf.conf should NOT. It is generated when compiling on the target platform.
|
||||
|
||||
direwolf.conf : generic.conf
|
||||
egrep '^C|^L' generic.conf | cut -c2-999 > direwolf.conf
|
||||
|
||||
|
||||
# Where should we install it?
|
||||
|
||||
# Something built from source and installed locally would normally go in /usr/local/...
|
||||
# If not specified on the make command line, this is our default.
|
||||
|
||||
DESTDIR ?= /usr/local
|
||||
|
||||
# However, if you are preparing a "binary" DEB or RPM package, the installation location
|
||||
# would normally be /usr/... instead. In this case, use a command line like this:
|
||||
#
|
||||
# make DESTDIR=/usr install
|
||||
|
||||
|
||||
|
||||
# Command to "install" to system directories. Use "ginstall" for Mac.
|
||||
|
||||
INSTALL=install
|
||||
|
||||
# direwolf.desktop was previously handcrafted for the Raspberry Pi.
|
||||
# It was hardcoded with lxterminal, /home/pi, and so on.
|
||||
# In version 1.2, try to customize this to match other situations better.
|
||||
|
||||
# TODO: Test this better.
|
||||
|
||||
|
||||
direwolf.desktop :
|
||||
@echo "Generating customized direwolf.desktop ..."
|
||||
@echo '[Desktop Entry]' > $@
|
||||
@echo 'Type=Application' >> $@
|
||||
ifneq ($(wildcard /usr/bin/lxterminal),)
|
||||
@echo "Exec=lxterminal -t \"Dire Wolf\" -e \"$(DESTDIR)/bin/direwolf\"" >> $@
|
||||
else ifneq ($(wildcard /usr/bin/lxterm),)
|
||||
@echo "Exec=lxterm -hold -title \"Dire Wolf\" -bg white -e \"$(DESTDIR)/bin/direwolf\"" >> $@
|
||||
else
|
||||
@echo "Exec=xterm -hold -title \"Dire Wolf\" -bg white -e \"$(DESTDIR)/bin/direwolf\"" >> $@
|
||||
endif
|
||||
@echo 'Name=Dire Wolf' >> $@
|
||||
@echo 'Comment=APRS Soundcard TNC' >> $@
|
||||
@echo 'Icon=$(DESTDIR)/share/direwolf/pixmaps/dw-icon.png' >> $@
|
||||
@echo "Path=$(HOME)" >> $@
|
||||
@echo '#Terminal=true' >> $@
|
||||
@echo 'Categories=HamRadio' >> $@
|
||||
@echo 'Keywords=Ham Radio;APRS;Soundcard TNC;KISS;AGWPE;AX.25' >> $@
|
||||
|
||||
|
||||
# Installation into $(DESTDIR), usually /usr/local/... or /usr/...
|
||||
# Needs to be run as root or with sudo.
|
||||
|
||||
|
||||
.PHONY: install
|
||||
install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
||||
#
|
||||
# Applications, not installed with package manager, normally go in /usr/local/bin.
|
||||
# /usr/bin is used instead when installing from .DEB or .RPM package.
|
||||
#
|
||||
$(INSTALL) -D --mode=755 direwolf $(DESTDIR)/bin/direwolf
|
||||
$(INSTALL) -D --mode=755 decode_aprs $(DESTDIR)/bin/decode_aprs
|
||||
$(INSTALL) -D --mode=755 text2tt $(DESTDIR)/bin/text2tt
|
||||
$(INSTALL) -D --mode=755 tt2text $(DESTDIR)/bin/tt2text
|
||||
$(INSTALL) -D --mode=755 ll2utm $(DESTDIR)/bin/ll2utm
|
||||
$(INSTALL) -D --mode=755 utm2ll $(DESTDIR)/bin/utm2ll
|
||||
$(INSTALL) -D --mode=755 aclients $(DESTDIR)/bin/aclients
|
||||
$(INSTALL) -D --mode=755 log2gpx $(DESTDIR)/bin/log2gpx
|
||||
$(INSTALL) -D --mode=755 gen_packets $(DESTDIR)/bin/gen_packets
|
||||
$(INSTALL) -D --mode=755 atest $(DESTDIR)/bin/atest
|
||||
$(INSTALL) -D --mode=755 ttcalc $(DESTDIR)/bin/ttcalc
|
||||
$(INSTALL) -D --mode=755 kissutil $(DESTDIR)/bin/kissutil
|
||||
$(INSTALL) -D --mode=755 cm108 $(DESTDIR)/bin/cm108
|
||||
$(INSTALL) -D --mode=755 dwespeak.sh $(DESTDIR)/bin/dwspeak.sh
|
||||
#
|
||||
# Telemetry Toolkit executables. Other .conf and .txt files will go into doc directory.
|
||||
#
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-balloon.pl $(DESTDIR)/bin/telem-balloon.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-bits.pl $(DESTDIR)/bin/telem-bits.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-data.pl $(DESTDIR)/bin/telem-data.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-data91.pl $(DESTDIR)/bin/telem-data91.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-eqns.pl $(DESTDIR)/bin/telem-eqns.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-parm.pl $(DESTDIR)/bin/telem-parm.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-seq.sh $(DESTDIR)/bin/telem-seq.sh
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-unit.pl $(DESTDIR)/bin/telem-unit.pl
|
||||
$(INSTALL) -D --mode=755 telemetry-toolkit/telem-volts.py $(DESTDIR)/bin/telem-volts.py
|
||||
#
|
||||
# Misc. data such as "tocall" to system mapping.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 tocalls.txt $(DESTDIR)/share/direwolf/tocalls.txt
|
||||
$(INSTALL) -D --mode=644 symbols-new.txt $(DESTDIR)/share/direwolf/symbols-new.txt
|
||||
$(INSTALL) -D --mode=644 symbolsX.txt $(DESTDIR)/share/direwolf/symbolsX.txt
|
||||
#
|
||||
# For desktop icon.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 dw-icon.png $(DESTDIR)/share/direwolf/pixmaps/dw-icon.png
|
||||
$(INSTALL) -D --mode=644 direwolf.desktop $(DESTDIR)/share/applications/direwolf.desktop
|
||||
#
|
||||
# Documentation. Various plain text files and PDF.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 CHANGES.md $(DESTDIR)/share/doc/direwolf/CHANGES.md
|
||||
$(INSTALL) -D --mode=644 LICENSE-dire-wolf.txt $(DESTDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
$(INSTALL) -D --mode=644 LICENSE-other.txt $(DESTDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
#
|
||||
# ./README.md is an overview for the project main page.
|
||||
# Maybe we could stick it in some other place.
|
||||
# doc/README.md contains an overview of the PDF file contents and is more useful here.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 doc/README.md $(DESTDIR)/share/doc/direwolf/README.md
|
||||
$(INSTALL) -D --mode=644 doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf $(DESTDIR)/share/doc/direwolf/2400-4800-PSK-for-APRS-Packet-Radio.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(DESTDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(DESTDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf $(DESTDIR)/share/doc/direwolf/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(DESTDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(DESTDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(DESTDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Listening-Example.pdf $(DESTDIR)/share/doc/direwolf/APRStt-Listening-Example.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Bluetooth-KISS-TNC.pdf $(DESTDIR)/share/doc/direwolf/Bluetooth-KISS-TNC.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Going-beyond-9600-baud.pdf $(DESTDIR)/share/doc/direwolf/Going-beyond-9600-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(DESTDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(DESTDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(DESTDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Successful-APRS-IGate-Operation.pdf $(DESTDIR)/share/doc/direwolf/Successful-APRS-IGate-Operation.pdf
|
||||
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(DESTDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
$(INSTALL) -D --mode=644 doc/WA8LMF-TNC-Test-CD-Results.pdf $(DESTDIR)/share/doc/direwolf/WA8LMF-TNC-Test-CD-Results.pdf
|
||||
#
|
||||
# Various sample config and other files go into examples under the doc directory.
|
||||
# When building from source, these can be put in home directory with "make install-conf".
|
||||
# When installed from .DEB or .RPM package, the user will need to copy these to
|
||||
# the home directory or other desired location.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 direwolf.conf $(DESTDIR)/share/doc/direwolf/examples/direwolf.conf
|
||||
$(INSTALL) -D --mode=755 dw-start.sh $(DESTDIR)/share/doc/direwolf/examples/dw-start.sh
|
||||
$(INSTALL) -D --mode=644 sdr.conf $(DESTDIR)/share/doc/direwolf/examples/sdr.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-m0xer-3.txt $(DESTDIR)/share/doc/direwolf/examples/telem-m0xer-3.txt
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-balloon.conf $(DESTDIR)/share/doc/direwolf/examples/telem-balloon.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-volts.conf $(DESTDIR)/share/doc/direwolf/examples/telem-volts.conf
|
||||
#
|
||||
# "man" pages
|
||||
#
|
||||
$(INSTALL) -D --mode=644 man1/aclients.1 $(DESTDIR)/share/man/man1/aclients.1
|
||||
$(INSTALL) -D --mode=644 man1/atest.1 $(DESTDIR)/share/man/man1/atest.1
|
||||
$(INSTALL) -D --mode=644 man1/decode_aprs.1 $(DESTDIR)/share/man/man1/decode_aprs.1
|
||||
$(INSTALL) -D --mode=644 man1/direwolf.1 $(DESTDIR)/share/man/man1/direwolf.1
|
||||
$(INSTALL) -D --mode=644 man1/gen_packets.1 $(DESTDIR)/share/man/man1/gen_packets.1
|
||||
$(INSTALL) -D --mode=644 man1/kissutil.1 $(DESTDIR)/share/man/man1/kissutil.1
|
||||
$(INSTALL) -D --mode=644 man1/ll2utm.1 $(DESTDIR)/share/man/man1/ll2utm.1
|
||||
$(INSTALL) -D --mode=644 man1/log2gpx.1 $(DESTDIR)/share/man/man1/log2gpx.1
|
||||
$(INSTALL) -D --mode=644 man1/text2tt.1 $(DESTDIR)/share/man/man1/text2tt.1
|
||||
$(INSTALL) -D --mode=644 man1/tt2text.1 $(DESTDIR)/share/man/man1/tt2text.1
|
||||
$(INSTALL) -D --mode=644 man1/utm2ll.1 $(DESTDIR)/share/man/man1/utm2ll.1
|
||||
#
|
||||
# Set group and mode of HID devices corresponding to C-Media USB Audio adapters.
|
||||
# This will allow us to use the CM108/CM119 GPIO pins for PTT.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 99-direwolf-cmedia.rules /etc/udev/rules.d/99-direwolf-cmedia.rules
|
||||
#
|
||||
@echo " "
|
||||
@echo "If this is your first install, not an upgrade, type this to put a copy"
|
||||
@echo "of the sample configuration file (direwolf.conf) in your home directory:"
|
||||
@echo " "
|
||||
@echo " make install-conf"
|
||||
@echo " "
|
||||
|
||||
|
||||
# Put sample configuration & startup files in home directory.
|
||||
# This step would be done as ordinary user.
|
||||
# Some people like to put the direwolf config file in /etc/ax25.
|
||||
# Note that all of these are also in $(DESTDIR)/share/doc/direwolf/examples/.
|
||||
|
||||
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
||||
|
||||
# TODO: Handle Linux variations correctly.
|
||||
|
||||
# Version 1.4 - Add "-n" option to avoid clobbering existing, probably customized, config files.
|
||||
|
||||
# dw-start.sh is greatly improved in version 1.4.
|
||||
# It was moved from isntall-rpi to install-conf because it is not just for the RPi.
|
||||
|
||||
.PHONY: install-conf
|
||||
install-conf : direwolf.conf
|
||||
cp -n direwolf.conf ~
|
||||
cp -n sdr.conf ~
|
||||
cp -n telemetry-toolkit/telem-m0xer-3.txt ~
|
||||
cp -n telemetry-toolkit/telem-*.conf ~
|
||||
chmod +x dw-start.sh
|
||||
cp -n dw-start.sh ~
|
||||
ifneq ($(wildcard $(HOME)/Desktop),)
|
||||
@echo " "
|
||||
@echo "This will add a desktop icon on some systems."
|
||||
@echo "This is known to work on Raspberry Pi but might not be compatible with other desktops."
|
||||
@echo " "
|
||||
@echo " make install-rpi"
|
||||
@echo " "
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: install-rpi
|
||||
install-rpi :
|
||||
ln -f -s $(DESTDIR)/share/applications/direwolf.desktop ~/Desktop/direwolf.desktop
|
||||
|
||||
|
||||
|
||||
# ---------------------------------- Automated Smoke Test --------------------------------
|
||||
|
||||
|
||||
|
||||
# Combine some unit tests into a single regression sanity check.
|
||||
|
||||
|
||||
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400 check-modem4800
|
||||
|
||||
# Can we encode and decode at popular data rates?
|
||||
|
||||
check-modem1200 : gen_packets atest
|
||||
./gen_packets -n 100 -o /tmp/test12.wav
|
||||
./atest -F0 -PE -L63 -G71 /tmp/test12.wav
|
||||
./atest -F1 -PE -L70 -G75 /tmp/test12.wav
|
||||
rm /tmp/test12.wav
|
||||
|
||||
check-modem300 : gen_packets atest
|
||||
./gen_packets -B300 -n 100 -o /tmp/test3.wav
|
||||
./atest -B300 -F0 -L68 -G69 /tmp/test3.wav
|
||||
./atest -B300 -F1 -L73 -G75 /tmp/test3.wav
|
||||
rm /tmp/test3.wav
|
||||
|
||||
check-modem9600 : gen_packets atest
|
||||
./gen_packets -B9600 -n 100 -o /tmp/test96.wav
|
||||
./atest -B9600 -F0 -L50 -G54 /tmp/test96.wav
|
||||
./atest -B9600 -F1 -L55 -G59 /tmp/test96.wav
|
||||
rm /tmp/test96.wav
|
||||
|
||||
check-modem19200 : gen_packets atest
|
||||
./gen_packets -r 96000 -B19200 -n 100 -o /tmp/test19.wav
|
||||
./atest -B19200 -F0 -L55 -G59 /tmp/test19.wav
|
||||
./atest -B19200 -F1 -L60 -G64 /tmp/test19.wav
|
||||
rm /tmp/test19.wav
|
||||
|
||||
check-modem2400 : gen_packets atest
|
||||
./gen_packets -B2400 -n 100 -o /tmp/test24.wav
|
||||
./atest -B2400 -F0 -L70 -G78 /tmp/test24.wav
|
||||
./atest -B2400 -F1 -L80 -G87 /tmp/test24.wav
|
||||
rm /tmp/test24.wav
|
||||
|
||||
check-modem4800 : gen_packets atest
|
||||
./gen_packets -B2400 -n 100 -o /tmp/test48.wav
|
||||
./atest -B2400 -F0 -L70 -G79 /tmp/test48.wav
|
||||
./atest -B2400 -F1 -L80 -G90 /tmp/test48.wav
|
||||
rm /tmp/test48.wav
|
||||
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
.PHONY : dtest
|
||||
dtest : digipeater.c dedupe.c pfilter.c \
|
||||
ax25_pad.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DDIGITEST -o $@ $^ $(LDFLAGS)
|
||||
./dtest
|
||||
rm dtest
|
||||
|
||||
|
||||
# Unit test for APRStt tone sequence parsing.
|
||||
|
||||
.PHONY : ttest
|
||||
ttest : aprs_tt.c tt_text.c latlong.o textcolor.o misc.a geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^ $(LDFLAGS)
|
||||
./ttest
|
||||
rm ttest
|
||||
|
||||
|
||||
# Unit test for APRStt tone sequence / text conversions.
|
||||
|
||||
.PHONY: tttexttest
|
||||
tttexttest : tt_text.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTTT_TEST -o $@ $^ $(LDFLAGS)
|
||||
./tttexttest
|
||||
rm tttexttest
|
||||
|
||||
|
||||
# Unit test for Packet Filtering.
|
||||
|
||||
.PHONY: pftest
|
||||
pftest : pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o latlong.o symbols.o telemetry.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DPFTEST -o $@ $^ $(LDFLAGS)
|
||||
./pftest
|
||||
rm pftest
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
.PHONY: tlmtest
|
||||
tlmtest : telemetry.c ax25_pad.o fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^ $(LDFLAGS)
|
||||
./tlmtest
|
||||
rm tlmtest
|
||||
|
||||
# Unit test for location coordinate conversion.
|
||||
|
||||
.PHONY: lltest
|
||||
lltest : latlong.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DLLTEST -o $@ $^ $(LDFLAGS)
|
||||
./lltest
|
||||
rm lltest
|
||||
|
||||
# Unit test for encoding position & object report.
|
||||
|
||||
.PHONY: enctest
|
||||
enctest : encode_aprs.c latlong.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -DEN_MAIN -o $@ $^ $(LDFLAGS)
|
||||
./enctest
|
||||
rm enctest
|
||||
|
||||
|
||||
# Unit test for KISS encapsulation.
|
||||
|
||||
.PHONY: kisstest
|
||||
kisstest : kiss_frame.c
|
||||
$(CC) $(CFLAGS) -DKISSTEST -o $@ $^ $(LDFLAGS)
|
||||
./kisstest
|
||||
rm kisstest
|
||||
|
||||
# Unit test for constructing frames besides UI.
|
||||
|
||||
.PHONY: pad2test
|
||||
pad2test : ax25_pad2.c ax25_pad.c fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DPAD2TEST -o $@ $^ $(LDFLAGS)
|
||||
./pad2test
|
||||
rm pad2test
|
||||
|
||||
|
||||
# Unit Test for XID frame encode/decode.
|
||||
|
||||
.PHONY: xidtest
|
||||
xidtest : xid.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DXIDTEST -o $@ $^ $(LDFLAGS)
|
||||
./xidtest
|
||||
rm xidtest
|
||||
|
||||
|
||||
# Unit Test for DTMF encode/decode.
|
||||
|
||||
.PHONY: dtmftest
|
||||
dtmftest : dtmf.c textcolor.o
|
||||
$(CC) $(CFLAGS) -DDTMF_TEST -o $@ $^ $(LDFLAGS)
|
||||
./dtmftest
|
||||
rm dtmftest
|
||||
|
||||
|
||||
|
||||
# ----------------------------- Manual tests and experiments ---------------------------
|
||||
|
||||
# These are not included in a normal build. Might be broken.
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^
|
||||
./itest
|
||||
|
||||
# Unit test for UDP reception with AFSK demodulator.
|
||||
# Temporary during development. Might not be useful anymore.
|
||||
|
||||
udptest : udp_test.c demod.o dsp.o demod_afsk.o demod_psk.o demod_9600.o hdlc_rec.o hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.o ax25_pad.o decode_aprs.o symbols.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
./udptest
|
||||
|
||||
# For demodulator tweaking experiments.
|
||||
# Dependencies of demod*.c, rather than .o, are intentional.
|
||||
|
||||
demod.o : tune.h
|
||||
|
||||
demod_afsk.o : tune.h
|
||||
|
||||
demod_9600.o : tune.h
|
||||
|
||||
demod_psk.o : tune.h
|
||||
|
||||
tune.h :
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
testagc : atest.c demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.c hdlc_rec.o hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.o ax25_pad.o decode_aprs.o telemetry.o dtime_now.o latlong.o symbols.o tune.h textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o atest $^ $(LDFLAGS)
|
||||
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
||||
|
||||
|
||||
testagc96 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o latlong.o \
|
||||
symbols.o tt_text.o textcolor.o telemetry.o dtime_now.o \
|
||||
misc.a
|
||||
rm -f atest96
|
||||
$(CC) $(CFLAGS) -o atest96 $^ $(LDFLAGS)
|
||||
./atest96 -B 9600 ../walkabout9600c.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 noisy96.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 19990303_0225_9600_8bis_22kHz.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 19990303_0225_9600_16bit_22kHz.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 -P + z8-22k.wav| grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 test9600.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
|
||||
|
||||
# ------------------------------- Source distribution ---------------------------------
|
||||
|
||||
# probably obsolete and can be removed after move to github.
|
||||
|
||||
|
||||
|
||||
.PHONY: dist-src
|
||||
dist-src : README.md CHANGES.md
|
||||
doc/User-Guide.pdf doc/Raspberry-Pi-APRS.pdf \
|
||||
doc/Raspberry-Pi-APRS-Tracker.pdf doc/APRStt-Implementation-Notes.pdf \
|
||||
dw-start.sh dwespeak.bat dwespeak.sh \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt direwolf.spec
|
||||
rm -f fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
rm -f ../$z-src.zip
|
||||
(cd .. ; zip $z-src.zip \
|
||||
$z/README.md \
|
||||
$z/CHANGES.md \
|
||||
$z/LICENSE* \
|
||||
$z/doc/User-Guide.pdf \
|
||||
$z/doc/Raspberry-Pi-APRS.pdf \
|
||||
$z/doc/Raspberry-Pi-APRS-Tracker.pdf \
|
||||
$z/doc/APRStt-Implementation-Notes.pdf \
|
||||
$z/doc/APRS-Telemetry-Toolkit.pdf \
|
||||
$z/Makefile* \
|
||||
$z/*.c $z/*.h \
|
||||
$z/regex/* $z/misc/* $z/geotranz/* \
|
||||
$z/man1/* \
|
||||
$z/generic.conf \
|
||||
$z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
||||
$z/dw-start.sh $z/direwolf.spec \
|
||||
$z/dwespeak.bat $z/dwespeak.sh \
|
||||
$z/telemetry-toolkit/* )
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -f $(APPS) gen_fff tune.h fsk_fast_filter.h *.o *.a direwolf.desktop
|
||||
|
||||
|
||||
depend : $(wildcard *.c)
|
||||
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||
|
||||
|
||||
#
|
||||
# The following is updated by "make depend"
|
||||
#
|
||||
# DO NOT DELETE
|
||||
|
||||
|
|
@ -0,0 +1,572 @@
|
|||
#
|
||||
# Makefile for Macintosh 10.6+ version of Dire Wolf.
|
||||
#
|
||||
|
||||
# TODO: This is a modified version of Makefile.linux and it
|
||||
# has fallen a little behind. For example, it is missing the check target.
|
||||
# It would be more maintainable if we could use a single file for both.
|
||||
# The differences are not that great.
|
||||
# Maybe the most of the differences could go in to platform specific include
|
||||
# files rather than cluttering it up with too many if blocks.
|
||||
|
||||
# Changes:
|
||||
#
|
||||
# 16 Dec 2015
|
||||
# 1. Added condition check for gps/gpsd code. Commented out due to 32/64 bit
|
||||
# library issues. Macports gpsd build problem.
|
||||
# 2. SDK version checks are now performed by a bash script 'search_sdks.sh'.
|
||||
# This should resolve the varied locations Apple stored the SDKs on the different
|
||||
# Xcode/OS versions. Executing 'make' on the first pass asks the operator
|
||||
# which SDK he/she wishes to use. Executing 'make clean' resets the SDK
|
||||
# selection and operator intervention is once again required. Selected SDK
|
||||
# information resides in a file named './use_this_sdk' in the current working
|
||||
# directory.
|
||||
# 3. Removed fsk_fast_filter.h from atest receipe, clang compiler was having
|
||||
# a hissy fit. Not check with GCC.
|
||||
|
||||
APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc kissutil
|
||||
|
||||
all : $(APPS) direwolf.conf
|
||||
@echo " "
|
||||
@echo "Next step install with: "
|
||||
@echo " "
|
||||
@echo " sudo make install"
|
||||
@echo " "
|
||||
@echo " "
|
||||
|
||||
SYS_LIBS :=
|
||||
SYS_MIN :=
|
||||
#SDK := $(shell find /Developer -maxdepth 1 -type d -name "SDKs")
|
||||
#$(info $$SDK = ${SDK})
|
||||
#ifeq (${SDK},/Developer/SDKs)
|
||||
# SDK := $(shell find /Developer/SDKs -maxdepth 1 -type d -name "MacOSX10.8.sdk")
|
||||
# ifeq (${SDK},/Developer/SDKs/MacOSX10.8.sdk)
|
||||
# SYS_LIBS := -isystem /Developer/SDKs/MacOSX10.8.sdk
|
||||
# SYS_MIN := -mmacosx-version-min=10.8
|
||||
# else
|
||||
# SDK := $(shell find /Developer/SDKs -maxdepth 1 -type d -name "MacOSX10.9.sdk")
|
||||
# ifeq (${SDK},/Developer/SDKs/MacOSX10.9.sdk)
|
||||
# SYS_LIBS := -isystem /Developer/SDKs/MacOSX10.9.sdk
|
||||
# SYS_MIN := -mmacosx-version-min=10.9
|
||||
# else
|
||||
# SDK := $(shell find /Developer/SDKs -maxdepth 1 -type d -name "MacOSX10.10.sdk")
|
||||
# ifeq (${SDK},/Developer/SDKs/MacOSX10.10.sdk)
|
||||
# SYS_LIBS := -isystem /Developer/SDKs/MacOSX10.10.sdk
|
||||
# SYS_MIN := -mmacosx-version-min=10.10
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
SYS_LIBS := $(shell ./search_sdks.sh)
|
||||
EXTRA_CFLAGS :=
|
||||
DARWIN_CC := $(shell which clang)
|
||||
ifeq (${DARWIN_CC},)
|
||||
DARWIN_CC := $(shell which gcc)
|
||||
EXTRA_CFLAGS :=
|
||||
else
|
||||
EXTRA_CFLAGS := -fvectorize -fslp-vectorize -fslp-vectorize-aggressive -pthread
|
||||
endif
|
||||
|
||||
# Change as required in support of the available libraries
|
||||
|
||||
#CC := $(DARWIN_CC) -m64 $(SYS_LIBS) $(SYS_MIN)
|
||||
CC := $(DARWIN_CC) -m32 $(SYS_LIBS) $(SYS_MIN)
|
||||
|
||||
# _XOPEN_SOURCE=600 and _DEFAULT_SOURCE=1 are needed for glibc >= 2.24.
|
||||
# Explanation here: https://github.com/wb2osz/direwolf/issues/62
|
||||
|
||||
CFLAGS := -Os -pthread -Igeotranz -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE=1 $(EXTRA_CFLAGS)
|
||||
|
||||
# That was fine for a recent Ubuntu and Raspbian Jessie.
|
||||
# However, Raspbian wheezy was then missing declaration for strsep and definition of fd_set.
|
||||
|
||||
CFLAGS += -D_BSD_SOURCE
|
||||
|
||||
|
||||
# $(info $$CC is [${CC}])
|
||||
|
||||
|
||||
# If the compiler is generating code for a 32 bit target (-m32), we can
|
||||
# get much better results by telling it we have at least a Pentium 3
|
||||
# which hass the SSE instructions.
|
||||
|
||||
CFLAGS += -march=core2 -msse4.1 -std=gnu99
|
||||
#CFLAGS += -march=pentium3 -sse
|
||||
|
||||
|
||||
# Add -ffastmath in only if compiler version recognizes it.
|
||||
|
||||
useffast := $(shell gcc --help -v 2>/dev/null | grep ffast-math)
|
||||
ifneq ($(useffast),)
|
||||
CFLAGS += -ffast-math
|
||||
endif
|
||||
|
||||
#CFLAGS += -D_FORTIFY_SOURCE
|
||||
|
||||
# Use PortAudio Library
|
||||
|
||||
# Force static linking of portaudio if the static library is available.
|
||||
PA_LIB_STATIC := $(shell find /opt/local/lib -maxdepth 1 -type f -name "libportaudio.a")
|
||||
#$(info $$PA_LIB_STATIC is [${PA_LIB_STATIC}])
|
||||
ifeq (${PA_LIB_STATIC},)
|
||||
LDLIBS += -L/opt/local/lib -lportaudio
|
||||
else
|
||||
LDLIBS += /opt/local/lib/libportaudio.a
|
||||
endif
|
||||
|
||||
# Include libraries portaudio requires.
|
||||
LDLIBS += -framework CoreAudio -framework AudioUnit -framework AudioToolbox
|
||||
LDLIBS += -framework Foundation -framework CoreServices
|
||||
|
||||
CFLAGS += -DUSE_PORTAUDIO -I/opt/local/include
|
||||
|
||||
# Uncomment following lines to enable GPS interface & tracker function.
|
||||
# Not available for MacOSX (as far as I know).
|
||||
# Although MacPorts has gpsd, wonder if it's the same thing. Add the check
|
||||
# just in case it works.
|
||||
# Well never mind, issue with Macports with 64bit libs ;-( leave the check in
|
||||
# until (if ever) Macports fixes the issue.
|
||||
|
||||
#GPS_HEADER := $(shell find /opt/local/include -maxdepth 1 -type f -name "gps.h")
|
||||
#ifeq (${GPS_HEADER},)
|
||||
#GPS_OBJS :=
|
||||
#else
|
||||
#CFLAGS += -DENABLE_GPSD
|
||||
#LDLIBS += -L/opt/local/lib -lgps -lgpsd
|
||||
#GPS_OBJS := dwgps.o dwgpsnmea.o dwgpsd.o
|
||||
#endif
|
||||
|
||||
# Name of current directory.
|
||||
# Used to generate zip file name for distribution.
|
||||
|
||||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
# Main application.
|
||||
|
||||
direwolf : direwolf.o aprs_tt.o audio_portaudio.o audio_stats.o ax25_link.o ax25_pad.o ax25_pad2.o beacon.o \
|
||||
config.o decode_aprs.o dedupe.o demod_9600.o demod_afsk.o demod_psk.o \
|
||||
demod.o digipeater.o cdigipeater.o dlq.o dsp.o dtime_now.o dtmf.o dwgps.o \
|
||||
encode_aprs.o encode_aprs.o fcs_calc.o fcs_calc.o gen_tone.o \
|
||||
geotranz.a hdlc_rec.o hdlc_rec2.o hdlc_send.o igate.o kiss_frame.o \
|
||||
kiss.o kissserial.o kissnet.o latlong.o latlong.o log.o morse.o multi_modem.o \
|
||||
waypoint.o serial_port.o pfilter.o ptt.o rdq.o recv.o rrbb.o server.o \
|
||||
symbols.o telemetry.o textcolor.o tq.o tt_text.o tt_user.o xid.o xmit.o \
|
||||
dwgps.o dwgpsnmea.o mheard.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread $(LDLIBS) -lm
|
||||
|
||||
|
||||
# Optimization for slow processors.
|
||||
|
||||
demod.o : fsk_fast_filter.h
|
||||
|
||||
demod_afsk.o : fsk_fast_filter.h
|
||||
|
||||
|
||||
fsk_fast_filter.h : gen_fff
|
||||
./gen_fff > fsk_fast_filter.h
|
||||
|
||||
gen_fff : demod_afsk.c dsp.c textcolor.c
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -DGEN_FFF -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
|
||||
# UTM, USNG, MGRS conversions.
|
||||
|
||||
geotranz.a : error_string.o mgrs.o polarst.o tranmerc.o ups.o usng.o utm.o
|
||||
ar -cr $@ $^
|
||||
|
||||
error_string.o : geotranz/error_string.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
mgrs.o : geotranz/mgrs.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
polarst.o : geotranz/polarst.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
tranmerc.o : geotranz/tranmerc.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
ups.o : geotranz/ups.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
usng.o : geotranz/usng.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
utm.o : geotranz/utm.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
|
||||
|
||||
# Generate apprpriate sample configuration file for this platform.
|
||||
|
||||
direwolf.conf : generic.conf
|
||||
egrep '^C|^M' generic.conf | cut -c2-999 > direwolf.conf
|
||||
|
||||
|
||||
# Where should we install it?
|
||||
# Macports typically installs in /opt/local so maybe you want to use that instead.
|
||||
|
||||
INSTALLDIR := /usr/local
|
||||
#INSTALLDIR := /opt/local
|
||||
|
||||
# TODO: Test this better.
|
||||
|
||||
# Optional installation into INSTALLDIR.
|
||||
# Needs to be run as root or with sudo.
|
||||
|
||||
# Command to "install" to system directories. "install" for Linux. "ginstall" for Mac.
|
||||
|
||||
INSTALL=ginstall
|
||||
|
||||
.PHONY: install
|
||||
install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png
|
||||
#
|
||||
# Applications.
|
||||
#
|
||||
$(INSTALL) direwolf $(INSTALLDIR)/bin
|
||||
$(INSTALL) decode_aprs $(INSTALLDIR)/bin
|
||||
$(INSTALL) text2tt $(INSTALLDIR)/bin
|
||||
$(INSTALL) tt2text $(INSTALLDIR)/bin
|
||||
$(INSTALL) ll2utm $(INSTALLDIR)/bin
|
||||
$(INSTALL) utm2ll $(INSTALLDIR)/bin
|
||||
$(INSTALL) aclients $(INSTALLDIR)/bin
|
||||
$(INSTALL) log2gpx $(INSTALLDIR)/bin
|
||||
$(INSTALL) gen_packets $(INSTALLDIR)/bin
|
||||
$(INSTALL) atest $(INSTALLDIR)/bin
|
||||
$(INSTALL) ttcalc $(INSTALLDIR)/bin
|
||||
$(INSTALL) kissutil $(INSTALLDIR)/bin
|
||||
$(INSTALL) dwespeak.sh $(INSTALLDIR)/bin
|
||||
#
|
||||
# Telemetry Toolkit executables. Other .conf and .txt files will go into doc directory.
|
||||
#
|
||||
$(INSTALL) telemetry-toolkit/telem-balloon.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-bits.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data91.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-eqns.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-parm.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-unit.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-volts.py $(INSTALLDIR)/bin
|
||||
#
|
||||
# Misc. data such as "tocall" to system mapping.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 tocalls.txt $(INSTALLDIR)/share/direwolf/tocalls.txt
|
||||
$(INSTALL) -D --mode=644 symbols-new.txt $(INSTALLDIR)/share/direwolf/symbols-new.txt
|
||||
$(INSTALL) -D --mode=644 symbolsX.txt $(INSTALLDIR)/share/direwolf/symbolsX.txt
|
||||
$(INSTALL) -D --mode=644 dw-icon.png $(INSTALLDIR)/share/direwolf/dw-icon.png
|
||||
|
||||
#
|
||||
# Documentation. Various plain text files and PDF.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
$(INSTALL) -D --mode=644 CHANGES.md $(INSTALLDIR)/share/doc/direwolf/CHANGES.md
|
||||
$(INSTALL) -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
$(INSTALL) -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
#
|
||||
# ./README.md is an overview for the project main page.
|
||||
# doc/README.md contains an overview of the PDF file contents and is more useful here.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 doc/README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
$(INSTALL) -D --mode=644 doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf $(INSTALLDIR)/share/doc/direwolf/2400-4800-PSK-for-APRS-Packet-Radio.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf $(INSTALLDIR)/share/doc/direwolf/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Listening-Example.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Listening-Example.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Bluetooth-KISS-TNC.pdf $(INSTALLDIR)/share/doc/direwolf/Bluetooth-KISS-TNC.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Going-beyond-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/Going-beyond-9600-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Successful-APRS-IGate-Operation.pdf $(INSTALLDIR)/share/doc/direwolf/Successful-APRS-IGate-Operation.pdf
|
||||
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
$(INSTALL) -D --mode=644 doc/WA8LMF-TNC-Test-CD-Results.pdf $(INSTALLDIR)/share/doc/direwolf/WA8LMF-TNC-Test-CD-Results.pdf
|
||||
#
|
||||
# Sample config files also go into the doc directory.
|
||||
# When building from source, these can be put in home directory with "make install-conf".
|
||||
# When installed from .DEB or .RPM package, the user will need to copy these to
|
||||
# the home directory or other desired location.
|
||||
# Someone suggested that these could go into an "examples" subdirectory under doc.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 direwolf.conf $(INSTALLDIR)/share/doc/direwolf/direwolf.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-m0xer-3.txt $(INSTALLDIR)/share/doc/direwolf/telem-m0xer-3.txt
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-balloon.conf $(INSTALLDIR)/share/doc/direwolf/telem-balloon.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-volts.conf $(INSTALLDIR)/share/doc/direwolf/telem-volts.conf
|
||||
#
|
||||
# "man" pages
|
||||
#
|
||||
$(INSTALL) -D --mode=644 man1/aclients.1 $(INSTALLDIR)/man/man1/aclients.1
|
||||
$(INSTALL) -D --mode=644 man1/atest.1 $(INSTALLDIR)/man/man1/atest.1
|
||||
$(INSTALL) -D --mode=644 man1/decode_aprs.1 $(INSTALLDIR)/man/man1/decode_aprs.1
|
||||
$(INSTALL) -D --mode=644 man1/direwolf.1 $(INSTALLDIR)/man/man1/direwolf.1
|
||||
$(INSTALL) -D --mode=644 man1/gen_packets.1 $(INSTALLDIR)/man/man1/gen_packets.1
|
||||
$(INSTALL) -D --mode=644 man1/ll2utm.1 $(INSTALLDIR)/man/man1/ll2utm.1
|
||||
$(INSTALL) -D --mode=644 man1/log2gpx.1 $(INSTALLDIR)/man/man1/log2gpx.1
|
||||
$(INSTALL) -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
|
||||
$(INSTALL) -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
|
||||
$(INSTALL) -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
|
||||
#
|
||||
@echo " "
|
||||
@echo "If this is your first install, not an upgrade, type this to put a copy"
|
||||
@echo "of the sample configuration file (direwolf.conf) in your home directory:"
|
||||
@echo " "
|
||||
@echo " make install-conf"
|
||||
@echo " "
|
||||
|
||||
|
||||
# TODO: Should we put the sample direwolf.conf file somewhere like
|
||||
# /usr/share/doc/direwolf/examples and add that to the
|
||||
# end of the search path list?
|
||||
# That would make it easy to see user customizations compared to the
|
||||
# latest sample.
|
||||
|
||||
# These would be done as ordinary user.
|
||||
|
||||
|
||||
.PHONY: install-conf
|
||||
install-conf : direwolf.conf
|
||||
cp direwolf.conf ~
|
||||
cp telemetry-toolkit/telem-m0xer-3.txt ~
|
||||
cp telemetry-toolkit/telem-*.conf ~
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
# First three use .c rather than .o because they depend on DECAMAIN definition.
|
||||
|
||||
decode_aprs : decode_aprs.c kiss_frame.c ax25_pad.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ -lm
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^
|
||||
|
||||
tt2text : tt_text.c
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c geotranz.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
utm2ll : utm2ll.c geotranz.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c morse.c dtmf.c textcolor.c dsp.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) -lm
|
||||
|
||||
demod.o : tune.h
|
||||
|
||||
demod_afsk.o : tune.h
|
||||
|
||||
demod_9600.o : tune.h
|
||||
|
||||
demod_psk.o : tune.h
|
||||
|
||||
tune.h :
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
testagc : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c dtime_now.o latlong.c symbols.c tune.h textcolor.c
|
||||
$(CC) $(CFLAGS) -o atest $^ -lm
|
||||
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
||||
|
||||
|
||||
# Unit test for demodulators
|
||||
|
||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o telemetry.c dtime_now.o latlong.c symbols.c textcolor.c tt_text.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
#atest : atest.c fsk_fast_filter.h demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
# fcs_calc.c ax25_pad.c decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o telemetry.c latlong.c symbols.c textcolor.c tt_text.c
|
||||
# $(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
|
||||
dtest : digipeater.c pfilter.o ax25_pad.o dedupe.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./dtest
|
||||
|
||||
|
||||
# Unit test for APRStt.
|
||||
|
||||
ttest : aprs_tt.c tt_text.c latlong.c geotranz.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^
|
||||
./itest
|
||||
|
||||
|
||||
# Unit test for UDP reception with AFSK demodulator
|
||||
|
||||
udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
./udptest
|
||||
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
|
||||
tlmtest : telemetry.c ax25_pad.c fcs_calc.c textcolor.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
./tlmtest
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# Talk to a KISS TNC.
|
||||
# Note: kiss_frame.c has conditional compilation on KISSUTIL.
|
||||
|
||||
kissutil : kissutil.c kiss_frame.c ax25_pad.o fcs_calc.o textcolor.o serial_port.o dtime_now.o sock.o
|
||||
$(CC) $(CFLAGS) -g -DKISSUTIL -o $@ $^
|
||||
|
||||
|
||||
|
||||
# Touch Tone to Speech sample application.
|
||||
|
||||
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
depend : $(wildcard *.c)
|
||||
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -f $(APPS) gen_fff \
|
||||
fsk_fast_filter.h *.o *.a use_this_sdk
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
.PHONY: dist-mac
|
||||
dist-mac: direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx gen_packets \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png
|
||||
rm -f ../direwolf_dist_bin.zip
|
||||
(cd .. ; zip direwolf_dist_bin.zip \
|
||||
$(INSTALLDIR)/bin/direwolf \
|
||||
$(INSTALLDIR)/bin/decode_aprs \
|
||||
$(INSTALLDIR)/bin/text2tt \
|
||||
$(INSTALLDIR)/bin/tt2text \
|
||||
$(INSTALLDIR)/bin/ll2utm \
|
||||
$(INSTALLDIR)/bin/utm2ll \
|
||||
$(INSTALLDIR)/bin/aclients \
|
||||
$(INSTALLDIR)/bin/log2gpx \
|
||||
$(INSTALLDIR)/bin/gen_packets \
|
||||
$(INSTALLDIR)/bin/atest \
|
||||
$(INSTALLDIR)/bin/ttcalc \
|
||||
$(INSTALLDIR)/bin/kissutil \
|
||||
$(INSTALLDIR)/bin/dwespeak.sh \
|
||||
$(INSTALLDIR)/share/direwolf/tocalls.txt \
|
||||
$(INSTALLDIR)/share/direwolf/config/direwolf.conf \
|
||||
$(INSTALLDIR)/share/direwolf/symbols-new.txt \
|
||||
$(INSTALLDIR)/share/direwolf/symbolsX.txt \
|
||||
$(INSTALLDIR)/share/direwolf/dw-icon.png \
|
||||
$(INSTALLDIR)/share/doc/direwolf/README.md \
|
||||
$(INSTALLDIR)/share/doc/direwolf/CHANGES.md \
|
||||
$(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt \
|
||||
$(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt \
|
||||
$(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf \
|
||||
$(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf \
|
||||
$(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf \
|
||||
$(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf \
|
||||
$(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf \
|
||||
$(INSTALLDIR)/man/man1/aclients.1 \
|
||||
$(INSTALLDIR)/man/man1/atest.1 \
|
||||
$(INSTALLDIR)/man/man1/decode_aprs.1 \
|
||||
$(INSTALLDIR)/man/man1/direwolf.1 \
|
||||
$(INSTALLDIR)/man/man1/gen_packets.1 \
|
||||
$(INSTALLDIR)/man/man1/kissutil.1 \
|
||||
$(INSTALLDIR)/man/man1/ll2utm.1 \
|
||||
$(INSTALLDIR)/man/man1/log2gpx.1 \
|
||||
$(INSTALLDIR)/man/man1/text2tt.1 \
|
||||
$(INSTALLDIR)/man/man1/tt2text.1 \
|
||||
$(INSTALLDIR)/man/man1/utm2ll.1 \
|
||||
)
|
||||
|
||||
# Package it up for distribution.
|
||||
|
||||
.PHONY: dist-src
|
||||
dist-src : README.md CHANGES.md \
|
||||
doc/User-Guide.pdf doc/Raspberry-Pi-APRS.pdf \
|
||||
doc/Raspberry-Pi-APRS-Tracker.pdf doc/APRStt-Implementation-Notes.pdf \
|
||||
dw-start.sh dwespeak.bat dwespeak.sh \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt direwolf.spec
|
||||
rm -f fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
rm -f ../$z-src.zip
|
||||
(cd .. ; zip $z-src.zip \
|
||||
$z/README.md \
|
||||
$z/CHANGES.md \
|
||||
$z/LICENSE* \
|
||||
$z/doc/User-Guide.pdf \
|
||||
$z/doc/Raspberry-Pi-APRS.pdf \
|
||||
$z/doc/Raspberry-Pi-APRS-Tracker.pdf \
|
||||
$z/doc/APRStt-Implementation-Notes.pdf \
|
||||
$z/Makefile* \
|
||||
$z/*.c $z/*.h \
|
||||
$z/regex/* $z/misc/* $z/geotranz/* \
|
||||
$z/man1/* \
|
||||
$z/generic.conf \
|
||||
$z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
||||
$z/dw-start.sh $z/direwolf.spec \
|
||||
$z/dwespeak.bat $z/dwespeak.sh \
|
||||
$z/telemetry-toolkit/* )
|
||||
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff -Z tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff -Z symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff -Z symbolsX.txt~ symbolsX.txt
|
|
@ -0,0 +1,695 @@
|
|||
#
|
||||
# Makefile for native Windows version of Dire Wolf.
|
||||
#
|
||||
#
|
||||
# This is built in the Cygwin environment but with the
|
||||
# compiler from http://www.mingw.org/ so there is no
|
||||
# dependency on extra DLLs.
|
||||
#
|
||||
# The MinGW/bin directory must be in the PATH for the
|
||||
# compiler. e.g. export PATH=/cygdrive/c/MinGW/bin:$PATH
|
||||
#
|
||||
# Failure to have the path set correctly will result in the
|
||||
# obscure message: Makefile.win:... recipe for target ... failed.
|
||||
#
|
||||
# Type "which gcc" to make sure you are getting the right one!
|
||||
#
|
||||
|
||||
|
||||
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx gen_packets atest ttcalc tnctest kissutil
|
||||
|
||||
|
||||
# People say we need -mthreads option for threads to work properly.
|
||||
# They also say it creates a dependency on mingwm10.dll but I'm not seeing that.
|
||||
# Maybe that is for pthreads. We are using the Windows threads.
|
||||
|
||||
# -Ofast was added in gcc 4.6 which was the MinGW version back in 2012.
|
||||
|
||||
CC := gcc
|
||||
CFLAGS := -Ofast -march=pentium3 -msse -Iregex -Iutm -Igeotranz -mthreads -DUSE_REGEX_STATIC -Wall -Wlogical-op
|
||||
AR := ar
|
||||
|
||||
CFLAGS += -g
|
||||
# TEMP EXPERIMENT - DO NOT RELEASE
|
||||
#CFLAGS += -fsanitize=undefined
|
||||
|
||||
# For version 1.4, we upgrade from gcc 4.6.2 to 4.9.3.
|
||||
|
||||
# gcc 4.8 adds these. Try them just for fun.
|
||||
# No, it needs libasan which is not on Windows.
|
||||
#CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||
|
||||
# Helpful for the demodulators. Overkill for non-hot spots.
|
||||
#CFLAGS += -Wdouble-promotion
|
||||
|
||||
# Don't have the patience for this right now.
|
||||
#CFLAGS += -Wextra
|
||||
|
||||
# Continue working on these.
|
||||
CFLAGS += -Wsign-compare
|
||||
CFLAGS += -Wuninitialized
|
||||
CFLAGS += -Wold-style-declaration
|
||||
# CFLAGS += -fdelete-null-pointer-checks -Wnull-dereference ---not recognized
|
||||
#CFLAGS += -Wold-style-definition
|
||||
#-Wmissing-prototypes
|
||||
|
||||
#
|
||||
# Let's see impact of various optimization levels.
|
||||
# Benchmark results with MinGW gcc version 4.6.2.
|
||||
#
|
||||
# seconds options, comments
|
||||
# ------ -----------------
|
||||
# 119.8 -O2 Used for version 0.8
|
||||
# 92.1 -O3
|
||||
# 88.7 -Ofast (should be same as -O3 -ffastmath)
|
||||
# 87.5 -Ofast -march=pentium
|
||||
# 74.1 -Ofast -msse
|
||||
# 72.2 -Ofast -march=pentium -msse
|
||||
# 62.0 -Ofast -march=pentium3 (this implies -msse)
|
||||
# 61.9 -Ofast -march=pentium3 -msse
|
||||
#
|
||||
# A minimum of Windows XP is required due to some of the system
|
||||
# features being used. XP requires a Pentium processor or later.
|
||||
# The DSP filters can be sped up considerably with the SSE instructions.
|
||||
# The SSE instructions were introduced in 1999 with the
|
||||
# Pentium III series.
|
||||
# SSE2 instructions, added in 2000, don't seem to offer any advantage.
|
||||
#
|
||||
# For version 0.9, a Pentium 3 or equivalent is now the minimum required
|
||||
# for the prebuilt Windows distribution.
|
||||
# If you insist on using a computer from the previous century,
|
||||
# you can compile this yourself with different options.
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
# -------------------------------------- Main application --------------------------------
|
||||
|
||||
# Not sure why this is here.
|
||||
|
||||
demod.o : fsk_demod_state.h
|
||||
|
||||
demod_9600.o : fsk_demod_state.h
|
||||
|
||||
demod_afsk.o : fsk_demod_state.h
|
||||
|
||||
demod_psk.o : fsk_demod_state.h
|
||||
|
||||
|
||||
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_psk.o demod_9600.o hdlc_rec.o \
|
||||
hdlc_rec2.o multi_modem.o rdq.o rrbb.o dlq.o \
|
||||
fcs_calc.o ax25_pad.o ax25_pad2.o xid.o \
|
||||
decode_aprs.o symbols.o server.o kiss.o kissserial.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||
gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o cdigipeater.o pfilter.o dedupe.o tq.o xmit.o \
|
||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o waypoint.o serial_port.o log.o telemetry.o \
|
||||
dwgps.o dwgpsnmea.o dtime_now.o mheard.o ax25_link.o cm108.c \
|
||||
dw-icon.o regex.a misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
dw-icon.o : dw-icon.rc dw-icon.ico
|
||||
windres dw-icon.rc -o $@
|
||||
|
||||
|
||||
# Optimization for slow processors.
|
||||
|
||||
demod.o : fsk_fast_filter.h
|
||||
|
||||
demod_afsk.o : fsk_fast_filter.h
|
||||
|
||||
|
||||
fsk_fast_filter.h : gen_fff
|
||||
./gen_fff > fsk_fast_filter.h
|
||||
|
||||
gen_fff : demod_afsk.c dsp.c textcolor.c
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -DGEN_FFF -o $@ $^
|
||||
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff symbolsX.txt~ symbolsX.txt
|
||||
|
||||
|
||||
|
||||
# ---------------------------- Other utilities included with distribution -------------------------
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
# First three use .c rather than .o because they depend on DECAMAIN definition.
|
||||
|
||||
decode_aprs : decode_aprs.c kiss_frame.c ax25_pad.c dwgpsnmea.o dwgps.o serial_port.o symbols.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o regex.a misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o decode_aprs $^
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^
|
||||
|
||||
tt2text : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c textcolor.c geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
utm2ll : utm2ll.c textcolor.c geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.o ax25_pad.o hdlc_send.o fcs_calc.o gen_tone.o morse.o dtmf.o textcolor.o dsp.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
# Connected mode packet application server.
|
||||
|
||||
appserver : appserver.o textcolor.o ax25_pad.o fcs_calc.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------- Libraries --------------------------------------------
|
||||
|
||||
|
||||
|
||||
# UTM, USNG, MGRS conversions.
|
||||
|
||||
geotranz.a : error_string.o mgrs.o polarst.o tranmerc.o ups.o usng.o utm.o
|
||||
ar -cr $@ $^
|
||||
|
||||
error_string.o : geotranz/error_string.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
mgrs.o : geotranz/mgrs.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
polarst.o : geotranz/polarst.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
tranmerc.o : geotranz/tranmerc.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
ups.o : geotranz/ups.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
usng.o : geotranz/usng.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
utm.o : geotranz/utm.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
|
||||
#
|
||||
# When building for Linux, we use regular expression
|
||||
# functions supplied by the gnu C library.
|
||||
# For the native WIN32 version, we need to use our own copy.
|
||||
# These were copied from http://gnuwin32.sourceforge.net/packages/regex.htm
|
||||
# Consider upgrading from https://www.gnu.org/software/libc/sources.html
|
||||
|
||||
regex.a : regex.o
|
||||
ar -cr $@ $^
|
||||
|
||||
regex.o : regex/regex.c
|
||||
$(CC) $(CFLAGS) -Dbool=int -Dtrue=1 -Dfalse=0 -c -o $@ $^
|
||||
|
||||
|
||||
|
||||
# There are several string functions found in Linux
|
||||
# but not on Windows. Need to provide our own copy.
|
||||
|
||||
misc.a : strsep.o strtok_r.o strcasestr.o strlcpy.o strlcat.o
|
||||
ar -cr $@ $^
|
||||
|
||||
strsep.o : misc/strsep.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
strtok_r.o : misc/strtok_r.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
strcasestr.o : misc/strcasestr.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
strlcpy.o : misc/strlcpy.c
|
||||
$(CC) $(CFLAGS) -I. -c -o $@ $^
|
||||
|
||||
strlcat.o : misc/strlcat.c
|
||||
$(CC) $(CFLAGS) -I. -c -o $@ $^
|
||||
|
||||
|
||||
# --------------------------------- Automated Smoke Test --------------------------------
|
||||
|
||||
|
||||
# Combine some unit tests into a single regression sanity check.
|
||||
|
||||
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest pad2test xidtest dtmftest check-modem1200 check-modem300 check-modem9600 check-modem19200 check-modem2400 check-modem4800
|
||||
|
||||
# Can we encode and decode at popular data rates?
|
||||
# Verify that single bit fixup increases the count.
|
||||
|
||||
check-modem1200 : gen_packets atest
|
||||
gen_packets -n 100 -o test12.wav
|
||||
atest -F0 -PE -L64 -G72 test12.wav
|
||||
atest -F1 -PE -L70 -G75 test12.wav
|
||||
rm test12.wav
|
||||
|
||||
check-modem300 : gen_packets atest
|
||||
gen_packets -B300 -n 100 -o test3.wav
|
||||
atest -B300 -F0 -L68 -G69 test3.wav
|
||||
atest -B300 -F1 -L71 -G75 test3.wav
|
||||
rm test3.wav
|
||||
|
||||
#FIXME: test full amplitude.
|
||||
|
||||
check-modem9600 : gen_packets atest
|
||||
gen_packets -B9600 -a 170 -o test96.wav
|
||||
sleep 1
|
||||
atest -B9600 -F0 -L4 -G4 test96.wav
|
||||
sleep 1
|
||||
rm test96.wav
|
||||
sleep 1
|
||||
gen_packets -B9600 -n 100 -o test96.wav
|
||||
sleep 1
|
||||
atest -B9600 -F0 -L50 -G54 test96.wav
|
||||
atest -B9600 -F1 -L55 -G59 test96.wav
|
||||
sleep 1
|
||||
rm test96.wav
|
||||
|
||||
check-modem19200 : gen_packets atest
|
||||
gen_packets -r 96000 -B19200 -a 170 -o test19.wav
|
||||
sleep 1
|
||||
atest -B19200 -F0 -L4 test19.wav
|
||||
sleep 1
|
||||
rm test19.wav
|
||||
sleep 1
|
||||
gen_packets -r 96000 -B19200 -n 100 -o test19.wav
|
||||
sleep 1
|
||||
atest -B19200 -F0 -L55 -G59 test19.wav
|
||||
atest -B19200 -F1 -L60 -G64 test19.wav
|
||||
sleep 1
|
||||
rm test19.wav
|
||||
|
||||
check-modem2400 : gen_packets atest
|
||||
gen_packets -B2400 -n 100 -o test24.wav
|
||||
sleep 1
|
||||
atest -B2400 -F0 -L70 -G78 test24.wav
|
||||
atest -B2400 -F1 -L80 -G87 test24.wav
|
||||
sleep 1
|
||||
rm test24.wav
|
||||
|
||||
check-modem4800 : gen_packets atest
|
||||
gen_packets -B4800 -n 100 -o test48.wav
|
||||
sleep 1
|
||||
atest -B4800 -F0 -L70 -G74 test48.wav
|
||||
atest -B4800 -F1 -L79 -G84 test48.wav
|
||||
sleep 1
|
||||
rm test48.wav
|
||||
|
||||
|
||||
# Unit test for demodulators
|
||||
|
||||
atest : atest.c fsk_fast_filter.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o latlong.c \
|
||||
symbols.c tt_text.c textcolor.c telemetry.c dtime_now.o \
|
||||
decode_aprs.o log.o \
|
||||
misc.a regex.a
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
#./atest ..\\direwolf-0.2\\02_Track_2.wav
|
||||
#atest -B 9600 z9.wav
|
||||
#atest za100.wav
|
||||
|
||||
atest9 : atest.c demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
||||
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c latlong.c symbols.c textcolor.c telemetry.c dtime_now.o misc.a regex.a \
|
||||
fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
./atest9 -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
||||
#./atest9 -B 9600 noise96.wav
|
||||
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
.PHONY: dtest
|
||||
dtest : digipeater.c dedupe.c pfilter.c \
|
||||
ax25_pad.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DDIGITEST -o $@ $^
|
||||
./dtest
|
||||
rm dtest.exe
|
||||
|
||||
# Unit test for APRStt tone seqence parsing.
|
||||
|
||||
.PHONTY: ttest
|
||||
ttest : aprs_tt.c tt_text.c latlong.o textcolor.o geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -Igeotranz -DTT_MAIN -o $@ $^
|
||||
./ttest
|
||||
rm ttest.exe
|
||||
|
||||
# Unit test for APRStt tone sequence / text conversions.
|
||||
|
||||
.PHONY: tttexttest
|
||||
tttexttest : tt_text.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTTT_TEST -o $@ $^
|
||||
./tttexttest
|
||||
rm tttexttest.exe
|
||||
|
||||
# Unit test for Packet Filtering.
|
||||
|
||||
.PHONY: pftest
|
||||
pftest : pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o symbols.o telemetry.o tt_text.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DPFTEST -o $@ $^
|
||||
./pftest
|
||||
rm pftest.exe
|
||||
|
||||
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
.PHONY: tlmtest
|
||||
tlmtest : telemetry.c ax25_pad.o fcs_calc.o textcolor.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./tlmtest
|
||||
rm tlmtest.exe
|
||||
|
||||
|
||||
# Unit test for location coordinate conversion.
|
||||
|
||||
.PHONY: lltest
|
||||
lltest : latlong.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DLLTEST -o $@ $^
|
||||
./lltest
|
||||
rm lltest.exe
|
||||
|
||||
# Unit test for encoding position & object report.
|
||||
|
||||
.PHONY: enctest
|
||||
enctest : encode_aprs.c latlong.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -DEN_MAIN -o $@ $^
|
||||
./enctest
|
||||
rm enctest.exe
|
||||
|
||||
|
||||
# Unit test for KISS encapsulation.
|
||||
|
||||
.PHONY: kisstest
|
||||
kisstest : kiss_frame.c
|
||||
$(CC) $(CFLAGS) -DKISSTEST -o $@ $^
|
||||
./kisstest
|
||||
rm kisstest.exe
|
||||
|
||||
|
||||
# Unit test for constructing frames besides UI.
|
||||
|
||||
.PHONY: pad2test
|
||||
pad2test : ax25_pad2.c ax25_pad.c fcs_calc.o textcolor.o regex.a misc.a
|
||||
$(CC) $(CFLAGS) -DPAD2TEST -o $@ $^
|
||||
./pad2test
|
||||
rm pad2test.exe
|
||||
|
||||
# Unit Test for XID frame encode/decode.
|
||||
|
||||
.PHONY: xidtest
|
||||
xidtest : xid.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DXIDTEST -o $@ $^
|
||||
./xidtest
|
||||
rm xidtest.exe
|
||||
|
||||
# Unit Test for DTMF encode/decode.
|
||||
|
||||
.PHONY: dtmftest
|
||||
dtmftest : dtmf.c textcolor.o
|
||||
$(CC) $(CFLAGS) -DDTMF_TEST -o $@ $^
|
||||
./dtmftest
|
||||
rm dtmftest.exe
|
||||
|
||||
|
||||
# ------------------------------ Other manual testing & experimenting -------------------------------
|
||||
|
||||
|
||||
tnctest : tnctest.c textcolor.o dtime_now.o serial_port.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
# For tweaking the demodulator.
|
||||
|
||||
demod.o : tune.h
|
||||
demod_9600.o : tune.h
|
||||
demod_afsk.o : tune.h
|
||||
demod_psk.o : tune.h
|
||||
|
||||
testagc : atest.c demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.o fsk_demod_agc.h \
|
||||
hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o latlong.o symbols.o textcolor.o telemetry.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o tt_text.o dtime_now.o regex.a misc.a
|
||||
rm -f atest.exe
|
||||
$(CC) $(CFLAGS) -o atest $^
|
||||
./atest -P GGG- -F 0 ../02_Track_2.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
noisy3.wav : gen_packets
|
||||
./gen_packets -B 300 -n 100 -o noisy3.wav
|
||||
|
||||
testagc3 : atest.c demod.c dsp.c demod_afsk.c demod_psk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
||||
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c latlong.c symbols.c textcolor.c telemetry.c dtime_now.o regex.a misc.a \
|
||||
tune.h
|
||||
rm -f atest3.exe
|
||||
$(CC) $(CFLAGS) -o atest3 $^
|
||||
./atest3 -B 300 -P D -D 3 noisy3.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
noisy96.wav : gen_packets
|
||||
./gen_packets -B 9600 -n 100 -o noisy96.wav
|
||||
|
||||
testagc96 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o latlong.o \
|
||||
symbols.o tt_text.o textcolor.o telemetry.o dtime_now.o \
|
||||
misc.a regex.a
|
||||
rm -f atest96.exe
|
||||
$(CC) $(CFLAGS) -o atest96 $^
|
||||
./atest96 -B 9600 ../walkabout9600c.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 noisy96.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 19990303_0225_9600_8bis_22kHz.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 19990303_0225_9600_16bit_22kHz.wav | grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 -P + z8-22k.wav| grep "packets decoded in" >atest.out
|
||||
#./atest96 -B 9600 test9600.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
testagc24 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o latlong.o \
|
||||
symbols.o tt_text.o textcolor.o telemetry.o dtime_now.o \
|
||||
misc.a regex.a
|
||||
rm -f atest24.exe
|
||||
sleep 1
|
||||
$(CC) $(CFLAGS) -o atest24 $^
|
||||
./atest24 -B 2400 test2400.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
testagc48 : atest.c fsk_fast_filter.h tune.h demod.c demod_afsk.c demod_psk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o latlong.o \
|
||||
symbols.o tt_text.o textcolor.o telemetry.o dtime_now.o \
|
||||
misc.a regex.a
|
||||
rm -f atest48.exe
|
||||
sleep 1
|
||||
$(CC) $(CFLAGS) -o atest48 $^
|
||||
./atest48 -B 4800 test4800.wav | grep "packets decoded in" >atest.out
|
||||
#./atest48 -B 4800 test4800.wav
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
# Talk to a KISS TNC.
|
||||
|
||||
# Note: kiss_frame.c has conditional compilation on KISSUTIL.
|
||||
|
||||
kissutil : kissutil.c kiss_frame.c ax25_pad.o fcs_calc.o textcolor.o serial_port.o sock.o dtime_now.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DKISSUTIL -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
# Touch Tone to Speech sample application.
|
||||
|
||||
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
# Send GPS location to KISS TNC each second.
|
||||
|
||||
walk96 : walk96.c dwgps.o dwgpsnmea.o kiss_frame.o \
|
||||
latlong.o encode_aprs.o serial_port.o textcolor.o \
|
||||
ax25_pad.o fcs_calc.o \
|
||||
xmit.o hdlc_send.o gen_tone.o ptt.o tq.o \
|
||||
hdlc_rec.o hdlc_rec2.o rrbb.o dsp.o audio_win.o \
|
||||
multi_modem.o demod.o demod_afsk.o demod_psk.c demod_9600.o rdq.o \
|
||||
server.o morse.o dtmf.o audio_stats.o dtime_now.o dlq.o \
|
||||
regex.a misc.a
|
||||
$(CC) $(CFLAGS) -DWALK96 -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
|
||||
|
||||
.PHONY: depend
|
||||
depend : $(wildcard *.c)
|
||||
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -f *.o *.a *.exe fsk_fast_filter.h noisy96.wav
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
|
||||
# ------------------------------- Packaging for distribution ----------------------
|
||||
|
||||
# Name of zip file for distribution.
|
||||
|
||||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
.PHONY: dist-win
|
||||
dist-win : direwolf.exe decode_aprs.exe text2tt.exe tt2text.exe ll2utm.exe utm2ll.exe \
|
||||
aclients.exe log2gpx.exe gen_packets.exe atest.exe ttcalc.exe kissutil.exe \
|
||||
generic.conf dwespeak.bat \
|
||||
README.md CHANGES.md \
|
||||
doc/User-Guide.pdf \
|
||||
doc/Raspberry-Pi-APRS.pdf \
|
||||
doc/APRStt-Implementation-Notes.pdf
|
||||
rm -f ../$z-win.zip
|
||||
egrep '^C|^W' generic.conf | cut -c2-999 > direwolf.conf
|
||||
unix2dos direwolf.conf
|
||||
cp doc/README.md README-doc.md
|
||||
zip --junk-paths ../$z-win.zip \
|
||||
README.md \
|
||||
CHANGES.md \
|
||||
README-doc.md \
|
||||
doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf \
|
||||
doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf \
|
||||
doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf \
|
||||
doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf \
|
||||
doc/APRS-Telemetry-Toolkit.pdf \
|
||||
doc/APRStt-Implementation-Notes.pdf \
|
||||
doc/APRStt-interface-for-SARTrack.pdf \
|
||||
doc/APRStt-Listening-Example.pdf \
|
||||
doc/Bluetooth-KISS-TNC.pdf \
|
||||
doc/Going-beyond-9600-baud.pdf \
|
||||
doc/Raspberry-Pi-APRS.pdf \
|
||||
doc/Raspberry-Pi-APRS-Tracker.pdf \
|
||||
doc/Raspberry-Pi-SDR-IGate.pdf \
|
||||
doc/Successful-APRS-IGate-Operation.pdf \
|
||||
doc/User-Guide.pdf \
|
||||
doc/WA8LMF-TNC-Test-CD-Results.pdf \
|
||||
LICENSE* \
|
||||
direwolf.conf \
|
||||
direwolf.exe \
|
||||
decode_aprs.exe \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt \
|
||||
text2tt.exe tt2text.exe \
|
||||
ll2utm.exe utm2ll.exe \
|
||||
aclients.exe \
|
||||
log2gpx.exe \
|
||||
gen_packets.exe \
|
||||
atest.exe \
|
||||
ttcalc.exe \
|
||||
kissutil.exe \
|
||||
dwespeak.bat \
|
||||
telemetry-toolkit/*
|
||||
rm README-doc.md
|
||||
|
||||
|
||||
# Reminders if pdf files are not up to date.
|
||||
|
||||
doc/User-Guide.pdf : doc/User-Guide.docx
|
||||
echo "***** User-Guide.pdf is out of date *****"
|
||||
|
||||
doc/Raspberry-Pi-APRS.pdf : doc/Raspberry-Pi-APRS.docx
|
||||
echo "***** Raspberry-Pi-APRS.pdf is out of date *****"
|
||||
|
||||
doc/Raspberry-Pi-APRS-Tracker.pdf : doc/Raspberry-Pi-APRS-Tracker.docx
|
||||
echo "***** Raspberry-Pi-APRS-Tracker.pdf is out of date *****"
|
||||
|
||||
doc/APRStt-Implementation-Notes.pdf : doc/APRStt-Implementation-Notes.docx
|
||||
echo "***** APRStt-Implementation-Notes.pdf is out of date *****"
|
||||
|
||||
doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf : doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.docx
|
||||
echo "***** A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf is out of date *****"
|
||||
|
||||
doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf : doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.docx
|
||||
echo "***** A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf is out of date *****"
|
||||
|
||||
doc/APRS-Telemetry-Toolkit.pdf : doc/APRS-Telemetry-Toolkit.docx
|
||||
echo "***** APRS-Telemetry-Toolkit.pdf is out of date *****"
|
||||
|
||||
|
||||
|
||||
.PHONY: backup
|
||||
backup :
|
||||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
cp -r . /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
|
||||
|
||||
#
|
||||
# The following is updated by "make depend"
|
||||
#
|
||||
# DO NOT DELETE
|
||||
|
||||
|
128
README.md
128
README.md
|
@ -3,21 +3,14 @@
|
|||
|
||||
### Decoded Information from Radio Emissions for Windows Or Linux Fans ###
|
||||
|
||||
In the early days of Amateur Packet Radio, it was necessary to use an expensive "Terminal Node Controller" (TNC) with specialized hardware. Those days are gone. You can now get better results at lower cost by connecting your radio to the "soundcard" interface of a computer and using software to decode the signals.
|
||||
In the early days of Amateur Packet Radio, it was necessary to use an expensive “Terminal Node Controller” (TNC) with specialized hardware. Those days are gone. You can now get better results at lower cost by connecting your radio to the “soundcard” interface of a computer and using software to decode the signals.
|
||||
|
||||
Why waste $200 and settle for mediocre receive performance from a 1980's technology TNC using an old modem chip? Dire Wolf decodes over 1000 error-free frames from Track 2 of the [WA8LMF TNC Test CD](https://github.com/wb2osz/direwolf/tree/dev/doc/WA8LMF-TNC-Test-CD-Results.pdf), leaving all the hardware TNCs, and first generation "soundcard" modems, behind in the dust.
|
||||
Why settle for mediocre receive performance from a 1980's technology TNC using an old modem chip? Dire Wolf decodes over 1000 error-free frames from Track 2 of the [WA8LMF TNC Test CD](https://github.com/wb2osz/direwolf/tree/dev/doc/WA8LMF-TNC-Test-CD-Results.pdf), leaving all the hardware TNCs, and first generation "soundcard" modems, behind in the dust.
|
||||
|
||||

|
||||
|
||||
Dire Wolf includes [FX.25](https://en.wikipedia.org/wiki/FX.25_Forward_Error_Correction) which adds Forward Error Correction (FEC) in a way that is completely compatible with existing systems. If both ends are capable of FX.25, your information will continue to get through under conditions where regular AX.25 is completely useless. This was originally developed for satellites and is now seeing widespread use on HF.
|
||||
|
||||

|
||||
|
||||
Version 1.7 adds [IL2P](https://en.wikipedia.org/wiki/Improved_Layer_2_Protocol), a different method of FEC with less overhead but it is not compatible with AX.25.
|
||||
|
||||
|
||||
|
||||
### Dire Wolf is a modern software replacement for the old 1980's style TNC built with special hardware. ###
|
||||
|
||||
Dire Wolf is a modern software replacement for the old 1980's style TNC built with special hardware.
|
||||
|
||||
Without any additional software, it can perform as:
|
||||
|
||||
|
@ -27,7 +20,7 @@ Without any additional software, it can perform as:
|
|||
- [APRStt](http://www.aprs.org/aprstt.html) gateway
|
||||
|
||||
|
||||
It can also be used as a virtual TNC for other applications such as [APRSIS32](http://aprsisce.wikidot.com/), [Xastir](http://xastir.org/index.php/Main_Page), [APRS-TW](http://aprstw.blandranch.net/), [YAAC](http://www.ka2ddo.org/ka2ddo/YAAC.html), [PinPoint APRS](http://www.pinpointaprs.com/), [UI-View32](http://www.ui-view.net/),[UISS](http://users.belgacom.net/hamradio/uiss.htm), [Linux AX25](http://www.linux-ax25.org/wiki/Main_Page), [SARTrack](http://www.sartrack.co.nz/index.html), [Winlink Express (formerly known as RMS Express, formerly known as Winlink 2000 or WL2K)](http://www.winlink.org/RMSExpress), [BPQ32](http://www.cantab.net/users/john.wiseman/Documents/BPQ32.html), [Outpost PM](http://www.outpostpm.org/), [Ham Radio of Things](https://github.com/wb2osz/hrot), [Packet Compressed Sensing Imaging (PCSI)](https://maqifrnswa.github.io/PCSI/), and many others.
|
||||
It can also be used as a virtual TNC for other applications such as [APRSIS32](http://aprsisce.wikidot.com/), [UI-View32](http://www.ui-view.net/), [Xastir](http://xastir.org/index.php/Main_Page), [APRS-TW](http://aprstw.blandranch.net/), [YAAC](http://www.ka2ddo.org/ka2ddo/YAAC.html), [UISS](http://users.belgacom.net/hamradio/uiss.htm), [Linux AX25](http://www.linux-ax25.org/wiki/Main_Page), [SARTrack](http://www.sartrack.co.nz/index.html), [RMS Express](http://www.winlink.org/RMSExpress), [BPQ32](http://www.cantab.net/users/john.wiseman/Documents/BPQ32.html), [Outpost PM](http://www.outpostpm.org/), and many others.
|
||||
|
||||
|
||||
## Features & Benefits ##
|
||||
|
@ -43,7 +36,6 @@ It can also be used as a virtual TNC for other applications such as [APRSIS32](h
|
|||
Send periodic beacons to provide information to others. For tracking the location is provided by a GPS receiver.
|
||||
Build your own telemetry applications with the toolkit.
|
||||
|
||||
|
||||
- **APRStt Gateway.**
|
||||
|
||||
Very few hams have portable equipment for APRS but nearly everyone has a handheld radio that can send DTMF tones. APRStt allows a user, equipped with only DTMF (commonly known as Touch Tone) generation capability, to enter information into the global APRS data network. Responses can be sent by Morse Code or synthesized speech.
|
||||
|
@ -56,11 +48,6 @@ It can also be used as a virtual TNC for other applications such as [APRSIS32](h
|
|||
|
||||
IGate stations allow communication between disjoint radio networks by allowing some content to flow between them over the Internet.
|
||||
|
||||
- **Ham Radio of Things (HRoT).**
|
||||
|
||||
There have been occasional mentions of merging Ham Radio with the Internet of Things but only ad hoc incompatible narrowly focused applications. Here is a proposal for a standardized more flexible method so different systems can communicate with each other.
|
||||
|
||||
[Ham Radio of Things - IoT over Ham Radio](https://github.com/wb2osz/hrot)
|
||||
|
||||
- **AX.25 v2.2 Link Layer.**
|
||||
|
||||
|
@ -68,37 +55,23 @@ It can also be used as a virtual TNC for other applications such as [APRSIS32](h
|
|||
|
||||
- **KISS Interface (TCP/IP, serial port, Bluetooth) & AGW network Interface (TCP/IP).**
|
||||
|
||||
Dire Wolf can be used as a virtual TNC for applications such as [APRSIS32](http://aprsisce.wikidot.com/), [Xastir](http://xastir.org/index.php/Main_Page), [APRS-TW](http://aprstw.blandranch.net/), [YAAC](http://www.ka2ddo.org/ka2ddo/YAAC.html), [PinPoint APRS](http://www.pinpointaprs.com/), [UI-View32](http://www.ui-view.net/),[UISS](http://users.belgacom.net/hamradio/uiss.htm), [Linux AX25](http://www.linux-ax25.org/wiki/Main_Page), [SARTrack](http://www.sartrack.co.nz/index.html), [Winlink Express (formerly known as RMS Express, formerly known as Winlink 2000 or WL2K)](http://www.winlink.org/RMSExpress), [BPQ32](http://www.cantab.net/users/john.wiseman/Documents/BPQ32.html), [Outpost PM](http://www.outpostpm.org/), [Ham Radio of Things](https://github.com/wb2osz/hrot), [Packet Compressed Sensing Imaging (PCSI)](https://maqifrnswa.github.io/PCSI/), and many others.
|
||||
Dire Wolf can be used as a virtual TNC for applications such as APRSIS32, UI-View32, Xastir, APRS-TW,YAAC, UISS, Linux AX25, SARTrack, Winlink / RMS Express, Outpost PM, and many others.
|
||||
|
||||
### Radio Interfaces: ###
|
||||
|
||||
- **Uses computer's "soundcard" and digital signal processing.**
|
||||
- **Uses computer’s “soundcard” and digital signal processing.**
|
||||
|
||||
Lower cost and better performance than specialized hardware.
|
||||
|
||||
Compatible interfaces include [DRAWS](http://nwdigitalradio.com/draws/), [UDRC](https://nw-digital-radio.groups.io/g/udrc/wiki/UDRC%E2%84%A2-and-Direwolf-Packet-Modem), [SignaLink USB](http://www.tigertronics.com/slusbmain.htm), [DMK URI](http://www.dmkeng.com/URI_Order_Page.htm), [RB-USB RIM](http://www.repeater-builder.com/products/usb-rim-lite.html), [RA-35](http://www.masterscommunications.com/products/radio-adapter/ra35.html), [DINAH](https://hamprojects.info/dinah/), [SHARI](https://hamprojects.info/shari/), and many others.
|
||||
Compatible interfaces include [UDRC](https://nw-digital-radio.groups.io/g/udrc/wiki/UDRC%E2%84%A2-and-Direwolf-Packet-Modem), [SignaLink USB](http://www.tigertronics.com/slusbmain.htm), [DMK URI](http://www.dmkeng.com/URI_Order_Page.htm), [RB-USB RIM](http://www.repeater-builder.com/products/usb-rim-lite.html), [RA-35](http://www.masterscommunications.com/products/radio-adapter/ra35.html), and many others.
|
||||
|
||||
|
||||
|
||||
- **Modems:**
|
||||
- **Standard 300, 1200 & 9600 bps modems and more.**
|
||||
|
||||
300 bps AFSK for HF
|
||||
|
||||
1200 bps AFSK most common for VHF/UHF
|
||||
|
||||
2400 & 4800 bps PSK
|
||||
|
||||
9600 bps GMSK/G3RUH
|
||||
|
||||
AIS reception
|
||||
|
||||
EAS SAME reception
|
||||
|
||||
|
||||
|
||||
- **DTMF ("Touch Tone") Decoding and Encoding.**
|
||||
- **DTMF (“Touch Tone”) Decoding and Encoding.**
|
||||
|
||||
- **Speech Synthesizer interface & Morse code generator.**
|
||||
- **Speech Synthesizer & Morse code generator.**
|
||||
|
||||
Transmit human understandable messages.
|
||||
|
||||
|
@ -114,16 +87,10 @@ It can also be used as a virtual TNC for other applications such as [APRSIS32](h
|
|||
|
||||
## Documentation ##
|
||||
|
||||
|
||||
[Stable Version](https://github.com/wb2osz/direwolf/tree/master/doc)
|
||||
|
||||
[Latest Development Version ("dev" branch)](https://github.com/wb2osz/direwolf/tree/dev/doc)
|
||||
[Latest Development Version](https://github.com/wb2osz/direwolf/tree/dev/doc)
|
||||
|
||||
[Additional Topics](https://github.com/wb2osz/direwolf-doc)
|
||||
|
||||
[Power Point presentations](https://github.com/wb2osz/direwolf-presentation) -- Why not give a talk at a local club meeting?
|
||||
|
||||
Youtube has many interesting and helpful videos. Searching for [direwolf tnc](https://www.youtube.com/results?search_query=direwolf+tnc) or [direwolf aprs](https://www.youtube.com/results?search_query=direwolf+aprs) will produce the most relevant results.
|
||||
|
||||
## Installation ##
|
||||
|
||||
|
@ -131,99 +98,58 @@ Youtube has many interesting and helpful videos. Searching for [direwolf tnc](h
|
|||
|
||||
Go to the [**releases** page](https://github.com/wb2osz/direwolf/releases). Download a zip file with "win" in its name, unzip it, and run direwolf.exe from a command window.
|
||||
|
||||
You can also build it yourself from source. For more details see the **User Guide** in the [**doc** directory](https://github.com/wb2osz/direwolf/tree/master/doc).
|
||||
For more details see the **User Guide** in the [**doc** directory](https://github.com/wb2osz/direwolf/tree/master/doc).
|
||||
|
||||
|
||||
|
||||
|
||||
### Linux - Using git clone (recommended) ###
|
||||
|
||||
***Note that this has changed for version 1.6. There are now a couple extra steps.***
|
||||
|
||||
|
||||
First you will need to install some software development packages using different commands depending on your flavor of Linux.
|
||||
In most cases, the first few will already be there and the package installer will tell you that installation is not necessary.
|
||||
|
||||
On Debian / Ubuntu / Raspbian / Raspberry Pi OS:
|
||||
|
||||
sudo apt-get install git
|
||||
sudo apt-get install gcc
|
||||
sudo apt-get install g++
|
||||
sudo apt-get install make
|
||||
sudo apt-get install cmake
|
||||
sudo apt-get install libasound2-dev
|
||||
sudo apt-get install libudev-dev
|
||||
sudo apt-get install libavahi-client-dev
|
||||
|
||||
Or on Red Hat / Fedora / CentOS:
|
||||
|
||||
sudo yum install git
|
||||
sudo yum install gcc
|
||||
sudo yum install gcc-c++
|
||||
sudo yum install make
|
||||
sudo yum install alsa-lib-devel
|
||||
sudo yum install libudev-devel
|
||||
sudo yum install avahi-devel
|
||||
|
||||
CentOS 6 & 7 currently have cmake 2.8 but we need 3.1 or later.
|
||||
First you need to enable the EPEL repository. Add a symlink if you don't already have the older version and want to type cmake rather than cmake3.
|
||||
|
||||
sudo yum install epel-release
|
||||
sudo rpm -e cmake
|
||||
sudo yum install cmake3
|
||||
sudo ln -s /usr/bin/cmake3 /usr/bin/cmake
|
||||
|
||||
Then on any flavor of Linux:
|
||||
|
||||
cd ~
|
||||
git clone https://www.github.com/wb2osz/direwolf
|
||||
cd direwolf
|
||||
git checkout dev
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make -j4
|
||||
make
|
||||
sudo make install
|
||||
make install-conf
|
||||
|
||||
This gives you the latest development version. Leave out the "git checkout dev" to get the most recent stable release.
|
||||
This should give you the most recent stable release. If you want the latest (possibly unstable) development version, use "git checkout dev" before the first "make" command.
|
||||
|
||||
For more details see the **User Guide** in the [**doc** directory](https://github.com/wb2osz/direwolf/tree/master/doc). Special considerations for the Raspberry Pi are found in **Raspberry-Pi-APRS.pdf**
|
||||
|
||||
|
||||
### Linux - Using apt-get (Debian flavor operating systems) ###
|
||||
|
||||
Results will vary depending on your hardware platform and operating system version because it depends on various volunteers who perform the packaging. Expect the version to lag significantly behind development.
|
||||
Results will vary depending on your hardware platform and operating system version because it depends on various volunteers who perform the packaging.
|
||||
|
||||
sudo apt-get update
|
||||
apt-cache showpkg direwolf
|
||||
apt-cache showpkg direwolf
|
||||
sudo apt-get install direwolf
|
||||
|
||||
|
||||
### Linux - Using yum (Red Hat flavor operating systems) ###
|
||||
|
||||
Results will vary depending on your hardware platform and operating system version because it depends on various volunteers who perform the packaging. Expect the version to lag significantly behind development.
|
||||
Results will vary depending on your hardware platform and operating system version because it depends on various volunteers who perform the packaging.
|
||||
|
||||
sudo yum check-update
|
||||
sudo yum list direwolf
|
||||
sudo yum list direwolf
|
||||
sudo yum install direwolf
|
||||
|
||||
### Linux - Download source in tar or zip file ###
|
||||
|
||||
### Macintosh OS X ###
|
||||
Go to the [releases page](https://github.com/wb2osz/direwolf/releases). Chose desired release and download the source as zip or compressed tar file. Unpack the files, with "unzip" or "tar xfz," and then:
|
||||
|
||||
Read the **User Guide** in the [**doc** directory](https://github.com/wb2osz/direwolf/tree/master/doc). It is more complicated than Linux.
|
||||
|
||||
If you have problems, post them to the [Dire Wolf packet TNC](https://groups.io/g/direwolf) discussion group.
|
||||
|
||||
You can also install a pre-built version from Mac Ports. Keeping this up to date depends on volunteers who perform the packaging. This version could lag behind development.
|
||||
|
||||
sudo port install direwolf
|
||||
cd direwolf-*
|
||||
make
|
||||
sudo make install
|
||||
make install-conf
|
||||
|
||||
For more details see the **User Guide** in the [**doc** directory](https://github.com/wb2osz/direwolf/tree/master/doc). Special considerations for the Raspberry Pi are found in **Raspberry-Pi-APRS.pdf**
|
||||
|
||||
## Join the conversation ##
|
||||
|
||||
Here are some good places to ask questions and share your experience:
|
||||
|
||||
- [Dire Wolf Software TNC](https://groups.io/g/direwolf)
|
||||
- [Dire Wolf packet TNC](https://groups.yahoo.com/neo/groups/direwolf_packet/info)
|
||||
|
||||
- [Raspberry Pi 4 Ham Radio](https://groups.io/g/RaspberryPi-4-HamRadio)
|
||||
|
||||
|
|
|
@ -69,14 +69,13 @@
|
|||
#include <netinet/tcp.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/errno.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
@ -284,10 +283,10 @@ int main (int argc, char *argv[])
|
|||
|
||||
#if __WIN32__
|
||||
if (isdigit(port[j][0])) {
|
||||
client_th[j] = (HANDLE)_beginthreadex (NULL, 0, client_thread_net, (void *)(ptrdiff_t)j, 0, NULL);
|
||||
client_th[j] = (HANDLE)_beginthreadex (NULL, 0, client_thread_net, (void *)j, 0, NULL);
|
||||
}
|
||||
else {
|
||||
client_th[j] = (HANDLE)_beginthreadex (NULL, 0, client_thread_serial, (void *)(ptrdiff_t)j, 0, NULL);
|
||||
client_th[j] = (HANDLE)_beginthreadex (NULL, 0, client_thread_serial, (void *)j, 0, NULL);
|
||||
}
|
||||
if (client_th[j] == NULL) {
|
||||
printf ("Internal error: Could not create client thread %d.\n", j);
|
||||
|
@ -295,10 +294,10 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
#else
|
||||
if (isdigit(port[j][0])) {
|
||||
e = pthread_create (&client_tid[j], NULL, client_thread_net, (void *)(ptrdiff_t)j);
|
||||
e = pthread_create (&client_tid[j], NULL, client_thread_net, (void *)(long)j);
|
||||
}
|
||||
else {
|
||||
e = pthread_create (&client_tid[j], NULL, client_thread_serial, (void *)(ptrdiff_t)j);
|
||||
e = pthread_create (&client_tid[j], NULL, client_thread_serial, (void *)(long)j);
|
||||
}
|
||||
if (e != 0) {
|
||||
perror("Internal error: Could not create client thread.");
|
||||
|
@ -395,7 +394,7 @@ static void * client_thread_net (void *arg)
|
|||
int use_chan = -1;
|
||||
|
||||
|
||||
my_index = (int)(ptrdiff_t)arg;
|
||||
my_index = (int)(long)arg;
|
||||
|
||||
#if DEBUGx
|
||||
printf ("DEBUG: client_thread_net %d start, port = '%s'\n", my_index, port[my_index]);
|
||||
|
@ -665,7 +664,7 @@ static unsigned __stdcall client_thread_serial (void *arg)
|
|||
static void * client_thread_serial (void *arg)
|
||||
#endif
|
||||
{
|
||||
int my_index = (int)(ptrdiff_t)arg;
|
||||
int my_index = (int)(long)arg;
|
||||
|
||||
#if __WIN32__
|
||||
|
|
@ -115,8 +115,6 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
static void check_result (void);
|
||||
#endif
|
||||
|
||||
static int tt_debug = 0;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
|
@ -124,8 +122,7 @@ static int tt_debug = 0;
|
|||
*
|
||||
* Purpose: Initialize the APRStt gateway at system startup time.
|
||||
*
|
||||
* Inputs: P - Pointer to configuration options gathered by config.c.
|
||||
* debug - Debug printing control.
|
||||
* Inputs: Configuration options gathered by config.c.
|
||||
*
|
||||
* Global out: Make our own local copy of the structure here.
|
||||
*
|
||||
|
@ -167,10 +164,9 @@ static struct ttloc_s test_config[] = {
|
|||
#endif
|
||||
|
||||
|
||||
void aprs_tt_init (struct tt_config_s *p, int debug)
|
||||
void aprs_tt_init (struct tt_config_s *p)
|
||||
{
|
||||
int c;
|
||||
tt_debug = debug;
|
||||
|
||||
#if TT_MAIN
|
||||
/* For unit testing. */
|
||||
|
@ -212,7 +208,7 @@ void aprs_tt_init (struct tt_config_s *p, int debug)
|
|||
* The complete message is then processed.
|
||||
* The touch tone decoder sends $ if no activity
|
||||
* for some amount of time, perhaps 5 seconds.
|
||||
* A partially accumulated message is discarded if
|
||||
* A partially accumulated messge is discarded if
|
||||
* there is a long gap.
|
||||
*
|
||||
* '.' means no activity during processing period.
|
||||
|
@ -426,7 +422,7 @@ void aprs_tt_sequence (int chan, char *msg)
|
|||
* Anything from script, above, will override other predefined responses.
|
||||
*/
|
||||
|
||||
char audible_response[sizeof(script_response) + 16];
|
||||
char audible_response[1000];
|
||||
|
||||
snprintf (audible_response, sizeof(audible_response),
|
||||
"APRSTT>%s:%s",
|
||||
|
@ -487,19 +483,7 @@ static int parse_fields (char *msg)
|
|||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("parse_fields (%s).\n", msg);
|
||||
|
||||
// Make a copy of msg because strtok corrupts the original.
|
||||
// While we are at it, remove any blanks.
|
||||
// This should not happen with DTMF reception but could happen
|
||||
// in manually crafted strings for testing.
|
||||
|
||||
int n = 0;
|
||||
for (char *m = msg; *m != '\0' && n < sizeof(stemp)-1; m++) {
|
||||
if (*m != ' ') {
|
||||
stemp[n++] = *m;
|
||||
}
|
||||
}
|
||||
stemp[n] = '\0';
|
||||
|
||||
strlcpy (stemp, msg, sizeof(stemp));
|
||||
e = strtok_r (stemp, "*#", &save);
|
||||
while (e != NULL) {
|
||||
|
||||
|
@ -567,7 +551,7 @@ static int parse_fields (char *msg)
|
|||
default:
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Field does not start with A, B, C, or digit: \"%s\"\n", e);
|
||||
dw_printf ("Field does not start with A, B, C, or digit: \"%s\"\n", msg);
|
||||
return (TT_ERROR_D_MSG);
|
||||
|
||||
}
|
||||
|
@ -590,7 +574,7 @@ static int parse_fields (char *msg)
|
|||
* Purpose: Expand compact form "macro" to full format then process.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should contain only digits.
|
||||
*
|
||||
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
||||
|
@ -705,16 +689,18 @@ static int expand_macro (char *e)
|
|||
* Purpose: Extract traditional format callsign or object name from touch tone sequence.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* In this case, it should start with "A" then a digit.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "A".
|
||||
*
|
||||
* Outputs: m_callsign
|
||||
*
|
||||
* m_symtab_or_overlay - Set to 0-9 or A-Z if specified.
|
||||
*
|
||||
* m_symbol_code - Always set to 'A' (Box, DTMF or RFID)
|
||||
* If you want a different symbol, use the new
|
||||
* object name format and separate symbol specification.
|
||||
* m_symbol_code - Always set to 'A'.
|
||||
* NO! This should be applied only if we
|
||||
* have the default value at this point.
|
||||
* The symbol might have been explicitly
|
||||
* set already and we don't want to overwrite that.
|
||||
*
|
||||
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
||||
*
|
||||
|
@ -766,11 +752,6 @@ static int parse_callsign (char *e)
|
|||
int len;
|
||||
char tttemp[40], stemp[30];
|
||||
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("APRStt parse callsign (starts with A then digit): \"%s\"\n", e);
|
||||
}
|
||||
|
||||
assert (*e == 'A');
|
||||
|
||||
len = strlen(e);
|
||||
|
@ -781,10 +762,6 @@ static int parse_callsign (char *e)
|
|||
|
||||
if (len == 4 && isdigit(e[1]) && isdigit(e[2]) && isdigit(e[3])) {
|
||||
strlcpy (m_callsign, e+1, sizeof(m_callsign));
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Special case, 3 digit tactical call: \"%s\"\n", m_callsign);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -802,7 +779,7 @@ static int parse_callsign (char *e)
|
|||
return (cs_err);
|
||||
}
|
||||
|
||||
memcpy (m_callsign, e+1, 3);
|
||||
strncpy (m_callsign, e+1, 3);
|
||||
m_callsign[3] = '\0';
|
||||
|
||||
if (len == 7) {
|
||||
|
@ -812,20 +789,10 @@ static int parse_callsign (char *e)
|
|||
tt_two_key_to_text (tttemp, 0, stemp);
|
||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||
m_symtab_or_overlay = stemp[0];
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Three digit abbreviation1: callsign \"%s\", symbol code '%c (Box DTMF)', overlay '%c', checksum %c\n",
|
||||
m_callsign, m_symbol_code, m_symtab_or_overlay, e[len-1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||
m_symtab_or_overlay = e[len-2];
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Three digit abbreviation2: callsign \"%s\", symbol code '%c' (Box DTMF), overlay '%c', checksum %c\n",
|
||||
m_callsign, m_symbol_code, m_symtab_or_overlay, e[len-1]);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -843,7 +810,7 @@ static int parse_callsign (char *e)
|
|||
}
|
||||
|
||||
if (isupper(e[len-2])) {
|
||||
memcpy (tttemp, e+1, len-4);
|
||||
strncpy (tttemp, e+1, len-4);
|
||||
tttemp[len-4] = '\0';
|
||||
tt_two_key_to_text (tttemp, 0, m_callsign);
|
||||
|
||||
|
@ -853,24 +820,14 @@ static int parse_callsign (char *e)
|
|||
tt_two_key_to_text (tttemp, 0, stemp);
|
||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||
m_symtab_or_overlay = stemp[0];
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Callsign in two key format1: callsign \"%s\", symbol code '%c' (Box DTMF), overlay '%c', checksum %c\n",
|
||||
m_callsign, m_symbol_code, m_symtab_or_overlay, e[len-1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy (tttemp, e+1, len-3);
|
||||
strncpy (tttemp, e+1, len-3);
|
||||
tttemp[len-3] = '\0';
|
||||
tt_two_key_to_text (tttemp, 0, m_callsign);
|
||||
|
||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||
m_symtab_or_overlay = e[len-2];
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Callsign in two key format2: callsign \"%s\", symbol code '%c' (Box DTMF), overlay '%c', checksum %c\n",
|
||||
m_callsign, m_symbol_code, m_symtab_or_overlay, e[len-1]);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
@ -888,7 +845,7 @@ static int parse_callsign (char *e)
|
|||
* Purpose: Extract object name from touch tone sequence.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "AA".
|
||||
*
|
||||
* Outputs: m_callsign
|
||||
|
@ -907,11 +864,9 @@ static int parse_callsign (char *e)
|
|||
static int parse_object_name (char *e)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("APRStt parse object name (starts with AA): \"%s\"\n", e);
|
||||
}
|
||||
//int c_length;
|
||||
//char tttemp[40];
|
||||
//char stemp[30];
|
||||
|
||||
assert (e[0] == 'A');
|
||||
assert (e[1] == 'A');
|
||||
|
@ -927,10 +882,6 @@ static int parse_object_name (char *e)
|
|||
if (tt_two_key_to_text (e+2, 0, m_callsign) == 0) {
|
||||
m_callsign[9] = '\0'; /* truncate to 9 */
|
||||
m_ssid = 0; /* No ssid for object name */
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Object name in two key format: \"%s\"\n", m_callsign);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
@ -950,7 +901,7 @@ static int parse_object_name (char *e)
|
|||
* Purpose: Extract symbol from touch tone sequence.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "AB".
|
||||
*
|
||||
* Outputs: m_symtab_or_overlay
|
||||
|
@ -984,11 +935,6 @@ static int parse_symbol (char *e)
|
|||
int nn;
|
||||
char stemp[10];
|
||||
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("APRStt parse symbol (starts with AB): \"%s\"\n", e);
|
||||
}
|
||||
|
||||
assert (e[0] == 'A');
|
||||
assert (e[1] == 'B');
|
||||
|
||||
|
@ -1013,22 +959,12 @@ static int parse_symbol (char *e)
|
|||
case '1':
|
||||
m_symtab_or_overlay = '/';
|
||||
m_symbol_code = 32 + nn;
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("symbol code '%c', primary symbol table '%c'\n",
|
||||
m_symbol_code, m_symtab_or_overlay);
|
||||
}
|
||||
return (0);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
m_symtab_or_overlay = '\\';
|
||||
m_symbol_code = 32 + nn;
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("symbol code '%c', alternate symbol table '%c'\n",
|
||||
m_symbol_code, m_symtab_or_overlay);
|
||||
}
|
||||
return (0);
|
||||
break;
|
||||
|
||||
|
@ -1037,11 +973,6 @@ static int parse_symbol (char *e)
|
|||
if (tt_two_key_to_text (e+5, 0, stemp) == 0) {
|
||||
m_symbol_code = 32 + nn;
|
||||
m_symtab_or_overlay = stemp[0];
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("symbol code '%c', alternate symbol table with overlay '%c'\n",
|
||||
m_symbol_code, m_symtab_or_overlay);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
@ -1064,7 +995,7 @@ static int parse_symbol (char *e)
|
|||
* Purpose: Extract QIKcom-2 / APRStt 3 ten digit call or five digit suffix.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "AC".
|
||||
*
|
||||
* Outputs: m_callsign
|
||||
|
@ -1087,11 +1018,6 @@ static int parse_aprstt3_call (char *e)
|
|||
assert (e[0] == 'A');
|
||||
assert (e[1] == 'C');
|
||||
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("APRStt parse QIKcom-2 / APRStt 3 ten digit call or five digit suffix (starts with AC): \"%s\"\n", e);
|
||||
}
|
||||
|
||||
if (strlen(e) == 2+10) {
|
||||
char call[12];
|
||||
|
||||
|
@ -1147,7 +1073,7 @@ static int parse_aprstt3_call (char *e)
|
|||
* Purpose: Extract location from touch tone sequence.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "B".
|
||||
*
|
||||
* Outputs: m_latitude
|
||||
|
@ -1199,11 +1125,6 @@ static int parse_location (char *e)
|
|||
char mh[20];
|
||||
char stemp[32];
|
||||
|
||||
if (tt_debug) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("APRStt parse location (starts with B): \"%s\"\n", e);
|
||||
// TODO: more detail later...
|
||||
}
|
||||
|
||||
assert (*e == 'B');
|
||||
|
||||
|
@ -1283,26 +1204,13 @@ static int parse_location (char *e)
|
|||
|
||||
lat0 = tt_config.ttloc_ptr[ipat].grid.lat0;
|
||||
lat9 = tt_config.ttloc_ptr[ipat].grid.lat9;
|
||||
double yrange = lat9 - lat0;
|
||||
y = atof(ystr);
|
||||
double user_y_max = round(pow(10., strlen(ystr)) - 1.); // e.g. 999 for 3 digits
|
||||
m_latitude = lat0 + yrange * y / user_y_max;
|
||||
#if 0
|
||||
dw_printf ("TTLOC_GRID LAT min=%f, max=%f, range=%f\n", lat0, lat9, yrange);
|
||||
dw_printf ("TTLOC_GRID LAT user_y=%f, user_y_max=%f\n", y, user_y_max);
|
||||
dw_printf ("TTLOC_GRID LAT min + yrange * user_y / user_y_range = %f\n", m_latitude);
|
||||
#endif
|
||||
m_latitude = lat0 + y * (lat9-lat0) / (pow(10., strlen(ystr)) - 1.);
|
||||
|
||||
lon0 = tt_config.ttloc_ptr[ipat].grid.lon0;
|
||||
lon9 = tt_config.ttloc_ptr[ipat].grid.lon9;
|
||||
double xrange = lon9 - lon0;
|
||||
x = atof(xstr);
|
||||
double user_x_max = round(pow(10., strlen(xstr)) - 1.);
|
||||
m_longitude = lon0 + xrange * x / user_x_max;
|
||||
#if 0
|
||||
dw_printf ("TTLOC_GRID LON min=%f, max=%f, range=%f\n", lon0, lon9, xrange);
|
||||
dw_printf ("TTLOC_GRID LON user_x=%f, user_x_max=%f\n", x, user_x_max);
|
||||
dw_printf ("TTLOC_GRID LON min + xrange * user_x / user_x_range = %f\n", m_longitude);
|
||||
#endif
|
||||
m_longitude = lon0 + x * (lon9-lon0) / (pow(10., strlen(xstr)) - 1.);
|
||||
|
||||
m_dao[2] = e[0];
|
||||
m_dao[3] = e[1];
|
||||
|
@ -1507,7 +1415,7 @@ static int parse_location (char *e)
|
|||
* defined in the configuration file.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "B".
|
||||
*
|
||||
* valstrsize - size of the outputs so we can check for buffer overflow.
|
||||
|
@ -1658,7 +1566,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
* Purpose: Extract comment / status or other special information from touch tone message.
|
||||
*
|
||||
* Inputs: e - An "entry" extracted from a complete
|
||||
* APRStt message.
|
||||
* APRStt messsage.
|
||||
* In this case, it should start with "C".
|
||||
*
|
||||
* Outputs: m_comment
|
||||
|
@ -1800,7 +1708,7 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
|||
alevel.mark = -2;
|
||||
alevel.space = -2;
|
||||
|
||||
dlq_rec_frame (chan, -1, 0, pp, alevel, 0, RETRY_NONE, "tt");
|
||||
dlq_rec_frame (chan, -1, 0, pp, alevel, RETRY_NONE, "tt");
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1985,7 +1893,6 @@ static const struct {
|
|||
/* Latitude comes out ok, 37.9137 -> 55.82 min. */
|
||||
/* Longitude -81.1254 -> 8.20 min */
|
||||
{ "B21234*A67979#", "679", "12", "7A", "", "", "12.3400", "56.1200", "!TB2!" },
|
||||
|
||||
{ "B533686*A67979#", "679", "12", "7A", "", "", "37.9222", "81.1143", "!TB5!" },
|
||||
|
||||
// TODO: should test other coordinate systems.
|
||||
|
@ -2078,7 +1985,7 @@ static void check_result (void)
|
|||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
aprs_tt_init (NULL, 0);
|
||||
aprs_tt_init (NULL);
|
||||
|
||||
error_count = 0;
|
||||
|
|
@ -123,7 +123,7 @@ struct tt_config_s {
|
|||
int obj_recv_chan; /* Channel to listen for tones. */
|
||||
|
||||
int obj_xmit_chan; /* Channel to transmit object report. */
|
||||
/* -1 for none. This could happen if we */
|
||||
/* -1 for none. This could happpen if we */
|
||||
/* are only sending to application */
|
||||
/* and/or IGate. */
|
||||
|
||||
|
@ -165,7 +165,7 @@ struct tt_config_s {
|
|||
|
||||
|
||||
|
||||
void aprs_tt_init (struct tt_config_s *p_config, int debug);
|
||||
void aprs_tt_init (struct tt_config_s *p_config);
|
||||
|
||||
void aprs_tt_button (int chan, char button);
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2019, 2021, 2022, 2023 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 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
|
||||
|
@ -23,12 +23,12 @@
|
|||
*
|
||||
* Name: atest.c
|
||||
*
|
||||
* Purpose: Test fixture for the Dire Wolf demodulators.
|
||||
* Purpose: Test fixture for the AFSK demodulator.
|
||||
*
|
||||
* Inputs: Takes audio from a .WAV file instead of the audio device.
|
||||
* Inputs: Takes audio from a .WAV file insted of the audio device.
|
||||
*
|
||||
* Description: This can be used to test the demodulators under
|
||||
* controlled and reproducible conditions for tweaking.
|
||||
* Description: This can be used to test the AFSK demodulator under
|
||||
* controlled and reproducable conditions for tweaking.
|
||||
*
|
||||
* For example
|
||||
*
|
||||
|
@ -68,7 +68,6 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <getopt.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define ATEST_C 1
|
||||
|
@ -82,9 +81,7 @@
|
|||
#include "dlq.h"
|
||||
#include "ptt.h"
|
||||
#include "dtime_now.h"
|
||||
#include "fx25.h"
|
||||
#include "il2p.h"
|
||||
#include "hdlc_rec.h"
|
||||
|
||||
|
||||
|
||||
#if 0 /* Typical but not flexible enough. */
|
||||
|
@ -108,7 +105,7 @@ struct wav_header { /* .WAV file header. */
|
|||
/* 8 bit samples are unsigned bytes */
|
||||
/* in range of 0 .. 255. */
|
||||
|
||||
/* 16 bit samples are little endian signed short */
|
||||
/* 16 bit samples are signed short */
|
||||
/* in range of -32768 .. +32767. */
|
||||
|
||||
static struct {
|
||||
|
@ -140,13 +137,9 @@ static struct {
|
|||
|
||||
static FILE *fp;
|
||||
static int e_o_f;
|
||||
static int packets_decoded_one = 0;
|
||||
static int packets_decoded_total = 0;
|
||||
static int packets_decoded = 0;
|
||||
static int decimate = 0; /* Reduce that sampling rate if set. */
|
||||
/* 1 = normal, 2 = half, 3 = 1/3, etc. */
|
||||
|
||||
static int upsample = 0; /* Upsample for G3RUH decoder. */
|
||||
/* Non-zero will override the default. */
|
||||
/* 1 = normal, 2 = half, etc. */
|
||||
|
||||
static struct audio_s my_audio_config;
|
||||
|
||||
|
@ -181,21 +174,6 @@ static int sample_number = -1; /* Sample number from the file. */
|
|||
/* Use to print timestamp, relative to beginning */
|
||||
/* of file, when frame was decoded. */
|
||||
|
||||
// command line options.
|
||||
|
||||
static int B_opt = DEFAULT_BAUD; // Bits per second. Need to change all baud references to bps.
|
||||
static int g_opt = 0; // G3RUH modem regardless of speed.
|
||||
static int j_opt = 0; /* 2400 bps PSK compatible with direwolf <= 1.5 */
|
||||
static int J_opt = 0; /* 2400 bps PSK compatible MFJ-2400 and maybe others. */
|
||||
static int h_opt = 0; // Hexadecimal display of received packet.
|
||||
static char P_opt[16] = ""; // Demodulator profiles.
|
||||
static int d_x_opt = 1; // FX.25 debug.
|
||||
static int d_o_opt = 0; // "-d o" option for DCD output control. */
|
||||
static int d_2_opt = 0; // "-d 2" option for IL2P details. */
|
||||
static int dcd_count = 0;
|
||||
static int dcd_missing_errors = 0;
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
@ -204,8 +182,7 @@ int main (int argc, char *argv[])
|
|||
int channel;
|
||||
|
||||
double start_time; // Time when we started so we can measure elapsed time.
|
||||
double one_filetime = 0; // Length of one audio file in seconds.
|
||||
double total_filetime = 0; // Length of all audio files in seconds.
|
||||
double duration; // Length of the audio file in seconds.
|
||||
double elapsed; // Time it took us to process it.
|
||||
|
||||
|
||||
|
@ -230,6 +207,49 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.adev[0].samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
|
||||
my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
|
||||
|
||||
// Results v0.9:
|
||||
//
|
||||
// fix_bits = 0 971 packets, 69 sec
|
||||
// fix_bits = SINGLE 990 64
|
||||
// fix_bits = DOUBLE 992 65
|
||||
// fix_bits = TRIPLE 992 67
|
||||
// fix_bits = TWO_SEP 1004 476
|
||||
|
||||
// Essentially no difference in time for those with order N time.
|
||||
// Time increases greatly for the one with order N^2 time.
|
||||
|
||||
|
||||
// Results: version 1.1, decoder C, my_audio_config.fix_bits = RETRY_MAX - 1
|
||||
//
|
||||
// 971 NONE
|
||||
// +19 SINGLE
|
||||
// +2 DOUBLE
|
||||
// +12 TWO_SEP
|
||||
// +3 REMOVE_MANY
|
||||
// ----
|
||||
// 1007 Total in 1008 sec. More than twice as long as earlier version.
|
||||
|
||||
// Results: version 1.1, decoders ABC, my_audio_config.fix_bits = RETRY_MAX - 1
|
||||
//
|
||||
// 976 NONE
|
||||
// +21 SINGLE
|
||||
// +1 DOUBLE
|
||||
// +22 TWO_SEP
|
||||
// +1 MANY
|
||||
// +3 REMOVE_MANY
|
||||
// ----
|
||||
// 1024 Total in 2042 sec.
|
||||
// About 34 minutes of CPU time for a roughly 40 minute CD.
|
||||
// Many computers wouldn't be able to keep up.
|
||||
|
||||
// The SINGLE and TWO_SEP techniques are the most effective.
|
||||
// Should we reorder the enum values so that TWO_SEP
|
||||
// comes after SINGLE? That way "FIX_BITS 2" would
|
||||
// use the two most productive techniques and not waste
|
||||
// time on the others. People with plenty of CPU power
|
||||
// to spare can still specify larger numbers for the other
|
||||
// techniques with less return on investment.
|
||||
|
||||
|
||||
for (channel=0; channel<MAX_CHANS; channel++) {
|
||||
|
||||
|
@ -239,7 +259,7 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.achan[channel].space_freq = DEFAULT_SPACE_FREQ;
|
||||
my_audio_config.achan[channel].baud = DEFAULT_BAUD;
|
||||
|
||||
strlcpy (my_audio_config.achan[channel].profiles, "A", sizeof(my_audio_config.achan[channel].profiles));
|
||||
strlcpy (my_audio_config.achan[channel].profiles, "E", sizeof(my_audio_config.achan[channel].profiles));
|
||||
|
||||
my_audio_config.achan[channel].num_freq = 1;
|
||||
my_audio_config.achan[channel].offset = 0;
|
||||
|
@ -254,7 +274,6 @@ int main (int argc, char *argv[])
|
|||
//my_audio_config.achan[channel].passall = 1;
|
||||
}
|
||||
|
||||
|
||||
while (1) {
|
||||
//int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
|
@ -267,7 +286,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
/* ':' following option character means arg is required. */
|
||||
|
||||
c = getopt_long(argc, argv, "B:P:D:U:gjJF:L:G:012he:d:",
|
||||
c = getopt_long(argc, argv, "B:P:D:F:L:G:012",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -275,38 +294,63 @@ int main (int argc, char *argv[])
|
|||
switch (c) {
|
||||
|
||||
case 'B': /* -B for data Bit rate */
|
||||
/* Also implies modem type based on speed. */
|
||||
/* Special cases AIS, EAS rather than number. */
|
||||
if (strcasecmp(optarg, "AIS") == 0) {
|
||||
B_opt = 0xA15A15; // See special case below.
|
||||
/* 300 implies 1600/1800 AFSK. */
|
||||
/* 1200 implies 1200/2200 AFSK. */
|
||||
/* 2400 implies V.26 */
|
||||
/* 9600 implies scrambled. */
|
||||
|
||||
my_audio_config.achan[0].baud = atoi(optarg);
|
||||
|
||||
dw_printf ("Data rate set to %d bits / second.\n", my_audio_config.achan[0].baud);
|
||||
|
||||
if (my_audio_config.achan[0].baud < MIN_BAUD || my_audio_config.achan[0].baud > MAX_BAUD) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Use a more reasonable bit rate in range of %d - %d.\n", MIN_BAUD, MAX_BAUD);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* We have similar logic in direwolf.c, config.c, gen_packets.c, and atest.c, */
|
||||
/* that need to be kept in sync. Maybe it could be a common function someday. */
|
||||
|
||||
if (my_audio_config.achan[0].baud < 600) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = 1600;
|
||||
my_audio_config.achan[0].space_freq = 1800;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "D", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
else if (strcasecmp(optarg, "EAS") == 0) {
|
||||
B_opt = 0xEA5EA5; // See special case below.
|
||||
else if (my_audio_config.achan[0].baud < 1800) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = DEFAULT_MARK_FREQ;
|
||||
my_audio_config.achan[0].space_freq = DEFAULT_SPACE_FREQ;
|
||||
// Should default to E+ or something similar later.
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 3600) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_QPSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
dw_printf ("Using V.26 QPSK rather than AFSK.\n");
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 7200) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_8PSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
dw_printf ("Using V.27 8PSK rather than AFSK.\n");
|
||||
}
|
||||
else {
|
||||
B_opt = atoi(optarg);
|
||||
my_audio_config.achan[0].modem_type = MODEM_SCRAMBLE;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
|
||||
dw_printf ("Using scrambled baseband signal rather than AFSK.\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g': /* -G Force G3RUH regardless of speed. */
|
||||
|
||||
g_opt = 1;
|
||||
break;
|
||||
|
||||
case 'j': /* -j V.26 compatible with earlier direwolf. */
|
||||
|
||||
j_opt = 1;
|
||||
break;
|
||||
|
||||
case 'J': /* -J V.26 compatible with MFJ-2400. */
|
||||
|
||||
J_opt = 1;
|
||||
break;
|
||||
|
||||
case 'P': /* -P for modem profile. */
|
||||
|
||||
// Wait until after other options processed.
|
||||
strlcpy (P_opt, optarg, sizeof(P_opt));
|
||||
dw_printf ("Demodulator profile set to \"%s\"\n", optarg);
|
||||
strlcpy (my_audio_config.achan[0].profiles, optarg, sizeof(my_audio_config.achan[0].profiles));
|
||||
break;
|
||||
|
||||
case 'D': /* -D reduce sampling rate for lower CPU usage. */
|
||||
|
@ -323,24 +367,7 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.achan[0].decimate = decimate;
|
||||
break;
|
||||
|
||||
case 'U': /* -U upsample for G3RUH to improve performance */
|
||||
/* when the sample rate to baud ratio is low. */
|
||||
/* Actually it is set automatically and this will */
|
||||
/* override the normal calculation. */
|
||||
|
||||
upsample = atoi(optarg);
|
||||
|
||||
dw_printf ("Multiply audio sample rate by %d\n", upsample);
|
||||
if (upsample < 1 || upsample > 4) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unreasonable value for -U.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
dw_printf ("Multiply audio sample rate by %d\n", upsample);
|
||||
my_audio_config.achan[0].upsample = upsample;
|
||||
break;
|
||||
|
||||
case 'F': /* -F set "fix bits" level. */
|
||||
case 'F': /* -D set "fix bits" level. */
|
||||
|
||||
my_audio_config.achan[0].fix_bits = atoi(optarg);
|
||||
|
||||
|
@ -376,28 +403,6 @@ int main (int argc, char *argv[])
|
|||
decode_only = 2;
|
||||
break;
|
||||
|
||||
case 'h': /* Hexadecimal display. */
|
||||
|
||||
h_opt = 1;
|
||||
break;
|
||||
|
||||
case 'e': /* Receive Bit Error Rate (BER). */
|
||||
|
||||
my_audio_config.recv_ber = atof(optarg);
|
||||
break;
|
||||
|
||||
case 'd': /* Debug message options. */
|
||||
|
||||
for (char *p=optarg; *p!='\0'; p++) {
|
||||
switch (*p) {
|
||||
case 'x': d_x_opt++; break; // FX.25
|
||||
case 'o': d_o_opt++; break; // DCD output control
|
||||
case '2': d_2_opt++; break; // IL2P debug out
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
|
||||
/* Unknown option message was already printed. */
|
||||
|
@ -413,124 +418,6 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set modem type based on data rate.
|
||||
* (Could be overridden by -g, -j, or -J later.)
|
||||
*/
|
||||
/* 300 implies 1600/1800 AFSK. */
|
||||
/* 1200 implies 1200/2200 AFSK. */
|
||||
/* 2400 implies V.26 QPSK. */
|
||||
/* 4800 implies V.27 8PSK. */
|
||||
/* 9600 implies G3RUH baseband scrambled. */
|
||||
|
||||
my_audio_config.achan[0].baud = B_opt;
|
||||
|
||||
|
||||
/* We have similar logic in direwolf.c, config.c, gen_packets.c, and atest.c, */
|
||||
/* that need to be kept in sync. Maybe it could be a common function someday. */
|
||||
|
||||
if (my_audio_config.achan[0].baud == 100) { // What was this for?
|
||||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = 1615;
|
||||
my_audio_config.achan[0].space_freq = 1785;
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 600) { // e.g. HF SSB packet
|
||||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = 1600;
|
||||
my_audio_config.achan[0].space_freq = 1800;
|
||||
// Previously we had a "D" which was fine tuned for 300 bps.
|
||||
// In v1.7, it's not clear if we should use "B" or just stick with "A".
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 1800) { // common 1200
|
||||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = DEFAULT_MARK_FREQ;
|
||||
my_audio_config.achan[0].space_freq = DEFAULT_SPACE_FREQ;
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 3600) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_QPSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud < 7200) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_8PSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud == 0xA15A15) { // Hack for different use of 9600
|
||||
my_audio_config.achan[0].modem_type = MODEM_AIS;
|
||||
my_audio_config.achan[0].baud = 9600;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud == 0xEA5EA5) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_EAS;
|
||||
my_audio_config.achan[0].baud = 521; // Actually 520.83 but we have an integer field here.
|
||||
// Will make more precise in afsk demod init.
|
||||
my_audio_config.achan[0].mark_freq = 2083; // Actually 2083.3 - logic 1.
|
||||
my_audio_config.achan[0].space_freq = 1563; // Actually 1562.5 - logic 0.
|
||||
strlcpy (my_audio_config.achan[0].profiles, "A", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
else {
|
||||
my_audio_config.achan[0].modem_type = MODEM_SCRAMBLE;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
|
||||
}
|
||||
|
||||
if (my_audio_config.achan[0].baud < MIN_BAUD || my_audio_config.achan[0].baud > MAX_BAUD) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Use a more reasonable bit rate in range of %d - %d.\n", MIN_BAUD, MAX_BAUD);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* -g option means force g3RUH regardless of speed.
|
||||
*/
|
||||
|
||||
if (g_opt) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_SCRAMBLE;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
|
||||
}
|
||||
|
||||
/*
|
||||
* We have two different incompatible flavors of V.26.
|
||||
*/
|
||||
if (j_opt) {
|
||||
|
||||
// V.26 compatible with earlier versions of direwolf.
|
||||
// Example: -B 2400 -j or simply -j
|
||||
|
||||
my_audio_config.achan[0].v26_alternative = V26_A;
|
||||
my_audio_config.achan[0].modem_type = MODEM_QPSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
my_audio_config.achan[0].baud = 2400;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
if (J_opt) {
|
||||
|
||||
// V.26 compatible with MFJ and maybe others.
|
||||
// Example: -B 2400 -J or simply -J
|
||||
|
||||
my_audio_config.achan[0].v26_alternative = V26_B;
|
||||
my_audio_config.achan[0].modem_type = MODEM_QPSK;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
my_audio_config.achan[0].baud = 2400;
|
||||
strlcpy (my_audio_config.achan[0].profiles, "", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
|
||||
// Needs to be after -B, -j, -J.
|
||||
if (strlen(P_opt) > 0) {
|
||||
dw_printf ("Demodulator profile set to \"%s\"\n", P_opt);
|
||||
strlcpy (my_audio_config.achan[0].profiles, P_opt, sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
|
||||
memcpy (&my_audio_config.achan[1], &my_audio_config.achan[0], sizeof(my_audio_config.achan[0]));
|
||||
|
||||
|
||||
|
@ -540,13 +427,6 @@ int main (int argc, char *argv[])
|
|||
usage ();
|
||||
}
|
||||
|
||||
fx25_init (d_x_opt);
|
||||
il2p_init (d_2_opt);
|
||||
|
||||
start_time = dtime_now();
|
||||
|
||||
while (optind < argc) {
|
||||
|
||||
fp = fopen(argv[optind], "rb");
|
||||
if (fp == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -555,6 +435,8 @@ int main (int argc, char *argv[])
|
|||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start_time = dtime_now();
|
||||
|
||||
/*
|
||||
* Read the file header.
|
||||
* Doesn't handle all possible cases but good enough for our purposes.
|
||||
|
@ -619,31 +501,25 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.adev[0].bits_per_sample = format.wbitspersample;
|
||||
my_audio_config.adev[0].num_channels = format.nchannels;
|
||||
|
||||
my_audio_config.chan_medium[0] = MEDIUM_RADIO;
|
||||
if (format.nchannels == 2) {
|
||||
my_audio_config.chan_medium[1] = MEDIUM_RADIO;
|
||||
}
|
||||
my_audio_config.achan[0].valid = 1;
|
||||
if (format.nchannels == 2) my_audio_config.achan[1].valid = 1;
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("%d samples per second. %d bits per sample. %d audio channels.\n",
|
||||
my_audio_config.adev[0].samples_per_sec,
|
||||
my_audio_config.adev[0].bits_per_sample,
|
||||
my_audio_config.adev[0].num_channels);
|
||||
one_filetime = (double) wav_data.datasize /
|
||||
duration = (double) wav_data.datasize /
|
||||
((my_audio_config.adev[0].bits_per_sample / 8) * my_audio_config.adev[0].num_channels * my_audio_config.adev[0].samples_per_sec);
|
||||
total_filetime += one_filetime;
|
||||
|
||||
dw_printf ("%d audio bytes in file. Duration = %.1f seconds.\n",
|
||||
(int)(wav_data.datasize),
|
||||
one_filetime);
|
||||
duration);
|
||||
dw_printf ("Fix Bits level = %d\n", my_audio_config.achan[0].fix_bits);
|
||||
|
||||
/*
|
||||
* Initialize the AFSK demodulator and HDLC decoder.
|
||||
* Needs to be done for each file because they could have different sample rates.
|
||||
*/
|
||||
multi_modem_init (&my_audio_config);
|
||||
packets_decoded_one = 0;
|
||||
|
||||
|
||||
e_o_f = 0;
|
||||
|
@ -696,27 +572,17 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
#endif
|
||||
|
||||
dw_printf ("%d from %s\n", packets_decoded_one, argv[optind]);
|
||||
packets_decoded_total += packets_decoded_one;
|
||||
|
||||
fclose (fp);
|
||||
optind++;
|
||||
}
|
||||
|
||||
elapsed = dtime_now() - start_time;
|
||||
|
||||
dw_printf ("%d packets decoded in %.3f seconds. %.1f x realtime\n", packets_decoded_total, elapsed, total_filetime/elapsed);
|
||||
if (d_o_opt) {
|
||||
dw_printf ("DCD count = %d\n", dcd_count);
|
||||
dw_printf ("DCD missing errors = %d\n", dcd_missing_errors);
|
||||
}
|
||||
dw_printf ("%d packets decoded in %.3f seconds. %.1f x realtime\n", packets_decoded, elapsed, duration/elapsed);
|
||||
|
||||
if (error_if_less_than != -1 && packets_decoded_total < error_if_less_than) {
|
||||
if (error_if_less_than != -1 && packets_decoded < error_if_less_than) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n * * * TEST FAILED: number decoded is less than %d * * * \n", error_if_less_than);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (error_if_greater_than != -1 && packets_decoded_total > error_if_greater_than) {
|
||||
if (error_if_greater_than != -1 && packets_decoded > error_if_greater_than) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n * * * TEST FAILED: number decoded is greater than %d * * * \n", error_if_greater_than);
|
||||
exit (EXIT_FAILURE);
|
||||
|
@ -753,22 +619,42 @@ int audio_get (int a)
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* Rather than queuing up frames with bad FCS,
|
||||
* try to fix them immediately.
|
||||
*/
|
||||
|
||||
void rdq_append (rrbb_t rrbb)
|
||||
{
|
||||
int chan, subchan, slice;
|
||||
alevel_t alevel;
|
||||
|
||||
|
||||
chan = rrbb_get_chan(rrbb);
|
||||
subchan = rrbb_get_subchan(rrbb);
|
||||
slice = rrbb_get_slice(rrbb);
|
||||
alevel = rrbb_get_audio_level(rrbb);
|
||||
|
||||
hdlc_rec2_try_to_fix_later (rrbb, chan, subchan, slice, alevel);
|
||||
rrbb_delete (rrbb);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is called when we have a good frame.
|
||||
*/
|
||||
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, fec_type_t fec_type, retry_t retries, char *spectrum)
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum)
|
||||
{
|
||||
|
||||
char stemp[500];
|
||||
unsigned char *pinfo;
|
||||
int info_len;
|
||||
int h;
|
||||
char heard[2 * AX25_MAX_ADDR_LEN + 20];
|
||||
char heard[AX25_MAX_ADDR_LEN];
|
||||
char alevel_text[AX25_ALEVEL_TO_TEXT_SIZE];
|
||||
|
||||
packets_decoded_one++;
|
||||
if ( ! hdlc_rec_data_detect_any(chan)) dcd_missing_errors++;
|
||||
packets_decoded++;
|
||||
|
||||
ax25_format_addrs (pp, stemp);
|
||||
|
||||
|
@ -794,7 +680,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\n");
|
||||
dw_printf("DECODED[%d] ", packets_decoded_one );
|
||||
dw_printf("DECODED[%d] ", packets_decoded );
|
||||
|
||||
/* Insert time stamp relative to start of file. */
|
||||
|
||||
|
@ -802,55 +688,32 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
int min = (int)(sec / 60.);
|
||||
sec -= min * 60;
|
||||
|
||||
dw_printf ("%d:%06.3f ", min, sec);
|
||||
dw_printf ("%d:%07.4f ", min, sec);
|
||||
|
||||
if (h != AX25_SOURCE) {
|
||||
dw_printf ("Digipeater ");
|
||||
}
|
||||
ax25_alevel_to_text (alevel, alevel_text);
|
||||
|
||||
/* As suggested by KJ4ERJ, if we are receiving from */
|
||||
/* WIDEn-0, it is quite likely (but not guaranteed), that */
|
||||
/* we are actually hearing the preceding station in the path. */
|
||||
|
||||
if (h >= AX25_REPEATER_2 &&
|
||||
strncmp(heard, "WIDE", 4) == 0 &&
|
||||
isdigit(heard[4]) &&
|
||||
heard[5] == '\0') {
|
||||
|
||||
char probably_really[AX25_MAX_ADDR_LEN];
|
||||
ax25_get_addr_with_ssid(pp, h-1, probably_really);
|
||||
|
||||
strlcat (heard, " (probably ", sizeof(heard));
|
||||
strlcat (heard, probably_really, sizeof(heard));
|
||||
strlcat (heard, ")", sizeof(heard));
|
||||
if (my_audio_config.achan[chan].fix_bits == RETRY_NONE && my_audio_config.achan[chan].passall == 0) {
|
||||
dw_printf ("%s audio level = %s %s\n", heard, alevel_text, spectrum);
|
||||
}
|
||||
|
||||
switch (fec_type) {
|
||||
|
||||
case fec_type_fx25:
|
||||
dw_printf ("%s audio level = %s FX.25 %s\n", heard, alevel_text, spectrum);
|
||||
break;
|
||||
|
||||
case fec_type_il2p:
|
||||
dw_printf ("%s audio level = %s IL2P %s\n", heard, alevel_text, spectrum);
|
||||
break;
|
||||
|
||||
case fec_type_none:
|
||||
default:
|
||||
if (my_audio_config.achan[chan].fix_bits == RETRY_NONE && my_audio_config.achan[chan].passall == 0) {
|
||||
// No fix_bits or passall specified.
|
||||
dw_printf ("%s audio level = %s %s\n", heard, alevel_text, spectrum);
|
||||
}
|
||||
else {
|
||||
assert (retries >= RETRY_NONE && retries <= RETRY_MAX); // validate array index.
|
||||
dw_printf ("%s audio level = %s [%s] %s\n", heard, alevel_text, retry_text[(int)retries], spectrum);
|
||||
}
|
||||
break;
|
||||
else {
|
||||
dw_printf ("%s audio level = %s [%s] %s\n", heard, alevel_text, retry_text[(int)retries], spectrum);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//#if defined(EXPERIMENT_G) || defined(EXPERIMENT_H)
|
||||
// int j;
|
||||
//
|
||||
// for (j=0; j<MAX_SUBCHANS; j++) {
|
||||
// if (spectrum[j] == '|') {
|
||||
// count[j]++;
|
||||
// }
|
||||
// }
|
||||
//#endif
|
||||
|
||||
|
||||
// Display non-APRS packets in a different color.
|
||||
|
||||
|
@ -880,22 +743,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
||||
dw_printf ("\n");
|
||||
|
||||
/*
|
||||
* -h option for hexadecimal display. (new in 1.6)
|
||||
*/
|
||||
|
||||
if (h_opt) {
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("------\n");
|
||||
ax25_hex_dump (pp);
|
||||
dw_printf ("------\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0 // temp experiment
|
||||
#if 1 // temp experiment TODO: remove this.
|
||||
|
||||
#include "decode_aprs.h"
|
||||
#include "log.h"
|
||||
|
@ -904,7 +752,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
|
||||
decode_aprs_t A;
|
||||
|
||||
decode_aprs (&A, pp, 0, NULL);
|
||||
decode_aprs (&A, pp, 0);
|
||||
|
||||
// Temp experiment to see how different systems set the RR bits in the source and destination.
|
||||
// log_rr_bits (&A, pp);
|
||||
|
@ -920,38 +768,6 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
|
||||
void ptt_set (int ot, int chan, int ptt_signal)
|
||||
{
|
||||
// Should only get here for DCD output control.
|
||||
static double dcd_start_time[MAX_CHANS];
|
||||
|
||||
if (d_o_opt) {
|
||||
double t = (double)sample_number / my_audio_config.adev[0].samples_per_sec;
|
||||
double sec1, sec2;
|
||||
int min1, min2;
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
||||
if (ptt_signal) {
|
||||
//sec1 = t;
|
||||
//min1 = (int)(sec1 / 60.);
|
||||
//sec1 -= min1 * 60;
|
||||
//dw_printf ("DCD[%d] = ON %d:%06.3f\n", chan, min1, sec1);
|
||||
dcd_count++;
|
||||
dcd_start_time[chan] = t;
|
||||
}
|
||||
else {
|
||||
//dw_printf ("DCD[%d] = off %d:%06.3f %3.0f\n", chan, min, sec, (t - dcd_start_time[chan]) * 1000.);
|
||||
|
||||
sec1 = dcd_start_time[chan];
|
||||
min1 = (int)(sec1 / 60.);
|
||||
sec1 -= min1 * 60;
|
||||
|
||||
sec2 = t;
|
||||
min2 = (int)(sec2 / 60.);
|
||||
sec2 -= min2 * 60;
|
||||
|
||||
dw_printf ("DCD[%d] %d:%06.3f - %d:%06.3f = %3.0f\n", chan, min1, sec1, min2, sec2, (t - dcd_start_time[chan]) * 1000.);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -974,35 +790,19 @@ static void usage (void) {
|
|||
dw_printf (" atest [ options ] wav-file-in\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -B n Bits/second for data. Proper modem automatically selected for speed.\n");
|
||||
dw_printf (" 300 bps defaults to AFSK tones of 1600 & 1800.\n");
|
||||
dw_printf (" 1200 bps uses AFSK tones of 1200 & 2200.\n");
|
||||
dw_printf (" 2400 bps uses QPSK based on V.26 standard.\n");
|
||||
dw_printf (" 4800 bps uses 8PSK based on V.27 standard.\n");
|
||||
dw_printf (" 9600 bps and up uses K9NG/G3RUH standard.\n");
|
||||
dw_printf (" AIS for ship Automatic Identification System.\n");
|
||||
dw_printf (" EAS for Emergency Alert System (EAS) Specific Area Message Encoding (SAME).\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -g Use G3RUH modem rather rather than default for data rate.\n");
|
||||
dw_printf (" -j 2400 bps QPSK compatible with direwolf <= 1.5.\n");
|
||||
dw_printf (" -J 2400 bps QPSK compatible with MFJ-2400.\n");
|
||||
dw_printf (" 300 baud uses 1600/1800 Hz AFSK.\n");
|
||||
dw_printf (" 1200 (default) baud uses 1200/2200 Hz AFSK.\n");
|
||||
dw_printf (" 9600 baud uses K9NG/G2RUH standard.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -D n Divide audio sample rate by n.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -h Print frame contents as hexadecimal bytes.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -F n Amount of effort to try fixing frames with an invalid CRC. \n");
|
||||
dw_printf (" 0 (default) = consider only correct frames. \n");
|
||||
dw_printf (" 1 = Try to fix only a single bit. \n");
|
||||
dw_printf (" more = Try modifying more bits to get a good CRC.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -d x Debug information for FX.25. Repeat for more detail.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -L Error if less than this number decoded.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -G Error if greater than this number decoded.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -P m Select the demodulator type such as D (default for 300 bps),\n");
|
||||
dw_printf (" E+ (default for 1200 bps), PQRS for 2400 bps, etc.\n");
|
||||
dw_printf (" -P m Select the demodulator type such as A, B, C, D (default for 300 baud),\n");
|
||||
dw_printf (" E (default for 1200 baud), F, A+, B+, C+, D+, E+, F+.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -0 Use channel 0 (left) of stereo audio (default).\n");
|
||||
dw_printf (" -1 use channel 1 (right) of stereo audio.\n");
|
||||
|
@ -1025,11 +825,11 @@ static void usage (void) {
|
|||
dw_printf (" bits per second.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" atest 02_Track_2.wav\n");
|
||||
dw_printf (" atest -P E- 02_Track_2.wav\n");
|
||||
dw_printf (" atest -P C+ 02_Track_2.wav\n");
|
||||
dw_printf (" atest -F 1 02_Track_2.wav\n");
|
||||
dw_printf (" atest -P E- -F 1 02_Track_2.wav\n");
|
||||
dw_printf (" atest -P C+ -F 1 02_Track_2.wav\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" Try different combinations of options to compare decoding\n");
|
||||
dw_printf (" Try different combinations of options to find the best decoding\n");
|
||||
dw_printf (" performance.\n");
|
||||
|
||||
exit (1);
|
|
@ -75,17 +75,18 @@
|
|||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#if USE_ALSA
|
||||
#include <alsa/asoundlib.h>
|
||||
#elif USE_SNDIO
|
||||
#include <sndio.h>
|
||||
#include <poll.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include "audio.h"
|
||||
|
@ -110,9 +111,6 @@ static struct adev_s {
|
|||
|
||||
int bytes_per_frame; /* number of bytes for a sample from all channels. */
|
||||
/* e.g. 4 for stereo 16 bit. */
|
||||
#elif USE_SNDIO
|
||||
struct sio_hdl *sndio_in_handle;
|
||||
struct sio_hdl *sndio_out_handle;
|
||||
|
||||
#else
|
||||
int oss_audio_device_fd; /* Single device, both directions. */
|
||||
|
@ -143,9 +141,6 @@ static struct adev_s {
|
|||
#if USE_ALSA
|
||||
static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *name, char *dir);
|
||||
//static void alsa_select_device (char *pick_dev, int direction, char *result);
|
||||
#elif USE_SNDIO
|
||||
static int set_sndio_params (int a, struct sio_hdl *handle, struct audio_s *pa, char *devname, char *inout);
|
||||
static int poll_sndio (struct sio_hdl *hdl, int events);
|
||||
#else
|
||||
static int set_oss_params (int a, int fd, struct audio_s *pa);
|
||||
#endif
|
||||
|
@ -206,7 +201,7 @@ static int calcbufsize(int rate, int chans, int bits)
|
|||
* more restrictive in its capabilities.
|
||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
||||
*
|
||||
* The software modem must use this ACTUAL information
|
||||
* The sofware modem must use this ACTUAL information
|
||||
* that the device is supplying, that could be different
|
||||
* than what the user specified.
|
||||
*
|
||||
|
@ -217,9 +212,7 @@ static int calcbufsize(int rate, int chans, int bits)
|
|||
|
||||
int audio_open (struct audio_s *pa)
|
||||
{
|
||||
#if !USE_SNDIO
|
||||
int err;
|
||||
#endif
|
||||
int chan;
|
||||
int a;
|
||||
char audio_in_name[30];
|
||||
|
@ -231,11 +224,7 @@ int audio_open (struct audio_s *pa)
|
|||
memset (adev, 0, sizeof(adev));
|
||||
|
||||
for (a=0; a<MAX_ADEVS; a++) {
|
||||
#if USE_ALSA
|
||||
adev[a].audio_in_handle = adev[a].audio_out_handle = NULL;
|
||||
#elif USE_SNDIO
|
||||
adev[a].sndio_in_handle = adev[a].sndio_out_handle = NULL;
|
||||
#else
|
||||
#ifndef USE_ALSA
|
||||
adev[a].oss_audio_device_fd = -1;
|
||||
#endif
|
||||
adev[a].udp_sock = -1;
|
||||
|
@ -354,33 +343,11 @@ int audio_open (struct audio_s *pa)
|
|||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open audio device %s for input\n%s\n",
|
||||
audio_in_name, snd_strerror(err));
|
||||
if (err == -EBUSY) {
|
||||
dw_printf ("This means that some other application is using that device.\n");
|
||||
dw_printf ("The solution is to identify that other application and stop it.\n");
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
adev[a].inbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_in_handle, pa, audio_in_name, "input");
|
||||
|
||||
#elif USE_SNDIO
|
||||
adev[a].sndio_in_handle = sio_open (audio_in_name, SIO_REC, 0);
|
||||
if (adev[a].sndio_in_handle == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open audio device %s for input\n",
|
||||
audio_in_name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
adev[a].inbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_in_handle, pa, audio_in_name, "input");
|
||||
|
||||
if (!sio_start (adev[a].sndio_in_handle)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not start audio device %s for input\n",
|
||||
audio_in_name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#else // OSS
|
||||
adev[a].oss_audio_device_fd = open (pa->adev[a].adevice_in, O_RDWR);
|
||||
|
||||
|
@ -463,10 +430,6 @@ int audio_open (struct audio_s *pa)
|
|||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open audio device %s for output\n%s\n",
|
||||
audio_out_name, snd_strerror(err));
|
||||
if (err == -EBUSY) {
|
||||
dw_printf ("This means that some other application is using that device.\n");
|
||||
dw_printf ("The solution is to identify that other application and stop it.\n");
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
@ -476,27 +439,6 @@ int audio_open (struct audio_s *pa)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
#elif USE_SNDIO
|
||||
adev[a].sndio_out_handle = sio_open (audio_out_name, SIO_PLAY, 0);
|
||||
if (adev[a].sndio_out_handle == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open audio device %s for output\n",
|
||||
audio_out_name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
adev[a].outbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_out_handle, pa, audio_out_name, "output");
|
||||
|
||||
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!sio_start (adev[a].sndio_out_handle)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not start audio device %s for output\n",
|
||||
audio_out_name);
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -733,112 +675,6 @@ static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *
|
|||
} /* end alsa_set_params */
|
||||
|
||||
|
||||
#elif USE_SNDIO
|
||||
|
||||
/*
|
||||
* Set parameters for sound card. (sndio)
|
||||
*
|
||||
* See /usr/include/sndio.h for details.
|
||||
*/
|
||||
|
||||
static int set_sndio_params (int a, struct sio_hdl *handle, struct audio_s *pa, char *devname, char *inout)
|
||||
{
|
||||
|
||||
struct sio_par q, r;
|
||||
|
||||
/* Signed 16 bit little endian or unsigned 8 bit. */
|
||||
sio_initpar (&q);
|
||||
q.bits = pa->adev[a].bits_per_sample;
|
||||
q.bps = (q.bits + 7) / 8;
|
||||
q.sig = (q.bits == 8) ? 0 : 1;
|
||||
q.le = 1; /* always little endian */
|
||||
q.msb = 0; /* LSB aligned */
|
||||
q.rchan = q.pchan = pa->adev[a].num_channels;
|
||||
q.rate = pa->adev[a].samples_per_sec;
|
||||
q.xrun = SIO_IGNORE;
|
||||
q.appbufsz = calcbufsize(pa->adev[a].samples_per_sec, pa->adev[a].num_channels, pa->adev[a].bits_per_sample);
|
||||
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("suggest buffer size %d bytes for %s %s.\n",
|
||||
q.appbufsz, devname, inout);
|
||||
#endif
|
||||
|
||||
/* challenge new setting */
|
||||
if (!sio_setpar (handle, &q)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not set hardware parameter for %s %s.\n",
|
||||
devname, inout);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* get response */
|
||||
if (!sio_getpar (handle, &r)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not obtain current hardware setting for %s %s.\n",
|
||||
devname, inout);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("audio buffer size %d bytes for %s %s.\n",
|
||||
r.appbufsz, devname, inout);
|
||||
#endif
|
||||
if (q.rate != r.rate) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Asked for %d samples/sec but got %d for %s %s.",
|
||||
pa->adev[a].samples_per_sec, r.rate, devname, inout);
|
||||
pa->adev[a].samples_per_sec = r.rate;
|
||||
}
|
||||
|
||||
/* not supported */
|
||||
if (q.bits != r.bits || q.bps != r.bps || q.sig != r.sig ||
|
||||
(q.bits > 8 && q.le != r.le) ||
|
||||
(*inout == 'o' && q.pchan != r.pchan) ||
|
||||
(*inout == 'i' && q.rchan != r.rchan)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unsupported format for %s %s.\n", devname, inout);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return r.appbufsz;
|
||||
|
||||
} /* end set_sndio_params */
|
||||
|
||||
static int poll_sndio (struct sio_hdl *hdl, int events)
|
||||
{
|
||||
struct pollfd *pfds;
|
||||
int nfds, revents;
|
||||
|
||||
nfds = sio_nfds (hdl);
|
||||
pfds = alloca (nfds * sizeof(struct pollfd));
|
||||
|
||||
do {
|
||||
nfds = sio_pollfd (hdl, pfds, events);
|
||||
if (nfds < 1) {
|
||||
/* no need to wait */
|
||||
return (0);
|
||||
}
|
||||
if (poll (pfds, nfds, -1) < 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("poll %d\n", errno);
|
||||
return (-1);
|
||||
}
|
||||
revents = sio_revents (hdl, pfds);
|
||||
} while (!(revents & (events | POLLHUP)));
|
||||
|
||||
/* unrecoverable error occurred */
|
||||
if (revents & POLLHUP) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("waited for %s, POLLHUP received\n", (events & POLLIN) ? "POLLIN" : "POLLOUT");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
@ -933,7 +769,7 @@ static int set_oss_params (int a, int fd, struct audio_s *pa)
|
|||
* This was long ago under different conditions.
|
||||
* Should study this again some day.
|
||||
*
|
||||
* Your mileage may vary.
|
||||
* Your milage may vary.
|
||||
*/
|
||||
err = ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &ossbuf_size_in_bytes);
|
||||
if (err == -1) {
|
||||
|
@ -1006,9 +842,7 @@ __attribute__((hot))
|
|||
int audio_get (int a)
|
||||
{
|
||||
int n;
|
||||
#if USE_ALSA
|
||||
int retries = 0;
|
||||
#endif
|
||||
|
||||
#if STATISTICS
|
||||
/* Gather numbers for read from audio device. */
|
||||
|
@ -1102,8 +936,6 @@ int audio_get (int a)
|
|||
dw_printf ("This is most likely caused by the CPU being too slow to keep up with the audio stream.\n");
|
||||
dw_printf ("Use the \"top\" command, in another command window, to look at CPU usage.\n");
|
||||
dw_printf ("This might be a temporary condition so we will attempt to recover a few times before giving up.\n");
|
||||
dw_printf ("If using a very slow CPU, try reducing the CPU load by using -P- command\n");
|
||||
dw_printf ("line option for 9600 bps or -D3 for slower AFSK .\n");
|
||||
}
|
||||
|
||||
audio_stats (a,
|
||||
|
@ -1138,28 +970,7 @@ int audio_get (int a)
|
|||
}
|
||||
|
||||
|
||||
#elif USE_SNDIO
|
||||
|
||||
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
||||
|
||||
assert (adev[a].sndio_in_handle != NULL);
|
||||
if (poll_sndio (adev[a].sndio_in_handle, POLLIN) < 0) {
|
||||
adev[a].inbuf_len = 0;
|
||||
adev[a].inbuf_next = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
n = sio_read (adev[a].sndio_in_handle, adev[a].inbuf_ptr, adev[a].inbuf_size_in_bytes);
|
||||
adev[a].inbuf_len = n;
|
||||
adev[a].inbuf_next = 0;
|
||||
|
||||
audio_stats (a,
|
||||
save_audio_config_p->adev[a].num_channels,
|
||||
n / (save_audio_config_p->adev[a].num_channels * save_audio_config_p->adev[a].bits_per_sample / 8),
|
||||
save_audio_config_p->statistics_interval);
|
||||
}
|
||||
|
||||
#else /* begin OSS */
|
||||
#else /* end ALSA, begin OSS */
|
||||
|
||||
/* Fixed in 1.2. This was formerly outside of the switch */
|
||||
/* so the OSS version did not process stdin or UDP. */
|
||||
|
@ -1393,17 +1204,6 @@ int audio_flush (int a)
|
|||
|
||||
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
|
||||
}
|
||||
else if (k == -ESTRPIPE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Driver suspended, recovering\n");
|
||||
snd_pcm_recover(adev[a].audio_out_handle, k, 1);
|
||||
}
|
||||
else if (k == -EBADFD) {
|
||||
k = snd_pcm_prepare (adev[a].audio_out_handle);
|
||||
if(k < 0) {
|
||||
dw_printf ("Error preparing after bad state: %s\n", snd_strerror(k));
|
||||
}
|
||||
}
|
||||
else if (k < 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio write error: %s\n", snd_strerror(k));
|
||||
|
@ -1411,10 +1211,7 @@ int audio_flush (int a)
|
|||
/* Some other error condition. */
|
||||
/* Try again. What do we have to lose? */
|
||||
|
||||
k = snd_pcm_prepare (adev[a].audio_out_handle);
|
||||
if(k < 0) {
|
||||
dw_printf ("Error preparing after error: %s\n", snd_strerror(k));
|
||||
}
|
||||
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
|
||||
}
|
||||
else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1439,37 +1236,6 @@ int audio_flush (int a)
|
|||
adev[a].outbuf_len = 0;
|
||||
return (-1);
|
||||
|
||||
#elif USE_SNDIO
|
||||
|
||||
int k;
|
||||
unsigned char *ptr;
|
||||
int len;
|
||||
|
||||
ptr = adev[a].outbuf_ptr;
|
||||
len = adev[a].outbuf_len;
|
||||
|
||||
while (len > 0) {
|
||||
assert (adev[a].sndio_out_handle != NULL);
|
||||
if (poll_sndio (adev[a].sndio_out_handle, POLLOUT) < 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Can't write to audio device");
|
||||
adev[a].outbuf_len = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
k = sio_write (adev[a].sndio_out_handle, ptr, len);
|
||||
#if DEBUGx
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
|
||||
fflush (stdout);
|
||||
#endif
|
||||
ptr += k;
|
||||
len -= k;
|
||||
}
|
||||
|
||||
adev[a].outbuf_len = 0;
|
||||
return (0);
|
||||
|
||||
#else /* OSS */
|
||||
|
||||
int k;
|
||||
|
@ -1540,7 +1306,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additional time if required.
|
||||
* and wait for additoinal time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
@ -1571,10 +1337,6 @@ void audio_wait (int a)
|
|||
* Either way, the caller will now compensate for it.
|
||||
*/
|
||||
|
||||
#elif USE_SNDIO
|
||||
|
||||
poll_sndio (adev[a].sndio_out_handle, POLLOUT);
|
||||
|
||||
#else
|
||||
|
||||
assert (adev[a].oss_audio_device_fd > 0);
|
||||
|
@ -1620,22 +1382,7 @@ int audio_close (void)
|
|||
|
||||
snd_pcm_close (adev[a].audio_in_handle);
|
||||
snd_pcm_close (adev[a].audio_out_handle);
|
||||
|
||||
adev[a].audio_in_handle = adev[a].audio_out_handle = NULL;
|
||||
|
||||
#elif USE_SNDIO
|
||||
|
||||
if (adev[a].sndio_in_handle != NULL && adev[a].sndio_out_handle != NULL) {
|
||||
|
||||
audio_wait (a);
|
||||
|
||||
sio_stop (adev[a].sndio_in_handle);
|
||||
sio_stop (adev[a].sndio_out_handle);
|
||||
sio_close (adev[a].sndio_in_handle);
|
||||
sio_close (adev[a].sndio_out_handle);
|
||||
|
||||
adev[a].sndio_in_handle = adev[a].sndio_out_handle = NULL;
|
||||
|
||||
|
||||
#else
|
||||
|
||||
if (adev[a].oss_audio_device_fd > 0) {
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include "direwolf.h" /* for MAX_CHANS used throughout the application. */
|
||||
#include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
|
||||
#include "version.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -53,13 +53,6 @@ typedef enum retry_e {
|
|||
RETRY_INVERT_TWO_SEP=4,
|
||||
RETRY_MAX = 5} retry_t;
|
||||
|
||||
// Type of communication medium associated with the channel.
|
||||
|
||||
enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use.
|
||||
MEDIUM_RADIO, // Internal modem for radio.
|
||||
MEDIUM_IGATE, // Access IGate as ordinary channel.
|
||||
MEDIUM_NETTNC }; // Remote network TNC. (possible future)
|
||||
|
||||
|
||||
typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;
|
||||
|
||||
|
@ -72,7 +65,7 @@ struct audio_s {
|
|||
|
||||
struct adev_param_s {
|
||||
|
||||
/* Properties of the sound device. */
|
||||
/* Properites of the sound device. */
|
||||
|
||||
int defined; /* Was device defined? */
|
||||
/* First one defaults to yes. */
|
||||
|
@ -102,72 +95,26 @@ struct audio_s {
|
|||
/* This is the probability, in per cent, of randomly corrupting it. */
|
||||
/* Normally this is 0. 25 would mean corrupt it 25% of the time. */
|
||||
|
||||
int recv_error_rate; /* Similar but the % probability of dropping a received frame. */
|
||||
|
||||
float recv_ber; /* Receive Bit Error Rate (BER). */
|
||||
/* Probability of inverting a bit coming out of the modem. */
|
||||
|
||||
//int fx25_xmit_enable; /* Enable transmission of FX.25. */
|
||||
/* See fx25_init.c for explanation of values. */
|
||||
/* Initially this applies to all channels. */
|
||||
/* This should probably be per channel. One step at a time. */
|
||||
/* v1.7 - replaced by layer2_xmit==LAYER2_FX25 */
|
||||
|
||||
int fx25_auto_enable; /* Turn on FX.25 for current connected mode session */
|
||||
/* under poor conditions. */
|
||||
/* Set to 0 to disable feature. */
|
||||
/* I put it here, rather than with the rest of the link layer */
|
||||
/* parameters because it is really a part of the HDLC layer */
|
||||
/* and is part of the KISS TNC functionality rather than our data link layer. */
|
||||
/* Future: not used yet. */
|
||||
|
||||
int recv_error_rate; /* Similar but the % probablity of dropping a received frame. */
|
||||
|
||||
char timestamp_format[40]; /* -T option */
|
||||
/* Precede received & transmitted frames with timestamp. */
|
||||
/* Command line option uses "strftime" format string. */
|
||||
|
||||
|
||||
|
||||
/* originally a "channel" was always connected to an internal modem. */
|
||||
/* In version 1.6, this is generalized so that a channel (as seen by client application) */
|
||||
/* can be connected to something else. Initially, this will allow application */
|
||||
/* access to the IGate. Later we might have network TNCs or other internal functions. */
|
||||
|
||||
// Properties for all channels.
|
||||
|
||||
enum medium_e chan_medium[MAX_TOTAL_CHANS];
|
||||
// MEDIUM_NONE for invalid.
|
||||
// MEDIUM_RADIO for internal modem. (only possibility earlier)
|
||||
// MEDIUM_IGATE allows application access to IGate.
|
||||
// MEDIUM_NETTNC for external TNC via TCP.
|
||||
|
||||
int igate_vchannel; /* Virtual channel mapped to APRS-IS. */
|
||||
/* -1 for none. */
|
||||
/* Redundant but it makes things quicker and simpler */
|
||||
/* than always searching thru above. */
|
||||
|
||||
/* Properties for each radio channel, common to receive and transmit. */
|
||||
/* Properties for each audio channel, common to receive and transmit. */
|
||||
/* Can be different for each radio channel. */
|
||||
|
||||
|
||||
struct achan_param_s {
|
||||
|
||||
// Currently, we have a fixed mapping from audio sources to channel.
|
||||
//
|
||||
// ADEVICE CHANNEL (mono) (stereo)
|
||||
// 0 0 0, 1
|
||||
// 1 2 2, 3
|
||||
// 2 4 4, 5
|
||||
//
|
||||
// A future feauture might allow the user to specify a different audio source.
|
||||
// This would allow multiple modems (with associated channel) to share an audio source.
|
||||
// int audio_source; // Default would be [0,1,2,3,4,5]
|
||||
int valid; /* Is this channel valid? */
|
||||
|
||||
// What else should be moved out of structure and enlarged when NETTNC is implemented. ???
|
||||
char mycall[AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */
|
||||
/* Could all be the same or different. */
|
||||
|
||||
|
||||
enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF, MODEM_16_QAM, MODEM_64_QAM, MODEM_AIS, MODEM_EAS } modem_type;
|
||||
enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF } modem_type;
|
||||
|
||||
/* Usual AFSK. */
|
||||
/* Baseband signal. Not used yet. */
|
||||
|
@ -175,32 +122,6 @@ struct audio_s {
|
|||
/* Might try MFJ-2400 / CCITT v.26 / Bell 201 someday. */
|
||||
/* No modem. Might want this for DTMF only channel. */
|
||||
|
||||
enum layer2_t { LAYER2_AX25 = 0, LAYER2_FX25, LAYER2_IL2P } layer2_xmit;
|
||||
|
||||
// IL2P - New for version 1.7.
|
||||
// New layer 2 with FEC. Much less overhead than FX.25 but no longer backward compatible.
|
||||
// Only applies to transmit.
|
||||
// Listening for FEC sync word should add negligible overhead so
|
||||
// we leave reception enabled all the time as we do with FX.25.
|
||||
// TODO: FX.25 should probably be put here rather than global for all channels.
|
||||
|
||||
int fx25_strength; // Strength of FX.25 FEC.
|
||||
// 16, 23, 64 for specific number of parity symbols.
|
||||
// 1 for automatic selection based on frame size.
|
||||
|
||||
int il2p_max_fec; // 1 for max FEC length, 0 for automatic based on size.
|
||||
|
||||
int il2p_invert_polarity; // 1 means invert on transmit. Receive handles either automatically.
|
||||
|
||||
enum v26_e { V26_UNSPECIFIED=0, V26_A, V26_B } v26_alternative;
|
||||
|
||||
// Original implementation used alternative A for 2400 bbps PSK.
|
||||
// Years later, we discover that MFJ-2400 used alternative B.
|
||||
// It's likely the others did too. it also works a little better.
|
||||
// Default to MFJ compatible and print warning if user did not
|
||||
// pick one explicitly.
|
||||
|
||||
#define V26_DEFAULT V26_B
|
||||
|
||||
enum dtmf_decode_t { DTMF_DECODE_OFF, DTMF_DECODE_ON } dtmf_decode;
|
||||
|
||||
|
@ -217,7 +138,8 @@ struct audio_s {
|
|||
int decimate; /* Reduce AFSK sample rate by this factor to */
|
||||
/* decrease computational requirements. */
|
||||
|
||||
int upsample; /* Upsample by this factor for G3RUH. */
|
||||
int interleave; /* If > 1, interleave samples among multiple decoders. */
|
||||
/* Quick hack for experiment. */
|
||||
|
||||
int mark_freq; /* Two tones for AFSK modulation, in Hz. */
|
||||
int space_freq; /* Standard tones are 1200 and 2200 for 1200 baud. */
|
||||
|
@ -276,17 +198,15 @@ struct audio_s {
|
|||
|
||||
ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB, CM108. */
|
||||
|
||||
char ptt_device[128]; /* Serial device name for PTT. e.g. COM1 or /dev/ttyS0 */
|
||||
char ptt_device[100]; /* Serial device name for PTT. e.g. COM1 or /dev/ttyS0 */
|
||||
/* Also used for HAMLIB. Could be host:port when model is 1. */
|
||||
/* For years, 20 characters was plenty then we start getting extreme names like this: */
|
||||
/* /dev/serial/by-id/usb-FTDI_Navigator__CAT___2nd_PTT__00000000-if00-port0 */
|
||||
/* /dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0 */
|
||||
/* Issue 104, changed to 100 bytes in version 1.5. */
|
||||
|
||||
/* This same field is also used for CM108/CM119 GPIO PTT which will */
|
||||
/* have a name like /dev/hidraw1 for Linux or */
|
||||
/* \\?\hid#vid_0d8c&pid_0008&mi_03#8&39d3555&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} */
|
||||
/* for Windows. Largest observed was 95 but add some extra to be safe. */
|
||||
/* This same field is also used for CM108 GPIO PTT which will */
|
||||
/* have a name like /dev/hidraw1. */
|
||||
|
||||
ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */
|
||||
ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */
|
||||
|
@ -294,12 +214,12 @@ struct audio_s {
|
|||
int out_gpio_num; /* GPIO number. Originally this was only for PTT. */
|
||||
/* It is now more general. */
|
||||
/* octrl array is indexed by PTT, DCD, or CONnected indicator. */
|
||||
/* For CM108/CM119, this should be in range of 1-8. */
|
||||
/* For CM108, this should be in range of 1-8. */
|
||||
|
||||
#define MAX_GPIO_NAME_LEN 20 // 12 would cover any case I've seen so this should be safe
|
||||
|
||||
char out_gpio_name[MAX_GPIO_NAME_LEN];
|
||||
/* originally, gpio number NN was assumed to simply */
|
||||
/* orginally, gpio number NN was assumed to simply */
|
||||
/* have the name gpioNN but this turned out not to be */
|
||||
/* the case for CubieBoard where it was longer. */
|
||||
/* This is filled in by ptt_init so we don't have to */
|
||||
|
@ -316,8 +236,6 @@ struct audio_s {
|
|||
#ifdef USE_HAMLIB
|
||||
|
||||
int ptt_model; /* HAMLIB model. -1 for AUTO. 2 for rigctld. Others are radio model. */
|
||||
int ptt_rate; /* Serial port speed when using hamlib CAT control for PTT. */
|
||||
/* If zero, hamlib will come up with a default for pariticular rig. */
|
||||
#endif
|
||||
|
||||
} octrl[NUM_OCTYPES];
|
||||
|
@ -336,7 +254,7 @@ struct audio_s {
|
|||
int in_gpio_num; /* GPIO number */
|
||||
|
||||
char in_gpio_name[MAX_GPIO_NAME_LEN];
|
||||
/* originally, gpio number NN was assumed to simply */
|
||||
/* orginally, gpio number NN was assumed to simply */
|
||||
/* have the name gpioNN but this turned out not to be */
|
||||
/* the case for CubieBoard where it was longer. */
|
||||
/* This is filled in by ptt_init so we don't have to */
|
||||
|
@ -350,7 +268,7 @@ struct audio_s {
|
|||
int dwait; /* First wait extra time for receiver squelch. */
|
||||
/* Default 0 units of 10 mS each . */
|
||||
|
||||
int slottime; /* Slot time in 10 mS units for persistence algorithm. */
|
||||
int slottime; /* Slot time in 10 mS units for persistance algorithm. */
|
||||
/* Typical value is 10 meaning 100 milliseconds. */
|
||||
|
||||
int persist; /* Sets probability for transmitting after each */
|
||||
|
@ -382,18 +300,15 @@ struct audio_s {
|
|||
};
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
#if __WIN32__ || __APPLE__
|
||||
#define DEFAULT_ADEVICE "" /* Windows: Empty string = default audio device. */
|
||||
#elif __APPLE__
|
||||
#define DEFAULT_ADEVICE "" /* Mac OSX: Empty string = default audio device. */
|
||||
#elif USE_ALSA
|
||||
#define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */
|
||||
#elif USE_SNDIO
|
||||
#define DEFAULT_ADEVICE "default" /* Use default device for sndio. */
|
||||
#else
|
||||
#define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. (FreeBSD) */
|
||||
#if USE_ALSA
|
||||
#define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */
|
||||
#else
|
||||
#define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
@ -426,8 +341,7 @@ struct audio_s {
|
|||
|
||||
#define DEFAULT_BITS_PER_SAMPLE 16
|
||||
|
||||
#define DEFAULT_FIX_BITS RETRY_NONE // Interesting research project but even a single bit fix up
|
||||
// will occasionally let corrupted packets through.
|
||||
#define DEFAULT_FIX_BITS RETRY_INVERT_SINGLE
|
||||
|
||||
/*
|
||||
* Standard for AFSK on VHF FM.
|
||||
|
@ -457,11 +371,11 @@ struct audio_s {
|
|||
*/
|
||||
|
||||
#define DEFAULT_DWAIT 0
|
||||
#define DEFAULT_SLOTTIME 10 // *10mS = 100mS
|
||||
#define DEFAULT_SLOTTIME 10
|
||||
#define DEFAULT_PERSIST 63
|
||||
#define DEFAULT_TXDELAY 30 // *10mS = 300mS
|
||||
#define DEFAULT_TXTAIL 10 // *10mS = 100mS
|
||||
#define DEFAULT_FULLDUP 0 // false = half duplex
|
||||
#define DEFAULT_TXDELAY 30
|
||||
#define DEFAULT_TXTAIL 10
|
||||
#define DEFAULT_FULLDUP 0
|
||||
|
||||
/*
|
||||
* Note that we have two versions of these in audio.c and audio_win.c.
|
|
@ -156,7 +156,7 @@ static int calcbufsize(int rate, int chans, int bits)
|
|||
* the same device name for more then one connected device
|
||||
* (ie two SignaLinks). Appending a Portaudio device index to the
|
||||
* the device name ensure we can find the correct one. And if it's not
|
||||
* available return the first occurrence that matches the device name.
|
||||
* available return the first occurence that matches the device name.
|
||||
*----------------------------------------------------------------*/
|
||||
static int searchPADevice(struct adev_s *dev, char *_devName, int reqDeviceNo, int io_flag)
|
||||
{
|
||||
|
@ -213,21 +213,7 @@ static int pa_devNN(char *deviceStr, char *_devName, size_t length, int *_devNo)
|
|||
while(*cPtr) {
|
||||
cVal = *cPtr++;
|
||||
if(cVal == ':') break;
|
||||
|
||||
// See Issue 417.
|
||||
// Originally this copied only printable ASCII characters (space thru ~).
|
||||
// That is a problem for some locales that use UTF-8 characters in the device name.
|
||||
// original: if(((cVal >= ' ') && (cVal <= '~')) && (count < length)) {
|
||||
|
||||
// At first I was thinking we should keep the test for < ' ' but then I
|
||||
// remembered that char type can be signed or unsigned depending on implementation.
|
||||
// If characters are signed then a value above 0x7f would be considered negative.
|
||||
|
||||
// It seems to me that the test for buffer full is off by one.
|
||||
// count could reach length, leaving no room for a nul terminator.
|
||||
// Compare has been changed so count is limited to length minus 1.
|
||||
|
||||
if(count < length - 1) {
|
||||
if(((cVal >= ' ') && (cVal <= '~')) && (count < length)) {
|
||||
_devName[count++] = cVal;
|
||||
}
|
||||
|
||||
|
@ -527,7 +513,7 @@ static int paOutput16CB( const void *inputBuffer, void *outputBuffer,
|
|||
* more restrictive in its capabilities.
|
||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
||||
*
|
||||
* The software modem must use this ACTUAL information
|
||||
* The sofware modem must use this ACTUAL information
|
||||
* that the device is supplying, that could be different
|
||||
* than what the user specified.
|
||||
*
|
||||
|
@ -1163,7 +1149,7 @@ int audio_put (int a, int c)
|
|||
static double start = 0, end = 0, diff = 0;
|
||||
|
||||
if(adev[a].outbuf_len == 0)
|
||||
start = dtime_monotonic();
|
||||
start = dtime_now();
|
||||
#endif
|
||||
|
||||
if(c >= 0) {
|
||||
|
@ -1192,7 +1178,7 @@ int audio_put (int a, int c)
|
|||
#ifdef __TIMED__
|
||||
count += frames;
|
||||
if(c < 0) { // When the Ax25 frames are flushed.
|
||||
end = dtime_monotonic();
|
||||
end = dtime_now();
|
||||
diff = end - start;
|
||||
if(count)
|
||||
dw_printf ("Transfer Time:%3.9f No of Frames:%d Per frame:%3.9f speed:%f\n",
|
||||
|
@ -1260,7 +1246,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additional time if required.
|
||||
* and wait for additoinal time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
|
@ -65,6 +65,7 @@
|
|||
|
||||
#include "audio_stats.h"
|
||||
#include "textcolor.h"
|
||||
#include "dtime_now.h"
|
||||
#include "demod.h" /* for alevel_t & demod_get_audio_level() */
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ static struct audio_s *save_audio_config_p;
|
|||
*/
|
||||
|
||||
/*
|
||||
* Originally, we had an arbitrary buf time of 40 mS.
|
||||
* Originally, we had an abitrary buf time of 40 mS.
|
||||
*
|
||||
* For mono, the buffer size was rounded up from 3528 to 4k so
|
||||
* it was really about 50 mS per buffer or about 20 per second.
|
||||
|
@ -209,7 +209,7 @@ static struct adev_s {
|
|||
* more restrictive in its capabilities.
|
||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
||||
*
|
||||
* The software modem must use this ACTUAL information
|
||||
* The sofware modem must use this ACTUAL information
|
||||
* that the device is supplying, that could be different
|
||||
* than what the user specified.
|
||||
*
|
||||
|
@ -222,8 +222,8 @@ static struct adev_s {
|
|||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
static void CALLBACK in_callback (HWAVEIN handle, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
|
||||
static void CALLBACK out_callback (HWAVEOUT handle, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
|
||||
static void CALLBACK in_callback (HWAVEIN handle, UINT msg, DWORD instance, DWORD param1, DWORD param2);
|
||||
static void CALLBACK out_callback (HWAVEOUT handle, UINT msg, DWORD instance, DWORD param1, DWORD param2);
|
||||
|
||||
int audio_open (struct audio_s *pa)
|
||||
{
|
||||
|
@ -561,8 +561,6 @@ int audio_open (struct audio_s *pa)
|
|||
*/
|
||||
case AUDIO_IN_TYPE_SOUNDCARD:
|
||||
|
||||
// Use InitializeCriticalSectionAndSpinCount to avoid exceptions in low memory situations?
|
||||
|
||||
InitializeCriticalSection (&(A->in_cs));
|
||||
|
||||
err = waveInOpen (&(A->audio_in_handle), in_dev_no[a], &wf, (DWORD_PTR)in_callback, a, CALLBACK_FUNCTION);
|
||||
|
@ -686,25 +684,24 @@ int audio_open (struct audio_s *pa)
|
|||
* Called when input audio block is ready.
|
||||
*/
|
||||
|
||||
static void CALLBACK in_callback (HWAVEIN handle, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2)
|
||||
static void CALLBACK in_callback (HWAVEIN handle, UINT msg, DWORD instance, DWORD param1, DWORD param2)
|
||||
{
|
||||
|
||||
//dw_printf ("in_callback, handle = %p, msg = %d, instance = %I64d\n", handle, msg, instance);
|
||||
|
||||
int a = instance;
|
||||
|
||||
//dw_printf ("in_callback, handle = %d, a = %d\n", (int)handle, a);
|
||||
|
||||
assert (a >= 0 && a < MAX_ADEVS);
|
||||
struct adev_s *A = &(adev[a]);
|
||||
|
||||
|
||||
if (msg == WIM_DATA) {
|
||||
|
||||
WAVEHDR *p = (WAVEHDR*)param1;
|
||||
|
||||
p->dwUser = 0x5a5a5a5a; /* needs to be unprepared. */
|
||||
/* dwUser can be 32 or 64 bit unsigned int. */
|
||||
p->dwUser = -1; /* needs to be unprepared. */
|
||||
p->lpNext = NULL;
|
||||
|
||||
// dw_printf ("dwBytesRecorded = %ld\n", p->dwBytesRecorded);
|
||||
|
||||
EnterCriticalSection (&(A->in_cs));
|
||||
|
||||
if (A->in_headp == NULL) {
|
||||
|
@ -729,7 +726,7 @@ static void CALLBACK in_callback (HWAVEIN handle, UINT msg, DWORD_PTR instance,
|
|||
*/
|
||||
|
||||
|
||||
static void CALLBACK out_callback (HWAVEOUT handle, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2)
|
||||
static void CALLBACK out_callback (HWAVEOUT handle, UINT msg, DWORD instance, DWORD param1, DWORD param2)
|
||||
{
|
||||
if (msg == WOM_DONE) {
|
||||
|
||||
|
@ -810,7 +807,7 @@ int audio_get (int a)
|
|||
|
||||
p = (WAVEHDR*)(A->in_headp); /* no need to be volatile at this point */
|
||||
|
||||
if (p->dwUser == 0x5a5a5a5a) { // dwUser can be 32 or bit unsigned.
|
||||
if (p->dwUser == (DWORD)(-1)) {
|
||||
waveInUnprepareHeader(A->audio_in_handle, p, sizeof(WAVEHDR));
|
||||
p->dwUser = 0; /* Index for next byte. */
|
||||
|
||||
|
@ -923,7 +920,7 @@ int audio_get (int a)
|
|||
* c - One byte in range of 0 - 255.
|
||||
*
|
||||
*
|
||||
* Global In: out_current - index of output buffer currently being filled.
|
||||
* Global In: out_current - index of output buffer currenly being filled.
|
||||
*
|
||||
* Returns: Normally non-negative.
|
||||
* -1 for any type of error.
|
||||
|
@ -954,15 +951,7 @@ int audio_put (int a, int c)
|
|||
timeout--;
|
||||
if (timeout <= 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
||||
// TODO: open issues 78 & 165. How can we avoid/improve this?
|
||||
|
||||
dw_printf ("Audio output failure waiting for buffer.\n");
|
||||
dw_printf ("This can occur when we are producing audio output for\n");
|
||||
dw_printf ("transmit and the operating system doesn't provide buffer\n");
|
||||
dw_printf ("space after waiting and retrying many times.\n");
|
||||
//dw_printf ("In recent years, this has been reported only when running the\n");
|
||||
//dw_printf ("Windows version with VMWare on a Macintosh.\n");
|
||||
ptt_term ();
|
||||
return (-1);
|
||||
}
|
||||
|
@ -1074,7 +1063,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additional time if required.
|
||||
* and wait for additoinal time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2016, 2017, 2018, 2023 John Langner, WB2OSZ
|
||||
// Copyright (C) 2016, 2017 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
|
||||
|
@ -26,10 +26,6 @@
|
|||
* Establish connections and transfer data in the proper
|
||||
* order with retries.
|
||||
*
|
||||
* Using the term "data link" is rather unfortunate because it causes
|
||||
* confusion to someone familiar with the OSI networking model.
|
||||
* This corresponds to the layer 4 transport, not layer 2 data link.
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Typical sequence for establishing a connection
|
||||
|
@ -160,8 +156,6 @@
|
|||
* Implemented Multi Selective Reject.
|
||||
* More efficient generation of SREJ frames.
|
||||
* Reduced number of duplicate I frames sent for both REJ and SREJ cases.
|
||||
* Avoided unnecessary RR when I frame could take care of the ack.
|
||||
* (This led to issue 132 where outgoing data sometimes got stuck in the queue.)
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
|
@ -194,16 +188,14 @@
|
|||
// Debug switches for different types of information.
|
||||
// Should have command line options instead of changing source and recompiling.
|
||||
|
||||
static int s_debug_protocol_errors = 0; // Less serious Protocol errors.
|
||||
static int s_debug_protocol_errors = 1; // Less serious Protocol errors.
|
||||
// Useful for debugging but unnecessarily alarming other times.
|
||||
// Was it intentially left on for release 1.6?
|
||||
|
||||
static int s_debug_client_app = 0; // Interaction with client application.
|
||||
// dl_connect_request, dl_data_request, dl_data_indication, etc.
|
||||
|
||||
static int s_debug_radio = 0; // Received frames and channel busy status.
|
||||
// lm_data_indication, lm_channel_busy
|
||||
|
||||
static int s_debug_variables = 0; // Variables, state changes.
|
||||
|
||||
static int s_debug_retry = 0; // Related to lost I frames, REJ, SREJ, timeout, resending.
|
||||
|
@ -252,7 +244,7 @@ typedef struct ax25_dlsm_s {
|
|||
// notifications about state changes.
|
||||
|
||||
|
||||
char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
|
||||
char addrs[AX25_MAX_REPEATERS][AX25_MAX_ADDR_LEN];
|
||||
// Up to 10 addresses, same order as in frame.
|
||||
|
||||
int num_addr; // Number of addresses. Should be in range 2 .. 10.
|
||||
|
@ -261,7 +253,7 @@ typedef struct ax25_dlsm_s {
|
|||
// addrs[OWNCALL] is owncall for this end of link.
|
||||
// Note that we are acting on behalf of
|
||||
// a client application so the APRS mycall
|
||||
// might not be relevant.
|
||||
// might not be relevent.
|
||||
|
||||
#define PEERCALL AX25_DESTINATION
|
||||
// addrs[PEERCALL] is call for other end.
|
||||
|
@ -294,7 +286,7 @@ typedef struct ax25_dlsm_s {
|
|||
int k_maxframe; // Window size. Defaults to 4 (mod 8) or 32 (mod 128).
|
||||
// Maximum number of unacknowledged information
|
||||
// frames that can be outstanding.
|
||||
// "MAXFRAME" or "EMAXFRAME" parameter in configuration file.
|
||||
// "MAXFRAME" parameter in configuration file.
|
||||
|
||||
int rc; // Retry count. Give up after n2.
|
||||
|
||||
|
@ -325,8 +317,8 @@ typedef struct ax25_dlsm_s {
|
|||
|
||||
int reject_exception; // A REJ frame has been sent to the remote station. (boolean)
|
||||
|
||||
// This is used only when receiving an I frame, in states 3 & 4, SREJ not enabled.
|
||||
// When an I frame has an unexpected N(S),
|
||||
// This is used only when receving an I frame, in states 3 & 4, SREJ not enabled.
|
||||
// When an I frame has an unepected N(S),
|
||||
// - if not already set, set it and send REJ.
|
||||
// When an I frame with expected N(S) is received, clear it.
|
||||
// This would prevent us from sending additional REJ while
|
||||
|
@ -349,7 +341,7 @@ typedef struct ax25_dlsm_s {
|
|||
// Sometimes the flow chart has SAT instead of SRT.
|
||||
// I think that is a typographical error.
|
||||
|
||||
float t1v; // How long to wait for an acknowledgement before resending.
|
||||
float t1v; // How long to wait for an acknowlegement before resending.
|
||||
// Value used when starting timer T1, in seconds.
|
||||
// "FRACK" parameter in some implementations.
|
||||
// Typically it might be 3 seconds after frame has been
|
||||
|
@ -426,7 +418,7 @@ typedef struct ax25_dlsm_s {
|
|||
// Counting outgoing could probably be done in lm_data_request so
|
||||
// it would not have to be scattered all over the place. TBD
|
||||
|
||||
int count_recv_frame_type[frame_not_AX25+1];
|
||||
int count_recv_frame_type[frame_not_AX25+1];
|
||||
|
||||
int peak_rc_value; // Peak value of retry count (rc).
|
||||
|
||||
|
@ -435,9 +427,6 @@ typedef struct ax25_dlsm_s {
|
|||
|
||||
cdata_t *i_frame_queue; // Connected data from client which has not been transmitted yet.
|
||||
// Linked list.
|
||||
// The name is misleading because these are just blocks of
|
||||
// data, not "I frames" at this point. The name comes from
|
||||
// the protocol specification.
|
||||
|
||||
cdata_t *txdata_by_ns[128]; // Data which has already been transmitted.
|
||||
// Indexed by N(S) in case it gets lost and needs to be sent again.
|
||||
|
@ -573,13 +562,6 @@ static int AX25MODULO(int n, int m, const char *file, const char *func, int line
|
|||
}
|
||||
|
||||
|
||||
// Test whether we can send more or if we need to wait
|
||||
// because we have reached 'maxframe' outstanding frames.
|
||||
// Argument must be 'S'.
|
||||
|
||||
#define WITHIN_WINDOW_SIZE(x) (x->vs != AX25MODULO(x->va + x->k_maxframe, x->modulo, __FILE__, __func__, __LINE__))
|
||||
|
||||
|
||||
// Timer macros to provide debug output with location from where they are called.
|
||||
|
||||
#define START_T1 start_t1(S, __func__, __LINE__)
|
||||
|
@ -596,11 +578,11 @@ static int AX25MODULO(int n, int m, const char *file, const char *func, int line
|
|||
#define PAUSE_TM201 pause_tm201(S, __func__, __LINE__)
|
||||
#define RESUME_TM201 resume_tm201(S, __func__, __LINE__)
|
||||
|
||||
// TODO: add SELECT_T1_VALUE for debugging.
|
||||
|
||||
|
||||
static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len);
|
||||
|
||||
static void lm_seize_confirm (ax25_dlsm_t *S);
|
||||
|
||||
static void i_frame (ax25_dlsm_t *S, cmdres_t cr, int p, int nr, int ns, int pid, char *info_ptr, int info_len);
|
||||
static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *info_ptr, int info_len);
|
||||
static int is_ns_in_window (ax25_dlsm_t *S, int ns);
|
||||
|
@ -832,11 +814,6 @@ static ax25_dlsm_t *get_link_handle (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LE
|
|||
// Create new data link state machine.
|
||||
|
||||
p = calloc (sizeof(ax25_dlsm_t), 1);
|
||||
if (p == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
p->magic1 = MAGIC1;
|
||||
p->start_time = dtime_now();
|
||||
p->stream_id = next_stream_id++;
|
||||
|
@ -900,7 +877,6 @@ static ax25_dlsm_t *get_link_handle (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LE
|
|||
//
|
||||
// dl_connect_request
|
||||
// dl_disconnect_request
|
||||
// dl_outstanding_frames_request - (mine) Ask about outgoing queue for a link.
|
||||
// dl_data_request - send connected data
|
||||
// dl_unit_data_request - not implemented. APRS & KISS bypass this
|
||||
// dl_flow_off - not implemented. Not in AGW API.
|
||||
|
@ -1079,31 +1055,12 @@ void dl_disconnect_request (dlq_item_t *E)
|
|||
case state_1_awaiting_connection:
|
||||
case state_5_awaiting_v22_connection:
|
||||
|
||||
// Erratum: The protocol spec says "requeue." If we put disconnect req back in the
|
||||
// queue we will probably get it back again here while still in same state.
|
||||
// I don't think we would want to delay it until the next state transition.
|
||||
// TODO: "requeue." Not sure what to do here.
|
||||
// If we put it back in the queue we will get it back again probably still in same state.
|
||||
// Need a way to defer it until the next state change.
|
||||
|
||||
// Suppose someone tried to connect to another station, which is not responding, and decided to cancel
|
||||
// before all of the SABMe retries were used up. I think we would want to transmit a DISC, send a disc
|
||||
// notice to the user, and go directly into disconnected state, rather than into awaiting release.
|
||||
|
||||
// New code v1.7 dev, May 6 2023
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Stream %d: In progress connection attempt to %s terminated by user.\n", S->stream_id, S->addrs[PEERCALL]);
|
||||
discard_i_queue (S);
|
||||
SET_RC(0);
|
||||
int p1 = 1;
|
||||
int nopid0 = 0;
|
||||
packet_t pp15 = ax25_u_frame (S->addrs, S->num_addr, cr_cmd, frame_type_U_DISC, p1, nopid0, NULL, 0);
|
||||
lm_data_request (S->chan, TQ_PRIO_1_LO, pp15);
|
||||
|
||||
STOP_T1; // started in establish_data_link.
|
||||
STOP_T3; // probably don't need.
|
||||
enter_new_state (S, state_0_disconnected, __func__, __LINE__);
|
||||
server_link_terminated (S->chan, S->client, S->addrs[PEERCALL], S->addrs[OWNCALL], 0);
|
||||
break;
|
||||
|
||||
|
||||
case state_2_awaiting_release:
|
||||
{
|
||||
// We have previously started the disconnect sequence and are waiting
|
||||
|
@ -1189,15 +1146,6 @@ void dl_disconnect_request (dlq_item_t *E)
|
|||
*
|
||||
* Erratum: Not sure how to interpret that. See example below for how it was implemented.
|
||||
*
|
||||
* Version 1.6: Bug 252. Segmentation was occurring for a V2.0 link. From the spec:
|
||||
* "The receipt of an XID response from the other station establishes that both
|
||||
* stations are using AX.25 version 2.2 or higher and enables the use of the
|
||||
* segmenter/reassembler and selective reject."
|
||||
* "The segmenter/reassembler procedure is only enabled if both stations on the
|
||||
* link are using AX.25 version 2.2 or higher."
|
||||
*
|
||||
* The Segmenter Ready State SDL has no decision based on protocol version.
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
static void data_request_good_size (ax25_dlsm_t *S, cdata_t *txdata);
|
||||
|
@ -1207,6 +1155,8 @@ void dl_data_request (dlq_item_t *E)
|
|||
{
|
||||
ax25_dlsm_t *S;
|
||||
int ok_to_create = 1;
|
||||
int nseg_to_follow;
|
||||
int orig_offset, remaining_len;
|
||||
|
||||
|
||||
S = get_link_handle (E->addrs, E->num_addr, E->chan, E->client, ok_to_create);
|
||||
|
@ -1224,39 +1174,6 @@ void dl_data_request (dlq_item_t *E)
|
|||
return;
|
||||
}
|
||||
|
||||
#define DIVROUNDUP(a,b) (((a)+(b)-1) / (b))
|
||||
|
||||
// Erratum: Don't do V2.2 segmentation for a V2.0 link.
|
||||
// In this case, we can just split it into multiple frames not exceeding the specified max size.
|
||||
// Hopefully the receiving end treats it like a stream and doesn't care about length of each frame.
|
||||
|
||||
if (S->modulo == 8) {
|
||||
|
||||
int num_frames = 0;
|
||||
int remaining_len = E->txdata->len;
|
||||
int offset = 0;
|
||||
|
||||
while (remaining_len > 0) {
|
||||
int this_len = MIN(remaining_len, S->n1_paclen);
|
||||
|
||||
cdata_t *new_txdata = cdata_new(E->txdata->pid, E->txdata->data + offset, this_len);
|
||||
data_request_good_size (S, new_txdata);
|
||||
|
||||
offset += this_len;
|
||||
remaining_len -= this_len;
|
||||
num_frames++;
|
||||
}
|
||||
|
||||
if (num_frames != DIVROUNDUP(E->txdata->len, S->n1_paclen) || remaining_len != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("INTERNAL ERROR, Segmentation line %d, data length = %d, N1 = %d, num frames = %d, remaining len = %d\n",
|
||||
__LINE__, E->txdata->len, S->n1_paclen, num_frames, remaining_len);
|
||||
}
|
||||
cdata_delete (E->txdata);
|
||||
E->txdata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// More interesting case.
|
||||
// It is too large to fit in one frame so we segment it.
|
||||
|
||||
|
@ -1323,7 +1240,7 @@ void dl_data_request (dlq_item_t *E)
|
|||
// We will decrement this before putting it in the frame so the first
|
||||
// will have one less than this number.
|
||||
|
||||
int nseg_to_follow = DIVROUNDUP(E->txdata->len + 1, S->n1_paclen - 1);
|
||||
nseg_to_follow = DIVROUNDUP(E->txdata->len + 1, S->n1_paclen - 1);
|
||||
|
||||
if (nseg_to_follow < 2 || nseg_to_follow > 128) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1334,8 +1251,8 @@ void dl_data_request (dlq_item_t *E)
|
|||
return;
|
||||
}
|
||||
|
||||
int orig_offset = 0;
|
||||
int remaining_len = E->txdata->len;
|
||||
orig_offset = 0;
|
||||
remaining_len = E->txdata->len;
|
||||
|
||||
// First segment.
|
||||
|
||||
|
@ -1479,7 +1396,8 @@ static void data_request_good_size (ax25_dlsm_t *S, cdata_t *txdata)
|
|||
case state_4_timer_recovery:
|
||||
|
||||
if ( ( ! S->peer_receiver_busy ) &&
|
||||
WITHIN_WINDOW_SIZE(S) ) {
|
||||
S->vs != AX25MODULO(S->va + S->k_maxframe, S->modulo, __FILE__, __func__, __LINE__) ) {
|
||||
|
||||
S->acknowledge_pending = 1;
|
||||
lm_seize_request (S->chan);
|
||||
}
|
||||
|
@ -1525,11 +1443,6 @@ void dl_register_callsign (dlq_item_t *E)
|
|||
}
|
||||
|
||||
r = calloc(sizeof(reg_callsign_t),1);
|
||||
if (r == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
strlcpy (r->callsign, E->addrs[0], sizeof(r->callsign));
|
||||
r->chan = E->chan;
|
||||
r->client = E->client;
|
||||
|
@ -1583,138 +1496,6 @@ void dl_unregister_callsign (dlq_item_t *E)
|
|||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
* Name: dl_outstanding_frames_request
|
||||
*
|
||||
* Purpose: Client app wants to know how many frames are still on their way
|
||||
* to other station. This is handy for flow control. We would like
|
||||
* to keep the pipeline filled sufficiently to take advantage of a
|
||||
* large window size (MAXFRAMES). It is also good to know that the
|
||||
* the last packet sent was actually received before we commence
|
||||
* the disconnect.
|
||||
*
|
||||
* Inputs: E - Event from the queue.
|
||||
* The caller will free it.
|
||||
*
|
||||
* Outputs: This gets back to the AGW server which sends the 'Y' reply.
|
||||
*
|
||||
* Description: This is the sum of:
|
||||
* - Incoming connected data, from application still in the queue.
|
||||
* - I frames which have been transmitted but not yet acknowledged.
|
||||
*
|
||||
* Confusion: https://github.com/wb2osz/direwolf/issues/427
|
||||
*
|
||||
* There are different, inconsistent versions of the protocol spec.
|
||||
*
|
||||
* One of them simply has:
|
||||
*
|
||||
* CallFrom is our call
|
||||
* CallTo is the call of the other station
|
||||
*
|
||||
* A more detailed version has the same thing in the table of fields:
|
||||
*
|
||||
* CallFrom 10 bytes Our CallSign
|
||||
* CallTo 10 bytes Other CallSign
|
||||
*
|
||||
* (My first implementation went with that.)
|
||||
*
|
||||
* HOWEVER, shortly after that, is contradictory information:
|
||||
*
|
||||
* Careful must be exercised to fill correctly both the CallFrom
|
||||
* and CallTo fields to match the ones of an existing connection,
|
||||
* otherwise AGWPE won’t return any information at all from this query.
|
||||
*
|
||||
* The order of the CallFrom and CallTo is not trivial, it should
|
||||
* reflect the order used to start the connection, so
|
||||
*
|
||||
* * If we started the connection CallFrom=US and CallTo=THEM
|
||||
* * If the other end started the connection CallFrom=THEM and CallTo=US
|
||||
*
|
||||
* This seems to make everything unnecessarily more complicated.
|
||||
* We should only care about the stream going from the local station to the
|
||||
* remote station. Why would it matter who reqested the link? The state
|
||||
* machine doesn't even contain this information so the TNC doesn't know.
|
||||
* The client app interface needs to behave differently for the two cases.
|
||||
*
|
||||
* The new code, below, May 2023, should handle both of those cases.
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
void dl_outstanding_frames_request (dlq_item_t *E)
|
||||
{
|
||||
ax25_dlsm_t *S;
|
||||
const int ok_to_create = 0; // must exist already.
|
||||
int reversed_addrs = 0;
|
||||
|
||||
if (s_debug_client_app) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dl_outstanding_frames_request ( to %s )\n", E->addrs[PEERCALL]);
|
||||
}
|
||||
|
||||
S = get_link_handle (E->addrs, E->num_addr, E->chan, E->client, ok_to_create);
|
||||
if (S != NULL) {
|
||||
reversed_addrs = 0;
|
||||
}
|
||||
else {
|
||||
// Try swapping the addresses.
|
||||
// this is communicating with the client app, not over the air,
|
||||
// so we don't need to worry about digipeaters.
|
||||
|
||||
char swapped[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
|
||||
memset (swapped, 0, sizeof(swapped));
|
||||
strlcpy (swapped[PEERCALL], E->addrs[OWNCALL], sizeof(swapped[PEERCALL]));
|
||||
strlcpy (swapped[OWNCALL], E->addrs[PEERCALL], sizeof(swapped[OWNCALL]));
|
||||
S = get_link_handle (swapped, E->num_addr, E->chan, E->client, ok_to_create);
|
||||
if (S != NULL) {
|
||||
reversed_addrs = 1;
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Can't get outstanding frames for %s -> %s, chan %d\n", E->addrs[OWNCALL], E->addrs[PEERCALL], E->chan);
|
||||
server_outstanding_frames_reply (E->chan, E->client, E->addrs[OWNCALL], E->addrs[PEERCALL], 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add up these
|
||||
//
|
||||
// cdata_t *i_frame_queue; // Connected data from client which has not been transmitted yet.
|
||||
// // Linked list.
|
||||
// // The name is misleading because these are just blocks of
|
||||
// // data, not "I frames" at this point. The name comes from
|
||||
// // the protocol specification.
|
||||
//
|
||||
// cdata_t *txdata_by_ns[128]; // Data which has already been transmitted.
|
||||
// // Indexed by N(S) in case it gets lost and needs to be sent again.
|
||||
// // Cleared out when we get ACK for it.
|
||||
|
||||
int count1 = 0;
|
||||
cdata_t *incoming;
|
||||
for (incoming = S->i_frame_queue; incoming != NULL; incoming = incoming->next) {
|
||||
count1++;
|
||||
}
|
||||
|
||||
int count2 = 0;
|
||||
int k;
|
||||
for (k = 0; k < S->modulo; k++) {
|
||||
if (S->txdata_by_ns[k] != NULL) {
|
||||
count2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (reversed_addrs) {
|
||||
// Other end initiated the link.
|
||||
server_outstanding_frames_reply (S->chan, S->client, S->addrs[PEERCALL], S->addrs[OWNCALL], count1 + count2);
|
||||
}
|
||||
else {
|
||||
server_outstanding_frames_reply (S->chan, S->client, S->addrs[OWNCALL], S->addrs[PEERCALL], count1 + count2);
|
||||
}
|
||||
|
||||
} // end dl_outstanding_frames_request
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
* Name: dl_client_cleanup
|
||||
|
@ -1728,7 +1509,7 @@ void dl_outstanding_frames_request (dlq_item_t *E)
|
|||
* Description: By client application we mean something that attached with the
|
||||
* AGW network protocol.
|
||||
*
|
||||
* Clean out anything related to the specified client application.
|
||||
* Clean out anything related to the specfied client application.
|
||||
* This would include state machines and registered callsigns.
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
@ -2011,6 +1792,8 @@ static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len)
|
|||
*
|
||||
* Description: We need to pause the timers when the channel is busy.
|
||||
*
|
||||
* Signal lm_seize_confirm when we have started to transmit.
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
static int dcd_status[MAX_CHANS];
|
||||
|
@ -2067,6 +1850,14 @@ void lm_channel_busy (dlq_item_t *E)
|
|||
S->radio_channel_busy = 1;
|
||||
PAUSE_T1;
|
||||
PAUSE_TM201;
|
||||
|
||||
// Did channel become busy due to PTT turning on?
|
||||
|
||||
if ( E->activity == OCTYPE_PTT && E->status == 1) {
|
||||
|
||||
lm_seize_confirm (S); // C4.2. "This primitive indicates, to the Data-link State
|
||||
// machine, that the transmission opportunity has arrived."
|
||||
}
|
||||
}
|
||||
else if ( ! busy && S->radio_channel_busy) {
|
||||
S->radio_channel_busy = 0;
|
||||
|
@ -2101,43 +1892,32 @@ void lm_channel_busy (dlq_item_t *E)
|
|||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
void lm_seize_confirm (dlq_item_t *E)
|
||||
static void lm_seize_confirm (ax25_dlsm_t *S)
|
||||
{
|
||||
|
||||
assert (E->chan >= 0 && E->chan < MAX_CHANS);
|
||||
switch (S->state) {
|
||||
|
||||
ax25_dlsm_t *S;
|
||||
case state_0_disconnected:
|
||||
case state_1_awaiting_connection:
|
||||
case state_2_awaiting_release:
|
||||
case state_5_awaiting_v22_connection:
|
||||
|
||||
for (S = list_head; S != NULL; S = S->next) {
|
||||
break;
|
||||
|
||||
if (E->chan == S->chan) {
|
||||
case state_3_connected:
|
||||
case state_4_timer_recovery:
|
||||
|
||||
// v1.5 change in strategy.
|
||||
// New I frames, not sent yet, are delayed until after processing anything in the received transmission.
|
||||
// Previously we started sending new frames, from the client app, as soon as they arrived.
|
||||
// Now, we first take care of those in progress before throwing more into the mix.
|
||||
|
||||
switch (S->state) {
|
||||
i_frame_pop_off_queue(S);
|
||||
|
||||
case state_0_disconnected:
|
||||
case state_1_awaiting_connection:
|
||||
case state_2_awaiting_release:
|
||||
case state_5_awaiting_v22_connection:
|
||||
|
||||
break;
|
||||
|
||||
case state_3_connected:
|
||||
case state_4_timer_recovery:
|
||||
|
||||
// v1.5 change in strategy.
|
||||
// New I frames, not sent yet, are delayed until after processing anything in the received transmission.
|
||||
// Previously we started sending new frames, from the client app, as soon as they arrived.
|
||||
// Now, we first take care of those in progress before throwing more into the mix.
|
||||
|
||||
i_frame_pop_off_queue(S);
|
||||
|
||||
// Need an RR if we didn't have I frame send the necessary ack.
|
||||
|
||||
if (S->acknowledge_pending) {
|
||||
S->acknowledge_pending = 0;
|
||||
enquiry_response (S, frame_not_AX25, 0);
|
||||
}
|
||||
if (S->acknowledge_pending) {
|
||||
S->acknowledge_pending = 0;
|
||||
enquiry_response (S, frame_not_AX25, 0);
|
||||
}
|
||||
|
||||
// Implementation difference: The flow chart for state 3 has LM-RELEASE Request here.
|
||||
// I don't think I need it because the transmitter will turn off
|
||||
|
@ -2146,9 +1926,7 @@ void lm_seize_confirm (dlq_item_t *E)
|
|||
// Erratum: The original spec had LM-SEIZE request here, for state 4, which didn't seem right.
|
||||
// The 2006 revision has LM-RELEASE Request so states 3 & 4 are the same.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} /* lm_seize_confirm */
|
||||
|
@ -2296,7 +2074,7 @@ void lm_data_indication (dlq_item_t *E)
|
|||
break;
|
||||
|
||||
// Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both.
|
||||
// The underlying X.25 spec clearly says it is response only. Let's go with that.
|
||||
// The underlying X.25 spec clearly says it is reponse only. Let's go with that.
|
||||
|
||||
case frame_type_S_SREJ:
|
||||
case frame_type_U_DM:
|
||||
|
@ -2319,7 +2097,7 @@ void lm_data_indication (dlq_item_t *E)
|
|||
case frame_type_U_UI:
|
||||
// Don't test at this point in case an APRS frame gets thru.
|
||||
// APRS doesn't specify what to put in the Source and Dest C bits.
|
||||
// In practice we see all 4 possible combinations.
|
||||
// In practice we see all 4 possble combinations.
|
||||
// I have an opinion about what would be "correct" (discussed elsewhere)
|
||||
// but in practice no one seems to care.
|
||||
break;
|
||||
|
@ -2425,21 +2203,6 @@ void lm_data_indication (dlq_item_t *E)
|
|||
break;
|
||||
}
|
||||
|
||||
// An incoming frame might have ack'ed frames we sent or indicated peer is no longer busy.
|
||||
// Rather than putting this test in many places, where those conditions, may have changed,
|
||||
// we will try to catch them all on this single path.
|
||||
// Start transmission if we now have some outgoing data ready to go.
|
||||
// (Added in 1.5 beta 3 for issue 132.)
|
||||
|
||||
if ( S->i_frame_queue != NULL &&
|
||||
(S->state == state_3_connected || S->state == state_4_timer_recovery) &&
|
||||
( ! S->peer_receiver_busy ) &&
|
||||
WITHIN_WINDOW_SIZE(S) ) {
|
||||
|
||||
//S->acknowledge_pending = 1;
|
||||
lm_seize_request (S->chan);
|
||||
}
|
||||
|
||||
} /* end lm_data_indication */
|
||||
|
||||
|
||||
|
@ -2796,7 +2559,7 @@ static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *inf
|
|||
|
||||
if (S->rxdata_by_ns[ns] != NULL) {
|
||||
// There is a possibility that we might have another received frame stashed
|
||||
// away from 8 or 128 (modulo) frames back. Remove it so it doesn't accidentally
|
||||
// away from 8 or 128 (modulo) frames back. Remove it so it doesn't accidently
|
||||
// show up at some future inopportune time.
|
||||
|
||||
cdata_delete (S->rxdata_by_ns[ns]);
|
||||
|
@ -2881,7 +2644,7 @@ static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *inf
|
|||
// we discard 3,4,5,6, and tell the other end to resend everything starting with 2.
|
||||
|
||||
// At one time, I had some doubts about when to use command or response for REJ.
|
||||
// I now believe that response, as implied by setting F in the flow chart, is correct.
|
||||
// I now believe that reponse, as implied by setting F in the flow chart, is correct.
|
||||
|
||||
int f = p;
|
||||
int nr = S->vr; // Next expected sequence number.
|
||||
|
@ -2891,7 +2654,7 @@ static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *inf
|
|||
S->reject_exception = 1;
|
||||
|
||||
if (s_debug_retry) {
|
||||
text_color_set(DW_COLOR_ERROR); // make it more noticeable.
|
||||
text_color_set(DW_COLOR_ERROR); // make it more noticable.
|
||||
dw_printf ("sending REJ, at %s %d, SREJ not enabled case, V(R)=%d", __func__, __LINE__, S->vr);
|
||||
}
|
||||
|
||||
|
@ -2955,7 +2718,7 @@ static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *inf
|
|||
// In version 1.4:
|
||||
// We end up sending more SREJ than necessary and and get back redundant information. Example:
|
||||
// When we see 113 missing, we ask for a resend.
|
||||
// When we see 115 & 116 missing, a cumulative SREJ asks for everything.
|
||||
// When we see 115 & 116 missing, a cummulative SREJ asks for everything.
|
||||
// The other end dutifully sends 113 twice.
|
||||
//
|
||||
// [0.4] DW1>DW0:(SREJ res, n(r)=113, f=0)
|
||||
|
@ -2985,7 +2748,7 @@ static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *inf
|
|||
// int allow_f1 = 0; // F=1 from X.25 2.4.6.4 b) 3)
|
||||
int allow_f1 = 1; // F=1 from X.25 2.4.6.4 b) 3)
|
||||
|
||||
// send only for this gap, not cumulative from V(R).
|
||||
// send only for this gap, not cummulative from V(R).
|
||||
|
||||
int last = AX25MODULO(ns - 1, S->modulo, __FILE__, __func__, __LINE__);
|
||||
int first = last;
|
||||
|
@ -3088,7 +2851,7 @@ dw_printf ("%s:%d, %d srej exceptions, V(R)=%d, N(S)=%d\n", __func__, __LINE__,
|
|||
if (first == AX25MODULO(S->vr - 1, S->modulo, __FILE__, __func__, __LINE__)) {
|
||||
// Oops! Went too far. This I frame was already processed.
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("INTERNAL ERROR calculating what to put in SREJ, %s line %d\n", __func__, __LINE__);
|
||||
dw_printf ("INTERNAL ERROR calulating what to put in SREJ, %s line %d\n", __func__, __LINE__);
|
||||
dw_printf ("V(R)=%d, N(S)=%d, SREJ exception=%d, first=%d, ask_resend_count=%d\n", S->vr, ns, selective_reject_exception(S), first, ask_resend_count);
|
||||
int k;
|
||||
for (k=0; k<128; k++) {
|
||||
|
@ -3241,7 +3004,7 @@ static void send_srej_frames (ax25_dlsm_t *S, int *resend, int count, int allow_
|
|||
if (s_debug_retry) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("%s line %d\n", __func__, __LINE__);
|
||||
//dw_printf ("state=%d, count=%d, k=%d, V(R)=%d, SREJ exception=%d\n", S->state, count, S->k_maxframe, S->vr, selective_reject_exception(S));
|
||||
//dw_printf ("state=%d, count=%d, k=%d, V(R)=%d, SREJ exeception=%d\n", S->state, count, S->k_maxframe, S->vr, selective_reject_exception(S));
|
||||
dw_printf ("state=%d, count=%d, k=%d, V(R)=%d\n", S->state, count, S->k_maxframe, S->vr);
|
||||
|
||||
dw_printf ("resend[]=");
|
||||
|
@ -3542,7 +3305,7 @@ static void rr_rnr_frame (ax25_dlsm_t *S, int ready, cmdres_t cr, int pf, int nr
|
|||
// we received RR frames with N(R) values indicating that the other side received everything
|
||||
// that we sent. Eventually rc could reach the limit and we would get an error.
|
||||
// If we are in state 4, and other guy ack'ed last I frame we sent, transition to state 3.
|
||||
// The same thing was done for receiving I frames after check_i_frame_ackd.
|
||||
// The same thing was done for receving I frames after check_i_frame_ackd.
|
||||
|
||||
// Thought: Could we simply call check_i_frame_ackd, for consistency, rather than only setting V(A)?
|
||||
|
||||
|
@ -3854,7 +3617,7 @@ static void rej_frame (ax25_dlsm_t *S, cmdres_t cr, int pf, int nr)
|
|||
*
|
||||
* The SREJ command/response initiates more-efficient error recovery by requesting the retransmission of a
|
||||
* single I frame following the detection of a sequence error. This is an advancement over the earlier versions in
|
||||
* which the requested I frame was retransmitted together with all additional I frames subsequently transmitted and
|
||||
* which the requested I frame was retransmitted togther with all additional I frames subsequently transmitted and
|
||||
* successfully received.
|
||||
*
|
||||
* When a TNC sends one or more SREJ commands, each with the P bit set to "0" or "1", or one or more SREJ
|
||||
|
@ -4504,7 +4267,7 @@ static void disc_frame (ax25_dlsm_t *S, int p)
|
|||
* earliest opportunity. If the TNC is not capable of accepting a SABME command, it responds with a DM frame.
|
||||
*
|
||||
* A TNC that uses a version of AX.25 prior to v2.2 responds with a FRMR.
|
||||
* ( I think the KPC-3+ has a bug - it replies with DM - WB2OSZ )
|
||||
* ( I think the KPC-3+ has a bug - it replys with DM - WB2OSZ )
|
||||
*
|
||||
* 4.3.3.5. Disconnected Mode (DM) Response
|
||||
*
|
||||
|
@ -4731,7 +4494,7 @@ static void ua_frame (ax25_dlsm_t *S, int f)
|
|||
if (f == 1) {
|
||||
if (S->layer_3_initiated) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
// TODO: add via if appropriate.
|
||||
// TODO: add via if apppropriate.
|
||||
dw_printf ("Stream %d: Connected to %s. (%s)\n", S->stream_id, S->addrs[PEERCALL], S->state == state_5_awaiting_v22_connection ? "v2.2" : "v2.0");
|
||||
// There is a subtle difference here between connect confirm and indication.
|
||||
// connect *confirm* means "has been made"
|
||||
|
@ -5710,7 +5473,7 @@ static void clear_exception_conditions (ax25_dlsm_t *S)
|
|||
*
|
||||
* Other guy gets RR/RNR command P=1.
|
||||
* Same action for either state 3 or 4.
|
||||
* Whether he has outstanding un-ack'ed sent I frames is irrelevant.
|
||||
* Whether he has outstanding un-ack'ed sent I frames is irrelevent.
|
||||
* He calls "enquiry response" which sends RR/RNR response F=1.
|
||||
* (Read about detour 1 below and in enquiry_response.)
|
||||
*
|
||||
|
@ -6130,7 +5893,7 @@ static void check_need_for_response (ax25_dlsm_t *S, ax25_frame_type_t frame_typ
|
|||
*
|
||||
* Outputs: S->srt New smoothed roundtrip time.
|
||||
*
|
||||
* S->t1v How long to wait for an acknowledgement before resending.
|
||||
* S->t1v How long to wait for an acknowlegement before resending.
|
||||
* Value used when starting timer T1, in seconds.
|
||||
* Here it is dynamically adjusted.
|
||||
*
|
||||
|
@ -6229,7 +5992,7 @@ static void select_t1_value (ax25_dlsm_t *S)
|
|||
|
||||
// This goes up exponentially if implemented as documented!
|
||||
// For example, if we were trying to connect to a station which is not there, we
|
||||
// would retry after 3, then 8, 16, 32, ... and not time out for over an hour.
|
||||
// would retry after 3, the 8, 16, 32, ... and not time out for over an hour.
|
||||
// That's ridiculous. Let's try increasing it by a quarter second each time.
|
||||
// We now give up after about a minute.
|
||||
|
||||
|
@ -6246,30 +6009,12 @@ static void select_t1_value (ax25_dlsm_t *S)
|
|||
}
|
||||
|
||||
|
||||
// See https://groups.io/g/direwolf/topic/100782658#8542
|
||||
// Perhaps the demands of file transfer lead to this problem.
|
||||
|
||||
// "Temporary" hack.
|
||||
// Automatic fine tuning of t1v generally works well, but on very rare occasions, it gets wildly out of control.
|
||||
// Until I have more time to properly diagnose this, add some guardrails so it does not go flying off a cliff.
|
||||
|
||||
// The initial value of t1v is frack + frack * 2 (number of digipeateers in path)
|
||||
// If anything, it should automatically be adjusted down.
|
||||
// Let's say, something smells fishy if it exceeds twice that initial value.
|
||||
|
||||
// TODO: Add some instrumentation to record where this was called from and all the values in the printf below.
|
||||
|
||||
#if 1
|
||||
if (S->t1v < 0.25 || S->t1v > 2 * (g_misc_config_p->frack * (2 * (S->num_addr - 2) + 1)) ) {
|
||||
INIT_T1V_SRT;
|
||||
}
|
||||
#else
|
||||
if (S->t1v < 0.99 || S->t1v > 30) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("INTERNAL ERROR? Stream %d: select_t1_value, rc = %d, t1 remaining = %.3f, old srt = %.3f, new srt = %.3f, Extreme new t1v = %.3f\n",
|
||||
S->stream_id, S->rc, S->t1_remaining_when_last_stopped, old_srt, S->srt, S->t1v);
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* end select_t1_value */
|
||||
|
||||
|
||||
|
@ -6456,7 +6201,7 @@ static void i_frame_pop_off_queue (ax25_dlsm_t *S)
|
|||
|
||||
while ( ( ! S->peer_receiver_busy ) &&
|
||||
S->i_frame_queue != NULL &&
|
||||
WITHIN_WINDOW_SIZE(S) ) {
|
||||
S->vs != AX25MODULO(S->va + S->k_maxframe, S->modulo, __FILE__, __func__, __LINE__) ) {
|
||||
|
||||
cdata_t *txdata;
|
||||
|
||||
|
@ -6612,18 +6357,7 @@ static void mdl_negotiate_request (ax25_dlsm_t *S)
|
|||
int p = 1;
|
||||
int nopid = 0;
|
||||
packet_t pp;
|
||||
int n;
|
||||
|
||||
// At least one known [partial] v2.2 implementation understands SABME but not XID.
|
||||
// Rather than wasting time, sending XID repeatedly until giving up, we have a workaround.
|
||||
// The configuration file can contain a list of stations known not to respond to XID.
|
||||
// Obviously this applies only to v2.2 because XID was not part of v2.0.
|
||||
|
||||
for (n = 0; n < g_misc_config_p->noxid_count; n++) {
|
||||
if (strcmp(S->addrs[PEERCALL],g_misc_config_p->noxid_addrs[n]) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (S->mdl_state) {
|
||||
|
|
@ -52,8 +52,6 @@ void ax25_link_init (struct misc_config_s *pconfig);
|
|||
// These functions must be called on a single thread, one at a time.
|
||||
// The Data Link Queue (DLQ) is used to serialize events from multiple sources.
|
||||
|
||||
// Maybe the dispatch switch should be moved to ax25_link.c so they can all
|
||||
// be made static and they can't be called from the wrong place accidentally.
|
||||
|
||||
void dl_connect_request (dlq_item_t *E);
|
||||
|
||||
|
@ -65,15 +63,11 @@ void dl_register_callsign (dlq_item_t *E);
|
|||
|
||||
void dl_unregister_callsign (dlq_item_t *E);
|
||||
|
||||
void dl_outstanding_frames_request (dlq_item_t *E);
|
||||
|
||||
void dl_client_cleanup (dlq_item_t *E);
|
||||
|
||||
|
||||
void lm_data_indication (dlq_item_t *E);
|
||||
|
||||
void lm_seize_confirm (dlq_item_t *E);
|
||||
|
||||
void lm_channel_busy (dlq_item_t *E);
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011 , 2013, 2014, 2015, 2019 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011 , 2013, 2014, 2015 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
|
||||
|
@ -49,7 +49,7 @@
|
|||
*
|
||||
*
|
||||
* APRS uses only UI frames.
|
||||
* Each starts with 2-10 addresses (14-70 octets):
|
||||
* Each starts with 2-10 addressses (14-70 octets):
|
||||
*
|
||||
* * Destination Address (note: opposite order in printed format)
|
||||
*
|
||||
|
@ -87,18 +87,18 @@
|
|||
* http://www.aprs.org/aprs12/preemptive-digipeating.txt
|
||||
* http://www.aprs.org/aprs12/RR-bits.txt
|
||||
*
|
||||
* I don't recall why I originally set the source & destination C bits both to 1.
|
||||
* I don't recall why I originally intended to set the source/destination C bits both to 1.
|
||||
* Reviewing this 5 years later, after spending more time delving into the
|
||||
* AX.25 spec, I think it should be 1 for destination and 0 for source.
|
||||
* In practice you see all four combinations being used by APRS stations
|
||||
* and everyone apparently ignores them for APRS. They do make a big
|
||||
* difference for connected mode.
|
||||
* and no one really cares about these two bits.
|
||||
*
|
||||
* The final octet of the Source has the form:
|
||||
*
|
||||
* C R R SSID 0, where,
|
||||
*
|
||||
* C = command/response = 0
|
||||
* C = command/response = 1 (originally, now I think it should be 0 for source.)
|
||||
* (Haven't gone back to check to see what code actually does.)
|
||||
* R R = Reserved = 1 1
|
||||
* SSID = substation ID
|
||||
* 0 = zero (or 1 if no repeaters)
|
||||
|
@ -350,9 +350,8 @@ void ax25_delete (packet_t this_p)
|
|||
* strict - True to enforce rules for packets sent over the air.
|
||||
* False to be more lenient for packets from IGate server.
|
||||
*
|
||||
* Packets from an IGate server can have longer
|
||||
* addresses after qAC. Up to 9 observed so far.
|
||||
* The SSID can be 2 alphanumeric characters, not just 1 to 15.
|
||||
* Messages from an IGate server can have longer
|
||||
* addresses after qAC. Up to 9 observed so far.
|
||||
*
|
||||
* We can just truncate the name because we will only
|
||||
* end up discarding it. TODO: check on this.
|
||||
|
@ -373,8 +372,11 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
/*
|
||||
* Tearing it apart is destructive so make our own copy first.
|
||||
*/
|
||||
char stuff[AX25_MAX_PACKET_LEN+1];
|
||||
char stuff[512];
|
||||
|
||||
char *pinfo;
|
||||
char *pa;
|
||||
char *saveptr; /* Used with strtok_r because strtok is not thread safe. */
|
||||
|
||||
int ssid_temp, heard_temp;
|
||||
char atemp[AX25_MAX_ADDR_LEN];
|
||||
|
@ -382,10 +384,6 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
char info_part[AX25_MAX_INFO_LEN+1];
|
||||
int info_len;
|
||||
|
||||
// text_color_set(DW_COLOR_DEBUG);
|
||||
// dw_printf ("DEBUG: ax25_from_text ('%s', %d)\n", monitor, strict);
|
||||
// fflush(stdout); sleep(1);
|
||||
|
||||
packet_t this_p = ax25_new ();
|
||||
|
||||
#if AX25MEMDEBUG
|
||||
|
@ -412,15 +410,14 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
this_p->frame_data[AX25_DESTINATION*7+6] = SSID_H_MASK | SSID_RR_MASK;
|
||||
|
||||
memset (this_p->frame_data + AX25_SOURCE*7, ' ' << 1, 6);
|
||||
this_p->frame_data[AX25_SOURCE*7+6] = SSID_RR_MASK | SSID_LAST_MASK;
|
||||
this_p->frame_data[AX25_SOURCE*7+6] = SSID_H_MASK | SSID_RR_MASK | SSID_LAST_MASK;
|
||||
|
||||
this_p->frame_data[14] = AX25_UI_FRAME;
|
||||
this_p->frame_data[15] = AX25_PID_NO_LAYER_3;
|
||||
|
||||
this_p->frame_len = 7 + 7 + 1 + 1;
|
||||
this_p->num_addr = (-1);
|
||||
(void) ax25_get_num_addr(this_p); // when num_addr is -1, this sets it properly.
|
||||
assert (this_p->num_addr == 2);
|
||||
assert (ax25_get_num_addr(this_p) == 2);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -443,10 +440,9 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
|
||||
/*
|
||||
* Source address.
|
||||
* Don't use traditional strtok because it is not thread safe.
|
||||
*/
|
||||
|
||||
char *pnxt = stuff;
|
||||
char *pa = strsep (&pnxt, ">");
|
||||
pa = strtok_r (stuff, ">", &saveptr);
|
||||
if (pa == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Failed to create packet from text. No source address\n");
|
||||
|
@ -469,7 +465,7 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
* Destination address.
|
||||
*/
|
||||
|
||||
pa = strsep (&pnxt, ",");
|
||||
pa = strtok_r (NULL, ",", &saveptr);
|
||||
if (pa == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Failed to create packet from text. No destination address\n");
|
||||
|
@ -491,33 +487,11 @@ packet_t ax25_from_text (char *monitor, int strict)
|
|||
/*
|
||||
* VIA path.
|
||||
*/
|
||||
while (( pa = strtok_r (NULL, ",", &saveptr)) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
|
||||
|
||||
// Originally this used strtok_r.
|
||||
// strtok considers all adjacent delimiters to be a single delimiter.
|
||||
// This is handy for varying amounts of whitespace.
|
||||
// It will never return a zero length string.
|
||||
// All was good until this bizarre case came along:
|
||||
int k;
|
||||
|
||||
// AISAT-1>CQ,,::CQ-0 :From AMSAT INDIA & Exseed Space |114304|48|45|42{962
|
||||
|
||||
// Apparently there are two digipeater fields but they are empty.
|
||||
// When we parsed this text representation, the extra commas were ignored rather
|
||||
// than pointed out as being invalid.
|
||||
|
||||
// Use strsep instead. This does not collapse adjacent delimiters.
|
||||
|
||||
while (( pa = strsep (&pnxt, ",")) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
|
||||
|
||||
int k = this_p->num_addr;
|
||||
|
||||
// printf ("DEBUG: get digi loop, num addr = %d, address = '%s'\n", k, pa);// FIXME
|
||||
|
||||
// Hack for q construct, from APRS-IS, so it does not cause panic later.
|
||||
|
||||
if ( ! strict && pa[0] == 'q' && pa[1] == 'A') {
|
||||
pa[0] = 'Q';
|
||||
pa[2] = toupper(pa[2]);
|
||||
}
|
||||
k = this_p->num_addr;
|
||||
|
||||
if ( ! ax25_parse_addr (k, pa, strict, atemp, &ssid_temp, &heard_temp)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -741,7 +715,6 @@ packet_t ax25_dup (packet_t copy_from)
|
|||
* alphanumeric characters for the SSID.
|
||||
* We also get messages like this from a server.
|
||||
* KB1POR>APU25N,TCPIP*,qAC,T2NUENGLD:...
|
||||
* K1BOS-B>APOSB,TCPIP,WR2X-2*:...
|
||||
*
|
||||
* 2 (extra true) will complain if * is found at end.
|
||||
*
|
||||
|
@ -753,7 +726,7 @@ packet_t ax25_dup (packet_t copy_from)
|
|||
* out_heard - True if "*" found.
|
||||
*
|
||||
* Returns: True (1) if OK, false (0) if any error.
|
||||
* When 0, out_addr, out_ssid, and out_heard are undefined.
|
||||
* When 0, out_addr, out_ssid, and out_heard are unpredictable.
|
||||
*
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
@ -774,17 +747,10 @@ int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, in
|
|||
*out_ssid = 0;
|
||||
*out_heard = 0;
|
||||
|
||||
// dw_printf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict);
|
||||
|
||||
if (position < -1) position = -1;
|
||||
if (position > AX25_REPEATER_8) position = AX25_REPEATER_8;
|
||||
position++; /* Adjust for position_name above. */
|
||||
|
||||
if (strlen(in_addr) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("%sAddress \"%s\" is empty.\n", position_name[position], in_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) {
|
||||
|
||||
|
@ -793,7 +759,8 @@ int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, in
|
|||
dw_printf ("APRS Internet Servers. It should never appear when going over the radio.\n");
|
||||
}
|
||||
|
||||
// dw_printf ("ax25_parse_addr in: %s\n", in_addr);
|
||||
//dw_printf ("ax25_parse_addr in: %s\n", in_addr);
|
||||
|
||||
|
||||
maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN-1);
|
||||
p = in_addr;
|
||||
|
@ -871,7 +838,7 @@ int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, in
|
|||
return 0;
|
||||
}
|
||||
|
||||
// dw_printf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard);
|
||||
//dw_printf ("ax25_parse_addr out: %s %d %d\n", out_addr, *out_ssid, *out_heard);
|
||||
|
||||
return (1);
|
||||
|
||||
|
@ -949,7 +916,7 @@ int ax25_check_addresses (packet_t pp)
|
|||
*
|
||||
* Name: ax25_unwrap_third_party
|
||||
*
|
||||
* Purpose: Unwrap a third party message from the header.
|
||||
* Purpose: Unwrap a third party messge from the header.
|
||||
*
|
||||
* Inputs: copy_from - Existing packet object.
|
||||
*
|
||||
|
@ -1017,11 +984,6 @@ void ax25_set_addr (packet_t this_p, int n, char *ad)
|
|||
|
||||
//dw_printf ("ax25_set_addr (%d, %s) num_addr=%d\n", n, ad, this_p->num_addr);
|
||||
|
||||
if (strlen(ad) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Set address error! Station address for position %d is empty!\n", n);
|
||||
}
|
||||
|
||||
if (n >= 0 && n < this_p->num_addr) {
|
||||
|
||||
//dw_printf ("ax25_set_addr , existing case\n");
|
||||
|
@ -1103,11 +1065,6 @@ void ax25_insert_addr (packet_t this_p, int n, char *ad)
|
|||
|
||||
//dw_printf ("ax25_insert_addr (%d, %s)\n", n, ad);
|
||||
|
||||
if (strlen(ad) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Set address error! Station address for position %d is empty!\n", n);
|
||||
}
|
||||
|
||||
/* Don't do it if we already have the maximum number. */
|
||||
/* Should probably return success/fail code but currently the caller doesn't care. */
|
||||
|
||||
|
@ -1338,21 +1295,12 @@ void ax25_get_addr_with_ssid (packet_t this_p, int n, char *station)
|
|||
station[6] = '\0';
|
||||
|
||||
for (i=5; i>=0; i--) {
|
||||
if (station[i] == '\0') {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Station address \"%s\" contains nul character. AX.25 protocol requires trailing ASCII spaces when less than 6 characters.\n", station);
|
||||
}
|
||||
else if (station[i] == ' ')
|
||||
if (station[i] == ' ')
|
||||
station[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen(station) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n);
|
||||
}
|
||||
|
||||
ssid = ax25_get_ssid (this_p, n);
|
||||
if (ssid != 0) {
|
||||
snprintf (sstr, sizeof(sstr), "-%d", ssid);
|
||||
|
@ -1427,11 +1375,6 @@ void ax25_get_addr_no_ssid (packet_t this_p, int n, char *station)
|
|||
break;
|
||||
}
|
||||
|
||||
if (strlen(station) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n);
|
||||
}
|
||||
|
||||
} /* end ax25_get_addr_no_ssid */
|
||||
|
||||
|
||||
|
@ -1726,19 +1669,6 @@ int ax25_get_info (packet_t this_p, unsigned char **paddr)
|
|||
} /* end ax25_get_info */
|
||||
|
||||
|
||||
void ax25_set_info (packet_t this_p, unsigned char *new_info_ptr, int new_info_len)
|
||||
{
|
||||
unsigned char *old_info_ptr;
|
||||
int old_info_len = ax25_get_info (this_p, &old_info_ptr);
|
||||
this_p->frame_len -= old_info_len;
|
||||
|
||||
if (new_info_len < 0) new_info_len = 0;
|
||||
if (new_info_len > AX25_MAX_INFO_LEN) new_info_len = AX25_MAX_INFO_LEN;
|
||||
memcpy (old_info_ptr, new_info_ptr, new_info_len);
|
||||
this_p->frame_len += new_info_len;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
* Name: ax25_cut_at_crlf
|
||||
|
@ -1866,7 +1796,7 @@ packet_t ax25_get_nextp (packet_t this_p)
|
|||
*
|
||||
* Inputs: this_p - Current packet object.
|
||||
*
|
||||
* release_time - Time as returned by dtime_monotonic().
|
||||
* release_time - Time as returned by dtime_now().
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -1914,25 +1844,6 @@ void ax25_set_modulo (packet_t this_p, int modulo)
|
|||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
* Name: ax25_get_modulo
|
||||
*
|
||||
* Purpose: Get modulo value for I and S frame sequence numbers.
|
||||
*
|
||||
* Returns: 8 or 128 if known.
|
||||
* 0 if unknown.
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
int ax25_get_modulo (packet_t this_p)
|
||||
{
|
||||
assert (this_p->magic1 == MAGIC);
|
||||
assert (this_p->magic2 == MAGIC);
|
||||
|
||||
return (this_p->modulo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1985,7 +1896,6 @@ void ax25_format_addrs (packet_t this_p, char *result)
|
|||
}
|
||||
|
||||
ax25_get_addr_with_ssid (this_p, AX25_SOURCE, stemp);
|
||||
// FIXME: For ALL strcat: Pass in sizeof result and use strlcat.
|
||||
strcat (result, stemp);
|
||||
strcat (result, ">");
|
||||
|
||||
|
@ -2004,8 +1914,6 @@ void ax25_format_addrs (packet_t this_p, char *result)
|
|||
}
|
||||
|
||||
strcat (result, ":");
|
||||
|
||||
// dw_printf ("DEBUG ax25_format_addrs, num_addr = %d, result = '%s'\n", this_p->num_addr, result);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2113,7 +2021,7 @@ int ax25_pack (packet_t this_p, unsigned char result[AX25_MAX_PACKET_LEN])
|
|||
*
|
||||
* Outputs: desc - Text description such as "I frame" or
|
||||
* "U frame SABME".
|
||||
* Supply 56 bytes to be safe.
|
||||
* Supply 40 bytes to be safe.
|
||||
*
|
||||
* cr - Command or response?
|
||||
*
|
||||
|
@ -2129,7 +2037,7 @@ int ax25_pack (packet_t this_p, unsigned char result[AX25_MAX_PACKET_LEN])
|
|||
|
||||
// TODO: need someway to ensure caller allocated enough space.
|
||||
// Should pass in as parameter.
|
||||
#define DESC_SIZ 56
|
||||
#define DESC_SIZ 40
|
||||
|
||||
|
||||
ax25_frame_type_t ax25_frame_type (packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns)
|
||||
|
@ -2400,30 +2308,16 @@ void ax25_hex_dump (packet_t this_p)
|
|||
dw_printf ("%s\n", cp_text);
|
||||
}
|
||||
|
||||
// Address fields must be only upper case letters and digits.
|
||||
// If less than 6 characters, trailing positions are filled with ASCII space.
|
||||
// Using all zero bits in one of these 6 positions is wrong.
|
||||
// Any non printable characters will be printed as "." here.
|
||||
|
||||
dw_printf (" dest %c%c%c%c%c%c %2d c/r=%d res=%d last=%d\n",
|
||||
isprint(fptr[0]>>1) ? fptr[0]>>1 : '.',
|
||||
isprint(fptr[1]>>1) ? fptr[1]>>1 : '.',
|
||||
isprint(fptr[2]>>1) ? fptr[2]>>1 : '.',
|
||||
isprint(fptr[3]>>1) ? fptr[3]>>1 : '.',
|
||||
isprint(fptr[4]>>1) ? fptr[4]>>1 : '.',
|
||||
isprint(fptr[5]>>1) ? fptr[5]>>1 : '.',
|
||||
dw_printf (" dest %c%c%c%c%c%c %2d c/r=%d res=%d last=%d\n",
|
||||
fptr[0]>>1, fptr[1]>>1, fptr[2]>>1, fptr[3]>>1, fptr[4]>>1, fptr[5]>>1,
|
||||
(fptr[6]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
|
||||
(fptr[6]&SSID_H_MASK)>>SSID_H_SHIFT,
|
||||
(fptr[6]&SSID_RR_MASK)>>SSID_RR_SHIFT,
|
||||
fptr[6]&SSID_LAST_MASK);
|
||||
|
||||
dw_printf (" source %c%c%c%c%c%c %2d c/r=%d res=%d last=%d\n",
|
||||
isprint(fptr[7]>>1) ? fptr[7]>>1 : '.',
|
||||
isprint(fptr[8]>>1) ? fptr[8]>>1 : '.',
|
||||
isprint(fptr[9]>>1) ? fptr[9]>>1 : '.',
|
||||
isprint(fptr[10]>>1) ? fptr[10]>>1 : '.',
|
||||
isprint(fptr[11]>>1) ? fptr[11]>>1 : '.',
|
||||
isprint(fptr[12]>>1) ? fptr[12]>>1 : '.',
|
||||
fptr[7]>>1, fptr[8]>>1, fptr[9]>>1, fptr[10]>>1, fptr[11]>>1, fptr[12]>>1,
|
||||
(fptr[13]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
|
||||
(fptr[13]&SSID_H_MASK)>>SSID_H_SHIFT,
|
||||
(fptr[13]&SSID_RR_MASK)>>SSID_RR_SHIFT,
|
||||
|
@ -2433,12 +2327,7 @@ void ax25_hex_dump (packet_t this_p)
|
|||
|
||||
dw_printf (" digi %d %c%c%c%c%c%c %2d h=%d res=%d last=%d\n",
|
||||
n - 1,
|
||||
isprint(fptr[n*7+0]>>1) ? fptr[n*7+0]>>1 : '.',
|
||||
isprint(fptr[n*7+1]>>1) ? fptr[n*7+1]>>1 : '.',
|
||||
isprint(fptr[n*7+2]>>1) ? fptr[n*7+2]>>1 : '.',
|
||||
isprint(fptr[n*7+3]>>1) ? fptr[n*7+3]>>1 : '.',
|
||||
isprint(fptr[n*7+4]>>1) ? fptr[n*7+4]>>1 : '.',
|
||||
isprint(fptr[n*7+5]>>1) ? fptr[n*7+5]>>1 : '.',
|
||||
fptr[n*7+0]>>1, fptr[n*7+1]>>1, fptr[n*7+2]>>1, fptr[n*7+3]>>1, fptr[n*7+4]>>1, fptr[n*7+5]>>1,
|
||||
(fptr[n*7+6]&SSID_SSID_MASK)>>SSID_SSID_SHIFT,
|
||||
(fptr[n*7+6]&SSID_H_MASK)>>SSID_H_SHIFT,
|
||||
(fptr[n*7+6]&SSID_RR_MASK)>>SSID_RR_SHIFT,
|
||||
|
@ -2640,15 +2529,6 @@ int ax25_get_frame_len (packet_t this_p)
|
|||
} /* end ax25_get_frame_len */
|
||||
|
||||
|
||||
unsigned char *ax25_get_frame_data_ptr (packet_t this_p)
|
||||
{
|
||||
assert (this_p->magic1 == MAGIC);
|
||||
assert (this_p->magic2 == MAGIC);
|
||||
|
||||
return (this_p->frame_data);
|
||||
|
||||
} /* end ax25_get_frame_data_ptr */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
|
@ -2761,7 +2641,6 @@ unsigned short ax25_m_m_crc (packet_t pp)
|
|||
unsigned char fbuf[AX25_MAX_PACKET_LEN];
|
||||
int flen;
|
||||
|
||||
// TODO: I think this can be more efficient by getting the packet content pointer instead of copying.
|
||||
flen = ax25_pack (pp, fbuf);
|
||||
|
||||
crc = 0xffff;
|
||||
|
@ -2814,8 +2693,7 @@ unsigned short ax25_m_m_crc (packet_t pp)
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
//#define MAXSAFE 500
|
||||
#define MAXSAFE AX25_MAX_INFO_LEN
|
||||
#define MAXSAFE 500
|
||||
|
||||
void ax25_safe_print (char *pstr, int len, int ascii_only)
|
||||
{
|
||||
|
@ -2923,9 +2801,7 @@ int ax25_alevel_to_text (alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE])
|
|||
|
||||
snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d(%+d/%+d)", alevel.rec, alevel.mark, alevel.space);
|
||||
}
|
||||
else if ((alevel.mark == -1 && alevel.space == -1) || /* PSK */
|
||||
(alevel.mark == -99 && alevel.space == -99)) { /* v. 1.7 "B" FM demodulator. */
|
||||
// ?? Where does -99 come from?
|
||||
else if (alevel.mark == -1 && alevel.space == -1) { /* PSK - single number. */
|
||||
|
||||
snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d", alevel.rec);
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
|
||||
#define AX25_MAX_REPEATERS 8
|
||||
#define AX25_MIN_ADDRS 2 /* Destination & Source. */
|
||||
#define AX25_MIN_ADDRS 2 /* Destinatin & Source. */
|
||||
#define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */
|
||||
|
||||
#define AX25_DESTINATION 0 /* Address positions in frame. */
|
||||
|
@ -98,7 +98,7 @@ struct packet_s {
|
|||
*
|
||||
* Bits: H R R SSID 0
|
||||
*
|
||||
* H for digipeaters set to 0 initially.
|
||||
* H for digipeaters set to 0 intially.
|
||||
* Changed to 1 when position has been used.
|
||||
*
|
||||
* for source & destination it is called
|
||||
|
@ -397,7 +397,6 @@ extern int ax25_get_first_not_repeated(packet_t pp);
|
|||
extern int ax25_get_rr (packet_t this_p, int n);
|
||||
|
||||
extern int ax25_get_info (packet_t pp, unsigned char **paddr);
|
||||
extern void ax25_set_info (packet_t pp, unsigned char *info_ptr, int info_len);
|
||||
extern int ax25_cut_at_crlf (packet_t this_p);
|
||||
|
||||
extern void ax25_set_nextp (packet_t this_p, packet_t next_p);
|
||||
|
@ -410,7 +409,6 @@ extern void ax25_set_release_time (packet_t this_p, double release_time);
|
|||
extern double ax25_get_release_time (packet_t this_p);
|
||||
|
||||
extern void ax25_set_modulo (packet_t this_p, int modulo);
|
||||
extern int ax25_get_modulo (packet_t this_p);
|
||||
|
||||
extern void ax25_format_addrs (packet_t pp, char *);
|
||||
extern void ax25_format_via_path (packet_t this_p, char *result, size_t result_size);
|
||||
|
@ -430,7 +428,6 @@ extern int ax25_get_c2 (packet_t this_p);
|
|||
extern int ax25_get_pid (packet_t this_p);
|
||||
|
||||
extern int ax25_get_frame_len (packet_t this_p);
|
||||
extern unsigned char *ax25_get_frame_data_ptr (packet_t this_p);
|
||||
|
||||
extern unsigned short ax25_dedupe_crc (packet_t pp);
|
||||
|
||||
|
@ -438,7 +435,7 @@ extern unsigned short ax25_m_m_crc (packet_t pp);
|
|||
|
||||
extern void ax25_safe_print (char *, int, int ascii_only);
|
||||
|
||||
#define AX25_ALEVEL_TO_TEXT_SIZE 40 // overkill but safe.
|
||||
#define AX25_ALEVEL_TO_TEXT_SIZE 32 // overkill but safe.
|
||||
extern int ax25_alevel_to_text (alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]);
|
||||
|
||||
|
|
@ -102,9 +102,7 @@
|
|||
*
|
||||
* RR note: It seems that some implementations put a hint
|
||||
* in the "RR" reserved bits.
|
||||
* http://www.tapr.org/pipermail/ax25-layer2/2005-October/000297.html (now broken)
|
||||
* https://elixir.bootlin.com/linux/latest/source/net/ax25/ax25_addr.c#L237
|
||||
*
|
||||
* http://www.tapr.org/pipermail/ax25-layer2/2005-October/000297.html
|
||||
* The RR bits can also be used for "DAMA" which is
|
||||
* some sort of channel access coordination scheme.
|
||||
* http://internet.freepage.de/cgi-bin/feets/freepage_ext/41030x030A/rewrite/hennig/afu/afudoc/afudama.html
|
||||
|
@ -408,7 +406,7 @@ packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_ad
|
|||
}
|
||||
|
||||
// Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both.
|
||||
// The underlying X.25 spec clearly says it is response only. Let's go with that.
|
||||
// The underlying X.25 spec clearly says it is reponse only. Let's go with that.
|
||||
|
||||
if (ftype == frame_type_S_SREJ && cr != cr_res) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -798,7 +796,7 @@ int main ()
|
|||
|
||||
for (pf = 0; pf <= 1; pf++) {
|
||||
|
||||
int cmin = 0, cmax = 1;
|
||||
int cmin, cmax;
|
||||
|
||||
switch (ftype) {
|
||||
// 0 = response, 1 = command
|
||||
|
@ -869,7 +867,7 @@ int main ()
|
|||
|
||||
/* SREJ is only S frame which can have information part. */
|
||||
|
||||
static unsigned char srej_info[] = { 1<<1, 2<<1, 3<<1, 4<<1 };
|
||||
static char srej_info[] = { 1<<1, 2<<1, 3<<1, 4<<1 };
|
||||
|
||||
ftype = frame_type_S_SREJ;
|
||||
for (pf = 0; pf <= 1; pf++) {
|
|
@ -59,6 +59,26 @@
|
|||
#include "mheard.h"
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
/*
|
||||
* Windows doesn't have localtime_r.
|
||||
* It should have the equivalent localtime_s, with opposite parameter
|
||||
* order, but I get undefined reference when trying to use it.
|
||||
*/
|
||||
|
||||
struct tm *localtime_r(time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tm;
|
||||
|
||||
tm = localtime (clock);
|
||||
memcpy (res, tm, sizeof(struct tm));
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Save pointers to configuration settings.
|
||||
*/
|
||||
|
@ -152,20 +172,12 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
* If a serious error is found, set type to BEACON_IGNORE and that
|
||||
* table entry should be ignored later on.
|
||||
*/
|
||||
|
||||
// TODO: Better checking.
|
||||
// We should really have a table for which keywords are are required,
|
||||
// optional, or not allowed for each beacon type. Options which
|
||||
// are not applicable are often silently ignored, causing confusion.
|
||||
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
int chan = g_misc_config_p->beacon[j].sendto_chan;
|
||||
|
||||
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
|
||||
if (chan >= MAX_CHANS) chan = 0; // For ICHANNEL, use channel 0 call.
|
||||
|
||||
if (g_modem_config_p->chan_medium[chan] == MEDIUM_RADIO ||
|
||||
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) {
|
||||
if (g_modem_config_p->achan[chan].valid) {
|
||||
|
||||
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 &&
|
||||
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 &&
|
||||
|
@ -195,18 +207,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* INFO and INFOCMD are only for Custom Beacon. */
|
||||
|
||||
if (g_misc_config_p->beacon[j].custom_info != NULL || g_misc_config_p->beacon[j].custom_infocmd != NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: INFO or INFOCMD are allowed only for custom beacon.\n", g_misc_config_p->beacon[j].lineno);
|
||||
dw_printf ("INFO and INFOCMD allow you to specify contents of the Information field so it\n");
|
||||
dw_printf ("so it would not make sense to use these with other beacon types which construct\n");
|
||||
dw_printf ("the Information field. Perhaps you want to use COMMENT or COMMENTCMD option.\n");
|
||||
//g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case BEACON_TRACKER:
|
||||
|
@ -221,29 +221,8 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: GPS must be configured to use TBEACON.\n", g_misc_config_p->beacon[j].lineno);
|
||||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
#if __WIN32__
|
||||
dw_printf ("You must specify the GPSNMEA command in your configuration file.\n");
|
||||
dw_printf ("This contains the name of the serial port where the receiver is connected.\n");
|
||||
#else
|
||||
dw_printf ("You must specify the source of the GPS data in your configuration file.\n");
|
||||
dw_printf ("It can be either GPSD, meaning the gpsd daemon, or GPSNMEA for\n");
|
||||
dw_printf ("for a serial port connection with exclusive use.\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* INFO and INFOCMD are only for Custom Beacon. */
|
||||
|
||||
if (g_misc_config_p->beacon[j].custom_info != NULL || g_misc_config_p->beacon[j].custom_infocmd != NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: INFO or INFOCMD are allowed only for custom beacon.\n", g_misc_config_p->beacon[j].lineno);
|
||||
dw_printf ("INFO and INFOCMD allow you to specify contents of the Information field so it\n");
|
||||
dw_printf ("so it would not make sense to use these with other beacon types which construct\n");
|
||||
dw_printf ("the Information field. Perhaps you want to use COMMENT or COMMENTCMD option.\n");
|
||||
//g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case BEACON_CUSTOM:
|
||||
|
@ -384,7 +363,7 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
#else
|
||||
int e;
|
||||
|
||||
e = pthread_create (&beacon_tid, NULL, beacon_thread, NULL);
|
||||
e = pthread_create (&beacon_tid, NULL, beacon_thread, (void *)0);
|
||||
if (e != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Could not create beacon thread");
|
||||
|
@ -615,22 +594,6 @@ static void * beacon_thread (void *arg)
|
|||
/* i.e. Don't take relative to now in case there was some delay. */
|
||||
|
||||
bp->next += bp->every;
|
||||
|
||||
// https://github.com/wb2osz/direwolf/pull/301
|
||||
// https://github.com/wb2osz/direwolf/pull/301
|
||||
// This happens with a portable system with no Internet connection.
|
||||
// On reboot, the time is in the past.
|
||||
// After time gets set from GPS, all beacons from that interval are sent.
|
||||
// FIXME: This will surely break time slotted scheduling.
|
||||
// TODO: The correct fix will be using monotonic, rather than clock, time.
|
||||
|
||||
/* craigerl: if next beacon is scheduled in the past, then set next beacon relative to now (happens when NTP pushes clock AHEAD) */
|
||||
/* fixme: if NTP sets clock BACK an hour, this thread will sleep for that hour */
|
||||
if ( bp->next < now ) {
|
||||
bp->next = now + bp->every;
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf("\nSystem clock appears to have jumped forward. Beacon schedule updated.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
} /* if time to send it */
|
||||
|
@ -807,17 +770,11 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
|
||||
assert (bp->sendto_chan >= 0);
|
||||
|
||||
if (g_modem_config_p->chan_medium[bp->sendto_chan] == MEDIUM_IGATE) { // ICHANNEL uses chan 0 mycall.
|
||||
// TODO: Maybe it should be allowed to have own.
|
||||
strlcpy (mycall, g_modem_config_p->achan[0].mycall, sizeof(mycall));
|
||||
}
|
||||
else {
|
||||
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall));
|
||||
}
|
||||
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall));
|
||||
|
||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("MYCALL not set for beacon to chan %d in config file line %d.\n", bp->sendto_chan, bp->lineno);
|
||||
dw_printf ("MYCALL not set for beacon in config file line %d.\n", bp->lineno);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -827,12 +784,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
* src > dest [ , via ]
|
||||
*/
|
||||
|
||||
if (bp->source != NULL) {
|
||||
strlcpy (beacon_text, bp->source, sizeof(beacon_text));
|
||||
}
|
||||
else {
|
||||
strlcpy (beacon_text, mycall, sizeof(beacon_text));
|
||||
}
|
||||
strlcpy (beacon_text, mycall, sizeof(beacon_text));
|
||||
strlcat (beacon_text, ">", sizeof(beacon_text));
|
||||
|
||||
if (bp->dest != NULL) {
|
||||
|
@ -1054,7 +1006,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[ig] %s\n", beacon_text);
|
||||
|
||||
igate_send_rec_packet (-1, pp); // Channel -1 to avoid RF>IS filtering.
|
||||
igate_send_rec_packet (0, pp);
|
||||
ax25_delete (pp);
|
||||
break;
|
||||
|
||||
|
@ -1069,7 +1021,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
/* Simulated reception from radio. */
|
||||
|
||||
memset (&alevel, 0xff, sizeof(alevel));
|
||||
dlq_rec_frame (bp->sendto_chan, 0, 0, pp, alevel, 0, 0, "");
|
||||
dlq_rec_frame (bp->sendto_chan, 0, 0, pp, alevel, 0, "");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@
|
|||
* are significantly different and I thought it would be
|
||||
* too confusing to munge them together.
|
||||
*
|
||||
* References: The Ax.25 protocol barely mentions digipeaters and
|
||||
* References: The Ax.25 protcol barely mentions digipeaters and
|
||||
* and doesn't describe how they should work.
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
@ -49,7 +49,7 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h> /* for isdigit, isupper */
|
||||
#include "regex.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include "ax25_pad.h"
|
||||
#include "cdigipeater.h"
|
||||
|
@ -129,10 +129,8 @@ void cdigipeater (int from_chan, packet_t pp)
|
|||
{
|
||||
int to_chan;
|
||||
|
||||
// Connected mode is allowed only for channels with internal modem.
|
||||
// It probably wouldn't matter for digipeating but let's keep that rule simple and consistent.
|
||||
|
||||
if ( from_chan < 0 || from_chan >= MAX_CHANS || save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO) {
|
||||
if ( from_chan < 0 || from_chan >= MAX_CHANS || ( ! save_audio_config_p->achan[from_chan].valid) ) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
|
||||
return;
|
||||
|
@ -255,7 +253,7 @@ static packet_t cdigipeat_match (int from_chan, packet_t pp, char *mycall_rec, c
|
|||
* Originally this was the only one.
|
||||
* Should we change it to AFILTER to make it clearer?
|
||||
* CFILTER - Similar for connected moded digipeater.
|
||||
* IGFILTER - APRS-IS (IGate) server side - completely different.
|
||||
* IGFILTER - APRS-IS (IGate) server side - completely diffeent.
|
||||
* Confusing with similar name but much different idea.
|
||||
* Maybe this should be renamed to SUBSCRIBE or something like that.
|
||||
*
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2017,2019,2021 John Langner, WB2OSZ
|
||||
// Copyright (C) 2017 John Langner, WB2OSZ
|
||||
//
|
||||
// Parts of this were adapted from "hamlib" which contains the notice:
|
||||
//
|
||||
|
@ -30,14 +30,11 @@
|
|||
*
|
||||
* Description:
|
||||
*
|
||||
* There is an increasing demand for using the GPIO pins of USB audio devices for PTT.
|
||||
* We have a few commercial products:
|
||||
* There is an incresing demand for using the GPIO pins of USB audio devices for PTT.
|
||||
* We have a couple commercial products:
|
||||
*
|
||||
* DINAH https://hamprojects.info/dinah/
|
||||
* PAUL https://hamprojects.info/paul/
|
||||
* DMK URI http://www.dmkeng.com/URI_Order_Page.htm
|
||||
* RB-USB RIM http://www.repeater-builder.com/products/usb-rim-lite.html
|
||||
* RA-35 http://www.masterscommunications.com/products/radio-adapter/ra35.html
|
||||
* DMK URI http://www.dmkeng.com/URI_Order_Page.htm
|
||||
* RB-USB RIM http://www.repeater-builder.com/products/usb-rim-lite.html
|
||||
*
|
||||
* and homebrew projects which are all very similar.
|
||||
*
|
||||
|
@ -46,15 +43,14 @@
|
|||
* http://www.repeater-builder.com/projects/fob/USB-Fob-Construction.pdf
|
||||
* https://irongarment.wordpress.com/2011/03/29/cm108-compatible-chips-with-gpio/
|
||||
*
|
||||
* Homebrew plans all use GPIO 3 because it is easier to tack solder a wire to a pin on the end.
|
||||
* All of the products, that I have seen, also use the same pin so this is the default.
|
||||
* Usually GPIO 3 is used because it is easier to tack solder a wire to a pin on the end.
|
||||
*
|
||||
* Soundmodem and hamlib paved the way but didn't get too far.
|
||||
* Dire Wolf 1.3 added HAMLIB support (Linux only) which theoretically allows this in a
|
||||
* painful roundabout way. This is documented in the User Guide, section called,
|
||||
* roundabout way. This is documented in the User Guide, section called,
|
||||
* "Hamlib PTT Example 2: Use GPIO of USB audio adapter. (e.g. DMK URI)"
|
||||
*
|
||||
* It's rather involved and the explanation doesn't cover the case of multiple
|
||||
* It's rather involved and the explantion doesn't cover the case of multiple
|
||||
* USB-Audio adapters. It is not as straightforward as you might expect. Here we have
|
||||
* an example of 3 C-Media USB adapters, a SignaLink USB, a keyboard, and a mouse.
|
||||
*
|
||||
|
@ -90,44 +86,29 @@
|
|||
* Dire Wolf version 1.5 makes this much more flexible and easier to use by supporting multiple
|
||||
* sound devices and automatically determining the corresponding HID for the PTT signal.
|
||||
*
|
||||
* In version 1.7, we add a half-backed solution for Windows. It's fine for situations
|
||||
* with a single USB Audio Adapter, but does not automatically handle the multiple device case.
|
||||
* Manual configuration needs to be used in this case.
|
||||
*
|
||||
* Here is something new and interesting. The All in One cable (AIOC).
|
||||
* https://github.com/skuep/AIOC/tree/master
|
||||
*
|
||||
* A microcontroller is used to emulate a CM108-compatible soundcard
|
||||
* and a serial port. It fits right on the side of a Bao Feng or similar.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
#include "direwolf.h"
|
||||
|
||||
#ifndef USE_CM108
|
||||
|
||||
#ifdef CM108_MAIN
|
||||
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
text_color_init (0); // Turn off text color.
|
||||
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||
dw_printf ("CM108 PTT support is not available for this operating system.\n");
|
||||
#else
|
||||
dw_printf ("CM108 PTT support was excluded because /usr/include/libudev.h was missing.\n");
|
||||
dw_printf ("Install it with \"sudo apt-get install libudev-dev\" or\n");
|
||||
dw_printf ("\"sudo yum install libudev-devel\" then rebuild.\n");
|
||||
#endif
|
||||
dw_printf ("CM108 PTT support was disabled in Makefile.linux.\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else // USE_CM108 is defined
|
||||
#else // USE_CM108 is defined.
|
||||
|
||||
#include "direwolf.h"
|
||||
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
|
@ -135,18 +116,12 @@ int main (void)
|
|||
#include <string.h>
|
||||
#include <regex.h>
|
||||
|
||||
#if __WIN32__
|
||||
#include <wchar.h>
|
||||
#include "hidapi.h"
|
||||
#else
|
||||
#include <libudev.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h> // ioctl, _IOR
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/hidraw.h> // for HIDIOCGRAWINFO
|
||||
#endif
|
||||
|
||||
#include "textcolor.h"
|
||||
#include "cm108.h"
|
||||
|
@ -170,7 +145,6 @@ static int cm108_write (char *name, int iomask, int iodata);
|
|||
#define CMEDIA_PID1_MAX 0x000f
|
||||
|
||||
#define CMEDIA_PID_CM108AH 0x0139 // CM108AH
|
||||
#define CMEDIA_PID_CM108AH_alt 0x013c // CM108AH? - see issue 210
|
||||
#define CMEDIA_PID_CM108B 0x0012 // CM108B
|
||||
#define CMEDIA_PID_CM119A 0x013a // CM119A
|
||||
#define CMEDIA_PID_CM119B 0x0013 // CM119B
|
||||
|
@ -185,11 +159,6 @@ static int cm108_write (char *name, int iomask, int iodata);
|
|||
#define SSS_PID2 0x1607
|
||||
#define SSS_PID3 0x160b
|
||||
|
||||
// https://github.com/skuep/AIOC/blob/master/stm32/aioc-fw/Src/usb_descriptors.h
|
||||
|
||||
#define AIOC_VID 0x1209
|
||||
#define AIOC_PID 0x7388
|
||||
|
||||
|
||||
// Device VID PID Number of GPIO
|
||||
// ------ --- --- --------------
|
||||
|
@ -200,8 +169,7 @@ static int cm108_write (char *name, int iomask, int iodata);
|
|||
// CM119 0d8c 0008-000f * 8
|
||||
// CM119A 0d8c 013a * 8
|
||||
// CM119B 0d8c 0013 8
|
||||
// HS100 0d8c 013c 0 (issue 210 reported 013c
|
||||
// being seen for CM108AH)
|
||||
// HS100 0d8c 013c 0
|
||||
//
|
||||
// SSS1621 0c76 1605 2 per ZL3AME, Can't find data sheet
|
||||
// SSS1623 0c76 1607,160b 2 per ZL3AME, Not in data sheet.
|
||||
|
@ -224,14 +192,11 @@ static int cm108_write (char *name, int iomask, int iodata);
|
|||
|
||||
#define GOOD_DEVICE(v,p) ( (v == CMEDIA_VID && ((p >= CMEDIA_PID1_MIN && p <= CMEDIA_PID1_MAX) \
|
||||
|| p == CMEDIA_PID_CM108AH \
|
||||
|| p == CMEDIA_PID_CM108AH_alt \
|
||||
|| p == CMEDIA_PID_CM108B \
|
||||
|| p == CMEDIA_PID_CM119A \
|
||||
|| p == CMEDIA_PID_CM119B )) \
|
||||
|| \
|
||||
(v == SSS_VID && (p == SSS_PID1 || p == SSS_PID2 || p == SSS_PID3)) \
|
||||
|| \
|
||||
(v == AIOC_VID && p == AIOC_PID) )
|
||||
(v == SSS_VID && (p == SSS_PID1 || p == SSS_PID2 || p == SSS_PID3)) )
|
||||
|
||||
// Look out for null source pointer, and avoid buffer overflow on destination.
|
||||
|
||||
|
@ -240,9 +205,7 @@ static int cm108_write (char *name, int iomask, int iodata);
|
|||
|
||||
// Used to process regular expression matching results.
|
||||
|
||||
#ifndef __WIN32__
|
||||
|
||||
static void substr_se (char *dest, const char *src, int start, int endp1)
|
||||
static void inline substr_se (char *dest, const char *src, int start, int endp1)
|
||||
{
|
||||
int len = endp1 - start;
|
||||
|
||||
|
@ -255,35 +218,19 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
|
|||
|
||||
} /* end substr_se */
|
||||
|
||||
#endif
|
||||
|
||||
// Maximum length of name for PTT HID.
|
||||
// For Linux, this was originally 17 to handle names like /dev/hidraw3.
|
||||
// Windows has more complicated names. The longest I saw was 95 but longer have been reported.
|
||||
|
||||
#define MAXX_HIDRAW_NAME_LEN 128
|
||||
|
||||
/*
|
||||
* Result of taking inventory of USB soundcards and USB HIDs.
|
||||
*/
|
||||
|
||||
struct thing_s {
|
||||
int vid; // vendor id, displayed as four hexadecimal digits.
|
||||
int pid; // product id, displayed as four hexadecimal digits.
|
||||
char card_number[8]; // "Card" Number. e.g. 2 for plughw:2,0
|
||||
char card_name[32]; // Audio Card Name, assigned by system (e.g. Device_1) or by udev rule.
|
||||
int vid; // vendor id
|
||||
int pid; // product id
|
||||
char product[32]; // product name (e.g. manufacturer, model)
|
||||
char devnode_sound[22]; // e.g. /dev/snd/pcmC0D0p
|
||||
char plughw[72]; // Above in more familiar format e.g. plughw:0,0
|
||||
// Oversized to silence a compiler warning.
|
||||
char plughw2[72]; // With name rather than number.
|
||||
char devpath[128]; // Kernel dev path. Does not include /sys mount point.
|
||||
char devnode_hidraw[MAXX_HIDRAW_NAME_LEN];
|
||||
// e.g. /dev/hidraw3 - for Linux - was length 17
|
||||
// The Windows path for a HID looks like this, lengths up to 95 seen.
|
||||
// \\?\hid#vid_0d8c&pid_000c&mi_03#8&164d11c9&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
|
||||
char plughw[15]; // Above in more familiar format e.g. plughw:0,0
|
||||
char devnode_hidraw[17]; // e.g. /dev/hidraw3
|
||||
char devnode_usb[25]; // e.g. /dev/bus/usb/001/012
|
||||
// This is what we use to match up audio and HID.
|
||||
};
|
||||
|
||||
int cm108_inventory (struct thing_s *things, int max_things);
|
||||
|
@ -293,158 +240,55 @@ int cm108_inventory (struct thing_s *things, int max_things);
|
|||
*
|
||||
* Name: main
|
||||
*
|
||||
* Purpose: Useful utility to list USB audio and HID devices.
|
||||
* Purpose: Test program to list USB audio and HID devices.
|
||||
*
|
||||
* Optional command line arguments:
|
||||
*
|
||||
* HID path
|
||||
* GPIO number (default 3)
|
||||
*
|
||||
* When specified the pin will be set high and low until interrupted.
|
||||
* sudo apt-get install libudev-dev
|
||||
* gcc -DCM108_MAIN textcolor.c -l udev
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
//#define EXTRA 1
|
||||
|
||||
#define MAXX_THINGS 60
|
||||
|
||||
#ifdef CM108_MAIN
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n");
|
||||
dw_printf ("Usage: cm108 [ device-path [ gpio-num ] ]\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf ("With no command line arguments, this will produce a list of\n");
|
||||
#if __WIN32__
|
||||
dw_printf ("Human Interface Devices (HID) and indicate which ones can be\n");
|
||||
dw_printf ("used for GPIO PTT.\n");
|
||||
#else
|
||||
dw_printf ("Audio devices and Human Interface Devices (HID) and indicate\n");
|
||||
dw_printf ("which ones can be used for GPIO PTT.\n");
|
||||
#endif
|
||||
dw_printf ("\n");
|
||||
dw_printf ("Specify the HID device path to test the PTT function.\n");
|
||||
dw_printf ("Its state should change once per second.\n");
|
||||
#if __WIN32__
|
||||
dw_printf ("You might need to quote the path depending on the command processor.\n");
|
||||
#endif
|
||||
dw_printf ("GPIO 3 is the default. A different number can be optionally specified.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
int main (void)
|
||||
{
|
||||
struct thing_s things[MAXX_THINGS];
|
||||
int num_things;
|
||||
int i;
|
||||
|
||||
text_color_init (0); // Turn off text color.
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
||||
if (argc >=2) {
|
||||
char path[128];
|
||||
strlcpy(path, argv[1], sizeof(path));
|
||||
int gpio = 3;
|
||||
if (argc >= 3) {
|
||||
gpio = atoi(argv[2]);
|
||||
}
|
||||
if (gpio < 1 || gpio > 8) {
|
||||
dw_printf ("GPIO number must be in range of 1 - 8.\n");
|
||||
usage();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
int state = 0;
|
||||
while (1) {
|
||||
dw_printf ("%d", state);
|
||||
fflush (stdout);
|
||||
int err = cm108_set_gpio_pin (path, gpio, state);
|
||||
if (err != 0) {
|
||||
dw_printf ("\nWRITE ERROR for USB Audio Adapter GPIO!\n");
|
||||
usage();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
SLEEP_SEC(1);
|
||||
state = ! state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Take inventory of USB Audio adapters and other HID devices.
|
||||
|
||||
num_things = cm108_inventory (things, MAXX_THINGS);
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// Windows - Remove the sound related columns for now.
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
dw_printf (" VID PID %-*s %-*s"
|
||||
"\n", (int)sizeof(things[0].product), "Product",
|
||||
17, "HID [ptt]"
|
||||
);
|
||||
|
||||
dw_printf (" --- --- %-*s %-*s"
|
||||
|
||||
"\n", (int)sizeof(things[0].product), "-------",
|
||||
17, "---------"
|
||||
);
|
||||
for (i = 0; i < num_things; i++) {
|
||||
|
||||
dw_printf ("%2s %04x %04x %-*s %s"
|
||||
|
||||
"\n",
|
||||
GOOD_DEVICE(things[i].vid,things[i].pid) ? "**" : " ",
|
||||
things[i].vid, things[i].pid,
|
||||
(int)sizeof(things[i].product), things[i].product,
|
||||
things[i].devnode_hidraw
|
||||
);
|
||||
}
|
||||
dw_printf ("\n");
|
||||
dw_printf ("** = Can use Audio Adapter GPIO for PTT.\n");
|
||||
dw_printf ("\n");
|
||||
|
||||
// T.B.D. - additional text ???
|
||||
|
||||
#else
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Linux
|
||||
/////////////////////////////////////////////
|
||||
|
||||
|
||||
dw_printf (" VID PID %-*s %-*s %-*s %-*s %-*s"
|
||||
dw_printf (" VID PID %-*s %-*s %-*s %-*s"
|
||||
#if EXTRA
|
||||
" %-*s"
|
||||
#endif
|
||||
"\n", (int)sizeof(things[0].product), "Product",
|
||||
(int)sizeof(things[0].devnode_sound), "Sound",
|
||||
(int)sizeof(things[0].plughw)/5, "ADEVICE",
|
||||
(int)sizeof(things[0].plughw2)/4, "ADEVICE",
|
||||
17, "HID [ptt]"
|
||||
(int)sizeof(things[0].plughw), "ADEVICE",
|
||||
(int)sizeof(things[0].devnode_hidraw), "HID [ptt]"
|
||||
#if EXTRA
|
||||
, (int)sizeof(things[0].devnode_usb), "USB"
|
||||
#endif
|
||||
);
|
||||
|
||||
dw_printf (" --- --- %-*s %-*s %-*s %-*s %-*s"
|
||||
dw_printf (" --- --- %-*s %-*s %-*s %-*s"
|
||||
#if EXTRA
|
||||
" %-*s"
|
||||
#endif
|
||||
"\n", (int)sizeof(things[0].product), "-------",
|
||||
(int)sizeof(things[0].devnode_sound), "-----",
|
||||
(int)sizeof(things[0].plughw)/5, "-------",
|
||||
(int)sizeof(things[0].plughw2)/4, "-------",
|
||||
17, "---------"
|
||||
(int)sizeof(things[0].plughw), "-------",
|
||||
(int)sizeof(things[0].devnode_hidraw), "---------"
|
||||
#if EXTRA
|
||||
, (int)sizeof(things[0].devnode_usb), "---"
|
||||
#endif
|
||||
);
|
||||
for (i = 0; i < num_things; i++) {
|
||||
|
||||
dw_printf ("%2s %04x %04x %-*s %-*s %-*s %-*s %s"
|
||||
dw_printf ("%2s %04x %04x %-*s %-*s %-*s %-*s"
|
||||
#if EXTRA
|
||||
" %-*s"
|
||||
#endif
|
||||
|
@ -453,62 +297,14 @@ int main (int argc, char **argv)
|
|||
things[i].vid, things[i].pid,
|
||||
(int)sizeof(things[i].product), things[i].product,
|
||||
(int)sizeof(things[i].devnode_sound), things[i].devnode_sound,
|
||||
(int)sizeof(things[0].plughw)/5, things[i].plughw,
|
||||
(int)sizeof(things[0].plughw2)/4, things[i].plughw2,
|
||||
things[i].devnode_hidraw
|
||||
(int)sizeof(things[0].plughw), things[i].plughw,
|
||||
(int)sizeof(things[i].devnode_hidraw), things[i].devnode_hidraw
|
||||
#if EXTRA
|
||||
, (int)sizeof(things[i].devnode_usb), things[i].devnode_usb
|
||||
#endif
|
||||
);
|
||||
//dw_printf (" %-*s\n", (int)sizeof(things[i].devpath), things[i].devpath);
|
||||
}
|
||||
dw_printf ("\n");
|
||||
dw_printf ("** = Can use Audio Adapter GPIO for PTT.\n");
|
||||
dw_printf ("\n");
|
||||
|
||||
static const char *suggested_names[] = {"Fred", "Wilma", "Pebbles", "Dino", "Barney", "Betty", "Bamm_Bamm", "Chip", "Roxy" };
|
||||
int iname = 0;
|
||||
|
||||
// From example in https://alsa.opensrc.org/Udev
|
||||
|
||||
dw_printf ("Notice that each USB Audio adapter is assigned a number and a name. These are not predictable so you could\n");
|
||||
dw_printf ("end up using the wrong adapter after adding or removing other USB devices or after rebooting. You can assign a\n");
|
||||
dw_printf ("name to each USB adapter so you can refer to the same one each time. This can be based on any characteristics\n");
|
||||
dw_printf ("that makes them unique such as product id or serial number. Unfortunately these devices don't have unique serial\n");
|
||||
dw_printf ("numbers so how can we tell them apart? A name can also be assigned based on the physical USB socket.\n");
|
||||
dw_printf ("Create a file like \"/etc/udev/rules.d/85-my-usb-audio.rules\" with the following contents and then reboot.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf ("SUBSYSTEM!=\"sound\", GOTO=\"my_usb_audio_end\"\n");
|
||||
dw_printf ("ACTION!=\"add\", GOTO=\"my_usb_audio_end\"\n");
|
||||
|
||||
// Consider only the 'devnode' paths that end with "card" and a number.
|
||||
// Replace the number with a question mark.
|
||||
|
||||
regex_t devpath_re;
|
||||
char emsg[100];
|
||||
// Drop any "/sys" at the beginning.
|
||||
int e = regcomp (&devpath_re, "(/devices/.+/card)[0-9]$", REG_EXTENDED);
|
||||
if (e) {
|
||||
regerror (e, &devpath_re, emsg, sizeof(emsg));
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("INTERNAL ERROR: %s:%d: %s\n", __FILE__, __LINE__, emsg);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_things; i++) {
|
||||
if (i == 0 || strcmp(things[i].devpath,things[i-1].devpath) != 0) {
|
||||
regmatch_t devpath_match[2];
|
||||
if (regexec (&devpath_re, things[i].devpath, 2, devpath_match, 0) == 0) {
|
||||
char without_number[256];
|
||||
substr_se (without_number, things[i].devpath, devpath_match[1].rm_so, devpath_match[1].rm_eo);
|
||||
dw_printf ("DEVPATH==\"%s?\", ATTR{id}=\"%s\"\n", without_number, suggested_names[iname]);
|
||||
if (iname < 6) iname++;
|
||||
}
|
||||
}
|
||||
}
|
||||
dw_printf ("LABEL=\"my_usb_audio_end\"\n");
|
||||
dw_printf ("\n");
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -536,57 +332,14 @@ int main (int argc, char **argv)
|
|||
|
||||
int cm108_inventory (struct thing_s *things, int max_things)
|
||||
{
|
||||
int num_things = 0;
|
||||
memset (things, 0, sizeof(struct thing_s) * max_things);
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
struct hid_device_info *devs, *cur_dev;
|
||||
|
||||
if (hid_init()) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("cm108_inventory: hid_init() failed.\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
devs = hid_enumerate(0x0, 0x0);
|
||||
cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
#if 0
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf(" Release: %hx\n", cur_dev->release_number);
|
||||
printf(" Interface: %d\n", cur_dev->interface_number);
|
||||
printf(" Usage (page): 0x%hx (0x%hx)\n", cur_dev->usage, cur_dev->usage_page);
|
||||
printf("\n");
|
||||
#endif
|
||||
if (num_things < max_things && cur_dev->vendor_id != 0x051d) { // FIXME - remove exception
|
||||
things[num_things].vid = cur_dev->vendor_id;
|
||||
things[num_things].pid = cur_dev->product_id;
|
||||
wcstombs (things[num_things].product, cur_dev->product_string, sizeof(things[num_things].product));
|
||||
things[num_things].product[sizeof(things[num_things].product) - 1] = '\0';
|
||||
strlcpy (things[num_things].devnode_hidraw, cur_dev->path, sizeof(things[num_things].devnode_hidraw));
|
||||
|
||||
num_things++;
|
||||
}
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
|
||||
#else // Linux, with udev
|
||||
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
struct udev_device *dev;
|
||||
struct udev_device *parentdev;
|
||||
|
||||
char const *pattrs_id = NULL;
|
||||
char const *pattrs_number = NULL;
|
||||
char card_devpath[128] = "";
|
||||
|
||||
int num_things = 0;
|
||||
memset (things, 0, sizeof(struct thing_s) * max_things);
|
||||
|
||||
/*
|
||||
* First get a list of the USB audio devices.
|
||||
|
@ -604,21 +357,11 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *path = udev_list_entry_get_name(dev_list_entry);
|
||||
const char *path;
|
||||
path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, path);
|
||||
char const *devnode = udev_device_get_devnode(dev);
|
||||
|
||||
if (devnode == NULL ) {
|
||||
// I'm not happy with this but couldn't figure out how
|
||||
// to get attributes from one level up from the pcmC?D?? node.
|
||||
strlcpy (card_devpath, path, sizeof(card_devpath));
|
||||
pattrs_id = udev_device_get_sysattr_value(dev,"id");
|
||||
pattrs_number = udev_device_get_sysattr_value(dev,"number");
|
||||
//dw_printf (" >card_devpath = %s\n", card_devpath);
|
||||
//dw_printf (" >>pattrs_id = %s\n", pattrs_id);
|
||||
//dw_printf (" >>pattrs_number = %s\n", pattrs_number);
|
||||
}
|
||||
else {
|
||||
if (devnode != NULL) {
|
||||
parentdev = udev_device_get_parent_with_subsystem_devtype( dev, "usb", "usb_device");
|
||||
if (parentdev != NULL) {
|
||||
char const *p;
|
||||
|
@ -633,12 +376,9 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
if (num_things < max_things) {
|
||||
things[num_things].vid = vid;
|
||||
things[num_things].pid = pid;
|
||||
SAFE_STRCPY (things[num_things].card_name, pattrs_id);
|
||||
SAFE_STRCPY (things[num_things].card_number, pattrs_number);
|
||||
SAFE_STRCPY (things[num_things].product, udev_device_get_sysattr_value(parentdev,"product"));
|
||||
SAFE_STRCPY (things[num_things].devnode_sound, devnode);
|
||||
SAFE_STRCPY (things[num_things].devnode_usb, udev_device_get_devnode(parentdev));
|
||||
strlcpy (things[num_things].devpath, card_devpath, sizeof(things[num_things].devpath));
|
||||
num_things++;
|
||||
}
|
||||
udev_device_unref(parentdev);
|
||||
|
@ -663,7 +403,8 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *path = udev_list_entry_get_name(dev_list_entry);
|
||||
const char *path;
|
||||
path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, path);
|
||||
char const *devnode = udev_device_get_devnode(dev);
|
||||
if (devnode != NULL) {
|
||||
|
@ -696,7 +437,6 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
SAFE_STRCPY (things[num_things].product, udev_device_get_sysattr_value(parentdev,"product"));
|
||||
SAFE_STRCPY (things[num_things].devnode_hidraw, devnode);
|
||||
SAFE_STRCPY (things[num_things].devnode_usb, usb);
|
||||
SAFE_STRCPY (things[num_things].devpath, udev_device_get_devpath(dev));
|
||||
num_things++;
|
||||
}
|
||||
udev_device_unref(parentdev);
|
||||
|
@ -710,8 +450,6 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
* Seeing the form /dev/snd/pcmC4D0p will be confusing to many because we
|
||||
* would generally something like plughw:4,0 for in the direwolf configuration file.
|
||||
* Construct the more familiar form.
|
||||
* Previously we only used the numeric form. In version 1.6, the name is listed as well
|
||||
* and we describe how to assign names based on the physical USB socket for repeatability.
|
||||
*/
|
||||
int i;
|
||||
regex_t pcm_re;
|
||||
|
@ -732,12 +470,9 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
substr_se (c, things[i].devnode_sound, match[1].rm_so, match[1].rm_eo);
|
||||
substr_se (d, things[i].devnode_sound, match[2].rm_so, match[2].rm_eo);
|
||||
snprintf (things[i].plughw, sizeof(things[i].plughw), "plughw:%s,%s", c, d);
|
||||
snprintf (things[i].plughw2, sizeof(things[i].plughw), "plughw:%s,%s", things[i].card_name, d);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // end Linux
|
||||
|
||||
return (num_things);
|
||||
|
||||
} /* end cm108_inventory */
|
||||
|
@ -747,21 +482,16 @@ int cm108_inventory (struct thing_s *things, int max_things)
|
|||
*
|
||||
* Name: cm108_find_ptt
|
||||
*
|
||||
* Purpose: Try to find /dev/hidraw corresponding to a USB audio "card."
|
||||
* Purpose: Try to find /dev/hidraw corresponding to plughw:n,n
|
||||
*
|
||||
* Inputs: output_audio_device
|
||||
* - Used in the ADEVICE configuration.
|
||||
* This can take many forms such as:
|
||||
* surround41:CARD=Fred,DEV=0
|
||||
* surround41:Fred,0
|
||||
* surround41:Fred
|
||||
* plughw:2,3
|
||||
* In our case we just need to extract the card number or name.
|
||||
* - Device name used in the ADEVICE configuration.
|
||||
* This would generally be something like plughw:1,0
|
||||
*
|
||||
* ptt_device_size - Size of result area to avoid buffer overflow.
|
||||
*
|
||||
* Outputs: ptt_device - Device name, something like /dev/hidraw2.
|
||||
* Will be empty string if no match found.
|
||||
* Will be emptry string if no match found.
|
||||
*
|
||||
* Returns: none
|
||||
*
|
||||
|
@ -771,86 +501,19 @@ void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_devic
|
|||
{
|
||||
struct thing_s things[MAXX_THINGS];
|
||||
int num_things;
|
||||
|
||||
//dw_printf ("DEBUG: cm108_find_ptt('%s')\n", output_audio_device);
|
||||
int i;
|
||||
|
||||
strlcpy (ptt_device, "", ptt_device_size);
|
||||
|
||||
// Possible improvement: Skip if inventory already taken.
|
||||
num_things = cm108_inventory (things, MAXX_THINGS);
|
||||
|
||||
#if __WIN32__
|
||||
// FIXME - This is just a half baked implementation.
|
||||
// I have not been able to figure out how to find the connection
|
||||
// between the audio device and HID in the same package.
|
||||
// This is fine for a single USB Audio Adapter, good enough for most people.
|
||||
// Those with multiple devices will need to manually configure PTT device path.
|
||||
for (i = 0; i < num_things; i++) {
|
||||
|
||||
// Count how many good devices we have.
|
||||
|
||||
int good_devices = 0;
|
||||
|
||||
for (int i = 0; i < num_things; i++) {
|
||||
if (GOOD_DEVICE(things[i].vid,things[i].pid) ) {
|
||||
good_devices++;
|
||||
//dw_printf ("DEBUG: success! returning '%s'\n", things[i].devnode_hidraw);
|
||||
strlcpy (ptt_device, things[i].devnode_hidraw, ptt_device_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (good_devices == 0) return; // None found - caller will print a message.
|
||||
|
||||
if (good_devices == 1) return; // Success - Only one candidate device.
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("There are multiple USB Audio Devices with GPIO capability.\n");
|
||||
dw_printf ("Explicitly specify one of them for more predictable results:\n");
|
||||
for (int i = 0; i < num_things; i++) {
|
||||
if (GOOD_DEVICE(things[i].vid,things[i].pid) ) {
|
||||
dw_printf (" \"%s\"\n", things[i].devnode_hidraw);
|
||||
}
|
||||
}
|
||||
dw_printf ("Run the \"cm108\" utility for more details.\n");
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
#else
|
||||
regex_t sound_re;
|
||||
char emsg[100];
|
||||
int e = regcomp (&sound_re, ".+:(CARD=)?([A-Za-z0-9_]+)(,.*)?", REG_EXTENDED);
|
||||
if (e) {
|
||||
regerror (e, &sound_re, emsg, sizeof(emsg));
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("INTERNAL ERROR: %s:%d: %s\n", __FILE__, __LINE__, emsg);
|
||||
return;
|
||||
}
|
||||
|
||||
char num_or_name[64];
|
||||
strcpy (num_or_name, "");
|
||||
regmatch_t sound_match[4];
|
||||
if (regexec (&sound_re, output_audio_device, 4, sound_match, 0) == 0) {
|
||||
substr_se (num_or_name, output_audio_device, sound_match[2].rm_so, sound_match[2].rm_eo);
|
||||
//dw_printf ("DEBUG: Got '%s' from '%s'\n", num_or_name, output_audio_device);
|
||||
}
|
||||
if (strlen(num_or_name) == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not extract card number or name from %s\n", output_audio_device);
|
||||
dw_printf ("Can't automatically find matching HID for PTT.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_things; i++) {
|
||||
//dw_printf ("DEBUG: i=%d, card_name='%s', card_number='%s'\n", i, things[i].card_name, things[i].card_number);
|
||||
if (strcmp(num_or_name,things[i].card_name) == 0 || strcmp(num_or_name,things[i].card_number) == 0) {
|
||||
//dw_printf ("DEBUG: success! returning '%s'\n", things[i].devnode_hidraw);
|
||||
strlcpy (ptt_device, things[i].devnode_hidraw, ptt_device_size);
|
||||
if ( ! GOOD_DEVICE(things[i].vid,things[i].pid) ) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Warning: USB audio card %s (%s) is not a device known to work with GPIO PTT.\n",
|
||||
things[i].card_number, things[i].card_name);
|
||||
if (strcmp(output_audio_device, things[i].plughw) == 0) {
|
||||
strlcpy (ptt_device, things[i].devnode_hidraw, ptt_device_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* end cm108_find_ptt */
|
||||
|
||||
|
@ -862,8 +525,7 @@ void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_devic
|
|||
*
|
||||
* Purpose: Set one GPIO pin of the CM108 or similar.
|
||||
*
|
||||
* Inputs: name - Name of device such as /dev/hidraw2 or
|
||||
* \\?\hid#vid_0d8c&pid_0008&mi_03#8&39d3555&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
|
||||
* Inputs: name - Name of device such as /dev/hidraw2.
|
||||
*
|
||||
* num - GPIO number, range 1 thru 8.
|
||||
*
|
||||
|
@ -873,9 +535,9 @@ void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_devic
|
|||
*
|
||||
* Errors: A descriptive error message will be printed for any problem.
|
||||
*
|
||||
* Shortcut: For our initial implementation we are making the simplifying
|
||||
* Future: For our initial implementation we are making the simplifying
|
||||
* restriction of using only one GPIO pin per device and limit
|
||||
* configuration to PTT only.
|
||||
* configuratin to PTT only.
|
||||
* Longer term, we might want to have DCD, and maybe other
|
||||
* controls thru the same chip.
|
||||
* In this case, we would need to retain bit masks for each
|
||||
|
@ -883,7 +545,6 @@ void cm108_find_ptt (char *output_audio_device, char *ptt_device, int ptt_devic
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
|
||||
int cm108_set_gpio_pin (char *name, int num, int state)
|
||||
{
|
||||
int iomask;
|
||||
|
@ -901,8 +562,9 @@ int cm108_set_gpio_pin (char *name, int num, int state)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
iomask = 1 << (num - 1); // 0=input, 1=output
|
||||
iodata = state << (num - 1); // 0=low, 1=high
|
||||
iomask = 1 << (num - 1);
|
||||
iodata = state << (num - 1);
|
||||
|
||||
return (cm108_write (name, iomask, iodata));
|
||||
|
||||
} /* end cm108_set_gpio_pin */
|
||||
|
@ -933,36 +595,6 @@ int cm108_set_gpio_pin (char *name, int num, int state)
|
|||
|
||||
static int cm108_write (char *name, int iomask, int iodata)
|
||||
{
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("TEMP DEBUG cm108_write: %s %d %d\n", name, iomask, iodata);
|
||||
|
||||
hid_device *handle = hid_open_path(name);
|
||||
if (handle == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open %s for write\n", name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
unsigned char io[5];
|
||||
io[0] = 0;
|
||||
io[1] = 0;
|
||||
io[2] = iodata;
|
||||
io[3] = iomask;
|
||||
io[4] = 0;
|
||||
|
||||
int res = hid_write(handle, io, sizeof(io));
|
||||
if (res < 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Write failed to %s\n", name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
hid_close(handle);
|
||||
|
||||
#else
|
||||
int fd;
|
||||
struct hidraw_devinfo info;
|
||||
char io[5];
|
||||
|
@ -1036,9 +668,8 @@ static int cm108_write (char *name, int iomask, int iodata)
|
|||
|
||||
io[0] = 0;
|
||||
io[1] = 0;
|
||||
// Issue 210 - These were reversed. Fixed in 1.6.
|
||||
io[2] = iodata;
|
||||
io[3] = iomask;
|
||||
io[2] = iomask;
|
||||
io[3] = iodata;
|
||||
io[4] = 0;
|
||||
|
||||
// Writing 4 bytes fails with errno 32, EPIPE, "broken pipe."
|
||||
|
@ -1067,8 +698,6 @@ static int cm108_write (char *name, int iomask, int iodata)
|
|||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
#endif
|
||||
return (0);
|
||||
|
||||
} /* end cm108_write */
|
||||
|
@ -1077,4 +706,4 @@ static int cm108_write (char *name, int iomask, int iodata)
|
|||
|
||||
/* end cm108.c */
|
||||
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
include(CPack)
|
|
@ -1,10 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=@APPLICATION_NAME@
|
||||
Comment=APRS Soundcard TNC
|
||||
Exec=@APPLICATION_DESKTOP_EXEC@
|
||||
Icon=@CMAKE_PROJECT_NAME@_icon.png
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=HamRadio
|
||||
Keywords=Ham Radio;APRS;Soundcard TNC;KISS;AGWPE;AX.25
|
|
@ -1 +0,0 @@
|
|||
MAINICON ICON "direwolf_icon.ico"
|
|
@ -1,16 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <arm_neon.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
uint32x4_t x={0};
|
||||
x=veorq_u32(x,x);
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m256d x = _mm256_setzero_pd();
|
||||
x=_mm256_addsub_pd(x,x);
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m256i x = _mm256_setzero_si256();
|
||||
x=_mm256_add_epi64 (x,x);
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
uint64_t x[8] = {0};
|
||||
__m512i y = _mm512_loadu_si512((__m512i*)x);
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m128i x = _mm_setzero_si128();
|
||||
x=_mm_add_epi64(x,x);
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <emmintrin.h>
|
||||
#include <pmmintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m128d x = _mm_setzero_pd();
|
||||
x=_mm_addsub_pd(x,x);
|
||||
return 0;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <emmintrin.h>
|
||||
#include <smmintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m128i x = _mm_setzero_si128();
|
||||
__m128i a = _mm_setzero_si128();
|
||||
__m128i b = _mm_setzero_si128();
|
||||
x=_mm_blend_epi16(a,b,4);
|
||||
return 0;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <nmmintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
unsigned int x=32;
|
||||
x=_mm_crc32_u8(x,4);
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <emmintrin.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
void signalHandler(int signum) {
|
||||
exit(signum); // SIGILL = 4
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
signal(SIGILL, signalHandler);
|
||||
__m128i x = _mm_setzero_si128();
|
||||
x=_mm_alignr_epi8(x,x,2);
|
||||
return 0;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
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}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
if(NOT "${rm_retval}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||
endif(NOT "${rm_retval}" STREQUAL 0)
|
||||
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
endforeach(file)
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
find_library(AVAHI_COMMON_LIBRARY NAMES avahi-common PATHS ${PC_AVAHI_CLIENT_LIBRARY_DIRS})
|
||||
if(AVAHI_COMMON_LIBRARY)
|
||||
set(AVAHI_COMMON_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
find_library(AVAHI_CLIENT_LIBRARY NAMES avahi-client PATHS ${PC_AVAHI_CLIENT_LIBRARY_DIRS})
|
||||
if(AVAHI_CLIENT_LIBRARY)
|
||||
set(AVAHI_CLIENT_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Avahi DEFAULT_MSG AVAHI_COMMON_FOUND AVAHI_CLIENT_FOUND)
|
||||
|
||||
if (AVAHI_FOUND)
|
||||
set(AVAHI_INCLUDE_DIRS ${AVAHI_UI_INCLUDE_DIR})
|
||||
set(AVAHI_LIBRARIES ${AVAHI_COMMON_LIBRARY} ${AVAHI_CLIENT_LIBRARY})
|
||||
endif()
|
||||
|
||||
mark_as_advanced(AVAHI_INCLUDE_DIRS AVAHI_LIBRARIES)
|
|
@ -1,383 +0,0 @@
|
|||
# Clang or AppleClang (see CMP0025)
|
||||
if(NOT DEFINED C_CLANG AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(C_CLANG 1)
|
||||
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)
|
||||
endif()
|
||||
|
||||
# Detect current compilation architecture and create standard definitions
|
||||
include(CheckSymbolExists)
|
||||
function(detect_architecture symbol arch)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
set(CMAKE_REQUIRED_QUIET 1)
|
||||
check_symbol_exists("${symbol}" "" ARCHITECTURE_${arch})
|
||||
unset(CMAKE_REQUIRED_QUIET)
|
||||
|
||||
# The output variable needs to be unique across invocations otherwise
|
||||
# CMake's crazy scope rules will keep it defined
|
||||
if (ARCHITECTURE_${arch})
|
||||
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
|
||||
set(ARCHITECTURE_${arch} 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_${arch}=1)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# direwolf versions thru 1.5 were available pre-built for 32 bit Windows targets.
|
||||
# Research and experimentation revealed that the SSE instructions made a big
|
||||
# difference in runtime speed but SSE2 and later were not significantly better
|
||||
# for this application. I decided to build with only the SSE instructions making
|
||||
# the Pentium 3 the minimum requirement. SSE2 would require at least a Pentium 4
|
||||
# and offered no significant performance advantage.
|
||||
# These are ancient history - from the previous Century - but old computers, generally
|
||||
# considered useless for anything else, often end up in the ham shack.
|
||||
#
|
||||
# When cmake was first used for direwolf, the default target became 64 bit and the
|
||||
# SSE2, SSE3, SSE4.1, and SSE4.2 instructions were automatically enabled based on the
|
||||
# build machine capabilities. This was fine until I tried running the application
|
||||
# on a computer much older than where it was built. It did not have the SSE4 instructions
|
||||
# and the application died without a clue for the reason.
|
||||
# Just how much benefit do these new instructions provide for this application?
|
||||
#
|
||||
# These were all run on the same computer, but compiled in different ways.
|
||||
# Times to run atest with Track 1 of the TNC test CD:
|
||||
#
|
||||
# direwolf 1.5 - 32 bit target - gcc 6.3.0
|
||||
#
|
||||
# 60.4 sec. Pentium 3 with SSE
|
||||
#
|
||||
# direwolf 1.6 - 32 bit target - gcc 7.4.0
|
||||
#
|
||||
# 81.0 sec. with no SIMD instructions enabled.
|
||||
# 54.4 sec. with SSE
|
||||
# 52.0 sec. with SSE2
|
||||
# 52.4 sec. with SSE2, SSE3
|
||||
# 52.3 sec. with SSE2, SSE3, SSE4.1, SSE4.2
|
||||
# 49.9 sec. Fedora standard: -m32 -march=i686 -mtune=generic -msse2 -mfpmath=sse
|
||||
# 50.4 sec. sse not sse2: -m32 -march=i686 -mtune=generic -msse -mfpmath=sse
|
||||
#
|
||||
# That's what I found several years ago with a much older compiler.
|
||||
# The original SSE helped a lot but SSE2 and later made little difference.
|
||||
#
|
||||
# direwolf 1.6 - 64 bit target - gcc 7.4.0
|
||||
#
|
||||
# 34.8 sec. with no SIMD instructions enabled.
|
||||
# 34.8 sec. with SSE
|
||||
# 34.8 sec. with SSE2
|
||||
# 34.2 sec. with SSE2, SSE3
|
||||
# 33.5 sec. with SSE2, SSE3, SSE4.1, SSE4.2
|
||||
# 33.4 Fedora standard: -mtune=generic
|
||||
#
|
||||
# Why do we see such little variation? 64-bit target implies
|
||||
# SSE, SSE2, SSE3 instructions are available.
|
||||
#
|
||||
# Building for a 64 bit target makes it run about 1.5x faster on the same hardware.
|
||||
#
|
||||
# The default will be set for maximum portability so packagers won't need to
|
||||
# to anything special.
|
||||
#
|
||||
#
|
||||
# While ENABLE_GENERIC also had the desired result (for x86_64), I don't think
|
||||
# it is the right approach. It prevents the detection of the architecture,
|
||||
# i.e. x86, x86_64, ARM, ARM64. That's why it did not go looking for the various
|
||||
# SSE instructions. For x86, we would miss out on using SSE.
|
||||
|
||||
if (NOT ENABLE_GENERIC)
|
||||
if (C_MSVC)
|
||||
detect_architecture("_M_AMD64" x86_64)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
detect_architecture("_M_ARM" ARM)
|
||||
detect_architecture("_M_ARM64" ARM64)
|
||||
else()
|
||||
detect_architecture("__x86_64__" x86_64)
|
||||
detect_architecture("__i386__" x86)
|
||||
detect_architecture("__arm__" ARM)
|
||||
detect_architecture("__aarch64__" ARM64)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
set(ARCHITECTURE "GENERIC")
|
||||
set(ARCHITECTURE_GENERIC 1)
|
||||
add_definitions(-DARCHITECTURE_GENERIC=1)
|
||||
endif()
|
||||
message(STATUS "Target architecture: ${ARCHITECTURE}")
|
||||
|
||||
set(TEST_DIR ${PROJECT_SOURCE_DIR}/cmake/cpu_tests)
|
||||
|
||||
# flag that set the minimum cpu flag requirements
|
||||
# used to create re-distribuitable binary
|
||||
|
||||
if (${ARCHITECTURE} MATCHES "x86_64|x86" AND (FORCE_SSE OR FORCE_SSSE3 OR FORCE_SSE41))
|
||||
if (FORCE_SSE)
|
||||
set(HAS_SSE ON CACHE BOOL "SSE SIMD enabled")
|
||||
if(C_GCC OR C_CLANG)
|
||||
if (${ARCHITECTURE} MATCHES "x86_64")
|
||||
# All 64-bit capable chips support MMX, SSE, SSE2, and SSE3
|
||||
# so they are all enabled automatically. We don't want to use
|
||||
# SSE4, based on build machine capabilites, because the application
|
||||
# would not run properly on an older CPU.
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtune=generic" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic" )
|
||||
else()
|
||||
# Fedora standard uses -msse2 here.
|
||||
# I dropped it down to -msse for greater compatibility and little penalty.
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686 -mtune=generic -msse -mfpmath=sse" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -march=i686 -mtune=generic -msse -mfpmath=sse" )
|
||||
endif()
|
||||
message(STATUS "Use SSE SIMD instructions")
|
||||
add_definitions(-DUSE_SSE)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:SSE" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSE" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
message(STATUS "Use MSVC SSSE3 SIMD instructions")
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
endif()
|
||||
elseif (FORCE_SSSE3)
|
||||
set(HAS_SSSE3 ON CACHE BOOL "SSSE3 SIMD enabled")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3" )
|
||||
message(STATUS "Use SSSE3 SIMD instructions")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:SSSE3" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSSE3" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
message(STATUS "Use MSVC SSSE3 SIMD instructions")
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
endif()
|
||||
elseif (FORCE_SSE41)
|
||||
set(HAS_SSSE3 ON CACHE BOOL "SSSE3 SIMD enabled")
|
||||
set(HAS_SSE4_1 ON CACHE BOOL "Architecture has SSE 4.1 SIMD enabled")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1" )
|
||||
message(STATUS "Use SSE 4.1 SIMD instructions")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
add_definitions(-DUSE_SSE4_1)
|
||||
elseif(C_MSVC)
|
||||
# seems that from MSVC 2015 comiler doesn't support those flags
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:SSE4_1" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSE4_1" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
message(STATUS "Use SSE 4.1 SIMD instructions")
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
add_definitions(-DUSE_SSE4_1)
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
if (${ARCHITECTURE} MATCHES "x86_64|x86")
|
||||
if(C_MSVC)
|
||||
try_run(RUN_SSE2 COMPILE_SSE2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse2.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_SSE2 COMPILE_SSE2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse2.cxx" COMPILE_DEFINITIONS -msse2 -O0)
|
||||
endif()
|
||||
if(COMPILE_SSE2 AND RUN_SSE2 EQUAL 0)
|
||||
set(HAS_SSE2 ON CACHE BOOL "Architecture has SSSE2 SIMD enabled")
|
||||
message(STATUS "Use SSE2 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2" )
|
||||
add_definitions(-DUSE_SSE2)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:SSE2" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSE2" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:SSE2" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:SSE2" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSE2)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_SSE2 OFF CACHE BOOL "Architecture does not have SSSE2 SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_SSSE3 COMPILE_SSSE3 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_ssse3.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_SSSE3 COMPILE_SSSE3 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_ssse3.cxx" COMPILE_DEFINITIONS -mssse3 -O0)
|
||||
endif()
|
||||
if(COMPILE_SSSE3 AND RUN_SSSE3 EQUAL 0)
|
||||
set(HAS_SSSE3 ON CACHE BOOL "Architecture has SSSE3 SIMD enabled")
|
||||
message(STATUS "Use SSSE3 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3" )
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
elseif(C_MSVC)
|
||||
# seems not present on MSVC 2017
|
||||
#set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:SSSE3" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSSE3)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_SSSE3 OFF CACHE BOOL "Architecture does not have SSSE3 SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_SSE4_1 COMPILE_SSE4_1 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse41.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_SSE4_1 COMPILE_SSE4_1 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse41.cxx" COMPILE_DEFINITIONS -msse4.1 -O0)
|
||||
endif()
|
||||
if(COMPILE_SSE4_1 AND RUN_SSE4_1 EQUAL 0)
|
||||
set(HAS_SSE4_1 ON CACHE BOOL "Architecture has SSE 4.1 SIMD enabled")
|
||||
message(STATUS "Use SSE 4.1 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1" )
|
||||
add_definitions(-DUSE_SSE4_1)
|
||||
elseif(C_MSVC)
|
||||
# seems not present on MSVC 2017
|
||||
#set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSE4_1" )
|
||||
#set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:SSE4_1" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSE4_1)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_SSE4_1 OFF CACHE BOOL "Architecture does not have SSE 4.1 SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_SSE4_2 COMPILE_SSE4_2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse42.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_SSE4_2 COMPILE_SSE4_2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_sse42.cxx" COMPILE_DEFINITIONS -msse4.2 -O0)
|
||||
endif()
|
||||
if(COMPILE_SSE4_2 AND RUN_SSE4_2 EQUAL 0)
|
||||
set(HAS_SSE4_2 ON CACHE BOOL "Architecture has SSE 4.2 SIMD enabled")
|
||||
message(STATUS "Use SSE 4.2 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.2" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2" )
|
||||
add_definitions(-DUSE_SSE4_2)
|
||||
elseif(C_MSVC)
|
||||
# seems not present on MSVC 2017
|
||||
#set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:SSE4_2" )
|
||||
#set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:SSE4_2" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_SSE4_2)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_SSE4_2 OFF CACHE BOOL "Architecture does not have SSE 4.2 SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_AVX COMPILE_AVX "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_AVX COMPILE_AVX "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx.cxx" COMPILE_DEFINITIONS -mavx -O0)
|
||||
endif()
|
||||
if(COMPILE_AVX AND RUN_AVX EQUAL 0)
|
||||
set(HAS_AVX ON CACHE BOOL "Architecture has AVX SIMD enabled")
|
||||
message(STATUS "Use AVX SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx" )
|
||||
add_definitions(-DUSE_AVX)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:AVX" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:AVX" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_AVX)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_AVX OFF CACHE BOOL "Architecture does not have AVX SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_AVX2 COMPILE_AVX2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx2.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_AVX2 COMPILE_AVX2 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx2.cxx" COMPILE_DEFINITIONS -mavx2 -O0)
|
||||
endif()
|
||||
if(COMPILE_AVX2 AND RUN_AVX2 EQUAL 0)
|
||||
set(HAS_AVX2 ON CACHE BOOL "Architecture has AVX2 SIMD enabled")
|
||||
message(STATUS "Use AVX2 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx2" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx2" )
|
||||
add_definitions(-DUSE_AVX2)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:AVX2" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:AVX2" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX2" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX2" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_AVX2)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_AVX2 OFF CACHE BOOL "Architecture does not have AVX2 SIMD enabled")
|
||||
endif()
|
||||
if(C_MSVC)
|
||||
try_run(RUN_AVX512 COMPILE_AVX512 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx512.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
try_run(RUN_AVX512 COMPILE_AVX512 "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_x86_avx512.cxx" COMPILE_DEFINITIONS -mavx512f -O0)
|
||||
endif()
|
||||
if(COMPILE_AVX512 AND RUN_AVX512 EQUAL 0)
|
||||
set(HAS_AVX512 ON CACHE BOOL "Architecture has AVX512 SIMD enabled")
|
||||
message(STATUS "Use AVX512 SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f" )
|
||||
add_definitions(-DUSE_AVX512)
|
||||
elseif(C_MSVC)
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /arch:AVX512" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /arch:AVX512" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX512" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL /Ot /Ox /arch:AVX512" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" )
|
||||
add_definitions (/D "_CRT_SECURE_NO_WARNINGS")
|
||||
add_definitions(-DUSE_AVX512)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_AVX512 OFF CACHE BOOL "Architecture does not have AVX512 SIMD enabled")
|
||||
endif()
|
||||
elseif(ARCHITECTURE_ARM)
|
||||
if(C_MSVC)
|
||||
try_run(RUN_NEON COMPILE_NEON "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_arm_neon.cxx" COMPILE_DEFINITIONS /O0)
|
||||
else()
|
||||
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL ${CMAKE_SYSTEM_PROCESSOR})
|
||||
try_run(RUN_NEON COMPILE_NEON "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_arm_neon.cxx" COMPILE_DEFINITIONS -mfpu=neon -O0)
|
||||
else()
|
||||
try_compile(COMPILE_NEON "${CMAKE_BINARY_DIR}/tmp" "${TEST_DIR}/test_arm_neon.cxx" COMPILE_DEFINITIONS -mfpu=neon -O0)
|
||||
set(RUN_NEON 0)
|
||||
endif()
|
||||
endif()
|
||||
if(COMPILE_NEON AND RUN_NEON EQUAL 0)
|
||||
set(HAS_NEON ON CACHE BOOL "Architecture has NEON SIMD enabled")
|
||||
message(STATUS "Use NEON SIMD instructions")
|
||||
if(C_GCC OR C_CLANG)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon" )
|
||||
add_definitions(-DUSE_NEON)
|
||||
endif()
|
||||
else()
|
||||
set(HAS_NEON OFF CACHE BOOL "Architecture does not have NEON SIMD enabled")
|
||||
endif()
|
||||
elseif(ARCHITECTURE_ARM64)
|
||||
# Advanced SIMD (aka NEON) is mandatory for AArch64
|
||||
set(HAS_NEON ON CACHE BOOL "Architecture has NEON SIMD enabled")
|
||||
message(STATUS "Use NEON SIMD instructions")
|
||||
add_definitions(-DUSE_NEON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# clear binary test folder
|
||||
FILE(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/tmp)
|
|
@ -1,15 +0,0 @@
|
|||
# Clang or AppleClang (see CMP0025)
|
||||
if(NOT DEFINED C_CLANG AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(C_CLANG 1)
|
||||
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)
|
||||
set(VS2019 ON)
|
||||
elseif(MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS_EQUAL 1919)
|
||||
set(VS2017 ON)
|
||||
elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910)
|
||||
set(VS2015 ON)
|
||||
endif()
|
||||
endif()
|
|
@ -1,88 +0,0 @@
|
|||
# - Try to find GPSD
|
||||
# Once done this will define
|
||||
#
|
||||
# GPSD_FOUND - system has GPSD
|
||||
# GPSD_INCLUDE_DIRS - the GPSD include directory
|
||||
# GPSD_LIBRARIES - Link these to use GPSD
|
||||
# GPSD_DEFINITIONS - Compiler switches required for using GPSD
|
||||
#
|
||||
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
set(GPSD_ROOT_DIR
|
||||
"${GPSD_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search for gpsd")
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_GPSD libgps)
|
||||
endif()
|
||||
|
||||
if (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(GPSD_FOUND TRUE)
|
||||
else (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS)
|
||||
find_path(GPSD_INCLUDE_DIRS
|
||||
NAMES
|
||||
gps.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
/usr/include/gps
|
||||
/usr/local/include/gps
|
||||
/opt/local/include/gps
|
||||
/sw/include/gps
|
||||
HINTS
|
||||
${PC_GPSD_INCLUDEDIR}
|
||||
${GPSD_ROOT_DIR}
|
||||
)
|
||||
|
||||
# debian uses version suffixes
|
||||
# add suffix evey new release
|
||||
find_library(GPSD_LIBRARIES
|
||||
NAMES
|
||||
gps
|
||||
PATHS
|
||||
/usr/lib64
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
HINTS
|
||||
${PC_GPSD_LIBDIR}
|
||||
${GPSD_ROOT_DIR}
|
||||
)
|
||||
|
||||
if (GPSD_INCLUDE_DIRS AND GPSD_LIBRARIES)
|
||||
set(GPSD_FOUND TRUE)
|
||||
endif (GPSD_INCLUDE_DIRS AND GPSD_LIBRARIES)
|
||||
|
||||
if (GPSD_FOUND)
|
||||
if (NOT GPSD_FIND_QUIETLY)
|
||||
message(STATUS "Found GPSD: ${GPSD_LIBRARIES}")
|
||||
endif (NOT GPSD_FIND_QUIETLY)
|
||||
else (GPSD_FOUND)
|
||||
if (GPSD_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find GPSD")
|
||||
endif (GPSD_FIND_REQUIRED)
|
||||
endif (GPSD_FOUND)
|
||||
|
||||
# show the GPSD_INCLUDE_DIRS and GPSD_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GPSD_INCLUDE_DIRS GPSD_LIBRARIES)
|
||||
|
||||
endif (GPSD_LIBRARIES AND GPSD_INCLUDE_DIRS)
|
||||
|
||||
# maybe on CYGWIN gpsd works
|
||||
if (WIN32)
|
||||
set(GPSD_FOUND FALSE)
|
||||
set(GPSD_LIBRARIES "")
|
||||
set(GPSD_INCLUDE_DIRS "")
|
||||
endif (WIN32)
|
|
@ -1,64 +0,0 @@
|
|||
# - Try to find Portaudio
|
||||
# Once done this will define
|
||||
#
|
||||
# PORTAUDIO_FOUND - system has Portaudio
|
||||
# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory
|
||||
# PORTAUDIO_LIBRARIES - Link these to use Portaudio
|
||||
|
||||
set(PORTAUDIO_ROOT_DIR
|
||||
"${PORTAUDIO_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search for portaudio")
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_PORTAUDIO portaudio-2.0)
|
||||
endif()
|
||||
|
||||
find_path(PORTAUDIO_INCLUDE_DIRS
|
||||
NAMES
|
||||
portaudio.h
|
||||
PATHS
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/opt/local/include
|
||||
HINTS
|
||||
${PC_PORTAUDIO_INCLUDEDIR}
|
||||
${PORTAUDIO_ROOT_DIR}
|
||||
)
|
||||
|
||||
find_library(PORTAUDIO_LIBRARIES
|
||||
NAMES
|
||||
portaudio
|
||||
PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
HINTS
|
||||
${PC_PORTAUDIO_LIBDIR}
|
||||
${PORTAUDIO_ROOT_DIR}
|
||||
)
|
||||
|
||||
mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
|
||||
|
||||
# Found PORTAUDIO, but it may be version 18 which is not acceptable.
|
||||
if(EXISTS ${PORTAUDIO_INCLUDE_DIRS}/portaudio.h)
|
||||
include(CheckCXXSourceCompiles)
|
||||
set(CMAKE_REQUIRED_INCLUDES_SAVED ${CMAKE_REQUIRED_INCLUDES})
|
||||
set(CMAKE_REQUIRED_INCLUDES ${PORTAUDIO_INCLUDE_DIRS})
|
||||
CHECK_CXX_SOURCE_COMPILES(
|
||||
"#include <portaudio.h>\nPaDeviceIndex pa_find_device_by_name(const char *name); int main () {return 0;}"
|
||||
PORTAUDIO2_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVED})
|
||||
unset(CMAKE_REQUIRED_INCLUDES_SAVED)
|
||||
if(PORTAUDIO2_FOUND)
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PORTAUDIO DEFAULT_MSG PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
|
||||
else(PORTAUDIO2_FOUND)
|
||||
message(STATUS
|
||||
" portaudio.h not compatible (requires API 2.0)")
|
||||
set(PORTAUDIO_FOUND FALSE)
|
||||
endif(PORTAUDIO2_FOUND)
|
||||
endif()
|
|
@ -1,67 +0,0 @@
|
|||
# - Try to find Hamlib
|
||||
#
|
||||
# HAMLIB_FOUND - system has Hamlib
|
||||
# HAMLIB_LIBRARIES - location of the library for hamlib
|
||||
# HAMLIB_INCLUDE_DIRS - location of the include files for hamlib
|
||||
#
|
||||
# Requires these CMake modules:
|
||||
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
|
||||
#
|
||||
# Original Author:
|
||||
# 2019 Davide Gerhard <rainbow@irh.it>
|
||||
|
||||
set(HAMLIB_ROOT_DIR
|
||||
"${HAMLIB_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search for hamlib")
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_HAMLIB hamlib)
|
||||
endif()
|
||||
|
||||
find_path(HAMLIB_INCLUDE_DIR
|
||||
NAMES hamlib/rig.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
HINTS
|
||||
${PC_HAMLIB_INCLUDEDIR}
|
||||
${HAMLIB_ROOT_DIR}
|
||||
)
|
||||
|
||||
find_library(HAMLIB_LIBRARY
|
||||
NAMES hamlib
|
||||
PATHS
|
||||
/usr/lib64/hamlib
|
||||
/usr/lib/hamlib
|
||||
/usr/lib64
|
||||
/usr/lib
|
||||
/usr/local/lib64/hamlib
|
||||
/usr/local/lib/hamlib
|
||||
/usr/local/lib64
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/opt/local/lib/hamlib
|
||||
HINTS
|
||||
${PC_HAMLIB_LIBDIR}
|
||||
${HAMLIB_ROOT_DIR}
|
||||
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(hamlib
|
||||
DEFAULT_MSG
|
||||
HAMLIB_LIBRARY
|
||||
HAMLIB_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(HAMLIB_FOUND)
|
||||
list(APPEND HAMLIB_LIBRARIES ${HAMLIB_LIBRARY})
|
||||
list(APPEND HAMLIB_INCLUDE_DIRS ${HAMLIB_INCLUDE_DIR})
|
||||
mark_as_advanced(HAMLIB_ROOT_DIR)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(HAMLIB_INCLUDE_DIR HAMLIB_LIBRARY)
|
|
@ -1,42 +0,0 @@
|
|||
# - Try to find sndio
|
||||
#
|
||||
# SNDIO_FOUND - system has sndio
|
||||
# SNDIO_LIBRARIES - location of the library for sndio
|
||||
# SNDIO_INCLUDE_DIRS - location of the include files for sndio
|
||||
|
||||
set(SNDIO_ROOT_DIR
|
||||
"${SNDIO_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search for sndio")
|
||||
|
||||
# no need to check pkg-config
|
||||
|
||||
find_path(SNDIO_INCLUDE_DIRS
|
||||
NAMES
|
||||
sndio.h
|
||||
PATHS
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/opt/local/include
|
||||
HINTS
|
||||
${SNDIO_ROOT_DIR}
|
||||
)
|
||||
|
||||
find_library(SNDIO_LIBRARIES
|
||||
NAMES
|
||||
sndio
|
||||
PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
HINTS
|
||||
${SNDIIO_ROOT_DIR}
|
||||
)
|
||||
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SNDIO DEFAULT_MSG SNDIO_INCLUDE_DIRS SNDIO_LIBRARIES)
|
||||
|
||||
mark_as_advanced(SNDIO_INCLUDE_DIRS SNDIO_LIBRARIES)
|
|
@ -1,85 +0,0 @@
|
|||
# - try to find the udev library
|
||||
#
|
||||
# Cache Variables: (probably not for direct use in your scripts)
|
||||
# UDEV_INCLUDE_DIR
|
||||
# UDEV_SOURCE_DIR
|
||||
# UDEV_LIBRARY
|
||||
#
|
||||
# Non-cache variables you might use in your CMakeLists.txt:
|
||||
# UDEV_FOUND
|
||||
# UDEV_INCLUDE_DIRS
|
||||
# UDEV_LIBRARIES
|
||||
#
|
||||
# Requires these CMake modules:
|
||||
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
|
||||
#
|
||||
# Original Author:
|
||||
# 2014 Kevin M. Godby <kevin@godby.org>
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(UDEV_ROOT_DIR
|
||||
"${UDEV_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Directory to search for udev")
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_LIBUDEV libudev)
|
||||
endif()
|
||||
|
||||
find_library(UDEV_LIBRARY
|
||||
NAMES
|
||||
udev
|
||||
PATHS
|
||||
${PC_LIBUDEV_LIBRARY_DIRS}
|
||||
${PC_LIBUDEV_LIBDIR}
|
||||
/usr/lib64
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
HINTS
|
||||
"${UDEV_ROOT_DIR}"
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
get_filename_component(_libdir "${UDEV_LIBRARY}" PATH)
|
||||
|
||||
find_path(UDEV_INCLUDE_DIR
|
||||
NAMES
|
||||
libudev.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
${PC_LIBUDEV_INCLUDE_DIRS}
|
||||
${PC_LIBUDEV_INCLUDEDIR}
|
||||
HINTS
|
||||
"${_libdir}"
|
||||
"${_libdir}/.."
|
||||
"${UDEV_ROOT_DIR}"
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(udev
|
||||
DEFAULT_MSG
|
||||
UDEV_LIBRARY
|
||||
UDEV_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (UDEV_INCLUDE_DIR AND UDEV_LIBRARY)
|
||||
set(UDEV_FOUND TRUE)
|
||||
endif (UDEV_INCLUDE_DIR AND UDEV_LIBRARY)
|
||||
|
||||
if(UDEV_FOUND)
|
||||
list(APPEND UDEV_LIBRARIES ${UDEV_LIBRARY})
|
||||
list(APPEND UDEV_INCLUDE_DIRS ${UDEV_INCLUDE_DIR})
|
||||
mark_as_advanced(UDEV_ROOT_DIR)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(UDEV_INCLUDE_DIR
|
||||
UDEV_LIBRARY)
|
|
@ -1,48 +0,0 @@
|
|||
# generate conf per platform
|
||||
file(READ "${CUSTOM_CONF_DIR}/generic.conf" file_content)
|
||||
|
||||
if(LINUX)
|
||||
string(REGEX REPLACE "\n%W%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%M%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%L%([^\n]*)" "\n\\1" file_content "${file_content}")
|
||||
elseif(WIN32 OR CYGWIN)
|
||||
string(REGEX REPLACE "\n%M%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%L%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%W%([^\n]*)" "\n\\1" file_content "${file_content}")
|
||||
else() # macOS FreeBSD OpenBSD
|
||||
string(REGEX REPLACE "\n%W%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%L%[^\n]*" "" file_content "${file_content}")
|
||||
string(REGEX REPLACE "\n%M%([^\n]*)" "\n\\1" file_content "${file_content}")
|
||||
endif()
|
||||
|
||||
# remove remark
|
||||
string(REGEX REPLACE "\n%R%[^\n]*" "" file_content "${file_content}")
|
||||
|
||||
# clear common lines
|
||||
string(REGEX REPLACE "\n%C%([^\n]*)" "\n\\1" file_content "${file_content}")
|
||||
string(REGEX REPLACE "^%C%([^\n]*)" "\\1" file_content "${file_content}")
|
||||
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/direwolf.conf" "${file_content}")
|
||||
|
||||
# install udev rules for CM108
|
||||
if(LINUX)
|
||||
install(FILES "${CUSTOM_CONF_DIR}/99-direwolf-cmedia.rules" DESTINATION /etc/udev/rules.d/)
|
||||
endif()
|
||||
|
||||
install(FILES "${CMAKE_BINARY_DIR}/direwolf.conf" DESTINATION ${INSTALL_CONF_DIR})
|
||||
install(FILES "${CUSTOM_CONF_DIR}/sdr.conf" DESTINATION ${INSTALL_CONF_DIR})
|
||||
|
||||
# Put sample configuration & startup files in home directory.
|
||||
# This step would be done as ordinary user.
|
||||
# Some people like to put the direwolf config file in /etc/ax25.
|
||||
# Note that all of these are also in $(DESTDIR)/share/doc/direwolf/examples/.
|
||||
if(NOT (WIN32 OR CYGWIN))
|
||||
add_custom_target(install-conf
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCUSTOM_BINARY_DIR="${CMAKE_BINARY_DIR}"
|
||||
-DCUSTOM_CONF_DIR="${CUSTOM_CONF_DIR}"
|
||||
-DCUSTOM_SCRIPTS_DIR="${CUSTOM_SCRIPTS_DIR}"
|
||||
-DCUSTOM_TELEMETRY_DIR="${CUSTOM_TELEMETRY_DIR}"
|
||||
-P "${CMAKE_SOURCE_DIR}/conf/install_conf.cmake"
|
||||
)
|
||||
endif()
|
|
@ -1,537 +0,0 @@
|
|||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# Configuration file for Dire Wolf #
|
||||
%C%# #
|
||||
%L%# Linux version #
|
||||
%W%# Windows version #
|
||||
%M%# Macintosh version #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%R%
|
||||
%R%
|
||||
%R% The sample config file was getting pretty messy
|
||||
%R% with the Windows and Linux differences.
|
||||
%R% It would be a maintenance burden to keep most of
|
||||
%R% two different versions in sync.
|
||||
%R% This common source is now used to generate the
|
||||
%R% two different variations while having only a single
|
||||
%R% copy of the common parts.
|
||||
%R%
|
||||
%R% The first column contains one of the following:
|
||||
%R%
|
||||
%R% R remark which is discarded.
|
||||
%R% C common to both versions.
|
||||
%R% W Windows version only.
|
||||
%R% L Linux version only.
|
||||
%R% M Macintosh version and possibly others (portaudio used).
|
||||
%R%
|
||||
%C%#
|
||||
%C%# Extensive documentation can be found here:
|
||||
%C%# Stable release - https://github.com/wb2osz/direwolf/tree/master/doc
|
||||
%C%# Latest development - https://github.com/wb2osz/direwolf/tree/dev/doc
|
||||
%C%# Additional topics - https://github.com/wb2osz/direwolf-doc
|
||||
%C%#
|
||||
%W%# The basic documentation set can also be found in the doc folder.
|
||||
%L%# The basic documentation set can also be found in
|
||||
%L%# /usr/local/share/doc/direwolf/ or /usr/share/doc/direwolf/
|
||||
%L%# Concise "man" pages are also available for Linux.
|
||||
%M%# /usr/local/share/doc/direwolf/ or /usr/share/doc/direwolf/
|
||||
%M%# Concise "man" pages are also available for Mac OSX.
|
||||
%C%#
|
||||
%C%# Questions??? Join the discussion forum: https://groups.io/g/direwolf
|
||||
%C%#
|
||||
%C%#
|
||||
%C%# This sample file does not have examples for all of the possibilities.
|
||||
%C%# Consult the User Guide for more details on configuration options
|
||||
%C%# and other documents for more details for different uses.
|
||||
%C%#
|
||||
%C%# These are the most likely settings you might change:
|
||||
%C%#
|
||||
%C%# (1) MYCALL - call sign and SSID for your station.
|
||||
%C%#
|
||||
%C%# Look for lines starting with MYCALL and
|
||||
%C%# change NOCALL to your own.
|
||||
%C%#
|
||||
%C%# (2) PBEACON - enable position beaconing.
|
||||
%C%#
|
||||
%C%# Look for lines starting with PBEACON and
|
||||
%C%# modify for your call, location, etc.
|
||||
%C%#
|
||||
%C%# (3) DIGIPEATER - configure digipeating rules.
|
||||
%C%#
|
||||
%C%# Look for lines starting with DIGIPEATER.
|
||||
%C%# Most people will probably use the given example.
|
||||
%C%# Just remove the "#" from the start of the line
|
||||
%C%# to enable it.
|
||||
%C%#
|
||||
%C%# (4) IGSERVER, IGLOGIN - IGate server and login
|
||||
%C%#
|
||||
%C%# Configure an IGate client to relay messages between
|
||||
%C%# radio and internet servers.
|
||||
%C%#
|
||||
%C%#
|
||||
%C%# The default location is "direwolf.conf" in the current working directory.
|
||||
%L%# On Linux, the user's home directory will also be searched.
|
||||
%C%# An alternate configuration file location can be specified with the "-c" command line option.
|
||||
%C%#
|
||||
%C%# As you probably guessed by now, # indicates a comment line.
|
||||
%C%#
|
||||
%C%# Remove the # at the beginning of a line if you want to use a sample
|
||||
%C%# configuration that is currently commented out.
|
||||
%C%#
|
||||
%C%# Commands are a keyword followed by parameters.
|
||||
%C%#
|
||||
%C%# Command key words are case insensitive. i.e. upper and lower case are equivalent.
|
||||
%C%#
|
||||
%C%# Command parameters are generally case sensitive. i.e. upper and lower case are different.
|
||||
%C%#
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# FIRST AUDIO DEVICE PROPERTIES #
|
||||
%C%# (Channel 0 + 1 if in stereo) #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Many people will simply use the default sound device.
|
||||
%C%# Some might want to use an alternative device by choosing it here.
|
||||
%C%#
|
||||
%C%#
|
||||
%C%# Many examples of radio interfaces and PTT options can be found in:
|
||||
%C%# https://github.com/wb2osz/direwolf-doc/blob/main/Radio-Interface-Guide.pdf
|
||||
%C%#
|
||||
%C%#
|
||||
%R% ---------- Windows ----------
|
||||
%R%
|
||||
%W%# When the Windows version starts up, it displays something like
|
||||
%W%# this with the available sound devices and capabilities:
|
||||
%W%#
|
||||
%W%# Available audio input devices for receive (*=selected):
|
||||
%W%# * 0: Microphone (C-Media USB Headpho (channel 2)
|
||||
%W%# 1: Microphone (Bluetooth SCO Audio
|
||||
%W%# 2: Microphone (Bluetooth AV Audio)
|
||||
%W%# * 3: Microphone (Realtek High Defini (channels 0 & 1)
|
||||
%W%# Available audio output devices for transmit (*=selected):
|
||||
%W%# * 0: Speakers (C-Media USB Headphone (channel 2)
|
||||
%W%# 1: Speakers (Bluetooth SCO Audio)
|
||||
%W%# 2: Realtek Digital Output(Optical)
|
||||
%W%# 3: Speakers (Bluetooth AV Audio)
|
||||
%W%# * 4: Speakers (Realtek High Definiti (channels 0 & 1)
|
||||
%W%# 5: Realtek Digital Output (Realtek
|
||||
%W%#
|
||||
%W%# Example: To use the microphone and speaker connections on the
|
||||
%W%# system board, either of these forms can be used:
|
||||
%W%
|
||||
%W%#ADEVICE High
|
||||
%W%#ADEVICE 3 4
|
||||
%W%
|
||||
%W%
|
||||
%W%# Example: To use the USB Audio, use a command like this with
|
||||
%W%# the input and output device numbers. (Remove the # comment character.)
|
||||
%W%#ADEVICE USB
|
||||
%W%
|
||||
%W%# You can also use "-" or "stdin" to pipe stdout from
|
||||
%W%# some other application such as a software defined radio.
|
||||
%W%# "stdin" is not an audio device. Don't use this unless you
|
||||
%W%# understand what this means. Read the User Guide.
|
||||
%W%# You can also specify "UDP:" and an optional port for input.
|
||||
%W%# Something different must be specified for output.
|
||||
%W%
|
||||
%W%# ADEVICE stdin 0
|
||||
%W%# ADEVICE UDP:7355 0
|
||||
%W%
|
||||
%W%# The position in the list can change when devices (e.g. USB) are added and removed.
|
||||
%W%# You can also specify devices by using part of the name.
|
||||
%W%# Here is an example of specifying the USB Audio device.
|
||||
%W%# This is case-sensitive. Upper and lower case are not treated the same.
|
||||
%W%
|
||||
%W%#ADEVICE USB
|
||||
%W%
|
||||
%W%
|
||||
%R% ---------- Linux ----------
|
||||
%R%
|
||||
%L%# Linux ALSA is complicated. See User Guide for discussion.
|
||||
%L%# To use something other than the default, generally use plughw
|
||||
%L%# and a card number reported by "arecord -l" command. Example:
|
||||
%L%
|
||||
%L%# ADEVICE plughw:1,0
|
||||
%L%
|
||||
%L%# You can also use "-" or "stdin" to pipe stdout from
|
||||
%L%# some other application such as a software defined radio.
|
||||
%L%# "stdin" is not an audio device. Don't use this unless you
|
||||
%L%# understand what this means. Read the User Guide.
|
||||
%L%# You can also specify "UDP:" and an optional port for input.
|
||||
%L%# Something different must be specified for output.
|
||||
%L%
|
||||
%L%# ADEVICE stdin plughw:1,0
|
||||
%L%# ADEVICE UDP:7355 default
|
||||
%L%
|
||||
%R% ---------- Mac ----------
|
||||
%R%
|
||||
%M%# Macintosh Operating System uses portaudio driver for audio
|
||||
%M%# input/output. Default device selection not available. User/OP
|
||||
%M%# must configure the sound input/output option. Note that
|
||||
%M%# the device names can contain spaces. In this case, the names
|
||||
%M%# must be enclosed by quotes.
|
||||
%M%#
|
||||
%M%# Examples:
|
||||
%M%#
|
||||
%M%ADEVICE "Built-in Input" "Built-in Output"
|
||||
%M%
|
||||
%M%# ADEVICE "USB Audio Codec:6" "USB Audio Codec:5"
|
||||
%M%#
|
||||
%M%#
|
||||
%M%# You can also use "-" or "stdin" to pipe stdout from
|
||||
%M%# some other application such as a software defined radio.
|
||||
%M%# "stdin" is not an audio device. Don't use this unless you
|
||||
%M%# understand what this means. Read the User Guide.
|
||||
%M%# You can also specify "UDP:" and an optional port for input.
|
||||
%M%# Something different must be specified for output.
|
||||
%M%
|
||||
%M%# ADEVICE UDP:7355 default
|
||||
%M%#
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Number of audio channels for this souncard: 1 (mono) or 2 (stereo).
|
||||
%C%# 1 is the default so there is no need to specify it.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#ACHANNELS 2
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# SECOND AUDIO DEVICE PROPERTIES #
|
||||
%C%# (Channel 2 + 3 if in stereo) #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#ADEVICE1 ...
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# THIRD AUDIO DEVICE PROPERTIES #
|
||||
%C%# (Channel 4 + 5 if in stereo) #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#ADEVICE2 ...
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# CHANNEL 0 PROPERTIES #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%CHANNEL 0
|
||||
%C%
|
||||
%C%#
|
||||
%C%# The following MYCALL, MODEM, PTT, etc. configuration items
|
||||
%C%# apply to the most recent CHANNEL.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Station identifier for this channel.
|
||||
%C%# Multiple channels can have the same or different names.
|
||||
%C%#
|
||||
%C%# It can be up to 6 letters and digits with an optional ssid.
|
||||
%C%# The APRS specification requires that it be upper case.
|
||||
%C%#
|
||||
%C%# Example (don't use this unless you are me): MYCALL WB2OSZ-5
|
||||
%C%#
|
||||
%C%
|
||||
%C%MYCALL N0CALL
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Pick a suitable modem speed based on your situation.
|
||||
%C%# 1200 Most common for VHF/UHF. This is the default if not specified.
|
||||
%C%# 2400 QPSK compatible with MFJ-2400, and probably PK232-2400 & KPC-2400.
|
||||
%C%# 300 Low speed for HF SSB. Default tones 1600 & 1800.
|
||||
%C%# EAS Emergency Alert System (EAS) Specific Area Message Encoding (SAME).
|
||||
%C%# 9600 G3RUH style - Can't use Microphone and Speaker connections.
|
||||
%C%# AIS International system for tracking ships on VHF.
|
||||
%C%# Also uses 9600 bps so Speaker connection won't work.
|
||||
%C%#
|
||||
%C%# In most cases you can just specify the speed. Examples:
|
||||
%C%#
|
||||
%C%
|
||||
%C%MODEM 1200
|
||||
%C%#MODEM 9600
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Many options are available for great flexibility.
|
||||
%C%# See User Guide for details.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Uncomment line below to enable the DTMF decoder for this channel.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#DTMF
|
||||
%C%
|
||||
%C%# Push to Talk (PTT) can be confusing because there are so many different cases.
|
||||
%C%# Radio-Interface-Guide.pdf in https://github.com/wb2osz/direwolf-doc
|
||||
%C%# goes into detail about the various options.
|
||||
%C%
|
||||
%L%# If using a C-Media CM108/CM119 or similar USB Audio Adapter,
|
||||
%L%# you can use a GPIO pin for PTT control. This is very convenient
|
||||
%L%# because a single USB connection is used for both audio and PTT.
|
||||
%L%# Example:
|
||||
%L%
|
||||
%L%#PTT CM108
|
||||
%L%
|
||||
%W%# If using a C-Media CM108/CM119 or similar USB Audio Adapter,
|
||||
%W%# you can use a GPIO pin for PTT control. This is very convenient
|
||||
%W%# because a single USB connection is used for both audio and PTT.
|
||||
%W%# Example:
|
||||
%W%
|
||||
%W%#PTT CM108
|
||||
%W%%C%#
|
||||
%C%# The transmitter Push to Talk (PTT) control can be wired to a serial port
|
||||
%C%# with a suitable interface circuit. DON'T connect it directly!
|
||||
%C%#
|
||||
%C%# For the PTT command, specify the device and either RTS or DTR.
|
||||
%C%# RTS or DTR may be preceded by "-" to invert the signal.
|
||||
%C%# Both can be used for interfaces that want them driven with opposite polarity.
|
||||
%C%#
|
||||
%L%# COM1 can be used instead of /dev/ttyS0, COM2 for /dev/ttyS1, and so on.
|
||||
%L%#
|
||||
%C%
|
||||
%C%#PTT COM1 RTS
|
||||
%C%#PTT COM1 RTS -DTR
|
||||
%L%#PTT /dev/ttyUSB0 RTS
|
||||
%L%#PTT /dev/ttyUSB0 RTS -DTR
|
||||
%C%
|
||||
%L%#
|
||||
%L%# On Linux, you can also use general purpose I/O pins if
|
||||
%L%# your system is configured for user access to them.
|
||||
%L%# This would apply mostly to microprocessor boards, not a regular PC.
|
||||
%L%# See separate Raspberry Pi document for more details.
|
||||
%L%# The number may be preceded by "-" to invert the signal.
|
||||
%L%#
|
||||
%L%
|
||||
%L%#PTT GPIO 25
|
||||
%L%
|
||||
%C%# The Data Carrier Detect (DCD) signal can be sent to most of the same places
|
||||
%C%# as the PTT signal. This could be used to light up an LED like a normal TNC.
|
||||
%C%
|
||||
%C%#DCD COM1 -DTR
|
||||
%L%#DCD GPIO 24
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# CHANNEL 1 PROPERTIES #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#CHANNEL 1
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Specify MYCALL, MODEM, PTT, etc. configuration items for
|
||||
%C%# CHANNEL 1. Repeat for any other channels.
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# TEXT TO SPEECH COMMAND FILE #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%W%#SPEECH dwespeak.bat
|
||||
%L%#SPEECH dwespeak.sh
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# VIRTUAL TNC SERVER PROPERTIES #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Dire Wolf acts as a virtual TNC and can communicate with
|
||||
%C%# client applications by different protocols:
|
||||
%C%#
|
||||
%C%# - the "AGW TCPIP Socket Interface" - default port 8000
|
||||
%C%# - KISS protocol over TCP socket - default port 8001
|
||||
%W%# - KISS TNC via serial port
|
||||
%L%# - KISS TNC via pseudo terminal (-p command line option)
|
||||
%C%#
|
||||
%C%
|
||||
%C%AGWPORT 8000
|
||||
%C%KISSPORT 8001
|
||||
%C%
|
||||
%W%#
|
||||
%W%# Some applications are designed to operate with only a physical
|
||||
%W%# TNC attached to a serial port. For these, we provide a virtual serial
|
||||
%W%# port that appears to be connected to a TNC.
|
||||
%W%#
|
||||
%W%# Take a look at the User Guide for instructions to set up
|
||||
%W%# two virtual serial ports named COM3 and COM4 connected by
|
||||
%W%# a null modem.
|
||||
%W%#
|
||||
%W%# Using the configuration described, Dire Wolf will connect to
|
||||
%W%# COM3 and the client application will use COM4.
|
||||
%W%#
|
||||
%W%# Uncomment following line to use this feature.
|
||||
%W%
|
||||
%W%#NULLMODEM COM3
|
||||
%W%
|
||||
%W%
|
||||
%C%#
|
||||
%C%# It is sometimes possible to recover frames with a bad FCS.
|
||||
%C%# This is not a global setting.
|
||||
%C%# It applies only the the most recent CHANNEL specified.
|
||||
%C%#
|
||||
%C%# 0 - Don't try to repair. (default)
|
||||
%C%# 1 - Attempt to fix single bit error.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#FIX_BITS 0
|
||||
%C%
|
||||
%C%#
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# FIXED POSIION BEACONING PROPERTIES #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Beaconing is configured with these two commands:
|
||||
%C%#
|
||||
%C%# PBEACON - for a position report (usually yourself)
|
||||
%C%# OBEACON - for an object report (usually some other entity)
|
||||
%C%#
|
||||
%C%# Each has a series of keywords and values for options.
|
||||
%C%# See User Guide for details.
|
||||
%C%#
|
||||
%C%# Example:
|
||||
%C%#
|
||||
%C%# This results in a broadcast once every 10 minutes.
|
||||
%C%# Every half hour, it can travel via one digipeater hop.
|
||||
%C%# The others are kept local.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#PBEACON delay=1 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1
|
||||
%C%#PBEACON delay=11 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||
%C%#PBEACON delay=21 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Did you know that APRS comments and messages can contain UTF-8 characters, not only plain ASCII?
|
||||
%C%#
|
||||
%C%#PBEACON delay=1 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W comment=" Did you know that APRS comments and messages can contain UTF-8 characters? \xe0\xb8\xa7\xe0\xb8\xb4\xe0\xb8\x97\xe0\xb8\xa2\xe0\xb8\xb8\xe0\xb8\xaa\xe0\xb8\xa1\xe0\xb8\xb1\xe0\xb8\x84\xe0\xb8\xa3\xe0\xb9\x80\xe0\xb8\xa5\xe0\xb9\x88\xe0\xb8\x99"
|
||||
%C%#PBEACON delay=11 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W comment=" Did you know that APRS comments and messages can contain UTF-8 characters? \xce\xa1\xce\xb1\xce\xb4\xce\xb9\xce\xbf\xce\xb5\xcf\x81\xce\xb1\xcf\x83\xce\xb9\xcf\x84\xce\xb5\xcf\x87\xce\xbd\xce\xb9\xcf\x83\xce\xbc\xcf\x8c\xcf\x82"
|
||||
%C%#PBEACON delay=21 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W comment=" Did you know that APRS comments and messages can contain UTF-8 characters? \xe3\x82\xa2\xe3\x83\x9e\xe3\x83\x81\xe3\x83\xa5\xe3\x82\xa2\xe7\x84\xa1\xe7\xb7\x9a"
|
||||
%C%#
|
||||
%C%# With UTM coordinates instead of latitude and longitude.
|
||||
%C%
|
||||
%C%#PBEACON delay=1 every=10 overlay=S symbol="digi" zone=19T easting=307477 northing=4720178
|
||||
%C%
|
||||
%C%
|
||||
%C%#
|
||||
%C%# When the destination field is set to "SPEECH" the information part is
|
||||
%C%# converted to speech rather than transmitted as a data frame.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#CBEACON dest="SPEECH" info="Club meeting tonight at 7 pm."
|
||||
%C%
|
||||
%C%# Similar for Morse code. If SSID is specified, it is multiplied
|
||||
%C%# by 2 to get speed in words per minute (WPM).
|
||||
%C%
|
||||
%C%#CBEACON dest="MORSE-6" info="de MYCALL"
|
||||
%C%
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Modify for your particular situation before removing
|
||||
%C%# the # comment character from the beginning of appropriate lines above.
|
||||
%C%#
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# APRS DIGIPEATER PROPERTIES #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#
|
||||
%C%# For most common situations, use something like this by removing
|
||||
%C%# the "#" from the beginning of the line below.
|
||||
%C%#
|
||||
%C%
|
||||
%C%#DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$
|
||||
%C%
|
||||
%C%# See User Guide and "APRS-Digipeaters.pdf" for more explanation of what
|
||||
%C%# this means and how it can be customized for your particular needs.
|
||||
%C%
|
||||
%C%
|
||||
%C%# Traditional connected mode packet radio uses a different
|
||||
%C%# type of digipeating. See User Guide for details.
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# INTERNET GATEWAY #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%# First you need to specify the name of a Tier 2 server.
|
||||
%C%# The current preferred way is to use one of these regional rotate addresses:
|
||||
%C%
|
||||
%C%# noam.aprs2.net - for North America
|
||||
%C%# soam.aprs2.net - for South America
|
||||
%C%# euro.aprs2.net - for Europe and Africa
|
||||
%C%# asia.aprs2.net - for Asia
|
||||
%C%# aunz.aprs2.net - for Oceania
|
||||
%C%
|
||||
%C%#IGSERVER noam.aprs2.net
|
||||
%C%
|
||||
%C%# You also need to specify your login name and passcode.
|
||||
%C%# Contact the author if you can't figure out how to generate the passcode.
|
||||
%C%
|
||||
%C%#IGLOGIN WB2OSZ-5 123456
|
||||
%C%
|
||||
%C%# That's all you need for a receive only IGate which relays
|
||||
%C%# messages from the local radio channel to the global servers.
|
||||
%C%
|
||||
%C%# Some might want to send an IGate client position directly to a server
|
||||
%C%# without sending it over the air and relying on someone else to
|
||||
%C%# forward it to an IGate server. This is done by using sendto=IG rather
|
||||
%C%# than a radio channel number. Overlay R for receive only, T for two way.
|
||||
%C%# There is no need to send it as often as you would over the radio.
|
||||
%C%
|
||||
%C%#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=R lat=42^37.14N long=071^20.83W
|
||||
%C%#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=T lat=42^37.14N long=071^20.83W
|
||||
%C%
|
||||
%C%
|
||||
%C%# To relay messages from the Internet to radio, you need to add
|
||||
%C%# one more option with the transmit channel number and a VIA path.
|
||||
%C%
|
||||
%C%#IGTXVIA 0 WIDE1-1,WIDE2-1
|
||||
%C%
|
||||
%C%
|
||||
%C%# Finally, we don't want to flood the radio channel.
|
||||
%C%# The IGate function will limit the number of packets transmitted
|
||||
%C%# during 1 minute and 5 minute intervals. If a limit would
|
||||
%C%# be exceeded, the packet is dropped and message is displayed in red.
|
||||
%C%# This might be low for APRS Thursday when there is abnormally high activity.
|
||||
%C%
|
||||
%C%IGTXLIMIT 6 10
|
||||
%C%
|
||||
%C%
|
||||
%C%#############################################################
|
||||
%C%# #
|
||||
%C%# APRStt GATEWAY #
|
||||
%C%# #
|
||||
%C%#############################################################
|
||||
%C%
|
||||
%C%#
|
||||
%C%# Dire Wolf can receive DTMF (commonly known as Touch Tone)
|
||||
%C%# messages and convert them to packet objects.
|
||||
%C%#
|
||||
%C%# See separate "APRStt-Implementation-Notes" document for details.
|
||||
%C%#
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
if(NOT EXISTS $ENV{HOME}/direwolf.conf)
|
||||
configure_file("${CUSTOM_BINARY_DIR}/direwolf.conf" $ENV{HOME})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS $ENV{HOME}/sdr.conf)
|
||||
configure_file("${CUSTOM_CONF_DIR}/sdr.conf" $ENV{HOME})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS $ENV{HOME}/dw-start.sh)
|
||||
configure_file("${CUSTOM_SCRIPTS_DIR}/dw-start.sh" $ENV{HOME})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS $ENV{HOME}/telem-m0xer-3.txt)
|
||||
configure_file("${CUSTOM_TELEMETRY_DIR}/telem-m0xer-3.txt" $ENV{HOME})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS $ENV{HOME}/telem-balloon.conf)
|
||||
configure_file("${CUSTOM_TELEMETRY_DIR}/telem-balloon.conf" $ENV{HOME})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS $ENV{HOME}/telem-volts.conf)
|
||||
configure_file("${CUSTOM_TELEMETRY_DIR}/telem-volts.conf" $ENV{HOME})
|
||||
endif()
|
File diff suppressed because it is too large
Load Diff
|
@ -30,32 +30,11 @@ enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
|
|||
|
||||
|
||||
#define MAX_BEACONS 30
|
||||
#define MAX_KISS_TCP_PORTS (MAX_CHANS+1)
|
||||
|
||||
struct misc_config_s {
|
||||
|
||||
int agwpe_port; /* TCP Port number for the "AGW TCPIP Socket Interface" */
|
||||
|
||||
// Previously we allowed only a single TCP port for KISS.
|
||||
// An increasing number of people want to run multiple radios.
|
||||
// Unfortunately, most applications don't know how to deal with multi-radio TNCs.
|
||||
// They ignore the channel on receive and always transmit to channel 0.
|
||||
// Running multiple instances of direwolf is a work-around but this leads to
|
||||
// more complex configuration and we lose the cross-channel digipeating capability.
|
||||
// In release 1.7 we add a new feature to assign a single radio channel to a TCP port.
|
||||
// e.g.
|
||||
// KISSPORT 8001 # default, all channels. Radio channel = KISS channel.
|
||||
//
|
||||
// KISSPORT 7000 0 # Only radio channel 0 for receive.
|
||||
// # Transmit to radio channel 0, ignoring KISS channel.
|
||||
//
|
||||
// KISSPORT 7001 1 # Only radio channel 1 for receive. KISS channel set to 0.
|
||||
// # Transmit to radio channel 1, ignoring KISS channel.
|
||||
|
||||
int kiss_port[MAX_KISS_TCP_PORTS]; /* TCP Port number for the "TCP KISS" protocol. */
|
||||
int kiss_chan[MAX_KISS_TCP_PORTS]; /* Radio Channel number for this port or -1 for all. */
|
||||
|
||||
int kiss_copy; /* Data from network KISS client is copied to all others. */
|
||||
int agwpe_port; /* Port number for the "AGW TCPIP Socket Interface" */
|
||||
int kiss_port; /* Port number for the "TCP KISS" protocol. */
|
||||
int enable_kiss_pt; /* Enable pseudo terminal for KISS. */
|
||||
/* Want this to be off by default because it hangs */
|
||||
/* after a while if nothing is reading from other end. */
|
||||
|
@ -76,8 +55,7 @@ struct misc_config_s {
|
|||
|
||||
char gpsnmea_port[20]; /* Serial port name for reading NMEA sentences from GPS. */
|
||||
/* e.g. COM22, /dev/ttyACM0 */
|
||||
|
||||
int gpsnmea_speed; /* Speed for above, baud, default 4800. */
|
||||
/* Currently no option for setting non-standard speed. */
|
||||
|
||||
char gpsd_host[20]; /* Host for gpsd server. */
|
||||
/* e.g. localhost, 192.168.1.2 */
|
||||
|
@ -86,32 +64,23 @@ struct misc_config_s {
|
|||
/* Default is 2947. */
|
||||
|
||||
|
||||
char waypoint_serial_port[20]; /* Serial port name for sending NMEA waypoint sentences */
|
||||
char waypoint_port[20]; /* Serial port name for sending NMEA waypoint sentences */
|
||||
/* to a GPS map display or other mapping application. */
|
||||
/* e.g. COM22, /dev/ttyACM0 */
|
||||
/* Currently no option for setting non-standard speed. */
|
||||
/* This was done in 2014 and no one has complained yet. */
|
||||
|
||||
char waypoint_udp_hostname[80]; /* Destination host when using UDP. */
|
||||
|
||||
int waypoint_udp_portnum; /* UDP port. */
|
||||
|
||||
int waypoint_formats; /* Which sentence formats should be generated? */
|
||||
|
||||
#define WPL_FORMAT_NMEA_GENERIC 0x01 /* N $GPWPL */
|
||||
#define WPL_FORMAT_GARMIN 0x02 /* G $PGRMW */
|
||||
#define WPL_FORMAT_MAGELLAN 0x04 /* M $PMGNWPL */
|
||||
#define WPL_FORMAT_KENWOOD 0x08 /* K $PKWDWPL */
|
||||
#define WPL_FORMAT_AIS 0x10 /* A !AIVDM */
|
||||
#define WPT_FORMAT_NMEA_GENERIC 0x01 /* N $GPWPT */
|
||||
#define WPT_FORMAT_GARMIN 0x02 /* G $PGRMW */
|
||||
#define WPT_FORMAT_MAGELLAN 0x04 /* M $PMGNWPL */
|
||||
#define WPT_FORMAT_KENWOOD 0x08 /* K $PKWDWPL */
|
||||
|
||||
|
||||
int log_daily_names; /* True to generate new log file each day. */
|
||||
|
||||
char log_path[80]; /* Either directory or full file name depending on above. */
|
||||
|
||||
int dns_sd_enabled; /* DNS Service Discovery announcement enabled. */
|
||||
char dns_sd_name[64]; /* Name announced on dns-sd; defaults to "Dire Wolf on <hostname>" */
|
||||
|
||||
int sb_configured; /* TRUE if SmartBeaconing is configured. */
|
||||
int sb_fast_speed; /* MPH */
|
||||
int sb_fast_rate; /* seconds */
|
||||
|
@ -142,13 +111,6 @@ struct misc_config_s {
|
|||
|
||||
int v20_count; /* Number of station addresses in array above. */
|
||||
|
||||
char **noxid_addrs; /* Stations known not to understand XID command so don't */
|
||||
/* waste time sending it and eventually giving up. */
|
||||
/* AX.25 for Linux is the one known case, so far, where */
|
||||
/* SABME is implemented but XID is not. */
|
||||
|
||||
int noxid_count; /* Number of station addresses in array above. */
|
||||
|
||||
|
||||
// Beacons.
|
||||
|
||||
|
@ -184,9 +146,6 @@ struct misc_config_s {
|
|||
|
||||
time_t next; /* Unix time to transmit next one. */
|
||||
|
||||
char *source; /* NULL or explicit AX.25 source address to use */
|
||||
/* instead of the mycall value for the channel. */
|
||||
|
||||
char *dest; /* NULL or explicit AX.25 destination to use */
|
||||
/* instead of the software version such as APDW11. */
|
||||
|
||||
|
@ -214,7 +173,7 @@ struct misc_config_s {
|
|||
char symbol; /* Symbol code. */
|
||||
|
||||
float power; /* For PHG. */
|
||||
float height; /* HAAT in feet */
|
||||
float height;
|
||||
float gain; /* Original protocol spec was unclear. */
|
||||
/* Addendum 1.1 clarifies it is dBi not dBd. */
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# Update: 1 May 2023 (still 1.7 dev version)
|
||||
#
|
||||
# The original intention was to allow an easy way to download the most
|
||||
# recent versions of some files.
|
||||
#
|
||||
# "update-data" would only work once.
|
||||
#
|
||||
# These locations are no longer being maintained:
|
||||
# http://www.aprs.org/aprs11/tocalls.txt -- 14 Dec 2021
|
||||
# http://www.aprs.org/symbols/symbols-new.txt -- 17 Mar 2021
|
||||
# http://www.aprs.org/symbols/symbolsX.txt -- 25 Nov 2015
|
||||
# so there is no reason to provide a capability grab the latest version.
|
||||
#
|
||||
# Rather than fixing an obsolete capability, it will just be removed.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
set(TOCALLS_TXT "tocalls.txt")
|
||||
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}/${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}/${SYMBOLS-NEW_TXT}" DESTINATION ${INSTALL_DATA_DIR})
|
||||
install(FILES "${CUSTOM_BINARY_DATA_DIR}/${SYMBOLSX_TXT}" DESTINATION ${INSTALL_DATA_DIR})
|
|
@ -1,5 +0,0 @@
|
|||
In order to start direwolf as a service the configuration file
|
||||
/etc/direwolf.conf needs to exist. Otherwise attempting to start the service
|
||||
returns an 'Assertion failed' error. An example configuration file which may be
|
||||
used as a model can be found in
|
||||
/usr/share/doc/direwolf/examples/direwolf.conf.gz
|
|
@ -1 +0,0 @@
|
|||
../CHANGES.md
|
|
@ -1 +0,0 @@
|
|||
10
|
|
@ -1,30 +0,0 @@
|
|||
Source: direwolf
|
||||
Maintainer: Debian Hamradio Maintainers <debian-hams@lists.debian.org>
|
||||
Uploaders: Iain R. Learmonth <irl@debian.org>
|
||||
Section: hamradio
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 9),
|
||||
libasound2-dev,
|
||||
libgps-dev,
|
||||
libhamlib-dev,
|
||||
dh-systemd
|
||||
Standards-Version: 4.1.0
|
||||
Vcs-Browser: https://anonscm.debian.org/cgit/pkg-hamradio/direwolf.git/
|
||||
Vcs-Git: https://anonscm.debian.org/git/pkg-hamradio/direwolf.git
|
||||
Homepage: https://github.com/wb2osz/direwolf
|
||||
|
||||
Package: direwolf
|
||||
Architecture: alpha amd64 arm64 armel armhf i386 mipsel ppc64el sh4 x32
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
adduser,
|
||||
libhamlib2
|
||||
Suggests: gpsd, libhamlib-utils
|
||||
Breaks: direwolf-docs (<< 1.1-1)
|
||||
Replaces: direwolf-docs (<< 1.1-1)
|
||||
Description: Soundcard TNC for APRS
|
||||
Dire Wolf is a software "soundcard" modem/TNC and APRS encoder/decoder. It can
|
||||
be used stand-alone to receive APRS messages, as a digipeater, APRStt gateway,
|
||||
or Internet Gateway (IGate). It can also be used as a virtual TNC for other
|
||||
applications such as APRSIS32, UI-View32, Xastir, APRS-TW, YAAC, UISS, Linux
|
||||
AX25, SARTrack, and many others.
|
|
@ -1,176 +0,0 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: direwolf
|
||||
Files-Excluded: doc/*.pdf
|
||||
Source: https://github.com/wb2osz/direwolf
|
||||
Comment:
|
||||
The files in misc/ are copied directly from the Cygwin source code. These are
|
||||
listed here as dual licensed as they are both part of the Cygwin distribution
|
||||
and originally part of BSD. See misc/README-dire-wolf.txt for more information.
|
||||
.
|
||||
Please see ftp-master's comments on this here:
|
||||
https://lists.debian.org/debian-hams/2014/09/msg00063.html
|
||||
https://lists.debian.org/debian-hams/2014/10/msg00003.html
|
||||
|
||||
Files: *
|
||||
Copyright: (C) 2011-2014 John Langner WB2OSZ
|
||||
License: GPL-2+
|
||||
|
||||
Files: geotranz/*
|
||||
Copyright: National Geospatial-Intelligence Agency
|
||||
License: Permissive-NGA
|
||||
|
||||
Files: regex/*
|
||||
Copyright: (C) 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: misc/strcasestr.c
|
||||
Copyright:
|
||||
(C) 1990, 1993 The Regents of the University of California
|
||||
(C) RedHat
|
||||
License: BSD-4-clause or GPL-2+
|
||||
|
||||
Files: misc/strtok_r.c misc/strsep.c
|
||||
Copyright:
|
||||
(C) 1988 Regents of the University of California
|
||||
(C) RedHat
|
||||
License: BSD-3-clause or GPL-2+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: (C) 2014 Iain R. Learmonth <irl@fsfe.org>
|
||||
License: GPL-2+
|
||||
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
.
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
.
|
||||
3. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
License: BSD-4-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
.
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by the University of
|
||||
California, Berkeley and its contributors.
|
||||
.
|
||||
4. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
License: GPL-2+
|
||||
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/>.
|
||||
.
|
||||
On Debian systems, a copy of the full license text is available in
|
||||
/usr/share/common-licenses/GPL-2.
|
||||
|
||||
License: LGPL-2.1+
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
.
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, a copy of the full license text is available in
|
||||
/usr/share/common-licenses/LGPL-2.1.
|
||||
|
||||
License: Permissive-NGA
|
||||
1. The GEOTRANS source code ("the software") is provided free of charge by the
|
||||
National Geospatial-Intelligence Agency (NGA) of the United States Department
|
||||
of Defense. Although NGA makes no copyright claim under Title 17 U.S.C., NGA
|
||||
claims copyrights in the source code under other legal regimes. NGA hereby
|
||||
grants to each user of the software a license to use and distribute the
|
||||
software, and develop derivative works.
|
||||
.
|
||||
2. NGA requests that products developed using the software credit the source of
|
||||
the software with the following statement, "The product was developed using
|
||||
GEOTRANS, a product of the National Geospatial-Intelligence Agency (NGA) and
|
||||
U.S. Army Engineering Research and Development Center." Do not use the name
|
||||
GEOTRANS for any derived work.
|
||||
.
|
||||
3. Warranty Disclaimer: The software was developed to meet only the internal
|
||||
requirements of the National Geospatial-Intelligence Agency (NGA). The software
|
||||
is provided "as is," and no warranty, express or implied, including but not
|
||||
limited to the implied warranties of merchantability and fitness for particular
|
||||
purpose or arising by statute or otherwise in law or from a course of dealing
|
||||
or usage in trade, is made by NGA as to the accuracy and functioning of the
|
||||
software.
|
||||
.
|
||||
4. NGA and its personnel are not required to provide technical support or
|
||||
general assistance with respect to public use of the software. Government
|
||||
customers may contact NGA.
|
||||
.
|
||||
5. Neither NGA nor its personnel will be liable for any claims, losses, or
|
||||
damages arising from or connected with the use of the software. The user agrees
|
||||
to hold harmless the United States National Geospatial-Intelligence Agency
|
||||
(NGA). The user's sole and exclusive remedy is to stop using the software.
|
||||
.
|
||||
6. Please be advised that pursuant to the United States Code, 10 U.S.C. 425,
|
||||
the name of the National Geospatial-Intelligence Agency, the initials "NGA",
|
||||
the seal of the National Geospatial-Intelligence Agency, or any colorable
|
||||
imitation thereof shall not be used to imply approval, endorsement, or
|
||||
authorization of a product without prior written permission from United States
|
||||
Secretary of Defense. Do not create the impression that NGA, the Secretary of
|
||||
Defense or the Director of National Intelligence has endorsed any product
|
||||
derived from GEOTRANS.
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
add_group_if_missing() {
|
||||
if ! getent group direwolf >/dev/null; then
|
||||
addgroup --system --force-badname direwolf || true
|
||||
fi
|
||||
}
|
||||
|
||||
add_user_if_missing() {
|
||||
if ! id -u direwolf > /dev/null 2>&1; then
|
||||
mkdir -m 02750 -p /var/lib/direwolf
|
||||
adduser --system --home /var/lib/direwolf \
|
||||
--disabled-password \
|
||||
--force-badname direwolf \
|
||||
--ingroup direwolf
|
||||
adduser direwolf dialout
|
||||
chown direwolf:direwolf /var/lib/direwolf
|
||||
fi
|
||||
}
|
||||
|
||||
add_group_if_missing
|
||||
add_user_if_missing
|
||||
|
||||
db_stop
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
rm -rf /var/lib/direwolf/
|
||||
;;
|
||||
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- -DFORCE_SSE=1
|
|
@ -1 +0,0 @@
|
|||
3.0 (quilt)
|
File diff suppressed because it is too large
Load Diff
|
@ -24,12 +24,11 @@ typedef struct decode_aprs_s {
|
|||
|
||||
int g_quiet; /* Suppress error messages when decoding. */
|
||||
|
||||
char g_src[AX25_MAX_ADDR_LEN]; // In the case of a packet encapsulated by a 3rd party
|
||||
// header, this is the encapsulated source.
|
||||
char g_src[AX25_MAX_ADDR_LEN];
|
||||
|
||||
char g_dest[AX25_MAX_ADDR_LEN];
|
||||
|
||||
char g_data_type_desc[100]; /* APRS data type description. Telemetry descriptions get pretty long. */
|
||||
char g_msg_type[60]; /* APRS data type. Telemetry descriptions get pretty long. */
|
||||
/* Putting msg in the name was a poor choice because */
|
||||
/* "message" has a specific meaning. Rename it someday. */
|
||||
|
||||
char g_symbol_table; /* The Symbol Table Identifier character selects one */
|
||||
/* of the two Symbol Tables, or it may be used as */
|
||||
|
@ -67,30 +66,10 @@ typedef struct decode_aprs_s {
|
|||
/* Also for Directed Station Query which is a */
|
||||
/* special case of message. */
|
||||
|
||||
// This is so pfilter.c:filt_t does not need to duplicate the same work.
|
||||
|
||||
int g_has_thirdparty_header;
|
||||
enum packet_type_e {
|
||||
packet_type_none=0,
|
||||
packet_type_position,
|
||||
packet_type_weather,
|
||||
packet_type_object,
|
||||
packet_type_item,
|
||||
packet_type_message,
|
||||
packet_type_query,
|
||||
packet_type_capabilities,
|
||||
packet_type_status,
|
||||
packet_type_telemetry,
|
||||
packet_type_userdefined,
|
||||
packet_type_nws
|
||||
} g_packet_type;
|
||||
|
||||
enum message_subtype_e { message_subtype_invalid = 0,
|
||||
message_subtype_message,
|
||||
message_subtype_ack,
|
||||
message_subtype_rej,
|
||||
message_subtype_bulletin,
|
||||
message_subtype_nws,
|
||||
message_subtype_telem_parm,
|
||||
message_subtype_telem_unit,
|
||||
message_subtype_telem_eqns,
|
||||
|
@ -98,31 +77,23 @@ typedef struct decode_aprs_s {
|
|||
message_subtype_directed_query
|
||||
} g_message_subtype; /* Various cases of the overloaded "message." */
|
||||
|
||||
char g_message_number[12]; /* Message number. Should be 1 - 5 alphanumeric characters if used. */
|
||||
/* Addendum 1.1 has new format {mm} or {mm}aa with only two */
|
||||
/* characters for message number and an ack riding piggyback. */
|
||||
char g_message_number[8]; /* Message number. Should be 1 - 5 characters if used. */
|
||||
|
||||
float g_speed_mph; /* Speed in MPH. */
|
||||
/* The APRS transmission uses knots so watch out for */
|
||||
/* conversions when sending and receiving APRS packets. */
|
||||
|
||||
float g_course; /* 0 = North, 90 = East, etc. */
|
||||
|
||||
int g_power; /* Transmitter power in watts. */
|
||||
|
||||
int g_height; /* Antenna height above average terrain, feet. */
|
||||
// TODO: rename to g_height_ft
|
||||
|
||||
int g_gain; /* Antenna gain in dBi. */
|
||||
int g_gain; /* Antenna gain in dB. */
|
||||
|
||||
char g_directivity[12]; /* Direction of max signal strength */
|
||||
|
||||
float g_range; /* Precomputed radio range in miles. */
|
||||
|
||||
float g_altitude_ft; /* Feet above median sea level. */
|
||||
/* I used feet here because the APRS specification */
|
||||
/* has units of feet for altitude. Meters would be */
|
||||
/* more natural to the other 96% of the world. */
|
||||
|
||||
char g_mfr[80]; /* Manufacturer or application. */
|
||||
|
||||
|
@ -164,9 +135,9 @@ typedef struct decode_aprs_s {
|
|||
|
||||
|
||||
|
||||
extern void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet, char *third_party_src);
|
||||
extern void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet);
|
||||
|
||||
extern void decode_aprs_print (decode_aprs_t *A);
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2019, 2021 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 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
|
||||
|
@ -47,6 +47,7 @@
|
|||
#include "tune.h"
|
||||
#include "fsk_demod_state.h"
|
||||
#include "fsk_gen_filter.h"
|
||||
#include "fsk_fast_filter.h"
|
||||
#include "hdlc_rec.h"
|
||||
#include "textcolor.h"
|
||||
#include "demod_9600.h"
|
||||
|
@ -60,6 +61,10 @@
|
|||
static struct audio_s *save_audio_config_p;
|
||||
|
||||
|
||||
// TODO: temp experiment.
|
||||
|
||||
static int upsample = 2; // temp experiment.
|
||||
static int zerostuff = 1; // temp experiment.
|
||||
|
||||
// Current state of all the decoders.
|
||||
|
||||
|
@ -89,6 +94,7 @@ static int sample_count[MAX_CHANS][MAX_SUBCHANS];
|
|||
|
||||
int demod_init (struct audio_s *pa)
|
||||
{
|
||||
//int j;
|
||||
int chan; /* Loop index over number of radio channels. */
|
||||
char profile;
|
||||
|
||||
|
@ -102,7 +108,7 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
for (chan = 0; chan < MAX_CHANS; chan++) {
|
||||
|
||||
if (save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) {
|
||||
if (save_audio_config_p->achan[chan].valid) {
|
||||
|
||||
char *p;
|
||||
char just_letters[16];
|
||||
|
@ -116,6 +122,7 @@ int demod_init (struct audio_s *pa)
|
|||
* This can be increased by:
|
||||
* Multiple frequencies.
|
||||
* Multiple letters (not sure if I will continue this).
|
||||
* New interleaved decoders.
|
||||
*
|
||||
* num_slicers is set to max by the "+" option.
|
||||
*/
|
||||
|
@ -129,20 +136,6 @@ int demod_init (struct audio_s *pa)
|
|||
break;
|
||||
|
||||
case MODEM_AFSK:
|
||||
case MODEM_EAS:
|
||||
|
||||
if (save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
|
||||
if (save_audio_config_p->achan[chan].fix_bits != RETRY_NONE) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Channel %d: FIX_BITS option has been turned off for EAS.\n", chan);
|
||||
save_audio_config_p->achan[chan].fix_bits = RETRY_NONE;
|
||||
}
|
||||
if (save_audio_config_p->achan[chan].passall != 0) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Channel %d: PASSALL option has been turned off for EAS.\n", chan);
|
||||
save_audio_config_p->achan[chan].passall = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear apart the profile and put it back together in a normalized form:
|
||||
|
@ -194,57 +187,46 @@ int demod_init (struct audio_s *pa)
|
|||
assert (num_letters == (int)(strlen(just_letters)));
|
||||
|
||||
/*
|
||||
* Pick a good default demodulator if none specified.
|
||||
* Previously, we had "D" optimized for 300 bps.
|
||||
* Gone in 1.7 so it is always "A+".
|
||||
* Pick a good default demodulator if none specified.
|
||||
*/
|
||||
if (num_letters == 0) {
|
||||
strlcpy (just_letters, "A", sizeof(just_letters));
|
||||
num_letters = strlen(just_letters);
|
||||
|
||||
if (have_plus != -1) have_plus = 1; // Add as default for version 1.2
|
||||
// If not explicitly turned off.
|
||||
}
|
||||
if (save_audio_config_p->achan[chan].baud < 600) {
|
||||
|
||||
/* This has been optimized for 300 baud. */
|
||||
|
||||
strlcpy (just_letters, "D", sizeof(just_letters));
|
||||
|
||||
/*
|
||||
* Special case for ARM.
|
||||
* The higher end ARM chips have loads of power but many people
|
||||
* are using a single core Pi Zero or similar.
|
||||
* (I'm still using a model 1 for my digipeater/IGate!)
|
||||
* Decreasing CPU requirement has a negligible impact on decoding performance.
|
||||
*
|
||||
* atest -PA- 01_Track_1.wav --> 1002 packets decoded.
|
||||
* atest -PA- -D3 01_Track_1.wav --> 997 packets decoded.
|
||||
*
|
||||
* Someone concerned about 1/2 of one percent difference can add "-D 1"
|
||||
*/
|
||||
#if __arm__
|
||||
if (save_audio_config_p->achan[chan].decimate == 0) {
|
||||
if (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
|
||||
save_audio_config_p->achan[chan].decimate = 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if __arm__
|
||||
/* We probably don't have a lot of CPU power available. */
|
||||
/* Previously we would use F if possible otherwise fall back to A. */
|
||||
|
||||
/* In version 1.2, new default is E+ /3. */
|
||||
strlcpy (just_letters, "E", sizeof(just_letters)); // version 1.2 now E.
|
||||
if (have_plus != -1) have_plus = 1; // Add as default for version 1.2
|
||||
// If not explicitly turned off.
|
||||
if (save_audio_config_p->achan[chan].decimate == 0) {
|
||||
if (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
|
||||
save_audio_config_p->achan[chan].decimate = 3;
|
||||
}
|
||||
}
|
||||
#else
|
||||
strlcpy (just_letters, "E", sizeof(just_letters)); // version 1.2 changed C to E.
|
||||
if (have_plus != -1) have_plus = 1; // Add as default for version 1.2
|
||||
// If not explicitly turned off.
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Number of filter taps is proportional to number of audio samples in a "symbol" duration.
|
||||
* These can get extremely large for low speeds, e.g. 300 baud.
|
||||
* In this case, increase the decimation ration. Crude approximation. Could be improved.
|
||||
*/
|
||||
if (save_audio_config_p->achan[chan].decimate == 0 &&
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000 &&
|
||||
save_audio_config_p->achan[chan].baud < 600) {
|
||||
|
||||
// Avoid enormous number of filter taps.
|
||||
|
||||
save_audio_config_p->achan[chan].decimate = 3;
|
||||
}
|
||||
num_letters = 1;
|
||||
}
|
||||
|
||||
|
||||
assert (num_letters == (int)(strlen(just_letters)));
|
||||
|
||||
/*
|
||||
* Put it back together again.
|
||||
*/
|
||||
assert (num_letters == (int)(strlen(just_letters)));
|
||||
|
||||
/* At this point, have_plus can have 3 values: */
|
||||
/* 1 = turned on, either explicitly or by applied default */
|
||||
|
@ -293,7 +275,7 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
if (save_audio_config_p->achan[chan].decimate == 0) {
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
if (strchr (just_letters, 'B') != NULL && save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
|
||||
if (strchr (just_letters, 'D') != NULL && save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
|
||||
save_audio_config_p->achan[chan].decimate = 3;
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +315,48 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
save_audio_config_p->achan[chan].num_subchan = num_letters;
|
||||
|
||||
/*
|
||||
* Quick hack with special case for another experiment.
|
||||
* Do this in a more general way if it turns out to be useful.
|
||||
*/
|
||||
save_audio_config_p->achan[chan].interleave = 1;
|
||||
if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EE") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 2;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEE") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 3;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEEE") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 4;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEEEE") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 5;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GG") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 2;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGG") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 3;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGG+") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 3;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGGG") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 4;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGGGG") == 0) {
|
||||
save_audio_config_p->achan[chan].interleave = 5;
|
||||
save_audio_config_p->achan[chan].decimate = 1;
|
||||
}
|
||||
|
||||
if (save_audio_config_p->achan[chan].num_subchan != num_letters) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n",
|
||||
|
@ -361,7 +385,7 @@ int demod_init (struct audio_s *pa)
|
|||
dw_printf (" %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
|
||||
}
|
||||
|
||||
demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
|
||||
demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / (save_audio_config_p->achan[chan].decimate * save_audio_config_p->achan[chan].interleave),
|
||||
save_audio_config_p->achan[chan].baud,
|
||||
mark,
|
||||
space,
|
||||
|
@ -496,31 +520,6 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
case MODEM_QPSK: // New for 1.4
|
||||
|
||||
// In versions 1.4 and 1.5, V.26 "Alternative A" was used.
|
||||
// years later, I discover that the MFJ-2400 used "Alternative B."
|
||||
// It looks like the other two manufacturers use the same but we
|
||||
// can't be sure until we find one for compatibility testing.
|
||||
|
||||
// In version 1.6 we add a choice for the user.
|
||||
// If neither one was explicitly specified, print a message and take
|
||||
// a default. My current thinking is that we default to direwolf <= 1.5
|
||||
// compatible for version 1.6 and MFJ compatible after that.
|
||||
|
||||
if (save_audio_config_p->achan[chan].v26_alternative == V26_UNSPECIFIED) {
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Two incompatible versions of 2400 bps QPSK are now available.\n");
|
||||
dw_printf ("For compatibility with direwolf <= 1.5, use 'V26A' modem option in config file.\n");
|
||||
dw_printf ("For compatibility MFJ-2400 use 'V26B' modem option in config file.\n");
|
||||
dw_printf ("Command line options -j and -J can be used for channel 0.\n");
|
||||
dw_printf ("For more information, read the Dire Wolf User Guide and\n");
|
||||
dw_printf ("2400-4800-PSK-for-APRS-Packet-Radio.pdf.\n");
|
||||
dw_printf ("The default is now MFJ-2400 compatibility mode.\n");
|
||||
|
||||
save_audio_config_p->achan[chan].v26_alternative = V26_DEFAULT;
|
||||
}
|
||||
|
||||
|
||||
// TODO: See how much CPU this takes on ARM and decide if we should have different defaults.
|
||||
|
||||
if (strlen(save_audio_config_p->achan[chan].profiles) == 0) {
|
||||
|
@ -540,12 +539,6 @@ int demod_init (struct audio_s *pa)
|
|||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
|
||||
if (save_audio_config_p->achan[chan].decimate != 1)
|
||||
dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
|
||||
|
||||
if (save_audio_config_p->achan[chan].v26_alternative == V26_B)
|
||||
dw_printf (", compatible with MFJ-2400");
|
||||
else
|
||||
dw_printf (", compatible with earlier direwolf");
|
||||
|
||||
if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
|
||||
dw_printf (", DTMF decoder enabled");
|
||||
dw_printf (".\n");
|
||||
|
@ -563,7 +556,6 @@ int demod_init (struct audio_s *pa)
|
|||
// save_audio_config_p->achan[chan].modem_type, profile);
|
||||
|
||||
demod_psk_init (save_audio_config_p->achan[chan].modem_type,
|
||||
save_audio_config_p->achan[chan].v26_alternative,
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
|
||||
save_audio_config_p->achan[chan].baud,
|
||||
profile,
|
||||
|
@ -618,7 +610,6 @@ int demod_init (struct audio_s *pa)
|
|||
// save_audio_config_p->achan[chan].modem_type, profile);
|
||||
|
||||
demod_psk_init (save_audio_config_p->achan[chan].modem_type,
|
||||
save_audio_config_p->achan[chan].v26_alternative,
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
|
||||
save_audio_config_p->achan[chan].baud,
|
||||
profile,
|
||||
|
@ -639,26 +630,9 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
case MODEM_BASEBAND:
|
||||
case MODEM_SCRAMBLE:
|
||||
case MODEM_AIS:
|
||||
default: /* Not AFSK */
|
||||
{
|
||||
|
||||
// For AIS we will accept only a good CRC without any fixup attempts.
|
||||
// Even with that, there are still a lot of CRC false matches with random noise.
|
||||
|
||||
if (save_audio_config_p->achan[chan].modem_type == MODEM_AIS) {
|
||||
if (save_audio_config_p->achan[chan].fix_bits != RETRY_NONE) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Channel %d: FIX_BITS option has been turned off for AIS.\n", chan);
|
||||
save_audio_config_p->achan[chan].fix_bits = RETRY_NONE;
|
||||
}
|
||||
if (save_audio_config_p->achan[chan].passall != 0) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Channel %d: PASSALL option has been turned off for AIS.\n", chan);
|
||||
save_audio_config_p->achan[chan].passall = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(save_audio_config_p->achan[chan].profiles, "") == 0) {
|
||||
|
||||
/* Apply default if not set earlier. */
|
||||
|
@ -669,73 +643,25 @@ int demod_init (struct audio_s *pa)
|
|||
/* We want higher performance to be the default. */
|
||||
/* "MODEM 9600 -" can be used on very slow CPU if necessary. */
|
||||
|
||||
//#ifndef __arm__
|
||||
strlcpy (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need a minimum number of audio samples per bit time for good performance.
|
||||
* Easier to check here because demod_9600_init might have an adjusted sample rate.
|
||||
*/
|
||||
|
||||
float ratio = (float)(save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec)
|
||||
/ (float)(save_audio_config_p->achan[chan].baud);
|
||||
|
||||
/*
|
||||
* Set reasonable upsample ratio if user did not override.
|
||||
*/
|
||||
|
||||
if (save_audio_config_p->achan[chan].upsample == 0) {
|
||||
|
||||
if (ratio < 4) {
|
||||
|
||||
// This is extreme.
|
||||
// No one should be using a sample rate this low but
|
||||
// amazingly a recording with 22050 rate can be decoded.
|
||||
// 3 and 4 are the same. Need more tests.
|
||||
|
||||
save_audio_config_p->achan[chan].upsample = 4;
|
||||
}
|
||||
else if (ratio < 5) {
|
||||
|
||||
// example: 44100 / 9600 is 4.59
|
||||
// 3 is slightly better than 2 or 4.
|
||||
|
||||
save_audio_config_p->achan[chan].upsample = 3;
|
||||
}
|
||||
else if (ratio < 10) {
|
||||
|
||||
// example: 48000 / 9600 = 5
|
||||
// 3 is slightly better than 2 or 4.
|
||||
|
||||
save_audio_config_p->achan[chan].upsample = 3;
|
||||
}
|
||||
else if (ratio < 15) {
|
||||
|
||||
// ... guessing
|
||||
|
||||
save_audio_config_p->achan[chan].upsample = 2;
|
||||
}
|
||||
else { // >= 15
|
||||
//
|
||||
// An example of this might be .....
|
||||
// Probably no benefit.
|
||||
|
||||
save_audio_config_p->achan[chan].upsample = 1;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
#ifdef TUNE_UPSAMPLE
|
||||
save_audio_config_p->achan[chan].upsample = TUNE_UPSAMPLE;
|
||||
upsample = TUNE_UPSAMPLE;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TUNE_ZEROSTUFF
|
||||
zerostuff = TUNE_ZEROSTUFF;
|
||||
#endif
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Channel %d: %d baud, %s, %s, %d sample rate x %d",
|
||||
chan,
|
||||
save_audio_config_p->achan[chan].baud,
|
||||
save_audio_config_p->achan[chan].modem_type == MODEM_AIS ? "AIS" : "K9NG/G3RUH",
|
||||
dw_printf ("Channel %d: %d baud, K9NG/G3RUH, %s, %d sample rate x %d",
|
||||
chan, save_audio_config_p->achan[chan].baud,
|
||||
save_audio_config_p->achan[chan].profiles,
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
|
||||
save_audio_config_p->achan[chan].upsample);
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, upsample);
|
||||
if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
|
||||
dw_printf (", DTMF decoder enabled");
|
||||
dw_printf (".\n");
|
||||
|
@ -743,7 +669,6 @@ int demod_init (struct audio_s *pa)
|
|||
struct demodulator_state_s *D;
|
||||
D = &demodulator_state[chan][0]; // first subchannel
|
||||
|
||||
|
||||
save_audio_config_p->achan[chan].num_subchan = 1;
|
||||
save_audio_config_p->achan[chan].num_slicers = 1;
|
||||
|
||||
|
@ -756,6 +681,12 @@ int demod_init (struct audio_s *pa)
|
|||
}
|
||||
|
||||
|
||||
/* We need a minimum number of audio samples per bit time for good performance. */
|
||||
/* Easier to check here because demod_9600_init might have an adjusted sample rate. */
|
||||
|
||||
float ratio = (float)(save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec)
|
||||
/ (float)(save_audio_config_p->achan[chan].baud);
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("The ratio of audio samples per sec (%d) to data rate in baud (%d) is %.1f\n",
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
|
||||
|
@ -767,9 +698,6 @@ int demod_init (struct audio_s *pa)
|
|||
}
|
||||
else if (ratio < 5) {
|
||||
dw_printf ("This is on the low side for best performance. Can you use a higher sample rate?\n");
|
||||
if (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec == 44100) {
|
||||
dw_printf ("For example, can you use 48000 rather than 44100?\n");
|
||||
}
|
||||
}
|
||||
else if (ratio < 6) {
|
||||
dw_printf ("Increasing the sample rate should improve decoder performance.\n");
|
||||
|
@ -781,10 +709,7 @@ int demod_init (struct audio_s *pa)
|
|||
dw_printf ("This is a suitable ratio for good performance.\n");
|
||||
}
|
||||
|
||||
demod_9600_init (save_audio_config_p->achan[chan].modem_type,
|
||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
|
||||
save_audio_config_p->achan[chan].upsample,
|
||||
save_audio_config_p->achan[chan].baud, D);
|
||||
demod_9600_init (upsample * save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, save_audio_config_p->achan[chan].baud, D);
|
||||
|
||||
if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {
|
||||
|
||||
|
@ -804,23 +729,10 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
} /* switch on modulation type. */
|
||||
|
||||
} /* if channel medium is radio */
|
||||
|
||||
// FIXME dw_printf ("-------- end of loop for chn %d \n", chan);
|
||||
} /* if channel number is valid */
|
||||
|
||||
} /* for chan ... */
|
||||
|
||||
// Now the virtual channels. FIXME: could be single loop.
|
||||
|
||||
for (chan = MAX_CHANS; chan < MAX_TOTAL_CHANS; chan++) {
|
||||
|
||||
// FIXME dw_printf ("-------- virtual channel loop %d \n", chan);
|
||||
|
||||
if (chan == save_audio_config_p->igate_vchannel) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Channel %d: IGate virtual channel.\n", chan);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
|
@ -832,7 +744,7 @@ int demod_init (struct audio_s *pa)
|
|||
*
|
||||
* Name: demod_get_sample
|
||||
*
|
||||
* Purpose: Get one audio sample from the specified sound input source.
|
||||
* Purpose: Get one audio sample fromt the specified sound input source.
|
||||
*
|
||||
* Inputs: a - Index for audio device. 0 = first.
|
||||
*
|
||||
|
@ -842,7 +754,7 @@ int demod_init (struct audio_s *pa)
|
|||
* Global In: save_audio_config_p->adev[ACHAN2ADEV(chan)].bits_per_sample - So we know whether to
|
||||
* read 1 or 2 bytes from audio stream.
|
||||
*
|
||||
* Description: Grab 1 or two bytes depending on data source.
|
||||
* Description: Grab 1 or two btyes depending on data source.
|
||||
*
|
||||
* When processing stereo, the caller will call this
|
||||
* at twice the normal rate to obtain alternating left
|
||||
|
@ -852,15 +764,17 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
#define FSK_READ_ERR (256*256)
|
||||
|
||||
|
||||
__attribute__((hot))
|
||||
int demod_get_sample (int a)
|
||||
{
|
||||
int x1, x2;
|
||||
signed short sam; /* short to force sign extension. */
|
||||
signed short sam; /* short to force sign extention. */
|
||||
|
||||
|
||||
assert (save_audio_config_p->adev[a].bits_per_sample == 8 || save_audio_config_p->adev[a].bits_per_sample == 16);
|
||||
|
||||
|
||||
if (save_audio_config_p->adev[a].bits_per_sample == 8) {
|
||||
|
||||
x1 = audio_get(a);
|
||||
|
@ -927,27 +841,12 @@ int demod_get_sample (int a)
|
|||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
static volatile int mute_input[MAX_CHANS];
|
||||
|
||||
// New in 1.7.
|
||||
// A few people have a really bad audio cross talk situation where they receive their own transmissions.
|
||||
// It usually doesn't cause a problem but it is confusing to look at.
|
||||
// "half duplex" setting applied only to the transmit logic. i.e. wait for clear channel before sending.
|
||||
// Receiving was still active.
|
||||
// I think the simplest solution is to mute/unmute the audio input at this point if not full duplex.
|
||||
// This is called from ptt_set for half duplex.
|
||||
|
||||
void demod_mute_input (int chan, int mute_during_xmit)
|
||||
{
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
mute_input[chan] = mute_during_xmit;
|
||||
}
|
||||
|
||||
__attribute__((hot))
|
||||
void demod_process_sample (int chan, int subchan, int sam)
|
||||
{
|
||||
float fsam;
|
||||
//int k;
|
||||
int k;
|
||||
|
||||
|
||||
struct demodulator_state_s *D;
|
||||
|
@ -955,10 +854,6 @@ void demod_process_sample (int chan, int subchan, int sam)
|
|||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
||||
|
||||
if (mute_input[chan]) {
|
||||
sam = 0;
|
||||
};
|
||||
|
||||
D = &demodulator_state[chan][subchan];
|
||||
|
||||
|
||||
|
@ -1006,7 +901,6 @@ void demod_process_sample (int chan, int subchan, int sam)
|
|||
break;
|
||||
|
||||
case MODEM_AFSK:
|
||||
case MODEM_EAS:
|
||||
|
||||
if (save_audio_config_p->achan[chan].decimate > 1) {
|
||||
|
||||
|
@ -1040,10 +934,49 @@ void demod_process_sample (int chan, int subchan, int sam)
|
|||
|
||||
case MODEM_BASEBAND:
|
||||
case MODEM_SCRAMBLE:
|
||||
case MODEM_AIS:
|
||||
default:
|
||||
|
||||
demod_9600_process_sample (chan, sam, save_audio_config_p->achan[chan].upsample, D);
|
||||
if (zerostuff) {
|
||||
/* Literature says this is better if followed */
|
||||
/* by appropriate low pass filter. */
|
||||
/* So far, both are same in tests with different */
|
||||
/* optimal low pass filter parameters. */
|
||||
|
||||
for (k=1; k<upsample; k++) {
|
||||
demod_9600_process_sample (chan, 0, D);
|
||||
}
|
||||
demod_9600_process_sample (chan, sam * upsample, D);
|
||||
}
|
||||
else {
|
||||
|
||||
/* Linear interpolation. */
|
||||
static int prev_sam;
|
||||
|
||||
switch (upsample) {
|
||||
case 1:
|
||||
demod_9600_process_sample (chan, sam, D);
|
||||
break;
|
||||
case 2:
|
||||
demod_9600_process_sample (chan, (prev_sam + sam) / 2, D);
|
||||
demod_9600_process_sample (chan, sam, D);
|
||||
break;
|
||||
case 3:
|
||||
demod_9600_process_sample (chan, (2 * prev_sam + sam) / 3, D);
|
||||
demod_9600_process_sample (chan, (prev_sam + 2 * sam) / 3, D);
|
||||
demod_9600_process_sample (chan, sam, D);
|
||||
break;
|
||||
case 4:
|
||||
demod_9600_process_sample (chan, (3 * prev_sam + sam) / 4, D);
|
||||
demod_9600_process_sample (chan, (prev_sam + sam) / 2, D);
|
||||
demod_9600_process_sample (chan, (prev_sam + 3 * sam) / 4, D);
|
||||
demod_9600_process_sample (chan, sam, D);
|
||||
break;
|
||||
default:
|
||||
assert (0);
|
||||
break;
|
||||
}
|
||||
prev_sam = sam;
|
||||
}
|
||||
break;
|
||||
|
||||
} /* switch modem_type */
|
||||
|
@ -1083,8 +1016,7 @@ alevel_t demod_get_audio_level (int chan, int subchan)
|
|||
|
||||
alevel.rec = (int) (( D->alevel_rec_peak - D->alevel_rec_valley ) * 50.0f + 0.5f);
|
||||
|
||||
if (save_audio_config_p->achan[chan].modem_type == MODEM_AFSK ||
|
||||
save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
|
||||
if (save_audio_config_p->achan[chan].modem_type == MODEM_AFSK) {
|
||||
|
||||
/* For AFSK, we have mark and space amplitudes. */
|
||||
|
|
@ -8,13 +8,10 @@
|
|||
|
||||
int demod_init (struct audio_s *pa);
|
||||
|
||||
void demod_mute_input (int chan, int mute);
|
||||
|
||||
int demod_get_sample (int a);
|
||||
|
||||
void demod_process_sample (int chan, int subchan, int sam);
|
||||
|
||||
void demod_print_agc (int chan, int subchan);
|
||||
|
||||
alevel_t demod_get_audio_level (int chan, int subchan);
|
||||
|
||||
alevel_t demod_get_audio_level (int chan, int subchan);
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2015, 2019, 2021 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011, 2012, 2013, 2015 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
|
||||
|
@ -25,8 +25,7 @@
|
|||
*
|
||||
* Module: demod_9600.c
|
||||
*
|
||||
* Purpose: Demodulator for baseband signal.
|
||||
* This is used for AX.25 (with scrambling) and IL2P without.
|
||||
* Purpose: Demodulator for scrambled baseband encoding.
|
||||
*
|
||||
* Input: Audio samples from either a file or the "sound card."
|
||||
*
|
||||
|
@ -45,26 +44,14 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Fine tuning for different demodulator types.
|
||||
// Don't remove this section. It is here for a reason.
|
||||
|
||||
#define DCD_THRESH_ON 32 // Hysteresis: Can miss 0 out of 32 for detecting lock.
|
||||
// This is best for actual on-the-air signals.
|
||||
// Still too many brief false matches.
|
||||
#define DCD_THRESH_OFF 8 // Might want a little more fine tuning.
|
||||
#define DCD_GOOD_WIDTH 1024 // No more than 1024!!!
|
||||
|
||||
#include "fsk_demod_state.h" // Values above override defaults.
|
||||
|
||||
#include "tune.h"
|
||||
#include "fsk_demod_state.h"
|
||||
#include "hdlc_rec.h"
|
||||
#include "demod_9600.h"
|
||||
#include "textcolor.h"
|
||||
#include "dsp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
static float slice_point[MAX_SUBCHANS];
|
||||
|
||||
|
||||
|
@ -126,14 +113,9 @@ static inline float agc (float in, float fast_attack, float slow_decay, float *p
|
|||
*
|
||||
* Purpose: Initialize the 9600 (or higher) baud demodulator.
|
||||
*
|
||||
* Inputs: modem_type - Determines whether scrambling is used.
|
||||
*
|
||||
* samples_per_sec - Number of samples per second for audio.
|
||||
*
|
||||
* upsample - Factor to upsample the incoming stream.
|
||||
* After a lot of experimentation, I discovered that
|
||||
* it works better if the data is upsampled.
|
||||
* This reduces the jitter for PLL synchronization.
|
||||
* Inputs: samples_per_sec - Number of samples per second.
|
||||
* Might be upsampled in hopes of
|
||||
* reducing the PLL jitter.
|
||||
*
|
||||
* baud - Data rate in bits per second.
|
||||
*
|
||||
|
@ -143,16 +125,12 @@ static inline float agc (float in, float fast_attack, float slow_decay, float *p
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int upsample, int baud, struct demodulator_state_s *D)
|
||||
void demod_9600_init (int samples_per_sec, int baud, struct demodulator_state_s *D)
|
||||
{
|
||||
float fc;
|
||||
int j;
|
||||
if (upsample < 1) upsample = 1;
|
||||
if (upsample > 4) upsample = 4;
|
||||
|
||||
|
||||
memset (D, 0, sizeof(struct demodulator_state_s));
|
||||
D->modem_type = modem_type;
|
||||
D->num_slicers = 1;
|
||||
|
||||
// Multiple profiles in future?
|
||||
|
@ -163,43 +141,25 @@ void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int ups
|
|||
// case 'K': // upsample x3 with filtering.
|
||||
// case 'L': // upsample x4 with filtering.
|
||||
|
||||
|
||||
D->lp_filter_len_bits = 1.0; // -U4 = 61 4.59 samples/symbol
|
||||
D->lp_filter_len_bits = 76 * 9600.0 / (44100.0 * 2.0);
|
||||
|
||||
// Works best with odd number in some tests. Even is better in others.
|
||||
//D->lp_filter_size = ((int) (0.5f * ( D->lp_filter_len_bits * (float)original_sample_rate / (float)baud ))) * 2 + 1;
|
||||
//D->lp_filter_size = ((int) (0.5f * ( D->lp_filter_len_bits * (float)samples_per_sec / (float)baud ))) * 2 + 1;
|
||||
D->lp_filter_size = (int) (( D->lp_filter_len_bits * (float)samples_per_sec / baud) + 0.5f);
|
||||
|
||||
// Just round to nearest integer.
|
||||
D->lp_filter_size = (int) (( D->lp_filter_len_bits * (float)original_sample_rate / baud) + 0.5f);
|
||||
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->lpf_baud = 1.00;
|
||||
D->lp_window = BP_WINDOW_HAMMING;
|
||||
D->lpf_baud = 0.62;
|
||||
|
||||
D->agc_fast_attack = 0.080;
|
||||
D->agc_slow_decay = 0.00012;
|
||||
|
||||
D->pll_locked_inertia = 0.89;
|
||||
D->pll_searching_inertia = 0.67;
|
||||
|
||||
// break;
|
||||
// }
|
||||
|
||||
#if 0
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("---------- %s (%d, %d) -----------\n", __func__, samples_per_sec, baud);
|
||||
dw_printf ("filter_len_bits = %.2f\n", D->lp_filter_len_bits);
|
||||
dw_printf ("lp_filter_size = %d\n", D->lp_filter_size);
|
||||
dw_printf ("lp_window = %d\n", D->lp_window);
|
||||
dw_printf ("lpf_baud = %.2f\n", D->lpf_baud);
|
||||
dw_printf ("samples per bit = %.1f\n", (double)samples_per_sec / baud);
|
||||
#endif
|
||||
|
||||
|
||||
// PLL needs to use the upsampled rate.
|
||||
|
||||
D->pll_step_per_sample =
|
||||
(int) round(TICKS_PER_PLL_CYCLE * (double) baud / (double)(original_sample_rate * upsample));
|
||||
(int) round(TICKS_PER_PLL_CYCLE * (double) baud / (double)samples_per_sec);
|
||||
|
||||
|
||||
#ifdef TUNE_LP_WINDOW
|
||||
|
@ -230,87 +190,13 @@ void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int ups
|
|||
D->pll_searching_inertia = TUNE_PLL_SEARCHING;
|
||||
#endif
|
||||
|
||||
// Initial filter (before scattering) is based on upsampled rate.
|
||||
|
||||
fc = (float)baud * D->lpf_baud / (float)(original_sample_rate * upsample);
|
||||
fc = (float)baud * D->lpf_baud / (float)samples_per_sec;
|
||||
|
||||
//dw_printf ("demod_9600_init: call gen_lowpass(fc=%.2f, , size=%d, )\n", fc, D->lp_filter_size);
|
||||
|
||||
gen_lowpass (fc, D->u.bb.lp_filter, D->lp_filter_size * upsample, D->lp_window);
|
||||
|
||||
// New in 1.7 -
|
||||
// Use a polyphase filter to reduce the CPU load.
|
||||
// Originally I used zero stuffing to upsample.
|
||||
// Here is the general idea.
|
||||
//
|
||||
// Suppose the input samples are 1 2 3 4 5 6 7 8 9 ...
|
||||
// Filter coefficients are a b c d e f g h i ...
|
||||
//
|
||||
// With original sampling rate, the filtering would involve multiplying and adding:
|
||||
//
|
||||
// 1a 2b 3c 4d 5e 6f ...
|
||||
//
|
||||
// When upsampling by 3, each of these would need to be evaluated
|
||||
// for each audio sample:
|
||||
//
|
||||
// 1a 0b 0c 2d 0e 0f 3g 0h 0i ...
|
||||
// 0a 1b 0c 0d 2e 0f 0g 3h 0i ...
|
||||
// 0a 0b 1c 0d 0e 2f 0g 0h 3i ...
|
||||
//
|
||||
// 2/3 of the multiplies are always by a stuffed zero.
|
||||
// We can do this more efficiently by removing them.
|
||||
//
|
||||
// 1a 2d 3g ...
|
||||
// 1b 2e 3h ...
|
||||
// 1c 2f 3i ...
|
||||
//
|
||||
// We scatter the original filter across multiple shorter filters.
|
||||
// Each input sample cycles around them to produce the upsampled rate.
|
||||
//
|
||||
// a d g ...
|
||||
// b e h ...
|
||||
// c f i ...
|
||||
//
|
||||
// There are countless sources of information DSP but this one is unique
|
||||
// in that it is a college course that mentions APRS.
|
||||
// https://www2.eecs.berkeley.edu/Courses/EE123
|
||||
//
|
||||
// Was the effort worthwhile? Times on an RPi 3.
|
||||
//
|
||||
// command: atest -B9600 ~/walkabout9600[abc]-compressed*.wav
|
||||
//
|
||||
// These are 3 recordings of a portable system being carried out of
|
||||
// range and back in again. It is a real world test for weak signals.
|
||||
//
|
||||
// options num decoded seconds x realtime
|
||||
// 1.6 1.7 1.6 1.7 1.6 1.7
|
||||
// --- --- --- --- --- ---
|
||||
// -P- 171 172 23.928 17.967 14.9 19.9
|
||||
// -P+ 180 180 54.688 48.772 6.5 7.3
|
||||
// -P- -F1 177 178 32.686 26.517 10.9 13.5
|
||||
//
|
||||
// So, it turns out that -P+ doesn't have a dramatic improvement, only
|
||||
// around 4%, for drastically increased CPU requirements.
|
||||
// Maybe we should turn that off by default, especially for ARM.
|
||||
//
|
||||
|
||||
int k = 0;
|
||||
for (int i = 0; i < D->lp_filter_size; i++) {
|
||||
D->u.bb.lp_polyphase_1[i] = D->u.bb.lp_filter[k++];
|
||||
if (upsample >= 2) {
|
||||
D->u.bb.lp_polyphase_2[i] = D->u.bb.lp_filter[k++];
|
||||
if (upsample >= 3) {
|
||||
D->u.bb.lp_polyphase_3[i] = D->u.bb.lp_filter[k++];
|
||||
if (upsample >= 4) {
|
||||
D->u.bb.lp_polyphase_4[i] = D->u.bb.lp_filter[k++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_lowpass (fc, D->lp_filter, D->lp_filter_size, D->lp_window);
|
||||
|
||||
/* Version 1.2: Experiment with different slicing levels. */
|
||||
// Really didn't help that much because we should have a symmetrical signal.
|
||||
|
||||
for (j = 0; j < MAX_SUBCHANS; j++) {
|
||||
slice_point[j] = 0.02f * (j - 0.5f * (MAX_SUBCHANS-1));
|
||||
|
@ -346,7 +232,7 @@ void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int ups
|
|||
* been distorted by going thru voice transceivers not
|
||||
* intended to pass this sort of "audio" signal.
|
||||
*
|
||||
* For G3RUH mode, data is "scrambled" to reduce the amount of DC bias.
|
||||
* Data is "scrambled" to reduce the amount of DC bias.
|
||||
* The data stream must be unscrambled at the receiving end.
|
||||
*
|
||||
* We also have a digital phase locked loop (PLL)
|
||||
|
@ -363,9 +249,6 @@ void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int ups
|
|||
* of the function to be called for each bit recovered
|
||||
* from the demodulator. For now, it's simply hard-coded.
|
||||
*
|
||||
* After experimentation, I found that this works better if
|
||||
* the original signal is upsampled by 2x or even 4x.
|
||||
*
|
||||
* References: 9600 Baud Packet Radio Modem Design
|
||||
* http://www.amsat.org/amsat/articles/g3ruh/109.html
|
||||
*
|
||||
|
@ -380,57 +263,63 @@ void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int ups
|
|||
|
||||
inline static void nudge_pll (int chan, int subchan, int slice, float demod_out, struct demodulator_state_s *D);
|
||||
|
||||
static void process_filtered_sample (int chan, float fsam, struct demodulator_state_s *D);
|
||||
|
||||
|
||||
__attribute__((hot))
|
||||
void demod_9600_process_sample (int chan, int sam, int upsample, struct demodulator_state_s *D)
|
||||
void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D)
|
||||
{
|
||||
|
||||
float fsam;
|
||||
float amp;
|
||||
float demod_out;
|
||||
|
||||
#if DEBUG4
|
||||
static FILE *demod_log_fp = NULL;
|
||||
static int log_file_seq = 0; /* Part of log file name */
|
||||
#endif
|
||||
|
||||
|
||||
int subchan = 0;
|
||||
int demod_data; /* Still scrambled. */
|
||||
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
||||
|
||||
|
||||
/*
|
||||
* Filters use last 'filter_size' samples.
|
||||
*
|
||||
* First push the older samples down.
|
||||
*
|
||||
* Finally, put the most recent at the beginning.
|
||||
*
|
||||
* Future project? Rather than shifting the samples,
|
||||
* it might be faster to add another variable to keep
|
||||
* track of the most recent sample and change the
|
||||
* indexing in the later loops that multipy and add.
|
||||
*/
|
||||
|
||||
/* Scale to nice number for convenience. */
|
||||
/* Consistent with the AFSK demodulator, we'd like to use */
|
||||
/* only half of the dynamic range to have some headroom. */
|
||||
/* i.e. input range +-16k becomes +-1 here and is */
|
||||
/* displayed in the heard line as audio level 100. */
|
||||
|
||||
fsam = (float)sam / 16384.0f;
|
||||
fsam = sam / 16384.0;
|
||||
|
||||
// Low pass filter
|
||||
push_sample (fsam, D->u.bb.audio_in, D->lp_filter_size);
|
||||
#if defined(TUNE_ZEROSTUFF) && TUNE_ZEROSTUFF == 0
|
||||
// experiment - no filtering.
|
||||
|
||||
fsam = convolve (D->u.bb.audio_in, D->u.bb.lp_polyphase_1, D->lp_filter_size);
|
||||
process_filtered_sample (chan, fsam, D);
|
||||
if (upsample >= 2) {
|
||||
fsam = convolve (D->u.bb.audio_in, D->u.bb.lp_polyphase_2, D->lp_filter_size);
|
||||
process_filtered_sample (chan, fsam, D);
|
||||
if (upsample >= 3) {
|
||||
fsam = convolve (D->u.bb.audio_in, D->u.bb.lp_polyphase_3, D->lp_filter_size);
|
||||
process_filtered_sample (chan, fsam, D);
|
||||
if (upsample >= 4) {
|
||||
fsam = convolve (D->u.bb.audio_in, D->u.bb.lp_polyphase_4, D->lp_filter_size);
|
||||
process_filtered_sample (chan, fsam, D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
amp = fsam;
|
||||
|
||||
#else
|
||||
push_sample (fsam, D->raw_cb, D->lp_filter_size);
|
||||
|
||||
__attribute__((hot))
|
||||
static void process_filtered_sample (int chan, float fsam, struct demodulator_state_s *D)
|
||||
{
|
||||
/*
|
||||
* Low pass filter to reduce noise yet pass the data.
|
||||
*/
|
||||
|
||||
int subchan = 0;
|
||||
amp = convolve (D->raw_cb, D->lp_filter, D->lp_filter_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Version 1.2: Capture the post-filtering amplitude for display.
|
||||
|
@ -443,18 +332,18 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
|
||||
// TODO: probably no need for this. Just use D->m_peak, D->m_valley
|
||||
|
||||
if (fsam >= D->alevel_mark_peak) {
|
||||
D->alevel_mark_peak = fsam * D->quick_attack + D->alevel_mark_peak * (1.0f - D->quick_attack);
|
||||
if (amp >= D->alevel_mark_peak) {
|
||||
D->alevel_mark_peak = amp * D->quick_attack + D->alevel_mark_peak * (1.0f - D->quick_attack);
|
||||
}
|
||||
else {
|
||||
D->alevel_mark_peak = fsam * D->sluggish_decay + D->alevel_mark_peak * (1.0f - D->sluggish_decay);
|
||||
D->alevel_mark_peak = amp * D->sluggish_decay + D->alevel_mark_peak * (1.0f - D->sluggish_decay);
|
||||
}
|
||||
|
||||
if (fsam <= D->alevel_space_peak) {
|
||||
D->alevel_space_peak = fsam * D->quick_attack + D->alevel_space_peak * (1.0f - D->quick_attack);
|
||||
if (amp <= D->alevel_space_peak) {
|
||||
D->alevel_space_peak = amp * D->quick_attack + D->alevel_space_peak * (1.0f - D->quick_attack);
|
||||
}
|
||||
else {
|
||||
D->alevel_space_peak = fsam * D->sluggish_decay + D->alevel_space_peak * (1.0f - D->sluggish_decay);
|
||||
D->alevel_space_peak = amp * D->sluggish_decay + D->alevel_space_peak * (1.0f - D->sluggish_decay);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -465,14 +354,12 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
* This works by looking at the minimum and maximum signal peaks
|
||||
* and scaling the results to be roughly in the -1.0 to +1.0 range.
|
||||
*/
|
||||
float demod_out;
|
||||
int demod_data; /* Still scrambled. */
|
||||
|
||||
demod_out = agc (fsam, D->agc_fast_attack, D->agc_slow_decay, &(D->m_peak), &(D->m_valley));
|
||||
demod_out = agc (amp, D->agc_fast_attack, D->agc_slow_decay, &(D->m_peak), &(D->m_valley));
|
||||
|
||||
// TODO: There is potential for multiple decoders with one filter.
|
||||
|
||||
//dw_printf ("peak=%.2f valley=%.2f fsam=%.2f norm=%.2f\n", D->m_peak, D->m_valley, fsam, norm);
|
||||
//dw_printf ("peak=%.2f valley=%.2f amp=%.2f norm=%.2f\n", D->m_peak, D->m_valley, amp, norm);
|
||||
|
||||
if (D->num_slicers <= 1) {
|
||||
|
||||
|
@ -503,7 +390,7 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
if (chan == 0) {
|
||||
|
||||
if (1) {
|
||||
//if (D->slicer[slice].data_detect) {
|
||||
//if (hdlc_rec_gathering (chan, subchan, slice)) {
|
||||
char fname[30];
|
||||
int slice = 0;
|
||||
|
||||
|
@ -521,7 +408,7 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
|
||||
fprintf (demod_log_fp, "%.3f, %.3f, %.3f, %.3f, %.3f, %d, %.2f\n",
|
||||
fsam + 6,
|
||||
fsam + 4,
|
||||
amp + 4,
|
||||
D->m_peak + 4,
|
||||
D->m_valley + 4,
|
||||
demod_out + 2,
|
||||
|
@ -564,7 +451,7 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
*
|
||||
* Returns: None
|
||||
*
|
||||
* Description: A PLL is used to sample near the centers of the data bits.
|
||||
* Descripton: A PLL is used to sample near the centers of the data bits.
|
||||
*
|
||||
* D->data_clock_pll is a SIGNED 32 bit variable.
|
||||
* When it overflows from a large positive value to a negative value, we
|
||||
|
@ -594,14 +481,15 @@ static void process_filtered_sample (int chan, float fsam, struct demodulator_st
|
|||
*
|
||||
* Results??? TBD
|
||||
*
|
||||
* Version 1.6: New experiment where filter size to extract clock is not the same
|
||||
* as filter to extract the data bit value.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
__attribute__((hot))
|
||||
inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_f, struct demodulator_state_s *D)
|
||||
{
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
D->slicer[slice].prev_d_c_pll = D->slicer[slice].data_clock_pll;
|
||||
|
||||
// Perform the add as unsigned to avoid signed overflow error.
|
||||
|
@ -611,8 +499,7 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_
|
|||
|
||||
/* Overflow. Was large positive, wrapped around, now large negative. */
|
||||
|
||||
hdlc_rec_bit (chan, subchan, slice, demod_out_f > 0, D->modem_type == MODEM_SCRAMBLE, D->slicer[slice].lfsr);
|
||||
pll_dcd_each_symbol2 (D, chan, subchan, slice);
|
||||
hdlc_rec_bit (chan, subchan, slice, demod_out_f > 0, 1, D->slicer[slice].lfsr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -623,11 +510,11 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_
|
|||
|
||||
// Note: Test for this demodulator, not overall for channel.
|
||||
|
||||
pll_dcd_signal_transition2 (D, slice, D->slicer[slice].data_clock_pll);
|
||||
float target = 0;
|
||||
|
||||
float target = D->pll_step_per_sample * demod_out_f / (demod_out_f - D->slicer[slice].prev_demod_out_f);
|
||||
target = D->pll_step_per_sample * demod_out_f / (demod_out_f - D->slicer[slice].prev_demod_out_f);
|
||||
|
||||
if (D->slicer[slice].data_detect) {
|
||||
if (hdlc_rec_gathering (chan, subchan, slice)) {
|
||||
D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_locked_inertia + target * (1.0f - D->pll_locked_inertia) );
|
||||
}
|
||||
else {
|
||||
|
@ -639,7 +526,7 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_
|
|||
#if DEBUG5
|
||||
|
||||
//if (chan == 0) {
|
||||
if (D->slicer[slice].data_detect) {
|
||||
if (hdlc_rec_gathering (chan,subchan,slice)) {
|
||||
|
||||
char fname[30];
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
#include "fsk_demod_state.h"
|
||||
|
||||
|
||||
void demod_9600_init (enum modem_t modem_type, int original_sample_rate, int upsample, int baud, struct demodulator_state_s *D);
|
||||
void demod_9600_init (int samples_per_sec, int baud, struct demodulator_state_s *D);
|
||||
|
||||
void demod_9600_process_sample (int chan, int sam, int upsample, struct demodulator_state_s *D);
|
||||
void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D);
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2016, 2019 John Langner, WB2OSZ
|
||||
//
|
||||
// Copyright (C) 2016 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
|
||||
|
@ -20,17 +20,35 @@
|
|||
|
||||
//#define DEBUG1 1 /* display debugging info */
|
||||
|
||||
//#define DEBUG3 1 /* print carrier detect changes. */
|
||||
|
||||
//#define DEBUG4 1 /* capture PSK demodulator output to log files */
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Module: demod_psk.c
|
||||
*
|
||||
* Purpose: Demodulator for 2400 and 4800 bits per second Phase Shift Keying (PSK).
|
||||
* Purpose: Demodulator for Phase Shift Keying (PSK).
|
||||
*
|
||||
* This is my initial attempt at implementing a 2400 bps mode.
|
||||
* The MFJ-2400 & AEA PK232-2400 used V.26 / Bell 201 so I will follow that precedent.
|
||||
*
|
||||
*
|
||||
* Input: Audio samples from either a file or the "sound card."
|
||||
*
|
||||
* Outputs: Calls hdlc_rec_bit() for each bit demodulated.
|
||||
*
|
||||
* Current Status: New for Version 1.4.
|
||||
*
|
||||
* Don't know if this is correct and/or compatible with
|
||||
* other implementations.
|
||||
* There is a lot of stuff going on here with phase
|
||||
* shifting, gray code, bit order for the dibit, NRZI and
|
||||
* bit-stuffing for HDLC. Plenty of opportunity for
|
||||
* misinterpreting a protocol spec or just stupid mistakes.
|
||||
*
|
||||
* References: MFJ-2400 Product description and manual:
|
||||
*
|
||||
* http://www.mfjenterprises.com/Product.php?productid=MFJ-2400
|
||||
|
@ -45,7 +63,8 @@
|
|||
* http://www.brazoriacountyares.org/winlink-collection/TNC%20manuals/Kantronics/2400_modem_operators_guide@rgf.pdf
|
||||
*
|
||||
*
|
||||
* From what I'm able to gather, they all used the EXAR XR-2123 PSK modem chip.
|
||||
* The MFJ and AEA both use the EXAR XR-2123 PSK modem chip.
|
||||
* The Kantronics has a P423 ???
|
||||
*
|
||||
* Can't find the chip specs on the EXAR website so Google it.
|
||||
*
|
||||
|
@ -60,19 +79,19 @@
|
|||
* "bis" and "ter" are from Latin for second and third.
|
||||
* I used the "ter" version which has phase shifts of 0, 90, 180, and 270 degrees.
|
||||
*
|
||||
* There are earlier references to an alternative B which uses other phase shifts offset
|
||||
* by another 45 degrees.
|
||||
* There are other references to an alternative B which uses other multiples of 45.
|
||||
* The XR-2123 data sheet mentions only multiples of 90. That's what I went with.
|
||||
*
|
||||
* The XR-2123 does not perform the scrambling as specified in V.26 so I wonder if
|
||||
* the vendors implemented it in software or just left it out.
|
||||
* I left out scrambling for now. Eventually, I'd like to get my hands on an old
|
||||
* 2400 bps TNC for compatibility testing.
|
||||
*
|
||||
* After getting QPSK working, it was not much more effort to add V.27 with 8 phases.
|
||||
*
|
||||
* https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-V.27bis-198811-I!!PDF-E&type=items
|
||||
* https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-V.27ter-198811-I!!PDF-E&type=items
|
||||
*
|
||||
* Compatibility:
|
||||
* V.26 has two variations, A and B. Initially I implemented the A alternative.
|
||||
* It later turned out that the MFJ-2400 used the B alternative. In version 1.6 you have a
|
||||
* choice between compatibility with MFJ (and probably the others) or the original implementation.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
#include "direwolf.h"
|
||||
|
@ -86,15 +105,10 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Fine tuning for different demodulator types.
|
||||
|
||||
#define DCD_THRESH_ON 30 // Hysteresis: Can miss 2 out of 32 for detecting lock.
|
||||
#define DCD_THRESH_OFF 6 // Might want a little more fine tuning.
|
||||
#define DCD_GOOD_WIDTH 512
|
||||
#include "fsk_demod_state.h" // Values above override defaults.
|
||||
|
||||
#include "audio.h"
|
||||
#include "tune.h"
|
||||
#include "fsk_demod_state.h"
|
||||
#include "fsk_gen_filter.h"
|
||||
#include "hdlc_rec.h"
|
||||
#include "textcolor.h"
|
||||
|
@ -102,15 +116,6 @@
|
|||
#include "dsp.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static const int phase_to_gray_v26[4] = {0, 1, 3, 2};
|
||||
static const int phase_to_gray_v27[8] = {1, 0, 2, 3, 7, 6, 4, 5};
|
||||
|
||||
|
||||
static int phase_shift_to_symbol (float phase_shift, int bits_per_symbol, int *bit_quality);
|
||||
|
||||
/* Add sample to buffer and shift the rest down. */
|
||||
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
|
@ -129,8 +134,6 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
float sum = 0.0;
|
||||
int j;
|
||||
|
||||
//Does pragma make any difference? Annoying warning on Mac.
|
||||
//#pragma GCC ivdep
|
||||
for (j=0; j<filter_size; j++) {
|
||||
sum += filter[j] * data[j];
|
||||
}
|
||||
|
@ -139,7 +142,7 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
}
|
||||
|
||||
|
||||
/* Might replace this with faster, lower precision, approximation someday if it does not harm results. */
|
||||
/* Might replace this with faster, lower precision version someday. */
|
||||
|
||||
static inline float my_atan2f (float y, float x)
|
||||
{
|
||||
|
@ -153,17 +156,16 @@ static inline float my_atan2f (float y, float x)
|
|||
*
|
||||
* Name: demod_psk_init
|
||||
*
|
||||
* Purpose: Initialization for a PSK demodulator.
|
||||
* Purpose: Initialization for an psk demodulator.
|
||||
* Select appropriate parameters and set up filters.
|
||||
*
|
||||
* Inputs: modem_type - MODEM_QPSK or MODEM_8PSK.
|
||||
*
|
||||
* v26_alt - V26_A (classic) or V25_B (MFJ compatible)
|
||||
*
|
||||
* samples_per_sec - Audio sample rate.
|
||||
*
|
||||
* bps - Bits per second.
|
||||
* Should be 2400 for V.26 or 4800 for V.27.
|
||||
* Should be 2400 for V.26 but we don't enforce it.
|
||||
* The carrier frequency will be proportional.
|
||||
*
|
||||
* profile - Select different variations. For QPSK:
|
||||
*
|
||||
|
@ -187,7 +189,7 @@ static inline float my_atan2f (float y, float x)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D)
|
||||
void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D)
|
||||
{
|
||||
int correct_baud; // baud is not same as bits/sec here!
|
||||
int carrier_freq;
|
||||
|
@ -197,9 +199,9 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
memset (D, 0, sizeof(struct demodulator_state_s));
|
||||
|
||||
D->modem_type = modem_type;
|
||||
D->u.psk.v26_alt = v26_alt;
|
||||
|
||||
D->num_slicers = 1; // Haven't thought about this yet. Is it even applicable?
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef TUNE_PROFILE
|
||||
|
@ -208,9 +210,10 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
if (modem_type == MODEM_QPSK) {
|
||||
|
||||
assert (D->u.psk.v26_alt != V26_UNSPECIFIED);
|
||||
|
||||
correct_baud = bps / 2;
|
||||
// Originally I thought of scaling it to the data rate,
|
||||
// e.g. 2400 bps -> 1800 Hz, but decided to make it a
|
||||
// constant since it is the same for V.26 and V.27.
|
||||
carrier_freq = 1800;
|
||||
|
||||
#if DEBUG1
|
||||
|
@ -222,11 +225,11 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'P': /* Self correlation technique. */
|
||||
|
||||
D->u.psk.use_prefilter = 0; /* No bandpass filter. */
|
||||
D->use_prefilter = 0; /* No bandpass filter. */
|
||||
|
||||
D->u.psk.lpf_baud = 0.60;
|
||||
D->u.psk.lp_filter_width_sym = 1.061; // 39. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 0.60;
|
||||
D->lp_filter_len_bits = 39. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.95;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -235,14 +238,14 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'Q': /* Self correlation technique. */
|
||||
|
||||
D->u.psk.use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->u.psk.prefilter_baud = 1.3;
|
||||
D->u.psk.pre_filter_width_sym = 1.497; // 55. * 1200. / 44100.;
|
||||
D->u.psk.pre_window = BP_WINDOW_COSINE;
|
||||
D->use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->prefilter_baud = 1.3;
|
||||
D->pre_filter_len_bits = 55. * 1200. / 44100.;
|
||||
D->pre_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->u.psk.lpf_baud = 0.60;
|
||||
D->u.psk.lp_filter_width_sym = 1.061; // 39. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 0.60;
|
||||
D->lp_filter_len_bits = 39. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.87;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -256,13 +259,13 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'R': /* Mix with local oscillator. */
|
||||
|
||||
D->u.psk.psk_use_lo = 1;
|
||||
D->psk_use_lo = 1;
|
||||
|
||||
D->u.psk.use_prefilter = 0; /* No bandpass filter. */
|
||||
D->use_prefilter = 0; /* No bandpass filter. */
|
||||
|
||||
D->u.psk.lpf_baud = 0.70;
|
||||
D->u.psk.lp_filter_width_sym = 1.007; // 37. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_TRUNCATED;
|
||||
D->lpf_baud = 0.70;
|
||||
D->lp_filter_len_bits = 37. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_TRUNCATED;
|
||||
|
||||
D->pll_locked_inertia = 0.925;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -271,16 +274,16 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'S': /* Mix with local oscillator. */
|
||||
|
||||
D->u.psk.psk_use_lo = 1;
|
||||
D->psk_use_lo = 1;
|
||||
|
||||
D->u.psk.use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->u.psk.prefilter_baud = 0.55;
|
||||
D->u.psk.pre_filter_width_sym = 2.014; // 74. * 1200. / 44100.;
|
||||
D->u.psk.pre_window = BP_WINDOW_FLATTOP;
|
||||
D->use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->prefilter_baud = 0.55;
|
||||
D->pre_filter_len_bits = 74. * 1200. / 44100.;
|
||||
D->pre_window = BP_WINDOW_FLATTOP;
|
||||
|
||||
D->u.psk.lpf_baud = 0.60;
|
||||
D->u.psk.lp_filter_width_sym = 1.061; // 39. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 0.60;
|
||||
D->lp_filter_len_bits = 39. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.925;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -288,11 +291,11 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
break;
|
||||
}
|
||||
|
||||
D->u.psk.delay_line_width_sym = 1.25; // Delay line > 13/12 * symbol period
|
||||
D->ms_filter_len_bits = 1.25; // Delay line > 13/12 * symbol period
|
||||
|
||||
D->u.psk.coffs = (int) round( (11.f / 12.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.boffs = (int) round( (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.soffs = (int) round( (13.f / 12.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->coffs = (int) round( (11.f / 12.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->boffs = (int) round( (float)samples_per_sec / (float)correct_baud );
|
||||
D->soffs = (int) round( (13.f / 12.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
}
|
||||
else {
|
||||
|
||||
|
@ -309,11 +312,11 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'T': /* Self correlation technique. */
|
||||
|
||||
D->u.psk.use_prefilter = 0; /* No bandpass filter. */
|
||||
D->use_prefilter = 0; /* No bandpass filter. */
|
||||
|
||||
D->u.psk.lpf_baud = 1.15;
|
||||
D->u.psk.lp_filter_width_sym = 0.871; // 32. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 1.15;
|
||||
D->lp_filter_len_bits = 32. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.95;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -322,14 +325,14 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'U': /* Self correlation technique. */
|
||||
|
||||
D->u.psk.use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->u.psk.prefilter_baud = 0.9;
|
||||
D->u.psk.pre_filter_width_sym = 0.571; // 21. * 1200. / 44100.;
|
||||
D->u.psk.pre_window = BP_WINDOW_FLATTOP;
|
||||
D->use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->prefilter_baud = 0.9;
|
||||
D->pre_filter_len_bits = 21. * 1200. / 44100.;
|
||||
D->pre_window = BP_WINDOW_FLATTOP;
|
||||
|
||||
D->u.psk.lpf_baud = 1.15;
|
||||
D->u.psk.lp_filter_width_sym = 0.871; // 32. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 1.15;
|
||||
D->lp_filter_len_bits = 32. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.87;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -343,13 +346,13 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'V': /* Mix with local oscillator. */
|
||||
|
||||
D->u.psk.psk_use_lo = 1;
|
||||
D->psk_use_lo = 1;
|
||||
|
||||
D->u.psk.use_prefilter = 0; /* No bandpass filter. */
|
||||
D->use_prefilter = 0; /* No bandpass filter. */
|
||||
|
||||
D->u.psk.lpf_baud = 0.85;
|
||||
D->u.psk.lp_filter_width_sym = 0.844; // 31. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 0.85;
|
||||
D->lp_filter_len_bits = 31. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.925;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -358,16 +361,16 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
|
||||
case 'W': /* Mix with local oscillator. */
|
||||
|
||||
D->u.psk.psk_use_lo = 1;
|
||||
D->psk_use_lo = 1;
|
||||
|
||||
D->u.psk.use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->u.psk.prefilter_baud = 0.85;
|
||||
D->u.psk.pre_filter_width_sym = 0.844; // 31. * 1200. / 44100.;
|
||||
D->u.psk.pre_window = BP_WINDOW_COSINE;
|
||||
D->use_prefilter = 1; /* Add a bandpass filter. */
|
||||
D->prefilter_baud = 0.85;
|
||||
D->pre_filter_len_bits = 31. * 1200. / 44100.;
|
||||
D->pre_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->u.psk.lpf_baud = 0.85;
|
||||
D->u.psk.lp_filter_width_sym = 0.844; // 31. * 1200. / 44100.;
|
||||
D->u.psk.lp_window = BP_WINDOW_COSINE;
|
||||
D->lpf_baud = 0.85;
|
||||
D->lp_filter_len_bits = 31. * 1200. / 44100.;
|
||||
D->lp_window = BP_WINDOW_COSINE;
|
||||
|
||||
D->pll_locked_inertia = 0.925;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
@ -375,36 +378,42 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
break;
|
||||
}
|
||||
|
||||
D->u.psk.delay_line_width_sym = 1.25; // Delay line > 10/9 * symbol period
|
||||
D->ms_filter_len_bits = 1.25; // Delay line > 10/9 * symbol period
|
||||
|
||||
D->u.psk.coffs = (int) round( (8.f / 9.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.boffs = (int) round( (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.soffs = (int) round( (10.f / 9.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->coffs = (int) round( (8.f / 9.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
D->boffs = (int) round( (float)samples_per_sec / (float)correct_baud );
|
||||
D->soffs = (int) round( (10.f / 9.f) * (float)samples_per_sec / (float)correct_baud );
|
||||
}
|
||||
|
||||
|
||||
if (D->u.psk.psk_use_lo) {
|
||||
D->u.psk.lo_step = (int) round( 256. * 256. * 256. * 256. * carrier_freq / (double)samples_per_sec);
|
||||
|
||||
// Our own sin table for speed later.
|
||||
if (D->psk_use_lo) {
|
||||
D->lo_step = (int) round( 256. * 256. * 256. * 256. * carrier_freq / (double)samples_per_sec);
|
||||
|
||||
assert (MAX_FILTER_SIZE >= 256);
|
||||
for (j = 0; j < 256; j++) {
|
||||
D->u.psk.sin_table256[j] = sinf(2.f * (float)M_PI * j / 256.f);
|
||||
D->m_sin_table[j] = sinf(2.f * (float)M_PI * j / 256.f);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TUNE_PRE_BAUD
|
||||
D->u.psk.prefilter_baud = TUNE_PRE_BAUD;
|
||||
D->prefilter_baud = TUNE_PRE_BAUD;
|
||||
#endif
|
||||
#ifdef TUNE_PRE_WINDOW
|
||||
D->u.psk.pre_window = TUNE_PRE_WINDOW;
|
||||
D->pre_window = TUNE_PRE_WINDOW;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef TUNE_LPF_BAUD
|
||||
D->u.psk.lpf_baud = TUNE_LPF_BAUD;
|
||||
D->lpf_baud = TUNE_LPF_BAUD;
|
||||
#endif
|
||||
#ifdef TUNE_LP_WINDOW
|
||||
D->u.psk.lp_window = TUNE_LP_WINDOW;
|
||||
D->lp_window = TUNE_LP_WINDOW;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TUNE_HYST
|
||||
D->hysteresis = TUNE_HYST;
|
||||
#endif
|
||||
|
||||
#if defined(TUNE_PLL_SEARCHING)
|
||||
|
@ -426,41 +435,44 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
* Convert number of symbol times to number of taps.
|
||||
*/
|
||||
|
||||
D->u.psk.pre_filter_taps = (int) round( D->u.psk.pre_filter_width_sym * (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.delay_line_taps = (int) round( D->u.psk.delay_line_width_sym * (float)samples_per_sec / (float)correct_baud );
|
||||
D->u.psk.lp_filter_taps = (int) round( D->u.psk.lp_filter_width_sym * (float)samples_per_sec / (float)correct_baud );
|
||||
D->pre_filter_size = (int) round( D->pre_filter_len_bits * (float)samples_per_sec / (float)correct_baud );
|
||||
D->ms_filter_size = (int) round( D->ms_filter_len_bits * (float)samples_per_sec / (float)correct_baud );
|
||||
D->lp_filter_size = (int) round( D->lp_filter_len_bits * (float)samples_per_sec / (float)correct_baud );
|
||||
|
||||
|
||||
#ifdef TUNE_PRE_FILTER_TAPS
|
||||
D->u.psk.pre_filter_taps = TUNE_PRE_FILTER_TAPS;
|
||||
#ifdef TUNE_PRE_FILTER_SIZE
|
||||
D->pre_filter_size = TUNE_PRE_FILTER_SIZE;
|
||||
#endif
|
||||
|
||||
#ifdef TUNE_lp_filter_taps
|
||||
D->u.psk.lp_filter_taps = TUNE_lp_filter_taps;
|
||||
#ifdef TUNE_LP_FILTER_SIZE
|
||||
D->lp_filter_size = TUNE_LP_FILTER_SIZE;
|
||||
#endif
|
||||
|
||||
|
||||
if (D->u.psk.pre_filter_taps > MAX_FILTER_SIZE) {
|
||||
if (D->pre_filter_size > MAX_FILTER_SIZE)
|
||||
{
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Calculated pre filter size of %d is too large.\n", D->u.psk.pre_filter_taps);
|
||||
dw_printf ("Calculated filter size of %d is too large.\n", D->pre_filter_size);
|
||||
dw_printf ("Decrease the audio sample rate or increase the baud rate or\n");
|
||||
dw_printf ("recompile the application with MAX_FILTER_SIZE larger than %d.\n",
|
||||
MAX_FILTER_SIZE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (D->u.psk.delay_line_taps > MAX_FILTER_SIZE) {
|
||||
if (D->ms_filter_size > MAX_FILTER_SIZE)
|
||||
{
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Calculated delay line size of %d is too large.\n", D->u.psk.delay_line_taps);
|
||||
dw_printf ("Calculated filter size of %d is too large.\n", D->ms_filter_size);
|
||||
dw_printf ("Decrease the audio sample rate or increase the baud rate or\n");
|
||||
dw_printf ("recompile the application with MAX_FILTER_SIZE larger than %d.\n",
|
||||
MAX_FILTER_SIZE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (D->u.psk.lp_filter_taps > MAX_FILTER_SIZE) {
|
||||
if (D->lp_filter_size > MAX_FILTER_SIZE)
|
||||
{
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Calculated low pass filter size of %d is too large.\n", D->u.psk.lp_filter_taps);
|
||||
dw_printf ("Calculated filter size of %d is too large.\n", D->pre_filter_size);
|
||||
dw_printf ("Decrease the audio sample rate or increase the baud rate or\n");
|
||||
dw_printf ("recompile the application with MAX_FILTER_SIZE larger than %d.\n",
|
||||
MAX_FILTER_SIZE);
|
||||
|
@ -470,17 +482,14 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
/*
|
||||
* Optionally apply a bandpass ("pre") filter to attenuate
|
||||
* frequencies outside the range of interest.
|
||||
* It's a tradeoff. Attenuate frequencies outside the the range of interest
|
||||
* but also distort the signal. This demodulator is not compuationally
|
||||
* intensive so we can usually run both in parallel.
|
||||
*/
|
||||
|
||||
if (D->u.psk.use_prefilter) {
|
||||
if (D->use_prefilter) {
|
||||
float f1, f2;
|
||||
|
||||
f1 = carrier_freq - D->u.psk.prefilter_baud * correct_baud;
|
||||
f2 = carrier_freq + D->u.psk.prefilter_baud * correct_baud;
|
||||
#if DEBUG1
|
||||
f1 = carrier_freq - D->prefilter_baud * correct_baud;
|
||||
f2 = carrier_freq + D->prefilter_baud * correct_baud;
|
||||
#if 0
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Generating prefilter %.0f to %.0f Hz.\n", (double)f1, (double)f2);
|
||||
#endif
|
||||
|
@ -493,15 +502,15 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
f1 = f1 / (float)samples_per_sec;
|
||||
f2 = f2 / (float)samples_per_sec;
|
||||
|
||||
gen_bandpass (f1, f2, D->u.psk.pre_filter, D->u.psk.pre_filter_taps, D->u.psk.pre_window);
|
||||
gen_bandpass (f1, f2, D->pre_filter, D->pre_filter_size, D->pre_window);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the lowpass filter.
|
||||
*/
|
||||
|
||||
float fc = correct_baud * D->u.psk.lpf_baud / (float)samples_per_sec;
|
||||
gen_lowpass (fc, D->u.psk.lp_filter, D->u.psk.lp_filter_taps, D->u.psk.lp_window);
|
||||
float fc = correct_baud * D->lpf_baud / (float)samples_per_sec;
|
||||
gen_lowpass (fc, D->lp_filter, D->lp_filter_size, D->lp_window);
|
||||
|
||||
/*
|
||||
* No point in having multiple numbers for signal level.
|
||||
|
@ -510,98 +519,10 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe
|
|||
D->alevel_mark_peak = -1;
|
||||
D->alevel_space_peak = -1;
|
||||
|
||||
#if 0
|
||||
// QPSK - CSV format to make plot.
|
||||
|
||||
printf ("Phase shift degrees, bit 0, quality 0, bit 1, quality 1\n");
|
||||
for (int degrees = 0; degrees <= 360; degrees++) {
|
||||
float a = degrees * M_PI * 2./ 360.;
|
||||
int bit_quality[3];
|
||||
|
||||
int new_gray = phase_shift_to_symbol (a, 2, bit_quality);
|
||||
|
||||
float offset = 3 * 1.5;
|
||||
printf ("%d, ", degrees);
|
||||
printf ("%.3f, ", offset + (new_gray & 1)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + (bit_quality[0] / 100.)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + ((new_gray >> 1) & 1)); offset -= 1.5;
|
||||
printf ("%.3f\n", offset + (bit_quality[1] / 100.));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// 8-PSK - CSV format to make plot.
|
||||
|
||||
printf ("Phase shift degrees, bit 0, quality 0, bit 1, quality 1, bit 2, quality 2\n");
|
||||
for (int degrees = 0; degrees <= 360; degrees++) {
|
||||
float a = degrees * M_PI * 2./ 360.;
|
||||
int bit_quality[3];
|
||||
|
||||
int new_gray = phase_shift_to_symbol (a, 3, bit_quality);
|
||||
|
||||
float offset = 5 * 1.5;
|
||||
printf ("%d, ", degrees);
|
||||
printf ("%.3f, ", offset + (new_gray & 1)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + (bit_quality[0] / 100.)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + ((new_gray >> 1) & 1)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + (bit_quality[1] / 100.)); offset -= 1.5;
|
||||
printf ("%.3f, ", offset + ((new_gray >> 2) & 1)); offset -= 1.5;
|
||||
printf ("%.3f\n", offset + (bit_quality[2] / 100.));
|
||||
}
|
||||
#endif
|
||||
} /* demod_psk_init */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: phase_shift_to_symbol
|
||||
*
|
||||
* Purpose: Translate phase shift, between two symbols, into 2 or 3 bits.
|
||||
*
|
||||
* Inputs: phase_shift - in radians.
|
||||
*
|
||||
* bits_per_symbol - 2 for QPSK, 3 for 8PSK.
|
||||
*
|
||||
* Outputs: bit_quality[] - Value of 0 (at threshold) to 100 (perfect) for each bit.
|
||||
*
|
||||
* Returns: 2 or 3 bit symbol value in Gray code.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline int phase_shift_to_symbol (float phase_shift, int bits_per_symbol, int * __restrict__ bit_quality)
|
||||
{
|
||||
// Number of different symbol states.
|
||||
assert (bits_per_symbol == 2 || bits_per_symbol == 3);
|
||||
int N = 1 << bits_per_symbol;
|
||||
assert (N == 4 || N == 8);
|
||||
|
||||
// Scale angle to 1 per symbol then separate into integer and fractional parts.
|
||||
float a = phase_shift * (float)N / (M_PI * 2.0f);
|
||||
while (a >= (float)N) a -= (float)N;
|
||||
while (a < 0.) a += (float)N;
|
||||
int i = (int)a;
|
||||
if (i == N) i = N-1; // Should be < N. Watch out for possible roundoff errors.
|
||||
float f = a - (float)i;
|
||||
assert (i >= 0 && i < N);
|
||||
assert (f >= -0.001f && f <= 1.001f);
|
||||
|
||||
// Interpolate between the ideal angles to get a level of certainty.
|
||||
int result = 0;
|
||||
for (int b = 0; b < bits_per_symbol; b++) {
|
||||
float demod = bits_per_symbol == 2 ?
|
||||
((phase_to_gray_v26[i] >> b) & 1) * (1.0f - f) + ((phase_to_gray_v26[(i+1)&3] >> b) & 1) * f :
|
||||
((phase_to_gray_v27[i] >> b) & 1) * (1.0f - f) + ((phase_to_gray_v27[(i+1)&7] >> b) & 1) * f;
|
||||
// Slice to get boolean value and quality measurement.
|
||||
if (demod >= 0.5f) result |= 1<<b;
|
||||
bit_quality[b] = lrintf (100.0f * 2.0f * fabsf(demod - 0.5f));
|
||||
}
|
||||
return (result);
|
||||
|
||||
} // end phase_shift_to_symbol
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
|
@ -618,7 +539,7 @@ static inline int phase_shift_to_symbol (float phase_shift, int bits_per_symbol,
|
|||
*
|
||||
* Outputs: For each recovered data bit, we call:
|
||||
*
|
||||
* hdlc_rec (channel etc., demodulated_bit, quality);
|
||||
* hdlc_rec (channel, demodulated_bit);
|
||||
*
|
||||
* to decode HDLC frames from the stream of bits.
|
||||
*
|
||||
|
@ -658,112 +579,193 @@ static inline int phase_shift_to_symbol (float phase_shift, int bits_per_symbol,
|
|||
|
||||
|
||||
|
||||
inline static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct demodulator_state_s *D, int *bit_quality);
|
||||
inline static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct demodulator_state_s *D);
|
||||
|
||||
__attribute__((hot))
|
||||
void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulator_state_s *D)
|
||||
{
|
||||
int slice = 0; // Would it make sense to have more than one?
|
||||
float fsam;
|
||||
float sam_x_cos, sam_x_sin;
|
||||
float I, Q;
|
||||
int demod_phase_shift; // Phase shift relative to previous symbol.
|
||||
// range 0-3, 1 unit for each 90 degrees.
|
||||
int slice = 0;
|
||||
|
||||
#if DEBUG4
|
||||
static FILE *demod_log_fp = NULL;
|
||||
static int log_file_seq = 0; /* Part of log file name */
|
||||
#endif
|
||||
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
||||
|
||||
|
||||
/* Scale to nice number for plotting during debug. */
|
||||
|
||||
float fsam = sam / 16384.0f;
|
||||
fsam = sam / 16384.0f;
|
||||
|
||||
|
||||
/*
|
||||
* Optional bandpass filter before the phase detector.
|
||||
*/
|
||||
|
||||
if (D->u.psk.use_prefilter) {
|
||||
push_sample (fsam, D->u.psk.audio_in, D->u.psk.pre_filter_taps);
|
||||
fsam = convolve (D->u.psk.audio_in, D->u.psk.pre_filter, D->u.psk.pre_filter_taps);
|
||||
if (D->use_prefilter) {
|
||||
push_sample (fsam, D->raw_cb, D->pre_filter_size);
|
||||
fsam = convolve (D->raw_cb, D->pre_filter, D->pre_filter_size);
|
||||
}
|
||||
|
||||
if (D->u.psk.psk_use_lo) {
|
||||
if (D->psk_use_lo) {
|
||||
float a, delta;
|
||||
int id;
|
||||
/*
|
||||
* Mix with local oscillator to obtain phase.
|
||||
* The absolute phase doesn't matter.
|
||||
* We are just concerned with the change since the previous symbol.
|
||||
*/
|
||||
|
||||
float sam_x_cos = fsam * D->u.psk.sin_table256[((D->u.psk.lo_phase >> 24) + 64) & 0xff];
|
||||
push_sample (sam_x_cos, D->u.psk.I_raw, D->u.psk.lp_filter_taps);
|
||||
float I = convolve (D->u.psk.I_raw, D->u.psk.lp_filter, D->u.psk.lp_filter_taps);
|
||||
sam_x_cos = fsam * D->m_sin_table[((D->lo_phase >> 24) + 64) & 0xff];
|
||||
|
||||
float sam_x_sin = fsam * D->u.psk.sin_table256[(D->u.psk.lo_phase >> 24) & 0xff];
|
||||
push_sample (sam_x_sin, D->u.psk.Q_raw, D->u.psk.lp_filter_taps);
|
||||
float Q = convolve (D->u.psk.Q_raw, D->u.psk.lp_filter, D->u.psk.lp_filter_taps);
|
||||
sam_x_sin = fsam * D->m_sin_table[(D->lo_phase >> 24) & 0xff];
|
||||
|
||||
float a = my_atan2f(I,Q);
|
||||
push_sample (sam_x_cos, D->m_amp_cb, D->lp_filter_size);
|
||||
I = convolve (D->m_amp_cb, D->lp_filter, D->lp_filter_size);
|
||||
|
||||
// This is just a delay line of one symbol time.
|
||||
push_sample (sam_x_sin, D->s_amp_cb, D->lp_filter_size);
|
||||
Q = convolve (D->s_amp_cb, D->lp_filter, D->lp_filter_size);
|
||||
|
||||
push_sample (a, D->u.psk.delay_line, D->u.psk.delay_line_taps);
|
||||
float delta = a - D->u.psk.delay_line[D->u.psk.boffs];
|
||||
a = my_atan2f(I,Q);
|
||||
push_sample (a, D->ms_in_cb, D->ms_filter_size);
|
||||
|
||||
int gray;
|
||||
int bit_quality[3];
|
||||
delta = a - D->ms_in_cb[D->boffs];
|
||||
|
||||
/* 256 units/cycle makes modulo processing easier. */
|
||||
/* Make sure it is positive before truncating to integer. */
|
||||
|
||||
id = ((int)((delta / (2.f * (float)M_PI) + 1.f) * 256.f)) & 0xff;
|
||||
|
||||
if (D->modem_type == MODEM_QPSK) {
|
||||
if (D->u.psk.v26_alt == V26_B) {
|
||||
gray = phase_shift_to_symbol (delta + (float)(-M_PI/4), 2, bit_quality);; // MFJ compatible
|
||||
}
|
||||
else {
|
||||
gray = phase_shift_to_symbol (delta, 2, bit_quality); // Classic
|
||||
}
|
||||
demod_phase_shift = ((id + 32) >> 6) & 0x3;
|
||||
}
|
||||
else {
|
||||
gray = phase_shift_to_symbol (delta, 3, bit_quality);; // 8-PSK
|
||||
demod_phase_shift = ((id + 16) >> 5) & 0x7;
|
||||
}
|
||||
nudge_pll (chan, subchan, slice, gray, D, bit_quality);
|
||||
nudge_pll (chan, subchan, slice, demod_phase_shift, D);
|
||||
|
||||
D->u.psk.lo_phase += D->u.psk.lo_step;
|
||||
D->lo_phase += D->lo_step;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Correlate with previous symbol. We are looking for the phase shift.
|
||||
*/
|
||||
push_sample (fsam, D->u.psk.delay_line, D->u.psk.delay_line_taps);
|
||||
push_sample (fsam, D->ms_in_cb, D->ms_filter_size);
|
||||
|
||||
float sam_x_cos = fsam * D->u.psk.delay_line[D->u.psk.coffs];
|
||||
push_sample (sam_x_cos, D->u.psk.I_raw, D->u.psk.lp_filter_taps);
|
||||
float I = convolve (D->u.psk.I_raw, D->u.psk.lp_filter, D->u.psk.lp_filter_taps);
|
||||
sam_x_cos = fsam * D->ms_in_cb[D->coffs];
|
||||
sam_x_sin = fsam * D->ms_in_cb[D->soffs];
|
||||
|
||||
float sam_x_sin = fsam * D->u.psk.delay_line[D->u.psk.soffs];
|
||||
push_sample (sam_x_sin, D->u.psk.Q_raw, D->u.psk.lp_filter_taps);
|
||||
float Q = convolve (D->u.psk.Q_raw, D->u.psk.lp_filter, D->u.psk.lp_filter_taps);
|
||||
push_sample (sam_x_cos, D->m_amp_cb, D->lp_filter_size);
|
||||
I = convolve (D->m_amp_cb, D->lp_filter, D->lp_filter_size);
|
||||
|
||||
int gray;
|
||||
int bit_quality[3];
|
||||
float delta = my_atan2f(I,Q);
|
||||
push_sample (sam_x_sin, D->s_amp_cb, D->lp_filter_size);
|
||||
Q = convolve (D->s_amp_cb, D->lp_filter, D->lp_filter_size);
|
||||
|
||||
if (D->modem_type == MODEM_QPSK) {
|
||||
if (D->u.psk.v26_alt == V26_B) {
|
||||
gray = phase_shift_to_symbol (delta + (float)(M_PI/2), 2, bit_quality); // MFJ compatible
|
||||
|
||||
#if 1 // Speed up special case.
|
||||
if (I > 0) {
|
||||
if (Q > 0)
|
||||
demod_phase_shift = 0; /* 0 to 90 degrees, etc. */
|
||||
else
|
||||
demod_phase_shift = 1;
|
||||
}
|
||||
else {
|
||||
gray = phase_shift_to_symbol (delta + (float)(3*M_PI/4), 2, bit_quality); // Classic
|
||||
if (Q > 0)
|
||||
demod_phase_shift = 3;
|
||||
else
|
||||
demod_phase_shift = 2;
|
||||
}
|
||||
#else
|
||||
a = my_atan2f(I,Q);
|
||||
int id = ((int)((a / (2.f * (float)M_PI) + 1.f) * 256.f)) & 0xff;
|
||||
// 128 compensates for 180 degree phase shift due
|
||||
// to 1 1/2 carrier cycles per symbol period.
|
||||
demod_phase_shift = ((id + 128) >> 6) & 0x3;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
gray = phase_shift_to_symbol (delta + (float)(3*M_PI/2), 3, bit_quality);
|
||||
float a;
|
||||
int idelta;
|
||||
|
||||
a = my_atan2f(I,Q);
|
||||
idelta = ((int)((a / (2.f * (float)M_PI) + 1.f) * 256.f)) & 0xff;
|
||||
// 32 (90 degrees) compensates for 1800 carrier vs. 1800 baud.
|
||||
// 16 is to set threshold between constellation points.
|
||||
demod_phase_shift = ((idelta - 32 - 16) >> 5) & 0x7;
|
||||
}
|
||||
nudge_pll (chan, subchan, slice, gray, D, bit_quality);
|
||||
|
||||
nudge_pll (chan, subchan, slice, demod_phase_shift, D);
|
||||
}
|
||||
|
||||
#if DEBUG4
|
||||
|
||||
if (chan == 0) {
|
||||
|
||||
if (1) {
|
||||
//if (hdlc_rec_gathering (chan, subchan, slice)) {
|
||||
char fname[30];
|
||||
|
||||
|
||||
if (demod_log_fp == NULL) {
|
||||
log_file_seq++;
|
||||
snprintf (fname, sizeof(fname), "demod/%04d.csv", log_file_seq);
|
||||
//if (log_file_seq == 1) mkdir ("demod", 0777);
|
||||
if (log_file_seq == 1) mkdir ("demod");
|
||||
|
||||
demod_log_fp = fopen (fname, "w");
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Starting demodulator log file %s\n", fname);
|
||||
fprintf (demod_log_fp, "Audio, sin, cos, *cos, *sin, I, Q, phase, Clock\n");
|
||||
}
|
||||
|
||||
fprintf (demod_log_fp, "%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.2f, %.2f, %.2f\n",
|
||||
fsam + 2,
|
||||
- D->ms_in_cb[D->soffs] + 6,
|
||||
- D->ms_in_cb[D->coffs] + 6,
|
||||
sam_x_cos + 8,
|
||||
sam_x_sin + 10,
|
||||
2 * I + 12,
|
||||
2 * Q + 12,
|
||||
demod_phase_shift * 2. / 3. + 14.,
|
||||
(D->slicer[slice].data_clock_pll & 0x80000000) ? .5 : .0);
|
||||
|
||||
fflush (demod_log_fp);
|
||||
}
|
||||
else {
|
||||
if (demod_log_fp != NULL) {
|
||||
fclose (demod_log_fp);
|
||||
demod_log_fp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
} /* end demod_psk_process_sample */
|
||||
|
||||
static const int phase_to_gray_v26[4] = {0, 1, 3, 2};
|
||||
static const int phase_to_gray_v27[8] = {1, 0, 2, 3, 7, 6, 4, 5};
|
||||
|
||||
|
||||
|
||||
__attribute__((hot))
|
||||
static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct demodulator_state_s *D, int *bit_quality)
|
||||
inline static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct demodulator_state_s *D)
|
||||
{
|
||||
|
||||
/*
|
||||
* Finally, a PLL is used to sample near the centers of the data bits.
|
||||
*
|
||||
* D points to a demodulator for a channel/subchannel pair.
|
||||
* D points to a demodulator for a channel/subchannel pair so we don't
|
||||
* have to keep recalculating it.
|
||||
*
|
||||
* D->data_clock_pll is a SIGNED 32 bit variable.
|
||||
* When it overflows from a large positive value to a negative value, we
|
||||
|
@ -781,11 +783,15 @@ static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct
|
|||
* If we adjust it too quickly, the clock will have too much jitter.
|
||||
* If we adjust it too slowly, it will take too long to lock on to a new signal.
|
||||
*
|
||||
* Be a little more aggressive about adjusting the PLL
|
||||
* Be a little more agressive about adjusting the PLL
|
||||
* phase when searching for a signal.
|
||||
* Don't change it as much when locked on to a signal.
|
||||
*
|
||||
* I don't think the optimal value will depend on the audio sample rate
|
||||
* because this happens for each transition from the demodulator.
|
||||
*/
|
||||
|
||||
|
||||
D->slicer[slice].prev_d_c_pll = D->slicer[slice].data_clock_pll;
|
||||
|
||||
// Perform the add as unsigned to avoid signed overflow error.
|
||||
|
@ -798,19 +804,26 @@ static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct
|
|||
|
||||
if (D->modem_type == MODEM_QPSK) {
|
||||
|
||||
int gray = demod_bits;
|
||||
int gray = phase_to_gray_v26[ demod_bits ];
|
||||
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1]);
|
||||
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, bit_quality[0]);
|
||||
#if DEBUG4
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
||||
dw_printf ("a=%.2f deg, delta=%.2f deg, phaseshift=%d, bits= %d %d \n",
|
||||
a * 360 / (2*M_PI), delta * 360 / (2*M_PI), demod_bits, (gray >> 1) & 1, gray & 1);
|
||||
|
||||
//dw_printf ("phaseshift=%d, bits= %d %d \n", demod_bits, (gray >> 1) & 1, gray & 1);
|
||||
#endif
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, -1);
|
||||
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, -1);
|
||||
}
|
||||
else {
|
||||
int gray = demod_bits;
|
||||
int gray = phase_to_gray_v27[ demod_bits ];
|
||||
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 2) & 1, 0, bit_quality[2]);
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1]);
|
||||
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, bit_quality[0]);
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 2) & 1, 0, -1);
|
||||
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, -1);
|
||||
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, -1);
|
||||
}
|
||||
pll_dcd_each_symbol2 (D, chan, subchan, slice);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -824,9 +837,7 @@ static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct
|
|||
|
||||
if (demod_bits != D->slicer[slice].prev_demod_data) {
|
||||
|
||||
pll_dcd_signal_transition2 (D, slice, D->slicer[slice].data_clock_pll);
|
||||
|
||||
if (D->slicer[slice].data_detect) {
|
||||
if (hdlc_rec_gathering (chan, subchan, slice)) {
|
||||
D->slicer[slice].data_clock_pll = (int)floorf((float)(D->slicer[slice].data_clock_pll) * D->pll_locked_inertia);
|
||||
}
|
||||
else {
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
/* demod_psk.h */
|
||||
|
||||
|
||||
void demod_psk_init (enum modem_t modem_type, int samples_per_sec, int bps, char profile, struct demodulator_state_s *D);
|
||||
|
||||
void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulator_state_s *D);
|
|
@ -49,8 +49,7 @@
|
|||
* Preemptive Digipeating (new in version 0.8)
|
||||
*
|
||||
* http://www.aprs.org/aprs12/preemptive-digipeating.txt
|
||||
* I ignored the part about the RR bits.
|
||||
*
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#define DIGIPEATER_C
|
||||
|
@ -63,7 +62,7 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h> /* for isdigit, isupper */
|
||||
#include "regex.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include "ax25_pad.h"
|
||||
#include "digipeater.h"
|
||||
|
@ -74,7 +73,7 @@
|
|||
|
||||
|
||||
static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, char *mycall_xmit,
|
||||
regex_t *uidigi, regex_t *uitrace, int to_chan, enum preempt_e preempt, char *atgp, char *type_filter);
|
||||
regex_t *uidigi, regex_t *uitrace, int to_chan, enum preempt_e preempt, char *type_filter);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -150,49 +149,18 @@ void digipeater (int from_chan, packet_t pp)
|
|||
|
||||
// dw_printf ("digipeater()\n");
|
||||
|
||||
assert (from_chan >= 0 && from_chan < MAX_CHANS);
|
||||
|
||||
|
||||
// Network TNC is OK for UI frames where we don't care about timing.
|
||||
|
||||
if ( from_chan < 0 || from_chan >= MAX_CHANS ||
|
||||
(save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO &&
|
||||
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC)) {
|
||||
if ( ! save_audio_config_p->achan[from_chan].valid) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("APRS digipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
|
||||
dw_printf ("digipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* First pass: Look at packets being digipeated to same channel.
|
||||
*
|
||||
* We want these to get out quickly, bypassing the usual random wait time.
|
||||
*
|
||||
* Some may disagree but I followed what WB4APR had to say about it.
|
||||
*
|
||||
* http://www.aprs.org/balloons.html
|
||||
*
|
||||
* APRS NETWORK FRATRICIDE: Generally, all APRS digipeaters are supposed to transmit
|
||||
* immediately and all at the same time. They should NOT wait long enough for each
|
||||
* one to QRM the channel with the same copy of each packet. NO, APRS digipeaters
|
||||
* are all supposed to STEP ON EACH OTHER with every packet. This makes sure that
|
||||
* everyone in range of a digi will hear one and only one copy of each packet.
|
||||
* and that the packet will digipeat OUTWARD and not backward. The goal is that a
|
||||
* digipeated packet is cleared out of the local area in ONE packet time and not
|
||||
* N packet times for every N digipeaters that heard the packet. This means no
|
||||
* PERSIST times, no DWAIT times and no UIDWAIT times. Notice, this is contrary
|
||||
* to other packet systems that might want to guarantee delivery (but at the
|
||||
* expense of throughput). APRS wants to clear the channel quickly to maximize throughput.
|
||||
*
|
||||
* http://www.aprs.org/kpc3/kpc3+WIDEn.txt
|
||||
*
|
||||
* THIRD: Eliminate the settings that are detrimental to the network.
|
||||
*
|
||||
* * UIDWAIT should be OFF. (the default). With it on, your digi is not doing the
|
||||
* fundamental APRS fratricide that is the primary mechanism for minimizing channel
|
||||
* loading. All digis that hear the same packet are supposed to DIGI it at the SAME
|
||||
* time so that all those copies only take up one additional time slot. (but outward
|
||||
* located digs will hear it without collision (and continue outward propagation)
|
||||
*
|
||||
* We want these to get out quickly.
|
||||
*/
|
||||
|
||||
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) {
|
||||
|
@ -204,11 +172,10 @@ void digipeater (int from_chan, packet_t pp)
|
|||
save_audio_config_p->achan[to_chan].mycall,
|
||||
&save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan],
|
||||
to_chan, save_digi_config_p->preempt[from_chan][to_chan],
|
||||
save_digi_config_p->atgp[from_chan][to_chan],
|
||||
save_digi_config_p->filter_str[from_chan][to_chan]);
|
||||
if (result != NULL) {
|
||||
dedupe_remember (pp, to_chan);
|
||||
tq_append (to_chan, TQ_PRIO_0_HI, result); // High priority queue.
|
||||
tq_append (to_chan, TQ_PRIO_0_HI, result);
|
||||
digi_count[from_chan][to_chan]++;
|
||||
}
|
||||
}
|
||||
|
@ -231,11 +198,10 @@ void digipeater (int from_chan, packet_t pp)
|
|||
save_audio_config_p->achan[to_chan].mycall,
|
||||
&save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan],
|
||||
to_chan, save_digi_config_p->preempt[from_chan][to_chan],
|
||||
save_digi_config_p->atgp[from_chan][to_chan],
|
||||
save_digi_config_p->filter_str[from_chan][to_chan]);
|
||||
if (result != NULL) {
|
||||
dedupe_remember (pp, to_chan);
|
||||
tq_append (to_chan, TQ_PRIO_1_LO, result); // Low priority queue.
|
||||
tq_append (to_chan, TQ_PRIO_1_LO, result);
|
||||
digi_count[from_chan][to_chan]++;
|
||||
}
|
||||
}
|
||||
|
@ -274,9 +240,6 @@ void digipeater (int from_chan, packet_t pp)
|
|||
*
|
||||
* preempt - Option for "preemptive" digipeating.
|
||||
*
|
||||
* atgp - No tracing if this matches alias prefix.
|
||||
* Hack added for special needs of ATGP.
|
||||
*
|
||||
* filter_str - Filter expression string or NULL.
|
||||
*
|
||||
* Returns: Packet object for transmission or NULL.
|
||||
|
@ -293,9 +256,32 @@ void digipeater (int from_chan, packet_t pp)
|
|||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#define OBSOLETE14 1
|
||||
|
||||
|
||||
#ifndef OBSOLETE14
|
||||
static char *dest_ssid_path[16] = {
|
||||
"", /* Use VIA path */
|
||||
"WIDE1-1",
|
||||
"WIDE2-2",
|
||||
"WIDE3-3",
|
||||
"WIDE4-4",
|
||||
"WIDE5-5",
|
||||
"WIDE6-6",
|
||||
"WIDE7-7",
|
||||
"WIDE1-1", /* North */
|
||||
"WIDE1-1", /* South */
|
||||
"WIDE1-1", /* East */
|
||||
"WIDE1-1", /* West */
|
||||
"WIDE2-2", /* North */
|
||||
"WIDE2-2", /* South */
|
||||
"WIDE2-2", /* East */
|
||||
"WIDE2-2" }; /* West */
|
||||
#endif
|
||||
|
||||
|
||||
static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, char *mycall_xmit,
|
||||
regex_t *alias, regex_t *wide, int to_chan, enum preempt_e preempt, char *atgp, char *filter_str)
|
||||
regex_t *alias, regex_t *wide, int to_chan, enum preempt_e preempt, char *filter_str)
|
||||
{
|
||||
char source[AX25_MAX_ADDR_LEN];
|
||||
int ssid;
|
||||
|
@ -333,6 +319,15 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
* Otherwise we don't want to modify the input because this could be called multiple times.
|
||||
*/
|
||||
|
||||
#ifndef OBSOLETE14 // Took it out in 1.4
|
||||
|
||||
if (ax25_get_num_repeaters(pp) == 0 && (ssid = ax25_get_ssid(pp, AX25_DESTINATION)) > 0) {
|
||||
ax25_set_addr(pp, AX25_REPEATER_1, dest_ssid_path[ssid]);
|
||||
ax25_set_ssid(pp, AX25_DESTINATION, 0);
|
||||
/* Continue with general case, below. */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Find the first repeater station which doesn't have "has been repeated" set.
|
||||
|
@ -441,10 +436,6 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
/*
|
||||
* If preemptive digipeating is enabled, try matching my call
|
||||
* and aliases against all remaining unused digipeaters.
|
||||
*
|
||||
* Bob says: "GENERIC XXXXn-N DIGIPEATING should not do preemptive digipeating."
|
||||
*
|
||||
* But consider this case: https://github.com/wb2osz/direwolf/issues/488
|
||||
*/
|
||||
|
||||
if (preempt != PREEMPT_OFF) {
|
||||
|
@ -470,22 +461,13 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
|
||||
switch (preempt) {
|
||||
case PREEMPT_DROP: /* remove all prior */
|
||||
// TODO: deprecate this option. Result is misleading.
|
||||
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("The digipeat DROP option will be removed in a future release. Use PREEMPT for preemptive digipeating.\n");
|
||||
|
||||
while (r2 > AX25_REPEATER_1) {
|
||||
ax25_remove_addr (result, r2-1);
|
||||
r2--;
|
||||
}
|
||||
break;
|
||||
|
||||
case PREEMPT_MARK: // TODO: deprecate this option. Result is misleading.
|
||||
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("The digipeat MARK option will be removed in a future release. Use PREEMPT for preemptive digipeating.\n");
|
||||
|
||||
case PREEMPT_MARK:
|
||||
r2--;
|
||||
while (r2 >= AX25_REPEATER_1 && ax25_get_h(result,r2) == 0) {
|
||||
ax25_set_h (result, r2);
|
||||
|
@ -493,12 +475,7 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
}
|
||||
break;
|
||||
|
||||
case PREEMPT_TRACE: /* My enhancement - remove prior unused digis. */
|
||||
/* this provides an accurate path of where packet traveled. */
|
||||
|
||||
// Uh oh. It looks like sample config files went out
|
||||
// with this option. Should it be renamed as
|
||||
// PREEMPT which is more descriptive?
|
||||
case PREEMPT_TRACE: /* remove prior unused */
|
||||
default:
|
||||
while (r2 > AX25_REPEATER_1 && ax25_get_h(result,r2-1) == 0) {
|
||||
ax25_remove_addr (result, r2-1);
|
||||
|
@ -529,40 +506,6 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
err = regexec(wide,repeater,0,NULL,0);
|
||||
if (err == 0) {
|
||||
|
||||
// Special hack added for ATGP to behave like some combination of options in some old TNC
|
||||
// so the via path does not continue to grow and exceed the 8 available positions.
|
||||
// The strange thing about this is that the used up digipeater is left there but
|
||||
// removed by the next digipeater.
|
||||
|
||||
if (strlen(atgp) > 0 && strncasecmp(repeater, atgp, strlen(atgp)) == 0) {
|
||||
|
||||
if (ssid >= 1 && ssid <= 7) {
|
||||
packet_t result;
|
||||
|
||||
result = ax25_dup (pp);
|
||||
assert (result != NULL);
|
||||
|
||||
// First, remove any already used digipeaters.
|
||||
|
||||
while (ax25_get_num_addr(result) >= 3 && ax25_get_h(result,AX25_REPEATER_1) == 1) {
|
||||
ax25_remove_addr (result, AX25_REPEATER_1);
|
||||
r--;
|
||||
}
|
||||
|
||||
ssid = ssid - 1;
|
||||
ax25_set_ssid(result, r, ssid); // could be zero.
|
||||
if (ssid == 0) {
|
||||
ax25_set_h (result, r);
|
||||
}
|
||||
|
||||
// Insert own call at beginning and mark it used.
|
||||
|
||||
ax25_insert_addr (result, AX25_REPEATER_1, mycall_xmit);
|
||||
ax25_set_h (result, AX25_REPEATER_1);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If ssid == 1, we simply replace the repeater with my call and
|
||||
* mark it as being used.
|
||||
|
@ -661,7 +604,7 @@ void digi_regen (int from_chan, packet_t pp)
|
|||
*
|
||||
* Name: main
|
||||
*
|
||||
* Purpose: Standalone test case for this functionality.
|
||||
* Purpose: Standalone test case for this funtionality.
|
||||
*
|
||||
* Usage: make -f Makefile.<platform> dtest
|
||||
* ./dtest
|
||||
|
@ -670,7 +613,7 @@ void digi_regen (int from_chan, packet_t pp)
|
|||
|
||||
#if DIGITEST
|
||||
|
||||
static char mycall[12];
|
||||
static char mycall[] = "WB2OSZ-9";
|
||||
|
||||
static regex_t alias_re;
|
||||
|
||||
|
@ -680,7 +623,6 @@ static int failed;
|
|||
|
||||
static enum preempt_e preempt = PREEMPT_OFF;
|
||||
|
||||
static char config_atgp[AX25_MAX_ADDR_LEN] = "HOP";
|
||||
|
||||
|
||||
static void test (char *in, char *out)
|
||||
|
@ -694,7 +636,6 @@ static void test (char *in, char *out)
|
|||
int frame_len;
|
||||
alevel_t alevel;
|
||||
|
||||
|
||||
dw_printf ("\n");
|
||||
|
||||
/*
|
||||
|
@ -744,9 +685,9 @@ static void test (char *in, char *out)
|
|||
text_color_set(DW_COLOR_REC);
|
||||
dw_printf ("Rec\t%s\n", rec);
|
||||
|
||||
//TODO: Add filtering to test.
|
||||
// V
|
||||
result = digipeat_match (0, pp, mycall, mycall, &alias_re, &wide_re, 0, preempt, config_atgp, NULL);
|
||||
//TODO: Add filtering to test.
|
||||
// V
|
||||
result = digipeat_match (0, pp, mycall, mycall, &alias_re, &wide_re, 0, preempt, NULL);
|
||||
|
||||
if (result != NULL) {
|
||||
|
||||
|
@ -781,7 +722,6 @@ int main (int argc, char *argv[])
|
|||
int e;
|
||||
failed = 0;
|
||||
char message[256];
|
||||
strlcpy(mycall, "WB2OSZ-9", sizeof(mycall));
|
||||
|
||||
dedupe_init (4);
|
||||
|
||||
|
@ -796,7 +736,7 @@ int main (int argc, char *argv[])
|
|||
exit (1);
|
||||
}
|
||||
|
||||
e = regcomp (&wide_re, "^WIDE[1-7]-[1-7]$|^TRACE[1-7]-[1-7]$|^MA[1-7]-[1-7]$|^HOP[1-7]-[1-7]$", REG_EXTENDED|REG_NOSUB);
|
||||
e = regcomp (&wide_re, "^WIDE[1-7]-[1-7]$|^TRACE[1-7]-[1-7]$|^MA[1-7]-[1-7]$", REG_EXTENDED|REG_NOSUB);
|
||||
if (e != 0) {
|
||||
regerror (e, &wide_re, message, sizeof(message));
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -886,8 +826,11 @@ int main (int argc, char *argv[])
|
|||
*/
|
||||
|
||||
test ( "W1ABC>TEST-3:",
|
||||
#ifndef OBSOLETE14
|
||||
"W1ABC>TEST,WB2OSZ-9*,WIDE3-2:");
|
||||
#else
|
||||
"");
|
||||
|
||||
#endif
|
||||
test ( "W1DEF>TEST-3,WIDE2-2:",
|
||||
"W1DEF>TEST-3,WB2OSZ-9*,WIDE2-1:");
|
||||
|
||||
|
@ -897,17 +840,17 @@ int main (int argc, char *argv[])
|
|||
* The 4th case might be controversial.
|
||||
*/
|
||||
|
||||
test ( "W1XYZ>TESTD,R1*,WIDE3-2:info1",
|
||||
"W1XYZ>TESTD,R1,WB2OSZ-9*,WIDE3-1:info1");
|
||||
test ( "W1XYZ>TEST,R1*,WIDE3-2:info1",
|
||||
"W1XYZ>TEST,R1,WB2OSZ-9*,WIDE3-1:info1");
|
||||
|
||||
test ( "W1XYZ>TESTD,R2*,WIDE3-2:info1",
|
||||
test ( "W1XYZ>TEST,R2*,WIDE3-2:info1",
|
||||
"");
|
||||
|
||||
test ( "W1XYZ>TESTD,R3*,WIDE3-2:info1",
|
||||
test ( "W1XYZ>TEST,R3*,WIDE3-2:info1",
|
||||
"");
|
||||
|
||||
test ( "W1XYZ>TESTD,R1*,WB2OSZ-9:has explicit routing",
|
||||
"W1XYZ>TESTD,R1,WB2OSZ-9*:has explicit routing");
|
||||
test ( "W1XYZ>TEST,R1*,WB2OSZ-9:has explicit routing",
|
||||
"W1XYZ>TEST,R1,WB2OSZ-9*:has explicit routing");
|
||||
|
||||
|
||||
/*
|
||||
|
@ -984,54 +927,6 @@ int main (int argc, char *argv[])
|
|||
test ( "WB2OSZ-15>TEST14,WIDE1-1,WIDE1-1:stuff",
|
||||
"WB2OSZ-15>TEST14,WB2OSZ-9*,WIDE1-1:stuff");
|
||||
|
||||
// New in 1.7 - ATGP Hack
|
||||
|
||||
preempt = PREEMPT_OFF; // Shouldn't make a difference here.
|
||||
|
||||
test ( "W1ABC>TEST51,HOP7-7,HOP7-7:stuff1",
|
||||
"W1ABC>TEST51,WB2OSZ-9*,HOP7-6,HOP7-7:stuff1");
|
||||
|
||||
test ( "W1ABC>TEST52,ABCD*,HOP7-1,HOP7-7:stuff2",
|
||||
"W1ABC>TEST52,WB2OSZ-9,HOP7*,HOP7-7:stuff2"); // Used up address remains.
|
||||
|
||||
test ( "W1ABC>TEST53,HOP7*,HOP7-7:stuff3",
|
||||
"W1ABC>TEST53,WB2OSZ-9*,HOP7-6:stuff3"); // But it gets removed here.
|
||||
|
||||
test ( "W1ABC>TEST54,HOP7*,HOP7-1:stuff4",
|
||||
"W1ABC>TEST54,WB2OSZ-9,HOP7*:stuff4"); // Remains again here.
|
||||
|
||||
test ( "W1ABC>TEST55,HOP7,HOP7*:stuff5",
|
||||
"");
|
||||
|
||||
// Examples given for desired result.
|
||||
|
||||
strlcpy (mycall, "CLNGMN-1", sizeof(mycall));
|
||||
test ( "W1ABC>TEST60,HOP7-7,HOP7-7:",
|
||||
"W1ABC>TEST60,CLNGMN-1*,HOP7-6,HOP7-7:");
|
||||
test ( "W1ABC>TEST61,ROAN-3*,HOP7-6,HOP7-7:",
|
||||
"W1ABC>TEST61,CLNGMN-1*,HOP7-5,HOP7-7:");
|
||||
|
||||
strlcpy (mycall, "GDHILL-8", sizeof(mycall));
|
||||
test ( "W1ABC>TEST62,MDMTNS-7*,HOP7-1,HOP7-7:",
|
||||
"W1ABC>TEST62,GDHILL-8,HOP7*,HOP7-7:");
|
||||
test ( "W1ABC>TEST63,CAMLBK-9*,HOP7-1,HOP7-7:",
|
||||
"W1ABC>TEST63,GDHILL-8,HOP7*,HOP7-7:");
|
||||
|
||||
strlcpy (mycall, "MDMTNS-7", sizeof(mycall));
|
||||
test ( "W1ABC>TEST64,GDHILL-8*,HOP7*,HOP7-7:",
|
||||
"W1ABC>TEST64,MDMTNS-7*,HOP7-6:");
|
||||
|
||||
strlcpy (mycall, "CAMLBK-9", sizeof(mycall));
|
||||
test ( "W1ABC>TEST65,GDHILL-8,HOP7*,HOP7-7:",
|
||||
"W1ABC>TEST65,CAMLBK-9*,HOP7-6:");
|
||||
|
||||
strlcpy (mycall, "KATHDN-15", sizeof(mycall));
|
||||
test ( "W1ABC>TEST66,MTWASH-14*,HOP7-1:",
|
||||
"W1ABC>TEST66,KATHDN-15,HOP7*:");
|
||||
|
||||
strlcpy (mycall, "SPRNGR-1", sizeof(mycall));
|
||||
test ( "W1ABC>TEST67,CLNGMN-1*,HOP7-1:",
|
||||
"W1ABC>TEST67,SPRNGR-1,HOP7*:");
|
||||
|
||||
|
||||
if (failed == 0) {
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
|
||||
#ifndef DIGIPEATER_H
|
||||
#define DIGIPEATER_H 1
|
||||
|
||||
|
@ -37,11 +38,6 @@ struct digi_config_s {
|
|||
|
||||
enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS];
|
||||
|
||||
// ATGP is an ugly hack for the specific need of ATGP which needs more that 8 digipeaters.
|
||||
// DO NOT put this in the User Guide. On a need to know basis.
|
||||
|
||||
char atgp[MAX_CHANS][MAX_CHANS][AX25_MAX_ADDR_LEN];
|
||||
|
||||
char *filter_str[MAX_CHANS+1][MAX_CHANS+1];
|
||||
// NULL or optional Packet Filter strings such as "t/m".
|
||||
// Notice the size of arrays is one larger than normal.
|
File diff suppressed because it is too large
Load Diff
|
@ -4,11 +4,6 @@
|
|||
// TODO: include this file first before anything else in each .c file.
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG // Because it would disable assert().
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DIREWOLF_H
|
||||
#define DIREWOLF_H 1
|
||||
|
||||
|
@ -32,13 +27,15 @@
|
|||
#define _WIN32_WINNT 0x0501 /* Minimum OS version is XP. */
|
||||
#define WINVER 0x0501 /* Minimum OS version is XP. */
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Maximum number of audio devices.
|
||||
* Previously, we could handle only a single audio device.
|
||||
* This meant we could have only two radio channels.
|
||||
* In version 1.2, we relax this restriction and allow more audio devices.
|
||||
* Three is probably adequate for standard version.
|
||||
* Larger reasonable numbers should also be fine.
|
||||
*
|
||||
|
@ -62,15 +59,7 @@
|
|||
* and make sure they handle undefined channels correctly.
|
||||
*/
|
||||
|
||||
#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2)
|
||||
|
||||
#define MAX_CHANS MAX_RADIO_CHANS // TODO: Replace all former with latter to avoid confusion with following.
|
||||
|
||||
#define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected
|
||||
// to something other than radio modems.
|
||||
// Total maximum channels is based on the 4 bit KISS field.
|
||||
// Someone with very unusual requirements could increase this and
|
||||
// use only the AGW network protocol.
|
||||
#define MAX_CHANS ((MAX_ADEVS) * 2)
|
||||
|
||||
/*
|
||||
* Maximum number of rigs.
|
||||
|
@ -102,7 +91,7 @@
|
|||
* Each one of these can have multiple slicers, at
|
||||
* different levels, to compensate for different
|
||||
* amplitudes of the AFSK tones.
|
||||
* Initially used same number as subchannels but
|
||||
* Intially used same number as subchannels but
|
||||
* we could probably trim this down a little
|
||||
* without impacting performance.
|
||||
*/
|
||||
|
@ -118,17 +107,15 @@
|
|||
#define SLEEP_MS(n) usleep((n)*1000)
|
||||
#endif
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
#if __WIN32__
|
||||
#define PTW32_STATIC_LIB
|
||||
//#include "pthreads/pthread.h"
|
||||
|
||||
// This enables definitions of localtime_r and gmtime_r in system time.h.
|
||||
//#define _POSIX_THREAD_SAFE_FUNCTIONS 1
|
||||
#define _POSIX_C_SOURCE 1
|
||||
|
||||
#define gmtime_r( _clock, _result ) \
|
||||
( *(_result) = *gmtime( (_clock) ), \
|
||||
(_result) )
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -181,7 +168,6 @@
|
|||
#define DW_METERS_TO_FEET(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 3.2808399)
|
||||
#define DW_FEET_TO_METERS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.3048)
|
||||
#define DW_KM_TO_MILES(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.621371192)
|
||||
#define DW_MILES_TO_KM(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 1.609344)
|
||||
|
||||
#define DW_KNOTS_TO_MPH(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 1.15077945)
|
||||
#define DW_KNOTS_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.51444444444)
|
||||
|
@ -267,7 +253,7 @@ typedef pthread_mutex_t dw_mutex_t;
|
|||
// but always using send/recv makes more sense.
|
||||
// Need option to prevent a SIGPIPE signal on Linux. (added for 1.5 beta 2)
|
||||
|
||||
#if __WIN32__ || __APPLE__
|
||||
#if __WIN32__
|
||||
#define SOCK_SEND(s,data,size) send(s,data,size,0)
|
||||
#else
|
||||
#define SOCK_SEND(s,data,size) send(s,data,size, MSG_NOSIGNAL)
|
||||
|
@ -278,78 +264,49 @@ typedef pthread_mutex_t dw_mutex_t;
|
|||
/* Platform differences for string functions. */
|
||||
|
||||
|
||||
// Windows is missing a few which are available on Unix/Linux platforms.
|
||||
// We provide our own copies when building on Windows.
|
||||
|
||||
#if __WIN32__
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||
#endif
|
||||
|
||||
// Don't recall why I added this for everyone rather than only for Windows.
|
||||
// Potential problem if some C library declares it a little differently.
|
||||
// Don't recall why for everyone.
|
||||
char *strcasestr(const char *S, const char *FIND);
|
||||
|
||||
|
||||
// cmake tries to determine whether strlcpy and strlcat are provided by the C runtime library.
|
||||
//
|
||||
// ../CMakeLists.txt:check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
|
||||
//
|
||||
// It sets HAVE_STRLCPY and HAVE_STRLCAT if the corresponding functions are declared.
|
||||
// Unfortunately this does not work right for glibc 2.38 which declares the functions
|
||||
// like this:
|
||||
//
|
||||
// extern __typeof (strlcpy) __strlcpy;
|
||||
// libc_hidden_proto (__strlcpy)
|
||||
// extern __typeof (strlcat) __strlcat;
|
||||
// libc_hidden_proto (__strlcat)
|
||||
//
|
||||
// Rather than the normal way found in earlier versions:
|
||||
//
|
||||
// extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
|
||||
//
|
||||
// Perhaps a later version of cmake will recognize this form but the version I'm
|
||||
// using does not.
|
||||
// So, our work around is to assume these functions are available for glibc >= 2.38.
|
||||
//
|
||||
// In theory, cmake should be able to find the version of the C runtime library,
|
||||
// but I could not get it to work. So we have the test here. We will still build
|
||||
// own library with the strl... functions but this does not cause a problem
|
||||
// because they have special debug names which will not cause a conflict.
|
||||
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 38))
|
||||
// These functions first added in 2.38.
|
||||
//#warning "DEBUG - glibc >= 2.38"
|
||||
#define HAVE_STRLCPY 1
|
||||
// strlcpy and strlcat should be in string.h and the C library.
|
||||
|
||||
#else // Use our own copy
|
||||
|
||||
|
||||
// These prevent /usr/include/gps.h from providing its own definition.
|
||||
#define HAVE_STRLCAT 1
|
||||
#else
|
||||
//#warning "DEBUG - glibc < 2.38"
|
||||
#endif
|
||||
#endif
|
||||
#define HAVE_STRLCPY 1
|
||||
|
||||
#define DEBUG_STRL 1 // Extra Debug version when using our own strlcpy, strlcat.
|
||||
// Should be ignored if not supplying our own.
|
||||
|
||||
#ifndef HAVE_STRLCPY // Need to supply our own.
|
||||
#define DEBUG_STRL 1
|
||||
|
||||
#if DEBUG_STRL
|
||||
|
||||
#define strlcpy(dst,src,siz) strlcpy_debug(dst,src,siz,__FILE__,__func__,__LINE__)
|
||||
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line);
|
||||
#else
|
||||
#define strlcpy(dst,src,siz) strlcpy_debug(dst,src,siz)
|
||||
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz);
|
||||
#endif /* DEBUG_STRL */
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT // Need to supply our own.
|
||||
#if DEBUG_STRL
|
||||
#define strlcat(dst,src,siz) strlcat_debug(dst,src,siz,__FILE__,__func__,__LINE__)
|
||||
|
||||
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line);
|
||||
size_t strlcat_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line);
|
||||
|
||||
#else
|
||||
|
||||
#define strlcpy(dst,src,siz) strlcpy_debug(dst,src,siz)
|
||||
#define strlcat(dst,src,siz) strlcat_debug(dst,src,siz)
|
||||
|
||||
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz);
|
||||
size_t strlcat_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz);
|
||||
|
||||
#endif /* DEBUG_STRL */
|
||||
#endif
|
||||
|
||||
#endif /* BSD or Apple */
|
||||
|
||||
|
||||
#endif /* ifndef DIREWOLF_H */
|
|
@ -0,0 +1,103 @@
|
|||
#%global git_commit b2548ec58f44f4b651626757a166b9f4f18d8000
|
||||
%global git_commit 37179479caf0bf36adf8c9bc0fde641884edaeac
|
||||
%global git_date 20171216
|
||||
|
||||
%global git_short_commit %(echo %{git_commit} | cut -c -8)
|
||||
%global git_suffix %{git_date}git%{git_short_commit}
|
||||
|
||||
Name: direwolf
|
||||
Version: 1.5Beta
|
||||
Release: 1.%{git_suffix}%{?dist}
|
||||
Summary: Soundcard based AX.25 TNC
|
||||
|
||||
Group: Applications/Communications
|
||||
License: GPLv2
|
||||
URL: https://github.com/wb2osz/direwolf
|
||||
#Source0: https://github.com/wb2osz/direwolf/archive/%{name}-%{version}.tar.gz
|
||||
Source: %{name}-%{version}-%{git_suffix}.tgz
|
||||
Packager: David Ranch (KI6ZHD) <dranch@trinnet.net>
|
||||
Distribution: RedHat Linux
|
||||
|
||||
Patch0: direwolf-1.5-makefile.patch
|
||||
|
||||
BuildRequires: automake
|
||||
BuildRequires: alsa-lib-devel
|
||||
|
||||
#If the gpsd and gpsd-devel packages are installed, Direwolf will add gps support
|
||||
|
||||
|
||||
|
||||
%description
|
||||
Dire Wolf is a software "soundcard" modem/TNC and APRS encoder/decoder. It can
|
||||
be used stand-alone to receive APRS messages, as a digipeater, APRStt gateway,
|
||||
or Internet Gateway (IGate). It can also be used as a virtual TNC for other
|
||||
applications such as APRSIS32, UI-View32, Xastir, APRS-TW, YAAC, UISS,
|
||||
Linux AX25, SARTrack, RMS Express, and many others.
|
||||
|
||||
%prep
|
||||
|
||||
%setup -q -n %{name}-%{version}
|
||||
%patch0 -p0
|
||||
|
||||
%build
|
||||
|
||||
make -f Makefile.linux
|
||||
#make -f Makefile.linux tocalls-symbols
|
||||
make %{?_smp_mflags}
|
||||
|
||||
|
||||
%install
|
||||
make install INSTALLDIR=$RPM_BUILD_ROOT/usr
|
||||
make install-conf INSTALLDIR=$RPM_BUILD_ROOT/usr
|
||||
|
||||
# Install icon
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/pixmaps/direwolf/
|
||||
cp dw-icon.png ${RPM_BUILD_ROOT}%{_datadir}/pixmaps/direwolf/
|
||||
mv symbols-new.txt ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
|
||||
mv symbolsX.txt ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
|
||||
mv tocalls.txt ${RPM_BUILD_ROOT}%{_docdir}/%{name}/
|
||||
desktop-file-install \
|
||||
--dir=${RPM_BUILD_ROOT}%{_datadir}/applications direwolf.desktop
|
||||
#temp bug
|
||||
#non echo "fixing $RPM_BUILD_ROOT/%{_bindir}/bin"
|
||||
#non rm -f $RPM_BUILD_ROOT/usr/bin
|
||||
|
||||
|
||||
%files
|
||||
%{_sysconfdir}/ax25/direwolf.conf
|
||||
%{_sysconfdir}/ax25/sdr.conf
|
||||
%{_sysconfdir}/ax25/telemetry-toolkit/telem-balloon.conf
|
||||
%{_sysconfdir}/ax25/telemetry-toolkit/telem-m0xer-3.txt
|
||||
%{_sysconfdir}/ax25/telemetry-toolkit/telem-volts.conf
|
||||
%{_sysconfdir}/udev/rules.d/99-direwolf-cmedia.rules
|
||||
%{_bindir}/*
|
||||
%{_datadir}/pixmaps/direwolf/dw-icon.png
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_datadir}/direwolf/*
|
||||
%{_docdir}/*
|
||||
%{_mandir}/man1/*
|
||||
|
||||
|
||||
|
||||
%changelog
|
||||
* Sat Dec 16 2017 David Ranch <dranch@trinnet.net> - 1.5-1
|
||||
- New 1.5-Beta version from Git
|
||||
* Sun Apr 2 2017 David Ranch <dranch@trinnet.net> - 1.4-1
|
||||
- New 1.4-Beta1 version from Git
|
||||
* Sun Mar 5 2017 David Ranch <dranch@trinnet.net> - 1.4-1
|
||||
- New 1.4-H Alpha version from Git version
|
||||
* Fri Aug 26 2016 David Ranch <dranch@trinnet.net> - 1.4-1
|
||||
- New version
|
||||
* Fri May 06 2016 David Ranch <dranch@trinnet.net> - 1.3-1
|
||||
- New version
|
||||
* Sat Sep 12 2015 David Ranch <dranch@trinnet.net> - 1.3F-1
|
||||
- New version with new features
|
||||
* Sun May 10 2015 David Ranch <dranch@trinnet.net> - 1.2E-1
|
||||
- New version that supports a PASSALL function
|
||||
- Updated the Makefile.linux patch
|
||||
* Sat Mar 21 2015 David Ranch <dranch@trinnet.net> - 1.2C-1
|
||||
- changed to support different make installation variable
|
||||
* Sat Feb 14 2015 David Ranch <dranch@trinnet.net> - 1.2b-1
|
||||
- new spec file
|
||||
* Sat Dec 20 2014 David Ranch <dranch@trinnet.net> - 1.1b1-1
|
||||
- new spec file
|
|
@ -0,0 +1,536 @@
|
|||
C#############################################################
|
||||
C# #
|
||||
C# Configuration file for Dire Wolf #
|
||||
C# #
|
||||
L# Linux version #
|
||||
W# Windows version #
|
||||
C# #
|
||||
C#############################################################
|
||||
R
|
||||
R
|
||||
R The sample config file was getting pretty messy
|
||||
R with the Windows and Linux differences.
|
||||
R It would be a maintenance burden to keep most of
|
||||
R two different versions in sync.
|
||||
R This common source is now used to generate the
|
||||
R two different variations while having only a single
|
||||
R copy of the common parts.
|
||||
R
|
||||
R The first column contains one of the following:
|
||||
R
|
||||
R R remark which is discarded.
|
||||
R C common to both versions.
|
||||
R W Windows version only.
|
||||
R L Linux version only.
|
||||
R
|
||||
C#
|
||||
C# Consult the User Guide for more details on configuration options.
|
||||
C#
|
||||
C#
|
||||
C# These are the most likely settings you might change:
|
||||
C#
|
||||
C# (1) MYCALL - call sign and SSID for your station.
|
||||
C#
|
||||
C# Look for lines starting with MYCALL and
|
||||
C# change NOCALL to your own.
|
||||
C#
|
||||
C# (2) PBEACON - enable position beaconing.
|
||||
C#
|
||||
C# Look for lines starting with PBEACON and
|
||||
C# modify for your call, location, etc.
|
||||
C#
|
||||
C# (3) DIGIPEATER - configure digipeating rules.
|
||||
C#
|
||||
C# Look for lines starting with DIGIPEATER.
|
||||
C# Most people will probably use the given example.
|
||||
C# Just remove the "#" from the start of the line
|
||||
C# to enable it.
|
||||
C#
|
||||
C# (4) IGSERVER, IGLOGIN - IGate server and login
|
||||
C#
|
||||
C# Configure an IGate client to relay messages between
|
||||
C# radio and internet servers.
|
||||
C#
|
||||
C#
|
||||
C# The default location is "direwolf.conf" in the current working directory.
|
||||
L# On Linux, the user's home directory will also be searched.
|
||||
C# An alternate configuration file location can be specified with the "-c" command line option.
|
||||
C#
|
||||
C# As you probably guessed by now, # indicates a comment line.
|
||||
C#
|
||||
C# Remove the # at the beginning of a line if you want to use a sample
|
||||
C# configuration that is currently commented out.
|
||||
C#
|
||||
C# Commands are a keyword followed by parameters.
|
||||
C#
|
||||
C# Command key words are case insensitive. i.e. upper and lower case are equivalent.
|
||||
C#
|
||||
C# Command parameters are generally case sensitive. i.e. upper and lower case are different.
|
||||
C#
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# FIRST AUDIO DEVICE PROPERTIES #
|
||||
C# (Channel 0 + 1 if in stereo) #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#
|
||||
C# Many people will simply use the default sound device.
|
||||
C# Some might want to use an alternative device by chosing it here.
|
||||
C#
|
||||
W# When the Windows version starts up, it displays something like
|
||||
W# this with the available sound devices and capabilities:
|
||||
W#
|
||||
W# Available audio input devices for receive (*=selected):
|
||||
W# * 0: Microphone (C-Media USB Headpho (channel 2)
|
||||
W# 1: Microphone (Bluetooth SCO Audio
|
||||
W# 2: Microphone (Bluetooth AV Audio)
|
||||
W# * 3: Microphone (Realtek High Defini (channels 0 & 1)
|
||||
W# Available audio output devices for transmit (*=selected):
|
||||
W# * 0: Speakers (C-Media USB Headphone (channel 2)
|
||||
W# 1: Speakers (Bluetooth SCO Audio)
|
||||
W# 2: Realtek Digital Output(Optical)
|
||||
W# 3: Speakers (Bluetooth AV Audio)
|
||||
W# * 4: Speakers (Realtek High Definiti (channels 0 & 1)
|
||||
W# 5: Realtek Digital Output (Realtek
|
||||
W#
|
||||
W# Example: To use the microphone and speaker connections on the
|
||||
W# system board, either of these forms can be used:
|
||||
W
|
||||
W#ADEVICE High
|
||||
W#ADEVICE 3 4
|
||||
W
|
||||
W
|
||||
W# Example: To use the USB Audio, use a command like this with
|
||||
W# the input and output device numbers. (Remove the # comment character.)
|
||||
W#ADEVICE USB
|
||||
W
|
||||
W# The position in the list can change when devices (e.g. USB) are added and removed.
|
||||
W# You can also specify devices by using part of the name.
|
||||
W# Here is an example of specifying the USB Audio device.
|
||||
W# This is case-sensitive. Upper and lower case are not treated the same.
|
||||
W
|
||||
W#ADEVICE USB
|
||||
W
|
||||
W
|
||||
L# Linux ALSA is complicated. See User Guide for discussion.
|
||||
L# To use something other than the default, generally use plughw
|
||||
L# and a card number reported by "arecord -l" command. Example:
|
||||
L
|
||||
L# ADEVICE plughw:1,0
|
||||
L
|
||||
L# Starting with version 1.0, you can also use "-" or "stdin" to
|
||||
L# pipe stdout from some other application such as a software defined
|
||||
L# radio. You can also specify "UDP:" and an optional port for input.
|
||||
L# Something different must be specified for output.
|
||||
L
|
||||
W# ADEVICE - 0
|
||||
W# ADEVICE UDP:7355 0
|
||||
L# ADEVICE - plughw:1,0
|
||||
L# ADEVICE UDP:7355 default
|
||||
L
|
||||
L
|
||||
C
|
||||
C#
|
||||
C# Number of audio channels for this souncard: 1 or 2.
|
||||
C#
|
||||
C
|
||||
CACHANNELS 1
|
||||
C#ACHANNELS 2
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# SECOND AUDIO DEVICE PROPERTIES #
|
||||
C# (Channel 2 + 3 if in stereo) #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#ADEVICE1 ...
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# THIRD AUDIO DEVICE PROPERTIES #
|
||||
C# (Channel 4 + 5 if in stereo) #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#ADEVICE2 ...
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# CHANNEL 0 PROPERTIES #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
CCHANNEL 0
|
||||
C
|
||||
C#
|
||||
C# The following MYCALL, MODEM, PTT, etc. configuration items
|
||||
C# apply to the most recent CHANNEL.
|
||||
C#
|
||||
C
|
||||
C#
|
||||
C# Station identifier for this channel.
|
||||
C# Multiple channels can have the same or different names.
|
||||
C#
|
||||
C# It can be up to 6 letters and digits with an optional ssid.
|
||||
C# The APRS specification requires that it be upper case.
|
||||
C#
|
||||
C# Example (don't use this unless you are me): MYCALL WB2OSZ-5
|
||||
C#
|
||||
C
|
||||
CMYCALL N0CALL
|
||||
C
|
||||
C#
|
||||
C# Pick a suitable modem speed based on your situation.
|
||||
C# 1200 Most common for VHF/UHF. Default if not specified.
|
||||
C# 300 Low speed for HF SSB.
|
||||
C# 9600 High speed - Can't use Microphone and Speaker connections.
|
||||
C#
|
||||
C# In the simplest form, just specify the speed.
|
||||
C#
|
||||
C
|
||||
CMODEM 1200
|
||||
C#MODEM 300
|
||||
C#MODEM 9600
|
||||
C
|
||||
C#
|
||||
C# These are the defaults should be fine for most cases. In special situations,
|
||||
C# you might want to specify different AFSK tones or the baseband mode which does
|
||||
C# not use AFSK.
|
||||
C#
|
||||
C#MODEM 1200 1200:2200
|
||||
C#MODEM 300 1600:1800
|
||||
C#MODEM 9600 0:0
|
||||
C#
|
||||
C#
|
||||
C# On HF SSB, you might want to use multiple demodulators on slightly different
|
||||
C# frequencies to compensate for stations off frequency. Here we have 7 different
|
||||
C# demodulators at 30 Hz intervals. This takes a lot of CPU power so you will
|
||||
C# probably need to reduce the audio sampling rate with the /n option.
|
||||
C
|
||||
C#MODEM 300 1600:1800 7@30 /4
|
||||
C
|
||||
C
|
||||
C#
|
||||
C# Uncomment line below to enable the DTMF decoder for this channel.
|
||||
C#
|
||||
C
|
||||
C#DTMF
|
||||
C
|
||||
C#
|
||||
C# If not using a VOX circuit, the transmitter Push to Talk (PTT)
|
||||
C# control is usually wired to a serial port with a suitable interface circuit.
|
||||
C# DON'T connect it directly!
|
||||
C#
|
||||
C# For the PTT command, specify the device and either RTS or DTR.
|
||||
C# RTS or DTR may be preceded by "-" to invert the signal.
|
||||
C# Both can be used for interfaces that want them driven with opposite polarity.
|
||||
C#
|
||||
L# COM1 can be used instead of /dev/ttyS0, COM2 for /dev/ttyS1, and so on.
|
||||
L#
|
||||
C
|
||||
C#PTT COM1 RTS
|
||||
C#PTT COM1 RTS -DTR
|
||||
L#PTT /dev/ttyUSB0 RTS
|
||||
C
|
||||
L#
|
||||
L# On Linux, you can also use general purpose I/O pins if
|
||||
L# your system is configured for user access to them.
|
||||
L# This would apply mostly to microprocessor boards, not a regular PC.
|
||||
L# See separate Raspberry Pi document for more details.
|
||||
L# The number may be preceded by "-" to invert the signal.
|
||||
L#
|
||||
L
|
||||
L#PTT GPIO 25
|
||||
L
|
||||
C# The Data Carrier Detect (DCD) signal can be sent to the same places
|
||||
C# as the PTT signal. This could be used to light up an LED like a normal TNC.
|
||||
C
|
||||
C#DCD COM1 -DTR
|
||||
L#DCD GPIO 24
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# CHANNEL 1 PROPERTIES #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#CHANNEL 1
|
||||
C
|
||||
C#
|
||||
C# Specify MYCALL, MODEM, PTT, etc. configuration items for
|
||||
C# CHANNEL 1. Repeat for any other channels.
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# TEXT TO SPEECH COMMAND FILE #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
W#SPEECH dwespeak.bat
|
||||
L#SPEECH dwespeak.sh
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# VIRTUAL TNC SERVER PROPERTIES #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#
|
||||
C# Dire Wolf acts as a virtual TNC and can communicate with
|
||||
C# client applications by different protocols:
|
||||
C#
|
||||
C# - the "AGW TCPIP Socket Interface" - default port 8000
|
||||
C# - KISS protocol over TCP socket - default port 8001
|
||||
W# - KISS TNC via serial port
|
||||
L# - KISS TNC via pseudo terminal (-p command line option)
|
||||
C#
|
||||
C
|
||||
CAGWPORT 8000
|
||||
CKISSPORT 8001
|
||||
C
|
||||
W#
|
||||
W# Some applications are designed to operate with only a physical
|
||||
W# TNC attached to a serial port. For these, we provide a virtual serial
|
||||
W# port that appears to be connected to a TNC.
|
||||
W#
|
||||
W# Take a look at the User Guide for instructions to set up
|
||||
W# two virtual serial ports named COM3 and COM4 connected by
|
||||
W# a null modem.
|
||||
W#
|
||||
W# Using the configuration described, Dire Wolf will connect to
|
||||
W# COM3 and the client application will use COM4.
|
||||
W#
|
||||
W# Uncomment following line to use this feature.
|
||||
W
|
||||
W#SERIALKISS COM3
|
||||
W
|
||||
W
|
||||
C#
|
||||
C# It is sometimes possible to recover frames with a bad FCS.
|
||||
C# This applies to all channels.
|
||||
C#
|
||||
C# 0 [NONE] - Don't try to repair.
|
||||
C# 1 [SINGLE] - Attempt to fix single bit error. (default)
|
||||
C# 2 [DOUBLE] - Also attempt to fix two adjacent bits.
|
||||
C# ... see User Guide for more values and in-depth discussion.
|
||||
C#
|
||||
C
|
||||
C#FIX_BITS 0
|
||||
C
|
||||
C#
|
||||
C#############################################################
|
||||
C# #
|
||||
C# BEACONING PROPERTIES #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C
|
||||
C#
|
||||
C# Beaconing is configured with these two commands:
|
||||
C#
|
||||
C# PBEACON - for a position report (usually yourself)
|
||||
C# OBEACON - for an object report (usually some other entity)
|
||||
C#
|
||||
C# Each has a series of keywords and values for options.
|
||||
C# See User Guide for details.
|
||||
C#
|
||||
C# Example:
|
||||
C#
|
||||
C# This results in a broadcast once every 10 minutes.
|
||||
C# Every half hour, it can travel via two digipeater hops.
|
||||
C# The others are kept local.
|
||||
C#
|
||||
C
|
||||
C#PBEACON delay=1 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1,WIDE2-1
|
||||
C#PBEACON delay=11 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||
C#PBEACON delay=21 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||
C
|
||||
C
|
||||
C# With UTM coordinates instead of latitude and longitude.
|
||||
C
|
||||
C#PBEACON delay=1 every=10 overlay=S symbol="digi" zone=19T easting=307477 northing=4720178
|
||||
C
|
||||
C
|
||||
C#
|
||||
C# When the destination field is set to "SPEECH" the information part is
|
||||
C# converted to speech rather than transmitted as a data frame.
|
||||
C#
|
||||
C
|
||||
C#CBEACON dest="SPEECH" info="Club meeting tonight at 7 pm."
|
||||
C
|
||||
C
|
||||
C#
|
||||
C# Modify for your particular situation before removing
|
||||
C# the # comment character from the beginning of appropriate lines above.
|
||||
C#
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# DIGIPEATER PROPERTIES #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#
|
||||
C# For most common situations, use something like this by removing
|
||||
C# the "#" from the beginning of the line below.
|
||||
C#
|
||||
C
|
||||
C#DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$ TRACE
|
||||
C
|
||||
C# See User Guide for more explanation of what this means and how
|
||||
C# it can be customized for your particular needs.
|
||||
C
|
||||
C# Filtering can be used to limit was is digipeated.
|
||||
C# For example, only weather weather reports, received on channel 0,
|
||||
C# will be retransmitted on channel 1.
|
||||
C#
|
||||
C
|
||||
C#FILTER 0 1 t/wn
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# INTERNET GATEWAY #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C# First you need to specify the name of a Tier 2 server.
|
||||
C# The current preferred way is to use one of these regional rotate addresses:
|
||||
C
|
||||
C# noam.aprs2.net - for North America
|
||||
C# soam.aprs2.net - for South America
|
||||
C# euro.aprs2.net - for Europe and Africa
|
||||
C# asia.aprs2.net - for Asia
|
||||
C# aunz.aprs2.net - for Oceania
|
||||
C
|
||||
C#IGSERVER noam.aprs2.net
|
||||
C
|
||||
C# You also need to specify your login name and passcode.
|
||||
C# Contact the author if you can't figure out how to generate the passcode.
|
||||
C
|
||||
C#IGLOGIN WB2OSZ-5 123456
|
||||
C
|
||||
C# That's all you need for a receive only IGate which relays
|
||||
C# messages from the local radio channel to the global servers.
|
||||
C
|
||||
C# Some might want to send an IGate client position directly to a server
|
||||
C# without sending it over the air and relying on someone else to
|
||||
C# forward it to an IGate server. This is done by using sendto=IG rather
|
||||
C# than a radio channel number. Overlay R for receive only, T for two way.
|
||||
C
|
||||
C#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=R lat=42^37.14N long=071^20.83W
|
||||
C#PBEACON sendto=IG delay=0:30 every=60:00 symbol="igate" overlay=T lat=42^37.14N long=071^20.83W
|
||||
C
|
||||
C
|
||||
C# To relay messages from the Internet to radio, you need to add
|
||||
C# one more options with the transmit channel number and a VIA path.
|
||||
C
|
||||
C#IGTXVIA 0 WIDE1-1
|
||||
C
|
||||
C# The APRS Internet Server (APRS-IS) has its own idea about what you
|
||||
C# should be transmitting. This includes "messages" addressed to stations
|
||||
C# recently heard in your area. For special situations, you can subscribe
|
||||
C# to
|
||||
C# decrease what you are already subscribed to. This is known as a server
|
||||
C# side filter. Read here: http://www.aprs-is.net/javaprsfilter.aspx
|
||||
C# Example, positions and objects within 50 km of my location:
|
||||
C
|
||||
C#IGFILTER m/50
|
||||
C
|
||||
C# Sometimes the server will send you more than you want. You can also apply
|
||||
C# local filtering to limit what will be transmitted on the RF side.
|
||||
C# For example, transmit only "messages" (which is the default) on channel 0
|
||||
C# and weather reports on channel 1.
|
||||
C
|
||||
C#FILTER IG 0 i/30
|
||||
C#FILTER IG 1 t/wn
|
||||
C
|
||||
C# Finally, we don't want to flood the radio channel.
|
||||
C# The IGate function will limit the number of packets transmitted
|
||||
C# during 1 minute and 5 minute intervals. If a limit would
|
||||
C# be exceeded, the packet is dropped and message is displayed in red.
|
||||
C
|
||||
CIGTXLIMIT 6 10
|
||||
C
|
||||
C
|
||||
C#############################################################
|
||||
C# #
|
||||
C# APRStt GATEWAY #
|
||||
C# #
|
||||
C#############################################################
|
||||
C
|
||||
C#
|
||||
C# Dire Wolf can receive DTMF (commonly known as Touch Tone)
|
||||
C# messages and convert them to packet objects.
|
||||
C#
|
||||
C# See separate "APRStt-Implementation-Notes" document for details.
|
||||
C#
|
||||
C
|
||||
C#
|
||||
C# Sample gateway configuration based on:
|
||||
C#
|
||||
C# http://www.aprs.org/aprstt/aprstt-coding24.txt
|
||||
C# http://www.aprs.org/aprs-jamboree-2013.html
|
||||
C#
|
||||
C
|
||||
C# Define specific points.
|
||||
C
|
||||
CTTPOINT B01 37^55.37N 81^7.86W
|
||||
CTTPOINT B7495088 42.605237 -71.34456
|
||||
CTTPOINT B934 42.605237 -71.34456
|
||||
C
|
||||
CTTPOINT B901 42.661279 -71.364452
|
||||
CTTPOINT B902 42.660411 -71.364419
|
||||
CTTPOINT B903 42.659046 -71.364452
|
||||
CTTPOINT B904 42.657578 -71.364602
|
||||
C
|
||||
C
|
||||
C# For location at given bearing and distance from starting point.
|
||||
C
|
||||
CTTVECTOR B5bbbddd 37^55.37N 81^7.86W 0.01 mi
|
||||
C
|
||||
C# For location specified by x, y coordinates.
|
||||
C
|
||||
CTTGRID Byyyxxx 37^50.00N 81^00.00W 37^59.99N 81^09.99W
|
||||
C
|
||||
C# UTM location for Lowell-Dracut-Tyngsborough State Forest.
|
||||
C
|
||||
CTTUTM B6xxxyyy 19T 10 300000 4720000
|
||||
C
|
||||
C
|
||||
C
|
||||
C# Location for the corral.
|
||||
C
|
||||
CTTCORRAL 37^55.50N 81^7.00W 0^0.02N
|
||||
C
|
||||
C# Compact messages - Fixed locations xx and object yyy where
|
||||
C# Object numbers 100 - 199 = bicycle
|
||||
C# Object numbers 200 - 299 = fire truck
|
||||
C# Others = dog
|
||||
C
|
||||
CTTMACRO xx1yy B9xx*AB166*AA2B4C5B3B0A1yy
|
||||
CTTMACRO xx2yy B9xx*AB170*AA3C4C7C3B0A2yy
|
||||
CTTMACRO xxyyy B9xx*AB180*AA3A6C4A0Ayyy
|
||||
C
|
||||
CTTMACRO z Cz
|
||||
C
|
||||
C# Receive on channel 0, Transmit object reports on channel 1 with optional via path.
|
||||
C
|
||||
C#TTOBJ 0 1 WIDE1-1
|
||||
C
|
||||
C# Advertise gateway position with beacon.
|
||||
C
|
||||
C# OBEACON DELAY=0:15 EVERY=10:00 VIA=WIDE1-1 OBJNAME=WB2OSZ-tt SYMBOL=APRStt LAT=42^37.14N LONG=71^20.83W COMMENT="APRStt Gateway"
|
||||
C
|
||||
C
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2014, 2015, 2016, 2018 John Langner, WB2OSZ
|
||||
// Copyright (C) 2014, 2015, 2016 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
|
||||
|
@ -130,18 +130,12 @@ void dlq_init (void)
|
|||
#else
|
||||
int err;
|
||||
err = pthread_mutex_init (&wake_up_mutex, NULL);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("dlq_init: pthread_mutex_init err=%d", err);
|
||||
perror ("");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
err = pthread_mutex_init (&dlq_mutex, NULL);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("dlq_init: pthread_mutex_init err=%d", err);
|
||||
perror ("");
|
||||
exit (EXIT_FAILURE);
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -215,10 +209,7 @@ void dlq_init (void)
|
|||
* display of audio level line.
|
||||
* Use -2 to indicate DTMF message.)
|
||||
*
|
||||
* fec_type - Was it from FX.25 or IL2P? Need to know because
|
||||
* meaning of retries is different.
|
||||
*
|
||||
* retries - Level of correction used.
|
||||
* retries - Level of bit correction used.
|
||||
*
|
||||
* spectrum - Display of how well multiple decoders did.
|
||||
*
|
||||
|
@ -228,7 +219,7 @@ void dlq_init (void)
|
|||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, fec_type_t fec_type, retry_t retries, char *spectrum)
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum)
|
||||
{
|
||||
|
||||
struct dlq_item_s *pnew;
|
||||
|
@ -239,7 +230,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
dw_printf ("dlq_rec_frame (chan=%d, pp=%p, ...)\n", chan, pp);
|
||||
#endif
|
||||
|
||||
assert (chan >= 0 && chan < MAX_TOTAL_CHANS); // TOTAL to include virtual channels.
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
|
||||
if (pp == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -259,11 +250,6 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
if (s_new_count > s_delete_count + 50) {
|
||||
|
@ -278,7 +264,6 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
|||
pnew->subchan = subchan;
|
||||
pnew->pp = pp;
|
||||
pnew->alevel = alevel;
|
||||
pnew->fec_type = fec_type;
|
||||
pnew->retries = retries;
|
||||
if (spectrum == NULL)
|
||||
strlcpy(pnew->spectrum, "", sizeof(pnew->spectrum));
|
||||
|
@ -503,11 +488,6 @@ void dlq_connect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_CONNECT_REQUEST;
|
||||
|
@ -561,11 +541,6 @@ void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_DISCONNECT_REQUEST;
|
||||
|
@ -578,74 +553,7 @@ void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int
|
|||
|
||||
append_to_queue (pnew);
|
||||
|
||||
} /* end dlq_disconnect_request */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dlq_outstanding_frames_request
|
||||
*
|
||||
* Purpose: Client application wants to know number of outstanding information
|
||||
* frames supplied, supplied by the client, that have not yet been
|
||||
* delivered to the remote station.
|
||||
*
|
||||
* Inputs: addrs - Source (owncall), destination (peercall)
|
||||
*
|
||||
* num_addr - Number of addresses. Should be 2.
|
||||
* If more they will be ignored.
|
||||
*
|
||||
* chan - Channel, 0 is first.
|
||||
*
|
||||
* client - Client application instance. We could have multiple
|
||||
* applications, all on the same channel, connecting
|
||||
* to different stations. We need to know which one
|
||||
* should get the results.
|
||||
*
|
||||
* Outputs: Request is appended to queue for processing by
|
||||
* the data link state machine.
|
||||
*
|
||||
* Description: The data link state machine will count up all information frames
|
||||
* for the given source(mycall) / destination(remote) / channel link.
|
||||
* A 'Y' response will be sent back to the client application.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client)
|
||||
{
|
||||
struct dlq_item_s *pnew;
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dlq_outstanding_frames_request (...)\n");
|
||||
#endif
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
|
||||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_OUTSTANDING_FRAMES_REQUEST;
|
||||
pnew->chan = chan;
|
||||
memcpy (pnew->addrs, addrs, sizeof(pnew->addrs));
|
||||
pnew->num_addr = num_addr;
|
||||
pnew->client = client;
|
||||
|
||||
/* Put it into queue. */
|
||||
|
||||
append_to_queue (pnew);
|
||||
|
||||
} /* end dlq_outstanding_frames_request */
|
||||
|
||||
|
||||
|
||||
|
||||
} /* end dlq_connect_request */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -696,11 +604,6 @@ void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int n
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_XMIT_DATA_REQUEST;
|
||||
|
@ -728,7 +631,8 @@ void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int n
|
|||
*
|
||||
* Purpose: Register callsigns that we will recognize for incoming connection requests.
|
||||
*
|
||||
* Inputs: addr - Callsign to [un]register.
|
||||
* Inputs: addrs - Source (owncall), destination (peercall),
|
||||
* and possibly digipeaters.
|
||||
*
|
||||
* chan - Channel, 0 is first.
|
||||
*
|
||||
|
@ -748,7 +652,7 @@ void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int n
|
|||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void dlq_register_callsign (char *addr, int chan, int client)
|
||||
void dlq_register_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client)
|
||||
{
|
||||
struct dlq_item_s *pnew;
|
||||
|
||||
|
@ -763,16 +667,11 @@ void dlq_register_callsign (char *addr, int chan, int client)
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_REGISTER_CALLSIGN;
|
||||
pnew->chan = chan;
|
||||
strlcpy (pnew->addrs[0], addr, sizeof(pnew->addrs[0]));
|
||||
strlcpy (pnew->addrs[0], addr, AX25_MAX_ADDR_LEN);
|
||||
pnew->num_addr = 1;
|
||||
pnew->client = client;
|
||||
|
||||
|
@ -783,7 +682,7 @@ void dlq_register_callsign (char *addr, int chan, int client)
|
|||
} /* end dlq_register_callsign */
|
||||
|
||||
|
||||
void dlq_unregister_callsign (char *addr, int chan, int client)
|
||||
void dlq_unregister_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client)
|
||||
{
|
||||
struct dlq_item_s *pnew;
|
||||
|
||||
|
@ -798,16 +697,11 @@ void dlq_unregister_callsign (char *addr, int chan, int client)
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_UNREGISTER_CALLSIGN;
|
||||
pnew->chan = chan;
|
||||
strlcpy (pnew->addrs[0], addr, sizeof(pnew->addrs[0]));
|
||||
strlcpy (pnew->addrs[0], addr, AX25_MAX_ADDR_LEN);
|
||||
pnew->num_addr = 1;
|
||||
pnew->client = client;
|
||||
|
||||
|
@ -857,11 +751,6 @@ void dlq_channel_busy (int chan, int activity, int status)
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_CHANNEL_BUSY;
|
||||
|
@ -878,58 +767,6 @@ void dlq_channel_busy (int chan, int activity, int status)
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dlq_seize_confirm
|
||||
*
|
||||
* Purpose: Inform data link state machine that the transmitter is on.
|
||||
* This is in response to lm_seize_request.
|
||||
*
|
||||
* Inputs: chan - Radio channel number.
|
||||
*
|
||||
* Outputs: Request is appended to queue for processing by
|
||||
* the data link state machine.
|
||||
*
|
||||
* Description: When removed from the data link state machine queue, this
|
||||
* becomes lm_seize_confirm.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
void dlq_seize_confirm (int chan)
|
||||
{
|
||||
struct dlq_item_s *pnew;
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dlq_seize_confirm (chan=%d)\n", chan);
|
||||
#endif
|
||||
|
||||
|
||||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
pnew->type = DLQ_SEIZE_CONFIRM;
|
||||
pnew->chan = chan;
|
||||
|
||||
/* Put it into queue. */
|
||||
|
||||
append_to_queue (pnew);
|
||||
|
||||
|
||||
} /* end dlq_seize_confirm */
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dlq_client_cleanup
|
||||
|
@ -960,11 +797,6 @@ void dlq_client_cleanup (int client)
|
|||
/* Allocate a new queue item. */
|
||||
|
||||
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||
if (pnew == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
s_new_count++;
|
||||
|
||||
// All we care about is the client number.
|
||||
|
@ -1247,11 +1079,6 @@ cdata_t *cdata_new (int pid, char *data, int len)
|
|||
size = ( len + 127 ) & ~0x7f;
|
||||
|
||||
cdata = malloc ( sizeof(cdata_t) + size );
|
||||
if (cdata == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("FATAL ERROR: Out of memory.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cdata->magic = TXDATA_MAGIC;
|
||||
cdata->next = NULL;
|
|
@ -33,12 +33,9 @@ typedef struct cdata_s {
|
|||
|
||||
|
||||
|
||||
|
||||
/* Types of things that can be in queue. */
|
||||
|
||||
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_OUTSTANDING_FRAMES_REQUEST, DLQ_CHANNEL_BUSY, DLQ_SEIZE_CONFIRM, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
||||
|
||||
typedef enum fec_type_e {fec_type_none=0, fec_type_fx25=1, fec_type_il2p=2} fec_type_t;
|
||||
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_CHANNEL_BUSY, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
||||
|
||||
|
||||
/* A queue item. */
|
||||
|
@ -71,11 +68,7 @@ typedef struct dlq_item_s {
|
|||
|
||||
alevel_t alevel; /* Audio level. */
|
||||
|
||||
fec_type_t fec_type; // Type of FEC for received signal: none, FX.25, or IL2P.
|
||||
|
||||
retry_t retries; /* Effort expended to get a valid CRC. */
|
||||
/* Bits changed for regular AX.25. */
|
||||
/* Number of bytes fixed for FX.25. */
|
||||
|
||||
char spectrum[MAX_SUBCHANS*MAX_SLICERS+1]; /* "Spectrum" display for multi-decoders. */
|
||||
|
||||
|
@ -109,24 +102,20 @@ void dlq_init (void);
|
|||
|
||||
|
||||
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, fec_type_t fec_type, retry_t retries, char *spectrum);
|
||||
void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum);
|
||||
|
||||
void dlq_connect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid);
|
||||
|
||||
void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
|
||||
|
||||
void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
|
||||
|
||||
void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid, char *xdata_ptr, int xdata_len);
|
||||
|
||||
void dlq_register_callsign (char *addr, int chan, int client);
|
||||
void dlq_register_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
|
||||
|
||||
void dlq_unregister_callsign (char *addr, int chan, int client);
|
||||
void dlq_unregister_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
|
||||
|
||||
void dlq_channel_busy (int chan, int activity, int status);
|
||||
|
||||
void dlq_seize_confirm (int chan);
|
||||
|
||||
void dlq_client_cleanup (int client);
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,21 +0,0 @@
|
|||
|
||||
install(FILES "${CUSTOM_DOC_DIR}/README.md" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/2400-4800-PSK-for-APRS-Packet-Radio.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/AIS-Reception.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/APRS-Telemetry-Toolkit.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/APRStt-Implementation-Notes.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/APRStt-interface-for-SARTrack.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/APRStt-Listening-Example.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/AX25_plus_FEC_equals_FX25.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Bluetooth-KISS-TNC.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Going-beyond-9600-baud.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Raspberry-Pi-APRS.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Raspberry-Pi-APRS-Tracker.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Raspberry-Pi-SDR-IGate.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Successful-APRS-IGate-Operation.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/User-Guide.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/WA8LMF-TNC-Test-CD-Results.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(FILES "${CUSTOM_DOC_DIR}/Why-is-9600-only-twice-as-fast-as-1200.pdf" DESTINATION ${INSTALL_DOC_DIR})
|
|
@ -2,20 +2,13 @@
|
|||
|
||||
Click on the document name to view in your web browser or the link following to download the PDF file.
|
||||
|
||||
|
||||
## Slide Show ##
|
||||
|
||||
Brief summary of packet radio / APRS history and the capbilities of Dire Wolf.
|
||||
|
||||
[Power Point presentation](https://github.com/wb2osz/direwolf-presentation) -- Why not give a talk at a local club meeting?
|
||||
|
||||
## Essential Reading ##
|
||||
|
||||
- [**User Guide**](User-Guide.pdf) [ [*download*](../../../raw/master/doc/User-Guide.pdf) ]
|
||||
- [**User Guide**](User-Guide.pdf) [ [*download*](../../../raw/dev/doc/User-Guide.pdf) ]
|
||||
|
||||
This is your primary source of information about installation, operation, and configuration.
|
||||
|
||||
- [**Raspberry Pi APRS**](Raspberry-Pi-APRS.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-APRS.pdf) ]
|
||||
- [**Raspberry Pi APRS**](Raspberry-Pi-APRS.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-APRS.pdf) ]
|
||||
|
||||
The Raspberry Pi has some special considerations that
|
||||
make it different from other generic Linux systems.
|
||||
|
@ -26,60 +19,40 @@ Brief summary of packet radio / APRS history and the capbilities of Dire Wolf.
|
|||
|
||||
These dive into more detail for specialized topics or typical usage scenarios.
|
||||
|
||||
|
||||
|
||||
- [**AX.25 + FEC = FX.25**](AX25_plus_FEC_equals_FX25.pdf) [ [*download*](../../../raw/dev/doc/AX25_plus_FEC_equals_FX25.pdf) ]
|
||||
|
||||
What can you do if your radio signal isn’t quite strong enough to get through reliably? Move to higher ground? Get a better antenna? More power? Use very narrow bandwidth and very slow data?
|
||||
|
||||
Sometimes those are not options. Another way to improve communication reliability is to add redundant information so the message will still get through even if small parts are missing. FX.25 adds forward error correction (FEC) which maintaining complete compatibility with older equipment.
|
||||
|
||||
|
||||
- [**AX.25 Throughput: Why is 9600 bps Packet Radio only twice as fast as 1200?**](Why-is-9600-only-twice-as-fast-as-1200.pdf) [ [*download*](../../../raw/dev/doc/Why-is-9600-only-twice-as-fast-as-1200.pdf) ]
|
||||
|
||||
Simply switching to a higher data rate will probably result in great disappointment. You might expect it to be 8 times faster but it can turn out to be only twice as fast.
|
||||
|
||||
In this document, we look at why a large increase in data bit rate can produce a much smaller increase in throughput. We will explore techniques that can be used to make large improvements and drastically speed up large data transfer.
|
||||
|
||||
|
||||
|
||||
|
||||
- [**Successful APRS IGate Operation**](Successful-APRS-IGate-Operation.pdf) [ [*download*](../../../raw/dev/doc/Successful-APRS-IGate-Operation.pdf) ]
|
||||
|
||||
|
||||
Dire Wolf can serve as a gateway between the APRS radio network and APRS-IS servers on the Internet.
|
||||
|
||||
This explains how it all works, proper configuration, and troubleshooting.
|
||||
|
||||
- [**Bluetooth KISS TNC**](Bluetooth-KISS-TNC.pdf) [ [*download*](../../../raw/master/doc/Bluetooth-KISS-TNC.pdf) ]
|
||||
- [**Bluetooth KISS TNC**](Bluetooth-KISS-TNC.pdf) [ [*download*](../../../raw/dev/doc/Bluetooth-KISS-TNC.pdf) ]
|
||||
|
||||
Eliminate the cable between your TNC and application. Use Bluetooth instead.
|
||||
|
||||
- [**APRStt Implementation Notes**](APRStt-Implementation-Notes.pdf) [ [*download*](../../../raw/master/doc/APRStt-Implementation-Notes.pdf) ]
|
||||
- [**APRStt Implementation Notes**](APRStt-Implementation-Notes.pdf) [ [*download*](../../../raw/dev/doc/APRStt-Implementation-Notes.pdf) ]
|
||||
|
||||
Very few hams have portable equipment for APRS but nearly everyone has a handheld radio that can send DTMF tones. APRStt allows a user, equipped with only DTMF (commonly known as Touch Tone) generation capability, to enter information into the global APRS data network.
|
||||
This document explains how the APRStt concept was implemented in the Dire Wolf application.
|
||||
|
||||
- [**APRStt Interface for SARTrack**](APRStt-interface-for-SARTrack.pdf) [ [*download*](../../../raw/master/doc/APRStt-interface-for-SARTrack.pdf) ]
|
||||
- [**APRStt Interface for SARTrack**](APRStt-interface-for-SARTrack.pdf) [ [*download*](../../../raw/dev/doc/APRStt-interface-for-SARTrack.pdf) ]
|
||||
|
||||
This example illustrates how APRStt can be integrated with other applications such as SARTrack, APRSISCE/32, YAAC, or Xastir.
|
||||
|
||||
- [**APRStt Listening Example**](APRStt-Listening-Example.pdf) [ [*download*](../../../raw/master/doc/APRStt-Listening-Example.pdf) ]
|
||||
- [**APRStt Listening Example**](APRStt-Listening-Example.pdf) [ [*download*](../../../raw/dev/doc/APRStt-Listening-Example.pdf) ]
|
||||
|
||||
|
||||
WB4APR described a useful application for the [QIKCOM-2 Satallite Transponder](http://www.tapr.org/pipermail/aprssig/2015-November/045035.html).
|
||||
|
||||
Don’t have your own QIKCOM-2 Satellite Transponder? No Problem. You can do the same thing with an ordinary computer and the APRStt gateway built into Dire Wolf. Here’s how.
|
||||
|
||||
- [**Raspberry Pi APRS Tracker**](Raspberry-Pi-APRS-Tracker.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-APRS-Tracker.pdf) ]
|
||||
- [**Raspberry Pi APRS Tracker**](Raspberry-Pi-APRS-Tracker.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-APRS-Tracker.pdf) ]
|
||||
|
||||
Build a tracking device which transmits position from a GPS receiver.
|
||||
|
||||
- [**Raspberry Pi SDR IGate**](Raspberry-Pi-SDR-IGate.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-SDR-IGate.pdf) ]
|
||||
- [**Raspberry Pi SDR IGate**](Raspberry-Pi-SDR-IGate.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-SDR-IGate.pdf) ]
|
||||
|
||||
It's easy to build a receive-only APRS Internet Gateway (IGate) with only a Raspberry Pi and a software defined radio (RTL-SDR) dongle. Here’s how.
|
||||
|
||||
- [**APRS Telemetry Toolkit**](APRS-Telemetry-Toolkit.pdf) [ [*download*](../../../raw/master/doc/APRS-Telemetry-Toolkit.pdf) ]
|
||||
- [**APRS Telemetry Toolkit**](APRS-Telemetry-Toolkit.pdf) [ [*download*](../../../raw/dev/doc/APRS-Telemetry-Toolkit.pdf) ]
|
||||
|
||||
Describes scripts and methods to generate telemetry.
|
||||
Includes a complete example of attaching an analog to
|
||||
|
@ -88,41 +61,21 @@ These dive into more detail for specialized topics or typical usage scenarios.
|
|||
|
||||
|
||||
|
||||
- [**2400 & 4800 bps PSK for APRS / Packet Radio**](2400-4800-PSK-for-APRS-Packet-Radio.pdf) [ [*download*](../../../raw/master/doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf) ]
|
||||
- [**2400 & 4800 bps PSK for APRS / Packet Radio**](2400-4800-PSK-for-APRS-Packet-Radio.pdf) [ [*download*](../../../raw/dev/doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf) ]
|
||||
|
||||
|
||||
Double or quadruple your data rate by sending multiple bits at the same time.
|
||||
|
||||
- [**Going beyond 9600 baud**](Going-beyond-9600-baud.pdf) [ [*download*](../../../raw/master/doc/Going-beyond-9600-baud.pdf) ]
|
||||
- [**Going beyond 9600 baud**](Going-beyond-9600-baud.pdf) [ [*download*](../../../raw/dev/doc/Going-beyond-9600-baud.pdf) ]
|
||||
|
||||
|
||||
Why stop at 9600 baud? Go faster if your soundcard and radio can handle it.
|
||||
|
||||
- [**AIS Reception**](AIS-Reception.pdf) [ [*download*](../../../raw/dev/doc/AIS-Reception.pdf) ]
|
||||
|
||||
|
||||
AIS is an international tracking system for ships. Messages can contain position, speed, course, name, destination, status, vessel dimensions, and many other types of information. Learn how to receive these signals with an ordindary ham transceiver and display the ship locations with APRS applications or [OpenCPN](https://opencpn.org).
|
||||
|
||||
- **[EAS to APRS message converter](https://github.com/wb2osz/eas2aprs)**
|
||||
|
||||
|
||||
The [U.S. National Weather Service](https://www.weather.gov/nwr/) (NWS) operates more than 1,000 VHF FM radio stations that continuously transmit weather information. These stations also transmit special warnings about severe weather, disasters (natural & manmade), and public safety.
|
||||
|
||||
Alerts are sent in a digital form known as Emergency Alert System (EAS) Specific Area Message Encoding (SAME). [You can hear a sample here](https://en.wikipedia.org/wiki/Specific_Area_Message_Encoding).
|
||||
|
||||
It is possible to buy radios that decode these messages but what fun is that? We are ham radio operators so we want to build our own from stuff that we already have sitting around.
|
||||
|
||||
|
||||
## Miscellaneous ##
|
||||
|
||||
- **[Ham Radio of Things (HRoT)](https://github.com/wb2osz/hrot)**
|
||||
|
||||
|
||||
Now that billions of computers and mobile phones (which are handheld computers) are all connected by the Internet, the large growth is expected from the “Internet of Things.” What is a “thing?” It could be a temperature sensor, garage door opener, motion detector, flood water level, smoke alarm, antenna rotator, coffee maker, lights, home thermostat, …, just about anything you might want to monitor or control.
|
||||
|
||||
There have been other occasional mentions of merging Ham Radio with the Internet of Things but only ad hoc incompatible narrowly focused applications. Here is a proposal for a standardized more flexible method so different systems can communicate with each other.
|
||||
|
||||
- [**A Better APRS Packet Demodulator, part 1, 1200 baud**](A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) [ [*download*](../../../raw/master/doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) ]
|
||||
- [**A Better APRS Packet Demodulator, part 1, 1200 baud**](A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) [ [*download*](../../../raw/dev/doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) ]
|
||||
|
||||
Sometimes it's a little mystifying why an
|
||||
APRS / AX.25 Packet TNC will decode some signals
|
||||
|
@ -134,7 +87,7 @@ and a couple things that can be done about it.
|
|||
|
||||
|
||||
|
||||
- [**A Better APRS Packet Demodulator, part 2, 9600 baud**](A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) [ [*download*](../../../raw/master/doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) ]
|
||||
- [**A Better APRS Packet Demodulator, part 2, 9600 baud**](A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) [ [*download*](../../../raw/dev/doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) ]
|
||||
|
||||
In the first part of this series we discussed 1200 baud audio frequency shift keying (AFSK). The mismatch
|
||||
between FM transmitter pre-emphasis and the
|
||||
|
@ -143,34 +96,26 @@ and a couple things that can be done about it.
|
|||
This makes it more difficult to demodulate them accurately.
|
||||
9600 baud operation is an entirely different animal. ...
|
||||
|
||||
- [**WA8LMF TNC Test CD Results a.k.a. Battle of the TNCs**](WA8LMF-TNC-Test-CD-Results.pdf) [ [*download*](../../../raw/master/doc/WA8LMF-TNC-Test-CD-Results.pdf) ]
|
||||
- [**WA8LMF TNC Test CD Results a.k.a. Battle of the TNCs**](WA8LMF-TNC-Test-CD-Results.pdf) [ [*download*](../../../raw/dev/doc/WA8LMF-TNC-Test-CD-Results.pdf) ]
|
||||
|
||||
How can we compare how well the TNCs perform under real world conditions?
|
||||
The de facto standard of measurement is the number of packets decoded from [WA8LMF’s TNC Test CD](http://wa8lmf.net/TNCtest/index.htm).
|
||||
Many have published the number of packets they have been able to decode from this test. Here they are, all gathered in one place, for your reading pleasure.
|
||||
|
||||
- [**A Closer Look at the WA8LMF TNC Test CD**](A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) [ [*download*](../../../raw/master/doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) ]
|
||||
- [**A Closer Look at the WA8LMF TNC Test CD**](A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) [ [*download*](../../../raw/dev/doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) ]
|
||||
|
||||
Here, we take a closer look at some of the frames on the TNC Test CD in hopes of gaining some insights into why some are easily decoded and others are more difficult.
|
||||
There are a lot of ugly signals out there. Many can be improved by decreasing the transmit volume. Others are just plain weird and you have to wonder how they are being generated.
|
||||
|
||||
|
||||
## Additional Documentation for Dire Wolf Software TNC #
|
||||
|
||||
|
||||
When there was little documentation, it was all added to the source code repository [https://github.com/wb2osz/direwolf/tree/master/doc](https://github.com/wb2osz/direwolf/tree/master/doc)
|
||||
|
||||
The growing number of documentation files and revisions are making the source code repository very large which means long download times. Additional documentation, not tied to a specific release, is now being added to [https://github.com/wb2osz/direwolf-doc](https://github.com/wb2osz/direwolf-doc)
|
||||
|
||||
## Questions? Experiences to share? ##
|
||||
|
||||
Here are some good places to ask questions and share your experiences:
|
||||
|
||||
- [Dire Wolf Software TNC](https://groups.io/g/direwolf)
|
||||
- [Dire Wolf packet TNC](https://groups.yahoo.com/neo/groups/direwolf_packet/info)
|
||||
|
||||
- [Raspberry Pi 4 Ham Radio](https://groups.io/g/RaspberryPi-4-HamRadio)
|
||||
- [Raspberry Pi 4 Ham Radio](https://groups.yahoo.com/neo/groups/Raspberry_Pi_4-Ham_RADIO/info)
|
||||
|
||||
- [linuxham](https://groups.io/g/linuxham)
|
||||
- [linuxham](https://groups.yahoo.com/neo/groups/linuxham/info)
|
||||
|
||||
- [TAPR aprssig](http://www.tapr.org/pipermail/aprssig/)
|
||||
|
||||
|
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue