mirror of https://github.com/wb2osz/direwolf.git
Compare commits
No commits in common. "master" and "1.3-dev-K" 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
|
|
|
@ -6,7 +6,9 @@ z*
|
||||||
*~
|
*~
|
||||||
*.xlsx
|
*.xlsx
|
||||||
*.stackdump
|
*.stackdump
|
||||||
|
direwolf.conf
|
||||||
*.wav
|
*.wav
|
||||||
|
fsk_fast_filter.h
|
||||||
|
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
|
@ -39,26 +41,6 @@ z*
|
||||||
*.x86_64
|
*.x86_64
|
||||||
*.hex
|
*.hex
|
||||||
|
|
||||||
# Binaries, other build results
|
|
||||||
|
|
||||||
aclients
|
|
||||||
atest
|
|
||||||
decode_aprs
|
|
||||||
direwolf
|
|
||||||
gen_fff
|
|
||||||
gen_packets
|
|
||||||
ll2utm
|
|
||||||
log2gpx
|
|
||||||
text2tt
|
|
||||||
tt2text
|
|
||||||
ttcalc
|
|
||||||
utm2ll
|
|
||||||
|
|
||||||
direwolf.conf
|
|
||||||
fsk_fast_filter.h
|
|
||||||
direwolf.desktop
|
|
||||||
|
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# Operating System Files
|
# Operating System Files
|
||||||
# =========================
|
# =========================
|
||||||
|
@ -105,9 +87,3 @@ $RECYCLE.BIN/
|
||||||
|
|
||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
/use_this_sdk
|
|
||||||
*.dSYM
|
|
||||||
|
|
||||||
# cmake
|
|
||||||
build/
|
|
||||||
tmp/
|
|
374
CHANGES.md
374
CHANGES.md
|
@ -1,309 +1,102 @@
|
||||||
|
|
||||||
# Revision History #
|
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 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: ###
|
|
||||||
|
|
||||||
|
|
||||||
- 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 ##
|
|
||||||
|
|
||||||
|
|
||||||
### 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.
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
- KISS "Set Hardware" command to report transmit queue length.
|
|
||||||
|
|
||||||
- TCP KISS can now handle multiple concurrent applications.
|
|
||||||
|
|
||||||
- Linux can use serial port for KISS in addition to a pseudo terminal.
|
|
||||||
|
|
||||||
- decode_aprs utility can now accept KISS frames and AX.25 frames as series of two digit hexadecimal numbers.
|
|
||||||
|
|
||||||
- Full Duplex operation. (Put "FULLDUP ON" in channel section of configuration file.)
|
|
||||||
|
|
||||||
- Time slots for beaconing.
|
|
||||||
|
|
||||||
- Allow single log file with fixed name rather than starting a new one each day.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Bugs Fixed: ###
|
|
||||||
|
|
||||||
- Possible crash when CDIGIPEAT did not include the optional alias.
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
|
|
||||||
### Documentation: ###
|
|
||||||
|
|
||||||
|
|
||||||
- New document ***Bluetooth-KISS-TNC.pdf*** explaining how to use KISS over Bluetooth.
|
|
||||||
|
|
||||||
- Updates describing cheap SDR frequency inaccuracy and how to compensate for it.
|
|
||||||
|
|
||||||
### Notes: ###
|
|
||||||
|
|
||||||
Windows binary distribution now uses gcc (MinGW) version 6.3.0.
|
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
## Version 1.4 -- April 2017 ##
|
## Version 1.3 -- Development snapshot K -- January 2016 ##
|
||||||
|
|
||||||
|
### New Feature: ###
|
||||||
### New Features: ###
|
|
||||||
|
|
||||||
- AX.25 v2.2 connected mode. See chapter 10 of User Guide for details.
|
|
||||||
|
|
||||||
- New client side packet filter to select "messages" only to stations that have been heard nearby recently. This is now the default if no IS to RF filter is specified.
|
|
||||||
|
|
||||||
- New beacon type, IBEACON, for sending IGate statistics.
|
|
||||||
|
|
||||||
- Expanded debug options so you can understand what is going on with packet filtering.
|
|
||||||
|
|
||||||
- Added new document ***Successful-APRS-IGate-Operation.pdf*** with IGate background, configuration, and troubleshooting tips.
|
|
||||||
- 2400 & 4800 bps PSK modems. See ***2400-4800-PSK-for-APRS-Packet-Radio.pdf*** in the doc directory for discussion.
|
|
||||||
|
|
||||||
- The top speed of 9600 bps has been increased to 38400. You will need a sound card capable of 96k or 192k samples per second for the higher rates. Radios must also have adequate bandwidth. See ***Going-beyond-9600-baud.pdf*** in the doc directory for more details.
|
|
||||||
|
|
||||||
- Better decoder performance for 9600 and higher especially for low audio sample rate to baud ratios.
|
|
||||||
|
|
||||||
- Generate waypoint sentences for use by AvMap G5 / G6 or other mapping devices or applications. Formats include
|
|
||||||
- $GPWPL - NMEA generic with only location and name.
|
|
||||||
- $PGRMW - Garmin, adds altitude, symbol, and comment to previously named waypoint.
|
|
||||||
- $PMGNWPL - Magellan, more complete for stationary objects.
|
|
||||||
- $PKWDWPL - Kenwood with APRS style symbol but missing comment.
|
|
||||||
|
|
||||||
|
|
||||||
- DTMF tones can be sent by putting "DTMF" in the destination address, similar to the way that Morse Code is sent.
|
|
||||||
|
|
||||||
- Take advantage of new 'gpio' group and new /sys/class/gpio ownership in Raspbian Jessie.
|
|
||||||
|
|
||||||
- Handle more complicated gpio naming for CubieBoard, etc.
|
|
||||||
|
|
||||||
- More flexible dw-start.sh start up script for both GUI and CLI environments.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Bugs Fixed: ###
|
|
||||||
|
|
||||||
- The transmitter (PTT control) was being turned off too soon when sending Morse Code.
|
|
||||||
|
|
||||||
- The -qd (quiet decode) command line option now suppresses errors about improperly formed Telemetry packets.
|
|
||||||
|
|
||||||
- Longer tocall.txt files can now be handled.
|
|
||||||
|
|
||||||
- Sometimes kissattach would have an issue with the Dire Wolf pseudo terminal. This showed up most often on Raspbian but sometimes occurred with other versions of Linux.
|
|
||||||
|
|
||||||
*kissattach: Error setting line discipline: TIOCSETD: Device or resource busy
|
|
||||||
Are you sure you have enabled MKISS support in the kernel
|
|
||||||
or, if you made it a module, that the module is loaded?*
|
|
||||||
|
|
||||||
|
|
||||||
- Sometimes writes to a pseudo terminal would block causing the received
|
|
||||||
frame processing thread to hang. The first thing you will notice is that
|
|
||||||
received frames are not being printed. After a while this message will appear:
|
|
||||||
|
|
||||||
*Received frame queue is out of control. Length=... Reader thread is probably
|
|
||||||
frozen. This can be caused by using a pseudo terminal (direwolf -p) where
|
|
||||||
another application is not reading the frames from the other side.*
|
|
||||||
|
|
||||||
- -p command line option caused segmentation fault with glibc >= 2.24.
|
|
||||||
|
|
||||||
|
|
||||||
- The Windows version 1.3 would crash when starting to transmit on Windows XP. There have also been some other reports of erratic behavior on Windows. The crashing problem was fixed in in the 1.3.1 patch release. Linux version was not affected.
|
|
||||||
|
|
||||||
- IGate did not retain nul characters in the information part of a packet. This should never happen with a valid APRS packet but there are a couple cases where it has. If we encounter these malformed packets, pass them along as-is, rather than truncating.
|
|
||||||
|
|
||||||
- Don't digipeat packets when the source is my call.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------
|
|
||||||
|
|
||||||
## Version 1.3 -- May 2016 ##
|
|
||||||
|
|
||||||
### New Features: ###
|
|
||||||
|
|
||||||
- Support for Mac OS X.
|
|
||||||
|
|
||||||
- Many APRStt enhancements including: Morse code and speech responses to to APRStt tone sequences, new 5 digit callsign suffix abbreviation,
|
|
||||||
position ambiguity for latitude and longitude in object reports
|
|
||||||
|
|
||||||
- APRS Telemetry Toolkit.
|
|
||||||
|
|
||||||
- GPS Tracker beacons are now available for the Windows version. Previously this was only in the Linux version.
|
|
||||||
|
|
||||||
- SATgate mode for IGate. Packets heard directly are delayed before being sent
|
- SATgate mode for IGate. Packets heard directly are delayed before being sent
|
||||||
to the Internet Server. This favors digipeated packets because the original
|
to the Internet Server. This favors digipeated packets because the original
|
||||||
arrives later and gets dropped if there are duplicates.
|
arrives later and gets dropped if there are duplicates.
|
||||||
|
|
||||||
- Added support for hamlib. This provides more flexible options for PTT control.
|
----------
|
||||||
|
|
||||||
- Implemented AGW network protocol 'M' message for sending UNPROTO information without digipeater path.
|
## Version 1.3 -- Development snapshot J -- January 2016 ##
|
||||||
|
|
||||||
|
|
||||||
- A list of all symbols available can be obtained with the -S
|
|
||||||
command line option.
|
|
||||||
|
|
||||||
- Command line option "-a n" to print audio device statistics each n seconds. Previously this was always each 100 seconds on Linux and not available on Windows.
|
|
||||||
|
|
||||||
### Bugs Fixed: ###
|
### Bugs Fixed: ###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- Fixed several cases where crashes were caused by unexpected packet contents:
|
|
||||||
|
|
||||||
- When receiving packet with unexpected form of GPS NMEA sentence.
|
|
||||||
|
|
||||||
- When receiving packet with comment of a few hundred characters.
|
|
||||||
|
|
||||||
- Address in path, from Internet server, more than 9 characters.
|
|
||||||
|
|
||||||
- "INTERNAL ERROR: dlq_append NULL packet pointer." when using PASSALL.
|
|
||||||
|
|
||||||
- In Mac OSX version: Assertion failed: (adev[a].inbuf_size_in_bytes >= 100 && adev[a].inbuf_size_in_bytes <= 32768), function audio_get, file audio_portaudio.c, line 917.
|
|
||||||
|
|
||||||
- Tracker beacons were not always updating the location properly.
|
|
||||||
|
|
||||||
- AGW network protocol now works properly for big-endian processors
|
- AGW network protocol now works properly for big-endian processors
|
||||||
such as PowerPC or MIPS.
|
such as PowerPC or MIPS.
|
||||||
|
|
||||||
- Packet filtering treated telemetry metadata as messages rather than telemetry.
|
- The Mac OSX build procedure is now better about locating the SDK.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot I -- December 2015 ##
|
||||||
|
|
||||||
|
### New Feature: ###
|
||||||
|
|
||||||
|
- Added support for hamlib. This will provide more flexible options for PTT control. Needs better documentation.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot H -- December 2015 ##
|
||||||
|
|
||||||
|
### New Feature: ###
|
||||||
|
|
||||||
|
- New experimental demodulator. More details later.
|
||||||
|
|
||||||
|
- APRStt enhancements including new 5 digit callsign suffix abbreviation and
|
||||||
|
position ambiguity for latitude and longitude in object reports.
|
||||||
|
|
||||||
|
### Bugs Fixed: ###
|
||||||
|
|
||||||
|
- "INTERNAL ERROR: dlq_append NULL packet pointer." when using PASSALL.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot G -- November 2015 ##
|
||||||
|
|
||||||
|
### New Feature: ###
|
||||||
|
|
||||||
|
- GPS Tracker beacons are now available for the Windows version. Previously this was only in the Linux version.
|
||||||
|
|
||||||
|
- Implemented AGW network protocol 'M' message for sending UNPROTO information without digipeater path.
|
||||||
|
|
||||||
|
### Bugs Fixed: ###
|
||||||
|
|
||||||
|
- Tracker beacons were not always updating the location properly.
|
||||||
|
|
||||||
|
- In Mac OSX version: Assertion failed: (adev[a].inbuf_size_in_bytes >= 100 && adev[a].inbuf_size_in_bytes <= 32768), function audio_get, file audio_portaudio.c, line 917.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot F -- September 2015 ##
|
||||||
|
|
||||||
|
### New Feature: ###
|
||||||
|
|
||||||
|
- Command line option "-a n" to print audio device statistics each n seconds. Previously this was always each 100 seconds on Linux and not available on Windows.
|
||||||
|
|
||||||
|
### Bug Fixed: ###
|
||||||
|
|
||||||
|
- Crashed when receiving packet with comment of a few hundred characters.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot E -- August 2015 ##
|
||||||
|
|
||||||
|
### Bug Fixed: ###
|
||||||
|
|
||||||
|
- Crashed when receiving packet with unexpected form of GPS NMEA sentence.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
## Version 1.3 -- Development snapshot D -- July 2015 ##
|
||||||
|
|
||||||
|
### New Features: ###
|
||||||
|
|
||||||
|
- Enhancements to APRStt gateway including Morse code and speech responses to to APRStt tone sequences.
|
||||||
|
|
||||||
|
- Preliminary support for Mac OS X. NEEDS MORE TESTING!
|
||||||
|
|
||||||
|
- A list of all symbols available can be obtained with the -S
|
||||||
|
command line option.
|
||||||
|
|
||||||
|
- APRS Telemetry Toolkit (incomplete).
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -313,7 +106,7 @@ such as PowerPC or MIPS.
|
||||||
|
|
||||||
- Improved decoder performance.
|
- Improved decoder performance.
|
||||||
Over 1000 error-free frames decoded from WA8LMF TNC Test CD.
|
Over 1000 error-free frames decoded from WA8LMF TNC Test CD.
|
||||||
See ***A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf*** for details.
|
See "A-Better-APRS-Packet-Demodulator.pdf" for details.
|
||||||
|
|
||||||
- Up to 3 soundcards and 6 radio channels can be handled at the same time.
|
- Up to 3 soundcards and 6 radio channels can be handled at the same time.
|
||||||
|
|
||||||
|
@ -524,7 +317,8 @@ to rebuild it from source.
|
||||||
|
|
||||||
### New Features: ###
|
### New Features: ###
|
||||||
|
|
||||||
- Added APRStt gateway capability. For details, see ***APRStt-Implementation-Notes.pdf***
|
- Added APRStt gateway capability. For details, see:
|
||||||
|
**APRStt-Implementation-Notes.pdf**
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
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:
|
# In my case, I see CYGWIN_NT-6.1-WOW so we don't check for
|
||||||
@echo "The build procedure has changed in version 1.6."
|
# equal to some value. Your mileage my vary.
|
||||||
@echo "In general, it now looks like this:"
|
|
||||||
@echo " "
|
win := $(shell uname | grep CYGWIN)
|
||||||
@echo "Download the source code:"
|
dar := $(shell uname | grep Darwin)
|
||||||
@echo " "
|
|
||||||
@echo " cd ~"
|
ifneq ($(win),)
|
||||||
@echo " git clone https://www.github.com/wb2osz/direwolf"
|
include Makefile.win
|
||||||
@echo " cd direwolf"
|
else ifeq ($(dar),Darwin)
|
||||||
@echo " "
|
include Makefile.macosx
|
||||||
@echo "Optional - Do this to get the latest development version"
|
else
|
||||||
@echo "rather than the latest stable release."
|
include Makefile.linux
|
||||||
@echo " "
|
endif
|
||||||
@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 " "
|
|
||||||
|
|
|
@ -0,0 +1,768 @@
|
||||||
|
#
|
||||||
|
# Makefile for Linux version of Dire Wolf.
|
||||||
|
#
|
||||||
|
|
||||||
|
APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc
|
||||||
|
|
||||||
|
all : $(APPS) direwolf.desktop direwolf.conf
|
||||||
|
@echo " "
|
||||||
|
@echo "Next step - install with:"
|
||||||
|
@echo " "
|
||||||
|
@echo " sudo make install"
|
||||||
|
@echo " "
|
||||||
|
|
||||||
|
CC := gcc
|
||||||
|
CFLAGS := -O3 -pthread -Igeotranz
|
||||||
|
|
||||||
|
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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# ---------- 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, 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# If you want to use OSS (for FreeBSD, OpenBSD) instead of
|
||||||
|
# ALSA (for Linux), comment out (or remove) the two lines below.
|
||||||
|
|
||||||
|
CFLAGS += -DUSE_ALSA
|
||||||
|
LDFLAGS += -lasound
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
# Uncomment following lines to enable hamlib support.
|
||||||
|
#CFLAGS += -DUSE_HAMLIB
|
||||||
|
#LDFLAGS += -lhamlib
|
||||||
|
|
||||||
|
|
||||||
|
# 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_9600.o hdlc_rec.o \
|
||||||
|
hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
|
||||||
|
fcs_calc.o ax25_pad.o \
|
||||||
|
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||||
|
gen_tone.o audio.o audio_stats.o digipeater.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 nmea.o serial_port.o log.o telemetry.o \
|
||||||
|
dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o \
|
||||||
|
misc.a geotranz.a
|
||||||
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
ifneq ($(enable_gpsd),)
|
||||||
|
@echo " "
|
||||||
|
@echo "This includes support for gpsd."
|
||||||
|
else
|
||||||
|
@echo " "
|
||||||
|
@echo "This does NOT include support for gpsd."
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Optimization for slow processors.
|
||||||
|
|
||||||
|
demod.o : fsk_fast_filter.h
|
||||||
|
|
||||||
|
demod_afsk.o : fsk_fast_filter.h
|
||||||
|
|
||||||
|
|
||||||
|
fsk_fast_filter.h : demod_afsk.c
|
||||||
|
$(CC) $(CFLAGS) -o gen_fff -DGEN_FFF demod_afsk.c dsp.c textcolor.c $(LDFLAGS)
|
||||||
|
./gen_fff > fsk_fast_filter.h
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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 ------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Separate application to decode raw data.
|
||||||
|
|
||||||
|
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o ax25_pad.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 textcolor.c dsp.c misc.a
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
# Unit test for AFSK demodulator
|
||||||
|
|
||||||
|
atest : atest.c fsk_fast_filter.h demod.c demod_afsk.c demod_9600.c \
|
||||||
|
dsp.o hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||||
|
fcs_calc.c ax25_pad.c decode_aprs.c dwgpsnmea.o \
|
||||||
|
dwgps.o dwgpsd.o serial_port.o telemetry.c latlong.c symbols.c tt_text.c textcolor.c \
|
||||||
|
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 $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
# 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?
|
||||||
|
|
||||||
|
# My understanding, of the convention, is that something you compile
|
||||||
|
# from source, that is not a standard part of the operating system,
|
||||||
|
# should go in /usr/local/bin.
|
||||||
|
|
||||||
|
# However, if you are preparing a "binary" DEB or RPM package, the
|
||||||
|
# installation location should be /usr/bin.
|
||||||
|
|
||||||
|
# This is a step in the right direction but not sufficient to use /usr instead.
|
||||||
|
# Eventually I'd like to have targets here to build the .DEB and .RPM packages.
|
||||||
|
|
||||||
|
INSTALLDIR := /usr/local
|
||||||
|
|
||||||
|
# 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 \"$(INSTALLDIR)/bin/direwolf\"" >> $@
|
||||||
|
else ifneq ($(wildcard /usr/bin/lxterm),)
|
||||||
|
@echo "Exec=lxterm -hold -title \"Dire Wolf\" -bg white -e \"$(INSTALLDIR)/bin/direwolf\"" >> $@
|
||||||
|
else
|
||||||
|
@echo "Exec=xterm -hold -title \"Dire Wolf\" -bg white -e \"$(INSTALLDIR)/bin/direwolf\"" >> $@
|
||||||
|
endif
|
||||||
|
@echo 'Name=Dire Wolf' >> $@
|
||||||
|
@echo 'Comment=APRS Soundcard TNC' >> $@
|
||||||
|
@echo 'Icon=/usr/share/direwolf/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 /usr/local/...
|
||||||
|
# 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) 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) 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-seq.sh $(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 /usr/share/direwolf/tocalls.txt
|
||||||
|
$(INSTALL) -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||||
|
$(INSTALL) -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||||
|
$(INSTALL) -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||||
|
$(INSTALL) -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||||
|
#
|
||||||
|
# Documentation. Various plain text files and PDF.
|
||||||
|
#
|
||||||
|
$(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/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.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/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/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.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
|
||||||
|
#
|
||||||
|
# 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 $(INSTALLDIR)/share/doc/direwolf/examples/direwolf.conf
|
||||||
|
$(INSTALL) -D --mode=644 dw-start.sh $(INSTALLDIR)/share/doc/direwolf/examples/dw-start.sh
|
||||||
|
$(INSTALL) -D --mode=644 sdr.conf $(INSTALLDIR)/share/doc/direwolf/examples/sdr.conf
|
||||||
|
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-m0xer-3.txt $(INSTALLDIR)/share/doc/direwolf/examples/telem-m0xer-3.txt
|
||||||
|
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-balloon.conf $(INSTALLDIR)/share/doc/direwolf/examples/telem-balloon.conf
|
||||||
|
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-volts.conf $(INSTALLDIR)/share/doc/direwolf/examples/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 " "
|
||||||
|
|
||||||
|
|
||||||
|
# These would be done as ordinary user.
|
||||||
|
|
||||||
|
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
||||||
|
|
||||||
|
# TODO: Handle Linux variations correctly.
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: install-conf
|
||||||
|
install-conf : direwolf.conf
|
||||||
|
cp direwolf.conf ~
|
||||||
|
cp sdr.conf ~
|
||||||
|
cp telemetry-toolkit/telem-m0xer-3.txt ~
|
||||||
|
cp telemetry-toolkit/telem-*.conf ~
|
||||||
|
ifneq ($(wildcard $(HOME)/Desktop),)
|
||||||
|
@echo " "
|
||||||
|
@echo "This will add a desktop icon on some systems:"
|
||||||
|
@echo " "
|
||||||
|
@echo " make install-rpi"
|
||||||
|
@echo " "
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: install-rpi
|
||||||
|
install-rpi : dw-start.sh
|
||||||
|
cp dw-start.sh ~
|
||||||
|
ln -f -s /usr/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 check-modem1200 check-modem300 check-modem9600
|
||||||
|
|
||||||
|
# Can we encode and decode at popular data rates?
|
||||||
|
|
||||||
|
check-modem1200 : gen_packets atest
|
||||||
|
./gen_packets -n 100 -o /tmp/test1.wav
|
||||||
|
./atest -F0 -PE -L70 -G71 /tmp/test1.wav
|
||||||
|
./atest -F1 -PE -L73 -G75 /tmp/test1.wav
|
||||||
|
#rm /tmp/test1.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/test9.wav
|
||||||
|
./atest -B9600 -F0 -L57 -G59 /tmp/test9.wav
|
||||||
|
./atest -B9600 -F1 -L66 -G67 /tmp/test9.wav
|
||||||
|
rm /tmp/test9.wav
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Unit test for inner digipeater algorithm
|
||||||
|
|
||||||
|
.PHONY : dtest
|
||||||
|
dtest : digipeater.c dedupe.c \
|
||||||
|
pfilter.o 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------- Manual tests and experiments ---------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
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 misc.a
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
./udptest
|
||||||
|
|
||||||
|
demod.o : tune.h
|
||||||
|
demod_afsk.o : tune.h
|
||||||
|
demod_9600.o : 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 latlong.c symbols.c tune.h textcolor.c misc.a
|
||||||
|
$(CC) $(CFLAGS) -o atest $^ $(LDFLAGS)
|
||||||
|
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------- 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) fsk_fast_filter.h *.o *.a direwolf.desktop
|
||||||
|
echo " " > tune.h
|
||||||
|
|
||||||
|
|
||||||
|
depend : $(wildcard *.c)
|
||||||
|
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following is updated by "make depend"
|
||||||
|
#
|
||||||
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,620 @@
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc 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)
|
||||||
|
CFLAGS := -Os -pthread -Igeotranz $(EXTRA_CFLAGS)
|
||||||
|
# $(info $$CC is [${CC}])
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
CFLAGS += -march=core2 -msse4.1 -std=gnu99
|
||||||
|
#CFLAGS += -march=pentium3 -sse
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
#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_pad.o beacon.o \
|
||||||
|
config.o decode_aprs.o dedupe.o demod_9600.o demod_afsk.o \
|
||||||
|
demod.o digipeater.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 kissnet.o latlong.o latlong.o log.o morse.o multi_modem.o \
|
||||||
|
nmea.o serial_port.o pfilter.o ptt.o rdq.o recv.o redecode.o rrbb.o server.o \
|
||||||
|
symbols.o telemetry.o textcolor.o tq.o tt_text.o tt_user.o xmit.o \
|
||||||
|
dwgps.o dwgpsnmea.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 : demod_afsk.c
|
||||||
|
$(CC) $(CFLAGS) -o gen_fff -DGEN_FFF demod_afsk.c dsp.c textcolor.c -lm
|
||||||
|
./gen_fff > fsk_fast_filter.h
|
||||||
|
|
||||||
|
# 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?
|
||||||
|
|
||||||
|
# My understanding, of the convention, is that something you compile
|
||||||
|
# from source, that is not a standard part of the operating system,
|
||||||
|
# should go in /usr/local/bin.
|
||||||
|
|
||||||
|
# This is a step in the right direction but not sufficient to use /usr instead.
|
||||||
|
|
||||||
|
INSTALLDIR := /usr/local
|
||||||
|
|
||||||
|
# TODO: Test this better.
|
||||||
|
|
||||||
|
# Optional installation into /usr/local/...
|
||||||
|
# Needs to be run as root or with sudo.
|
||||||
|
# TODO: Review file locations.
|
||||||
|
|
||||||
|
# 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 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) 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) 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 /usr/share/direwolf/tocalls.txt
|
||||||
|
$(INSTALL) -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||||
|
$(INSTALL) -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||||
|
$(INSTALL) -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||||
|
$(INSTALL) -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.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/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/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.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
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
||||||
|
|
||||||
|
# TODO: Handle Linux variations correctly.
|
||||||
|
|
||||||
|
|
||||||
|
.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.
|
||||||
|
|
||||||
|
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.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 textcolor.c dsp.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) -lm
|
||||||
|
|
||||||
|
demod.o : tune.h
|
||||||
|
demod_afsk.o : tune.h
|
||||||
|
demod_9600.o : 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 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 AFSK demodulator
|
||||||
|
|
||||||
|
atest : 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 dwgpsnmea.o dwgps.o serial_port.o telemetry.c 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_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 $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
# 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 direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc \
|
||||||
|
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/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/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 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
|
|
@ -0,0 +1,594 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
CC := gcc
|
||||||
|
CFLAGS := -Wall -Ofast -march=pentium3 -msse -Iregex -Iutm -Igeotranz -mthreads -DUSE_REGEX_STATIC
|
||||||
|
AR := ar
|
||||||
|
|
||||||
|
CFLAGS += -g
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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 --------------------------------
|
||||||
|
|
||||||
|
demod.o : fsk_demod_state.h
|
||||||
|
demod_9600.o : fsk_demod_state.h
|
||||||
|
demod_afsk.o : fsk_demod_state.h
|
||||||
|
|
||||||
|
|
||||||
|
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hdlc_rec.o \
|
||||||
|
hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
|
||||||
|
fcs_calc.o ax25_pad.o \
|
||||||
|
decode_aprs.o symbols.o server.o kiss.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 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 nmea.o serial_port.o log.o telemetry.o \
|
||||||
|
dwgps.o dwgpsnmea.o dtime_now.o \
|
||||||
|
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 : demod_afsk.c
|
||||||
|
$(CC) $(CFLAGS) -o gen_fff -DGEN_FFF demod_afsk.c dsp.c textcolor.c
|
||||||
|
./gen_fff > fsk_fast_filter.h
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.c 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 textcolor.o dsp.o misc.a regex.a
|
||||||
|
$(CC) $(CFLAGS) -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 $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
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 functios 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 check-modem1200 check-modem300 check-modem9600
|
||||||
|
|
||||||
|
# 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 test1.wav
|
||||||
|
atest -F0 -PE -L70 -G71 test1.wav
|
||||||
|
atest -F1 -PE -L73 -G75 test1.wav
|
||||||
|
#rm test1.wav
|
||||||
|
|
||||||
|
check-modem300 : gen_packets atest
|
||||||
|
gen_packets -B300 -n 100 -o test3.wav
|
||||||
|
atest -B300 -F0 -L68 -G69 test3.wav
|
||||||
|
atest -B300 -F1 -L73 -G75 test3.wav
|
||||||
|
rm test3.wav
|
||||||
|
|
||||||
|
check-modem9600 : gen_packets atest
|
||||||
|
gen_packets -B9600 -n 100 -o test9.wav
|
||||||
|
atest -B9600 -F0 -L57 -G59 test9.wav
|
||||||
|
atest -B9600 -F1 -L66 -G67 test9.wav
|
||||||
|
rm test9.wav
|
||||||
|
|
||||||
|
# Unit test for AFSK demodulator
|
||||||
|
|
||||||
|
atest : atest.c fsk_fast_filter.h demod.c demod_afsk.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 \
|
||||||
|
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_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 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.o 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
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------ Other manual testing & experimenting -------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# For tweaking the demodulator.
|
||||||
|
|
||||||
|
demod.o : tune.h
|
||||||
|
demod_9600.o : tune.h
|
||||||
|
demod_afsk.o : tune.h
|
||||||
|
|
||||||
|
|
||||||
|
testagc : atest.c demod.c dsp.c demod_afsk.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 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_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 regex.a misc.a \
|
||||||
|
tune.h
|
||||||
|
rm -f atest.exe
|
||||||
|
$(CC) $(CFLAGS) -o atest $^
|
||||||
|
./atest -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
|
||||||
|
|
||||||
|
testagc9 : atest.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 latlong.c symbols.c textcolor.c telemetry.c regex.a misc.a \
|
||||||
|
tune.h
|
||||||
|
rm -f atest.exe
|
||||||
|
$(CC) $(CFLAGS) -o atest $^
|
||||||
|
./atest -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
||||||
|
#./atest -B 9600 noisy96.wav | grep "packets decoded in" >atest.out
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# 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_9600.o rdq.o \
|
||||||
|
server.o morse.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 \
|
||||||
|
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
|
||||||
|
zip --junk-paths ../$z-win.zip \
|
||||||
|
README.md \
|
||||||
|
CHANGES.md \
|
||||||
|
doc/User-Guide.pdf \
|
||||||
|
doc/Raspberry-Pi-APRS.pdf \
|
||||||
|
doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf \
|
||||||
|
doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf \
|
||||||
|
doc/APRS-Telemetry-Toolkit.pdf \
|
||||||
|
doc/APRStt-Implementation-Notes.pdf \
|
||||||
|
doc/APRStt-interface-for-SARTrack.pdf \
|
||||||
|
doc/APRStt-Listening-Example.pdf \
|
||||||
|
doc/Raspberry-Pi-APRS.pdf \
|
||||||
|
doc/Raspberry-Pi-APRS-Tracker.pdf \
|
||||||
|
doc/Raspberry-Pi-SDR-IGate.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 \
|
||||||
|
dwespeak.bat \
|
||||||
|
telemetry-toolkit/*
|
||||||
|
|
||||||
|
.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 \
|
||||||
|
doc/APRS-Telemetry-Toolkit.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
|
||||||
|
dos2unix generic.conf
|
||||||
|
dos2unix Makefile
|
||||||
|
dos2unix Makefile.linux
|
||||||
|
dos2unix Makefile.macosx
|
||||||
|
dos2unix telemetry-toolkit/telem-balloon.conf
|
||||||
|
dos2unix telemetry-toolkit/telem-balloon.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-bits.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-data.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-data91.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-eqns.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-m0xer-3.txt
|
||||||
|
dos2unix telemetry-toolkit/telem-parm.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-unit.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-volts.py
|
||||||
|
dos2unix telemetry-toolkit/telem-volts.conf
|
||||||
|
(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.win $z/Makefile.linux $z/Makefile.macosx $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/* )
|
||||||
|
unix2dos Makefile
|
||||||
|
unix2dos Makefile.linux
|
||||||
|
unix2dos Makefile.macosx
|
||||||
|
unix2dos telemetry-toolkit/telem-balloon.conf
|
||||||
|
unix2dos telemetry-toolkit/telem-balloon.pl
|
||||||
|
dos2unix telemetry-toolkit/telem-bits.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-data.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-data91.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-eqns.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-m0xer-3.txt
|
||||||
|
unix2dos telemetry-toolkit/telem-parm.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-unit.pl
|
||||||
|
unix2dos telemetry-toolkit/telem-volts.py
|
||||||
|
unix2dos telemetry-toolkit/telem-volts.conf
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
230
README.md
230
README.md
|
@ -3,233 +3,93 @@
|
||||||
|
|
||||||
### Decoded Information from Radio Emissions for Windows Or Linux Fans ###
|
### 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 a “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.
|
Dire Wolf is a software "soundcard" modem/TNC and [APRS](http://www.aprs.org/) encoder/decoder. It can be used stand-alone to observe APRS traffic, as a digipeater, [APRStt](http://www.aprs.org/aprstt.html) gateway, or Internet Gateway (IGate). 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), and many others.
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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. ###
|
|
||||||
|
|
||||||
Without any additional software, it can perform as:
|
|
||||||
|
|
||||||
- APRS GPS Tracker
|
|
||||||
- Digipeater
|
|
||||||
- Internet Gateway (IGate)
|
|
||||||
- [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.
|
|
||||||
|
|
||||||
|
|
||||||
## Features & Benefits ##
|
## Features ##
|
||||||
|
|
||||||

|
- Lower cost, higher performance alternative to hardware TNC.
|
||||||
|
Version 1.2 decodes more than 1000 error-free frames from [WA8LMF TNC Test CD](http://wa8lmf.net/TNCtest/).
|
||||||
|
|
||||||
### Dire Wolf includes: ###
|
- Ideal for building a Raspberry Pi digipeater & IGate.
|
||||||
|
|
||||||
|
- 300, 1200, and 9600 baud operation.
|
||||||
|
|
||||||
|
- Interface with applications by
|
||||||
|
- [AGW](http://uz7.ho.ua/includes/agwpeapi.htm) network protocol
|
||||||
|
- [KISS](http://www.ax25.net/kiss.aspx) serial port
|
||||||
|
- [KISS](http://www.ax25.net/kiss.aspx) network protocol
|
||||||
|
|
||||||
|
- Decoding of received information for troubleshooting.
|
||||||
|
|
||||||
- **Beaconing, Tracker, Telemetry Toolkit.**
|
- Logging and conversion to GPX file format.
|
||||||
|
|
||||||
Send periodic beacons to provide information to others. For tracking the location is provided by a GPS receiver.
|
- Beaconing for yourself or other nearby entities.
|
||||||
Build your own telemetry applications with the toolkit.
|
|
||||||
|
|
||||||
|
- Very flexible Digipeating with routing and filtering between up to 6 ports.
|
||||||
|
|
||||||
- **APRStt Gateway.**
|
- APRStt gateway - converts touch tone sequences to APRS objects.
|
||||||
|
|
||||||
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.
|
- APRS Internet Gateway (IGate) with IPv6 support.
|
||||||
|
|
||||||
- **Digipeaters for APRS and traditional Packet Radio.**
|
- Compatible with software defined radios (SDR) such as [gqrx](http://gqrx.dk/) and [rtl_fm](http://sdr.osmocom.org/trac/wiki/rtl-sdr).
|
||||||
|
|
||||||
Extend the range of other stations by re-transmitting their signals. Unmatched flexibility for cross band repeating and filtering to limit what is retransmitted.
|
- Includes separate raw packet decoder, decode_aprs.
|
||||||
|
|
||||||
- **Internet Gateway (IGate).**
|
- Open source so you can see how it works and make your own modifications.
|
||||||
|
|
||||||
IGate stations allow communication between disjoint radio networks by allowing some content to flow between them over the Internet.
|
- Runs in 3 different environments:
|
||||||
|
- Microsoft Windows XP or later
|
||||||
- **Ham Radio of Things (HRoT).**
|
- Linux, regular PC or single board computer such as Raspberry Pi, BeagleBone Black, or cubieboard 2
|
||||||
|
- Mac OS X
|
||||||
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.**
|
|
||||||
|
|
||||||
Traditional connected mode packet radio where the TNC automatically retries transmissions and delivers data in the right order.
|
|
||||||
|
|
||||||
- **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.
|
|
||||||
|
|
||||||
### Radio Interfaces: ###
|
|
||||||
|
|
||||||
- **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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- **Modems:**
|
|
||||||
|
|
||||||
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.**
|
|
||||||
|
|
||||||
- **Speech Synthesizer interface & Morse code generator.**
|
|
||||||
|
|
||||||
Transmit human understandable messages.
|
|
||||||
|
|
||||||
- **Compatible with Software Defined Radios such as gqrx, rtl_fm, and SDR#.**
|
|
||||||
|
|
||||||
- **Concurrent operation with up to 3 soundcards and 6 radios.**
|
|
||||||
|
|
||||||
### Portable & Open Source: ###
|
|
||||||
|
|
||||||
- **Runs on Windows, Linux (PC/laptop, Raspberry Pi, etc.), Mac OSX.**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation ##
|
|
||||||
|
|
||||||
|
|
||||||
[Stable Version](https://github.com/wb2osz/direwolf/tree/master/doc)
|
|
||||||
|
|
||||||
[Latest Development Version ("dev" branch)](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 ##
|
## Installation ##
|
||||||
|
|
||||||
### Windows ###
|
### Windows ###
|
||||||
|
|
||||||
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.
|
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 - Download with web browser ###
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
### Linux - Using git clone (recommended) ###
|
cd direwolf-*
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
make install-conf
|
||||||
|
|
||||||
***Note that this has changed for version 1.6. There are now a couple extra steps.***
|
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 git clone ###
|
||||||
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 ~
|
cd ~
|
||||||
git clone https://www.github.com/wb2osz/direwolf
|
git clone https://www.github.com/wb2osz/direwolf
|
||||||
cd direwolf
|
cd direwolf
|
||||||
git checkout dev
|
git checkout 1.2
|
||||||
mkdir build && cd build
|
make
|
||||||
cmake ..
|
|
||||||
make -j4
|
|
||||||
sudo make install
|
sudo make install
|
||||||
make install-conf
|
make install-conf
|
||||||
|
|
||||||
This gives you the latest development version. Leave out the "git checkout dev" to get the most recent stable release.
|
The "git checkout 1.2" is necessary to get the most recent stable release. The tip of the master branch is temporarily in an inconsistent state during the transition from the old website. If you want the latest (unstable) development version, use "git checkout dev" instead.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
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.
|
|
||||||
|
|
||||||
sudo yum check-update
|
|
||||||
sudo yum list direwolf
|
|
||||||
sudo yum install direwolf
|
|
||||||
|
|
||||||
|
|
||||||
### Macintosh OS X ###
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
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 ##
|
## Join the conversation ##
|
||||||
|
|
||||||
Here are some good places to ask questions and share your experience:
|
Here are some good places to share information:
|
||||||
|
|
||||||
- [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/)
|
- [TAPR aprssig](http://www.tapr.org/pipermail/aprssig/)
|
||||||
|
|
||||||
|
|
||||||
The github "issues" section is for reporting software defects and enhancement requests. It is NOT a place to ask questions or have general discussions. Please use one of the locations above.
|
|
||||||
|
|
|
@ -51,36 +51,38 @@
|
||||||
* Linux: Use the BSD socket interface.
|
* Linux: Use the BSD socket interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "direwolf.h" // Sets _WIN32_WINNT for XP API level needed by ws2tcpip.h
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h> // _WIN32_WINNT must be set to 0x0501 before including this
|
// default is 0x0400
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0501 /* Minimum OS version is XP. */
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
|
//#define __USE_XOPEN2KXSI 1
|
||||||
|
//#define __USE_XOPEN 1
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <errno.h>
|
#include <sys/errno.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "ax25_pad.h"
|
#include "ax25_pad.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -284,10 +286,10 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
if (isdigit(port[j][0])) {
|
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 {
|
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) {
|
if (client_th[j] == NULL) {
|
||||||
printf ("Internal error: Could not create client thread %d.\n", j);
|
printf ("Internal error: Could not create client thread %d.\n", j);
|
||||||
|
@ -295,10 +297,10 @@ int main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (isdigit(port[j][0])) {
|
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 {
|
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) {
|
if (e != 0) {
|
||||||
perror("Internal error: Could not create client thread.");
|
perror("Internal error: Could not create client thread.");
|
||||||
|
@ -395,7 +397,7 @@ static void * client_thread_net (void *arg)
|
||||||
int use_chan = -1;
|
int use_chan = -1;
|
||||||
|
|
||||||
|
|
||||||
my_index = (int)(ptrdiff_t)arg;
|
my_index = (int)(long)arg;
|
||||||
|
|
||||||
#if DEBUGx
|
#if DEBUGx
|
||||||
printf ("DEBUG: client_thread_net %d start, port = '%s'\n", my_index, port[my_index]);
|
printf ("DEBUG: client_thread_net %d start, port = '%s'\n", my_index, port[my_index]);
|
||||||
|
@ -465,11 +467,7 @@ static void * client_thread_net (void *arg)
|
||||||
// Try each address until we find one that is successful.
|
// Try each address until we find one that is successful.
|
||||||
|
|
||||||
for (n=0; n<num_hosts; n++) {
|
for (n=0; n<num_hosts; n++) {
|
||||||
#if __WIN32__
|
|
||||||
SOCKET is;
|
|
||||||
#else
|
|
||||||
int is;
|
int is;
|
||||||
#endif
|
|
||||||
|
|
||||||
ai = hosts[n];
|
ai = hosts[n];
|
||||||
|
|
||||||
|
@ -550,7 +548,12 @@ static void * client_thread_net (void *arg)
|
||||||
|
|
||||||
mon_cmd.kind_lo = 'k';
|
mon_cmd.kind_lo = 'k';
|
||||||
|
|
||||||
SOCK_SEND (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
#if __WIN32__
|
||||||
|
send (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd), 0);
|
||||||
|
#else
|
||||||
|
err = write (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print all of the monitored packets.
|
* Print all of the monitored packets.
|
||||||
|
@ -559,10 +562,14 @@ static void * client_thread_net (void *arg)
|
||||||
while (1) {
|
while (1) {
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = SOCK_RECV (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
#if __WIN32__
|
||||||
|
n = recv (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd), 0);
|
||||||
|
#else
|
||||||
|
n = read (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (n != sizeof(mon_cmd)) {
|
if (n != sizeof(mon_cmd)) {
|
||||||
printf ("Read error, client %d received %d command bytes. Terminating.\n", my_index, n);
|
printf ("Read error, client %d received %d command bytes.\n", my_index, n);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,10 +577,14 @@ static void * client_thread_net (void *arg)
|
||||||
printf ("client %d received '%c' data, data_len = %d\n",
|
printf ("client %d received '%c' data, data_len = %d\n",
|
||||||
my_index, mon_cmd.kind_lo, mon_cmd.data_len);
|
my_index, mon_cmd.kind_lo, mon_cmd.data_len);
|
||||||
#endif
|
#endif
|
||||||
assert (mon_cmd.data_len >= 0 && mon_cmd.data_len < (int)(sizeof(data)));
|
assert (mon_cmd.data_len >= 0 && mon_cmd.data_len < sizeof(data));
|
||||||
|
|
||||||
if (mon_cmd.data_len > 0) {
|
if (mon_cmd.data_len > 0) {
|
||||||
n = SOCK_RECV (server_sock, data, mon_cmd.data_len);
|
#if __WIN32__
|
||||||
|
n = recv (server_sock, data, mon_cmd.data_len, 0);
|
||||||
|
#else
|
||||||
|
n = read (server_sock, data, mon_cmd.data_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (n != mon_cmd.data_len) {
|
if (n != mon_cmd.data_len) {
|
||||||
printf ("Read error, client %d received %d data bytes.\n", my_index, n);
|
printf ("Read error, client %d received %d data bytes.\n", my_index, n);
|
||||||
|
@ -665,7 +676,7 @@ static unsigned __stdcall client_thread_serial (void *arg)
|
||||||
static void * client_thread_serial (void *arg)
|
static void * client_thread_serial (void *arg)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int my_index = (int)(ptrdiff_t)arg;
|
int my_index = (int)(long)arg;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
|
@ -39,8 +39,6 @@
|
||||||
|
|
||||||
#define APRS_TT_C 1
|
#define APRS_TT_C 1
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: clean up terminolgy.
|
// TODO: clean up terminolgy.
|
||||||
// "Message" has a specific meaning in APRS and this is not it.
|
// "Message" has a specific meaning in APRS and this is not it.
|
||||||
|
@ -58,6 +56,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "ax25_pad.h"
|
#include "ax25_pad.h"
|
||||||
#include "hdlc_rec2.h" /* for process_rec_frame */
|
#include "hdlc_rec2.h" /* for process_rec_frame */
|
||||||
|
@ -106,17 +105,13 @@ static int parse_aprstt3_call (char *e);
|
||||||
static int parse_location (char *e);
|
static int parse_location (char *e);
|
||||||
static int parse_comment (char *e);
|
static int parse_comment (char *e);
|
||||||
static int expand_macro (char *e);
|
static int expand_macro (char *e);
|
||||||
#ifndef TT_MAIN
|
|
||||||
static void raw_tt_data_to_app (int chan, char *msg);
|
static void raw_tt_data_to_app (int chan, char *msg);
|
||||||
#endif
|
|
||||||
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr, size_t valstrsize);
|
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr, size_t valstrsize);
|
||||||
|
|
||||||
#if TT_MAIN
|
#if TT_MAIN
|
||||||
static void check_result (void);
|
static void check_result (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int tt_debug = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
@ -124,8 +119,7 @@ static int tt_debug = 0;
|
||||||
*
|
*
|
||||||
* Purpose: Initialize the APRStt gateway at system startup time.
|
* Purpose: Initialize the APRStt gateway at system startup time.
|
||||||
*
|
*
|
||||||
* Inputs: P - Pointer to configuration options gathered by config.c.
|
* Inputs: Configuration options gathered by config.c.
|
||||||
* debug - Debug printing control.
|
|
||||||
*
|
*
|
||||||
* Global out: Make our own local copy of the structure here.
|
* Global out: Make our own local copy of the structure here.
|
||||||
*
|
*
|
||||||
|
@ -167,10 +161,9 @@ static struct ttloc_s test_config[] = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void aprs_tt_init (struct tt_config_s *p, int debug)
|
void aprs_tt_init (struct tt_config_s *p)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
tt_debug = debug;
|
|
||||||
|
|
||||||
#if TT_MAIN
|
#if TT_MAIN
|
||||||
/* For unit testing. */
|
/* For unit testing. */
|
||||||
|
@ -212,7 +205,7 @@ void aprs_tt_init (struct tt_config_s *p, int debug)
|
||||||
* The complete message is then processed.
|
* The complete message is then processed.
|
||||||
* The touch tone decoder sends $ if no activity
|
* The touch tone decoder sends $ if no activity
|
||||||
* for some amount of time, perhaps 5 seconds.
|
* 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.
|
* there is a long gap.
|
||||||
*
|
*
|
||||||
* '.' means no activity during processing period.
|
* '.' means no activity during processing period.
|
||||||
|
@ -385,7 +378,6 @@ void aprs_tt_sequence (int chan, char *msg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TT_MAIN
|
#if TT_MAIN
|
||||||
(void)err; // suppress variable set but not used warning.
|
|
||||||
check_result (); // for unit testing.
|
check_result (); // for unit testing.
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -426,7 +418,7 @@ void aprs_tt_sequence (int chan, char *msg)
|
||||||
* Anything from script, above, will override other predefined responses.
|
* 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),
|
snprintf (audible_response, sizeof(audible_response),
|
||||||
"APRSTT>%s:%s",
|
"APRSTT>%s:%s",
|
||||||
|
@ -487,19 +479,7 @@ static int parse_fields (char *msg)
|
||||||
//text_color_set(DW_COLOR_DEBUG);
|
//text_color_set(DW_COLOR_DEBUG);
|
||||||
//dw_printf ("parse_fields (%s).\n", msg);
|
//dw_printf ("parse_fields (%s).\n", msg);
|
||||||
|
|
||||||
// Make a copy of msg because strtok corrupts the original.
|
strlcpy (stemp, msg, sizeof(stemp));
|
||||||
// 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';
|
|
||||||
|
|
||||||
e = strtok_r (stemp, "*#", &save);
|
e = strtok_r (stemp, "*#", &save);
|
||||||
while (e != NULL) {
|
while (e != NULL) {
|
||||||
|
|
||||||
|
@ -567,7 +547,7 @@ static int parse_fields (char *msg)
|
||||||
default:
|
default:
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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);
|
return (TT_ERROR_D_MSG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -590,7 +570,7 @@ static int parse_fields (char *msg)
|
||||||
* Purpose: Expand compact form "macro" to full format then process.
|
* Purpose: Expand compact form "macro" to full format then process.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should contain only digits.
|
* In this case, it should contain only digits.
|
||||||
*
|
*
|
||||||
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
||||||
|
@ -705,16 +685,18 @@ static int expand_macro (char *e)
|
||||||
* Purpose: Extract traditional format callsign or object name from touch tone sequence.
|
* Purpose: Extract traditional format callsign or object name from touch tone sequence.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "A" then a digit.
|
* In this case, it should start with "A".
|
||||||
*
|
*
|
||||||
* Outputs: m_callsign
|
* Outputs: m_callsign
|
||||||
*
|
*
|
||||||
* m_symtab_or_overlay - Set to 0-9 or A-Z if specified.
|
* m_symtab_or_overlay - Set to 0-9 or A-Z if specified.
|
||||||
*
|
*
|
||||||
* m_symbol_code - Always set to 'A' (Box, DTMF or RFID)
|
* m_symbol_code - Always set to 'A'.
|
||||||
* If you want a different symbol, use the new
|
* NO! This should be applied only if we
|
||||||
* object name format and separate symbol specification.
|
* 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.
|
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
||||||
*
|
*
|
||||||
|
@ -766,11 +748,6 @@ static int parse_callsign (char *e)
|
||||||
int len;
|
int len;
|
||||||
char tttemp[40], stemp[30];
|
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');
|
assert (*e == 'A');
|
||||||
|
|
||||||
len = strlen(e);
|
len = strlen(e);
|
||||||
|
@ -781,10 +758,6 @@ static int parse_callsign (char *e)
|
||||||
|
|
||||||
if (len == 4 && isdigit(e[1]) && isdigit(e[2]) && isdigit(e[3])) {
|
if (len == 4 && isdigit(e[1]) && isdigit(e[2]) && isdigit(e[3])) {
|
||||||
strlcpy (m_callsign, e+1, sizeof(m_callsign));
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,7 +775,7 @@ static int parse_callsign (char *e)
|
||||||
return (cs_err);
|
return (cs_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (m_callsign, e+1, 3);
|
strncpy (m_callsign, e+1, 3);
|
||||||
m_callsign[3] = '\0';
|
m_callsign[3] = '\0';
|
||||||
|
|
||||||
if (len == 7) {
|
if (len == 7) {
|
||||||
|
@ -812,20 +785,10 @@ static int parse_callsign (char *e)
|
||||||
tt_two_key_to_text (tttemp, 0, stemp);
|
tt_two_key_to_text (tttemp, 0, stemp);
|
||||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||||
m_symtab_or_overlay = stemp[0];
|
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 {
|
else {
|
||||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||||
m_symtab_or_overlay = e[len-2];
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -843,7 +806,7 @@ static int parse_callsign (char *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isupper(e[len-2])) {
|
if (isupper(e[len-2])) {
|
||||||
memcpy (tttemp, e+1, len-4);
|
strncpy (tttemp, e+1, len-4);
|
||||||
tttemp[len-4] = '\0';
|
tttemp[len-4] = '\0';
|
||||||
tt_two_key_to_text (tttemp, 0, m_callsign);
|
tt_two_key_to_text (tttemp, 0, m_callsign);
|
||||||
|
|
||||||
|
@ -853,24 +816,14 @@ static int parse_callsign (char *e)
|
||||||
tt_two_key_to_text (tttemp, 0, stemp);
|
tt_two_key_to_text (tttemp, 0, stemp);
|
||||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||||
m_symtab_or_overlay = stemp[0];
|
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 {
|
else {
|
||||||
memcpy (tttemp, e+1, len-3);
|
strncpy (tttemp, e+1, len-3);
|
||||||
tttemp[len-3] = '\0';
|
tttemp[len-3] = '\0';
|
||||||
tt_two_key_to_text (tttemp, 0, m_callsign);
|
tt_two_key_to_text (tttemp, 0, m_callsign);
|
||||||
|
|
||||||
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
m_symbol_code = APRSTT_DEFAULT_SYMBOL;
|
||||||
m_symtab_or_overlay = e[len-2];
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -888,7 +841,7 @@ static int parse_callsign (char *e)
|
||||||
* Purpose: Extract object name from touch tone sequence.
|
* Purpose: Extract object name from touch tone sequence.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "AA".
|
* In this case, it should start with "AA".
|
||||||
*
|
*
|
||||||
* Outputs: m_callsign
|
* Outputs: m_callsign
|
||||||
|
@ -907,11 +860,9 @@ static int parse_callsign (char *e)
|
||||||
static int parse_object_name (char *e)
|
static int parse_object_name (char *e)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
//int c_length;
|
||||||
if (tt_debug) {
|
//char tttemp[40];
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
//char stemp[30];
|
||||||
dw_printf ("APRStt parse object name (starts with AA): \"%s\"\n", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (e[0] == 'A');
|
assert (e[0] == 'A');
|
||||||
assert (e[1] == 'A');
|
assert (e[1] == 'A');
|
||||||
|
@ -927,10 +878,6 @@ static int parse_object_name (char *e)
|
||||||
if (tt_two_key_to_text (e+2, 0, m_callsign) == 0) {
|
if (tt_two_key_to_text (e+2, 0, m_callsign) == 0) {
|
||||||
m_callsign[9] = '\0'; /* truncate to 9 */
|
m_callsign[9] = '\0'; /* truncate to 9 */
|
||||||
m_ssid = 0; /* No ssid for object name */
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -950,7 +897,7 @@ static int parse_object_name (char *e)
|
||||||
* Purpose: Extract symbol from touch tone sequence.
|
* Purpose: Extract symbol from touch tone sequence.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "AB".
|
* In this case, it should start with "AB".
|
||||||
*
|
*
|
||||||
* Outputs: m_symtab_or_overlay
|
* Outputs: m_symtab_or_overlay
|
||||||
|
@ -984,11 +931,6 @@ static int parse_symbol (char *e)
|
||||||
int nn;
|
int nn;
|
||||||
char stemp[10];
|
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[0] == 'A');
|
||||||
assert (e[1] == 'B');
|
assert (e[1] == 'B');
|
||||||
|
|
||||||
|
@ -1013,22 +955,12 @@ static int parse_symbol (char *e)
|
||||||
case '1':
|
case '1':
|
||||||
m_symtab_or_overlay = '/';
|
m_symtab_or_overlay = '/';
|
||||||
m_symbol_code = 32 + nn;
|
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);
|
return (0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2':
|
case '2':
|
||||||
m_symtab_or_overlay = '\\';
|
m_symtab_or_overlay = '\\';
|
||||||
m_symbol_code = 32 + nn;
|
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);
|
return (0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1037,11 +969,6 @@ static int parse_symbol (char *e)
|
||||||
if (tt_two_key_to_text (e+5, 0, stemp) == 0) {
|
if (tt_two_key_to_text (e+5, 0, stemp) == 0) {
|
||||||
m_symbol_code = 32 + nn;
|
m_symbol_code = 32 + nn;
|
||||||
m_symtab_or_overlay = stemp[0];
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1064,7 +991,7 @@ static int parse_symbol (char *e)
|
||||||
* Purpose: Extract QIKcom-2 / APRStt 3 ten digit call or five digit suffix.
|
* Purpose: Extract QIKcom-2 / APRStt 3 ten digit call or five digit suffix.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "AC".
|
* In this case, it should start with "AC".
|
||||||
*
|
*
|
||||||
* Outputs: m_callsign
|
* Outputs: m_callsign
|
||||||
|
@ -1087,11 +1014,6 @@ static int parse_aprstt3_call (char *e)
|
||||||
assert (e[0] == 'A');
|
assert (e[0] == 'A');
|
||||||
assert (e[1] == 'C');
|
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) {
|
if (strlen(e) == 2+10) {
|
||||||
char call[12];
|
char call[12];
|
||||||
|
|
||||||
|
@ -1147,7 +1069,7 @@ static int parse_aprstt3_call (char *e)
|
||||||
* Purpose: Extract location from touch tone sequence.
|
* Purpose: Extract location from touch tone sequence.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "B".
|
* In this case, it should start with "B".
|
||||||
*
|
*
|
||||||
* Outputs: m_latitude
|
* Outputs: m_latitude
|
||||||
|
@ -1199,11 +1121,6 @@ static int parse_location (char *e)
|
||||||
char mh[20];
|
char mh[20];
|
||||||
char stemp[32];
|
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');
|
assert (*e == 'B');
|
||||||
|
|
||||||
|
@ -1283,26 +1200,13 @@ static int parse_location (char *e)
|
||||||
|
|
||||||
lat0 = tt_config.ttloc_ptr[ipat].grid.lat0;
|
lat0 = tt_config.ttloc_ptr[ipat].grid.lat0;
|
||||||
lat9 = tt_config.ttloc_ptr[ipat].grid.lat9;
|
lat9 = tt_config.ttloc_ptr[ipat].grid.lat9;
|
||||||
double yrange = lat9 - lat0;
|
|
||||||
y = atof(ystr);
|
y = atof(ystr);
|
||||||
double user_y_max = round(pow(10., strlen(ystr)) - 1.); // e.g. 999 for 3 digits
|
m_latitude = lat0 + y * (lat9-lat0) / (pow(10., strlen(ystr)) - 1.);
|
||||||
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
|
|
||||||
lon0 = tt_config.ttloc_ptr[ipat].grid.lon0;
|
lon0 = tt_config.ttloc_ptr[ipat].grid.lon0;
|
||||||
lon9 = tt_config.ttloc_ptr[ipat].grid.lon9;
|
lon9 = tt_config.ttloc_ptr[ipat].grid.lon9;
|
||||||
double xrange = lon9 - lon0;
|
|
||||||
x = atof(xstr);
|
x = atof(xstr);
|
||||||
double user_x_max = round(pow(10., strlen(xstr)) - 1.);
|
m_longitude = lon0 + x * (lon9-lon0) / (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_dao[2] = e[0];
|
m_dao[2] = e[0];
|
||||||
m_dao[3] = e[1];
|
m_dao[3] = e[1];
|
||||||
|
@ -1507,7 +1411,7 @@ static int parse_location (char *e)
|
||||||
* defined in the configuration file.
|
* defined in the configuration file.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "B".
|
* In this case, it should start with "B".
|
||||||
*
|
*
|
||||||
* valstrsize - size of the outputs so we can check for buffer overflow.
|
* valstrsize - size of the outputs so we can check for buffer overflow.
|
||||||
|
@ -1539,7 +1443,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
||||||
|
|
||||||
len = strlen(tt_config.ttloc_ptr[ipat].pattern);
|
len = strlen(tt_config.ttloc_ptr[ipat].pattern);
|
||||||
|
|
||||||
if ((int)(strlen(e)) == len) {
|
if (strlen(e) == len) {
|
||||||
|
|
||||||
match = 1;
|
match = 1;
|
||||||
strlcpy (xstr, "", valstrsize);
|
strlcpy (xstr, "", valstrsize);
|
||||||
|
@ -1658,7 +1562,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.
|
* Purpose: Extract comment / status or other special information from touch tone message.
|
||||||
*
|
*
|
||||||
* Inputs: e - An "entry" extracted from a complete
|
* Inputs: e - An "entry" extracted from a complete
|
||||||
* APRStt message.
|
* APRStt messsage.
|
||||||
* In this case, it should start with "C".
|
* In this case, it should start with "C".
|
||||||
*
|
*
|
||||||
* Outputs: m_comment
|
* Outputs: m_comment
|
||||||
|
@ -1754,7 +1658,6 @@ static int parse_comment (char *e)
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------*/
|
*----------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef TT_MAIN
|
|
||||||
|
|
||||||
static void raw_tt_data_to_app (int chan, char *msg)
|
static void raw_tt_data_to_app (int chan, char *msg)
|
||||||
{
|
{
|
||||||
|
@ -1765,6 +1668,9 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
||||||
char src[10], dest[10];
|
char src[10], dest[10];
|
||||||
char raw_tt_msg[256];
|
char raw_tt_msg[256];
|
||||||
packet_t pp;
|
packet_t pp;
|
||||||
|
char *c, *s;
|
||||||
|
int i;
|
||||||
|
int err;
|
||||||
alevel_t alevel;
|
alevel_t alevel;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1800,7 +1706,7 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
||||||
alevel.mark = -2;
|
alevel.mark = -2;
|
||||||
alevel.space = -2;
|
alevel.space = -2;
|
||||||
|
|
||||||
dlq_rec_frame (chan, -1, 0, pp, alevel, 0, RETRY_NONE, "tt");
|
dlq_append (DLQ_REC_FRAME, chan, -1, 0, pp, alevel, RETRY_NONE, "tt");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -1810,7 +1716,6 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
|
@ -1985,7 +1890,6 @@ static const struct {
|
||||||
/* Latitude comes out ok, 37.9137 -> 55.82 min. */
|
/* Latitude comes out ok, 37.9137 -> 55.82 min. */
|
||||||
/* Longitude -81.1254 -> 8.20 min */
|
/* Longitude -81.1254 -> 8.20 min */
|
||||||
{ "B21234*A67979#", "679", "12", "7A", "", "", "12.3400", "56.1200", "!TB2!" },
|
{ "B21234*A67979#", "679", "12", "7A", "", "", "12.3400", "56.1200", "!TB2!" },
|
||||||
|
|
||||||
{ "B533686*A67979#", "679", "12", "7A", "", "", "37.9222", "81.1143", "!TB5!" },
|
{ "B533686*A67979#", "679", "12", "7A", "", "", "37.9222", "81.1143", "!TB5!" },
|
||||||
|
|
||||||
// TODO: should test other coordinate systems.
|
// TODO: should test other coordinate systems.
|
||||||
|
@ -2078,7 +1982,7 @@ static void check_result (void)
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
aprs_tt_init (NULL, 0);
|
aprs_tt_init (NULL);
|
||||||
|
|
||||||
error_count = 0;
|
error_count = 0;
|
||||||
|
|
|
@ -123,7 +123,7 @@ struct tt_config_s {
|
||||||
int obj_recv_chan; /* Channel to listen for tones. */
|
int obj_recv_chan; /* Channel to listen for tones. */
|
||||||
|
|
||||||
int obj_xmit_chan; /* Channel to transmit object report. */
|
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 */
|
/* are only sending to application */
|
||||||
/* and/or IGate. */
|
/* 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);
|
void aprs_tt_button (int chan, char button);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// 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 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -23,12 +23,12 @@
|
||||||
*
|
*
|
||||||
* Name: atest.c
|
* 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
|
* Description: This can be used to test the AFSK demodulator under
|
||||||
* controlled and reproducible conditions for tweaking.
|
* controlled and reproducable conditions for tweaking.
|
||||||
*
|
*
|
||||||
* For example
|
* For example
|
||||||
*
|
*
|
||||||
|
@ -59,7 +59,6 @@
|
||||||
|
|
||||||
// #define X 1
|
// #define X 1
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -68,7 +67,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define ATEST_C 1
|
#define ATEST_C 1
|
||||||
|
@ -81,10 +79,7 @@
|
||||||
#include "hdlc_rec2.h"
|
#include "hdlc_rec2.h"
|
||||||
#include "dlq.h"
|
#include "dlq.h"
|
||||||
#include "ptt.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. */
|
#if 0 /* Typical but not flexible enough. */
|
||||||
|
@ -108,7 +103,7 @@ struct wav_header { /* .WAV file header. */
|
||||||
/* 8 bit samples are unsigned bytes */
|
/* 8 bit samples are unsigned bytes */
|
||||||
/* in range of 0 .. 255. */
|
/* in range of 0 .. 255. */
|
||||||
|
|
||||||
/* 16 bit samples are little endian signed short */
|
/* 16 bit samples are signed short */
|
||||||
/* in range of -32768 .. +32767. */
|
/* in range of -32768 .. +32767. */
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -140,13 +135,9 @@ static struct {
|
||||||
|
|
||||||
static FILE *fp;
|
static FILE *fp;
|
||||||
static int e_o_f;
|
static int e_o_f;
|
||||||
static int packets_decoded_one = 0;
|
static int packets_decoded = 0;
|
||||||
static int packets_decoded_total = 0;
|
|
||||||
static int decimate = 0; /* Reduce that sampling rate if set. */
|
static int decimate = 0; /* Reduce that sampling rate if set. */
|
||||||
/* 1 = normal, 2 = half, 3 = 1/3, etc. */
|
/* 1 = normal, 2 = half, etc. */
|
||||||
|
|
||||||
static int upsample = 0; /* Upsample for G3RUH decoder. */
|
|
||||||
/* Non-zero will override the default. */
|
|
||||||
|
|
||||||
static struct audio_s my_audio_config;
|
static struct audio_s my_audio_config;
|
||||||
|
|
||||||
|
@ -181,32 +172,13 @@ static int sample_number = -1; /* Sample number from the file. */
|
||||||
/* Use to print timestamp, relative to beginning */
|
/* Use to print timestamp, relative to beginning */
|
||||||
/* of file, when frame was decoded. */
|
/* 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[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
int c;
|
int c;
|
||||||
int channel;
|
int channel;
|
||||||
|
time_t start_time;
|
||||||
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 elapsed; // Time it took us to process it.
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(EXPERIMENT_G) || defined(EXPERIMENT_H)
|
#if defined(EXPERIMENT_G) || defined(EXPERIMENT_H)
|
||||||
|
@ -230,6 +202,49 @@ int main (int argc, char *argv[])
|
||||||
my_audio_config.adev[0].samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
|
my_audio_config.adev[0].samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
|
||||||
my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
|
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++) {
|
for (channel=0; channel<MAX_CHANS; channel++) {
|
||||||
|
|
||||||
|
@ -239,7 +254,7 @@ int main (int argc, char *argv[])
|
||||||
my_audio_config.achan[channel].space_freq = DEFAULT_SPACE_FREQ;
|
my_audio_config.achan[channel].space_freq = DEFAULT_SPACE_FREQ;
|
||||||
my_audio_config.achan[channel].baud = DEFAULT_BAUD;
|
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].num_freq = 1;
|
||||||
my_audio_config.achan[channel].offset = 0;
|
my_audio_config.achan[channel].offset = 0;
|
||||||
|
@ -254,7 +269,6 @@ int main (int argc, char *argv[])
|
||||||
//my_audio_config.achan[channel].passall = 1;
|
//my_audio_config.achan[channel].passall = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
//int this_option_optind = optind ? optind : 1;
|
//int this_option_optind = optind ? optind : 1;
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -267,7 +281,7 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
/* ':' following option character means arg is required. */
|
/* ':' 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);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -275,38 +289,43 @@ int main (int argc, char *argv[])
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
case 'B': /* -B for data Bit rate */
|
case 'B': /* -B for data Bit rate */
|
||||||
/* Also implies modem type based on speed. */
|
/* 300 implies 1600/1800 AFSK. */
|
||||||
/* Special cases AIS, EAS rather than number. */
|
/* 1200 implies 1200/2200 AFSK. */
|
||||||
if (strcasecmp(optarg, "AIS") == 0) {
|
/* 9600 implies scrambled. */
|
||||||
B_opt = 0xA15A15; // See special case below.
|
|
||||||
|
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 < 100 || my_audio_config.achan[0].baud > 10000) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Use a more reasonable bit rate in range of 100 - 10000.\n");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
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) {
|
else if (my_audio_config.achan[0].baud > 2400) {
|
||||||
B_opt = 0xEA5EA5; // See special case below.
|
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");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
B_opt = atoi(optarg);
|
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||||
|
my_audio_config.achan[0].mark_freq = 1200;
|
||||||
|
my_audio_config.achan[0].space_freq = 2200;
|
||||||
}
|
}
|
||||||
break;
|
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. */
|
case 'P': /* -P for modem profile. */
|
||||||
|
|
||||||
// Wait until after other options processed.
|
dw_printf ("Demodulator profile set to \"%s\"\n", optarg);
|
||||||
strlcpy (P_opt, optarg, sizeof(P_opt));
|
strlcpy (my_audio_config.achan[0].profiles, optarg, sizeof(my_audio_config.achan[0].profiles));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D': /* -D reduce sampling rate for lower CPU usage. */
|
case 'D': /* -D reduce sampling rate for lower CPU usage. */
|
||||||
|
@ -317,37 +336,20 @@ int main (int argc, char *argv[])
|
||||||
if (decimate < 1 || decimate > 8) {
|
if (decimate < 1 || decimate > 8) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Unreasonable value for -D.\n");
|
dw_printf ("Unreasonable value for -D.\n");
|
||||||
exit (EXIT_FAILURE);
|
exit (1);
|
||||||
}
|
}
|
||||||
dw_printf ("Divide audio sample rate by %d\n", decimate);
|
dw_printf ("Divide audio sample rate by %d\n", decimate);
|
||||||
my_audio_config.achan[0].decimate = decimate;
|
my_audio_config.achan[0].decimate = decimate;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U': /* -U upsample for G3RUH to improve performance */
|
case 'F': /* -D set "fix bits" level. */
|
||||||
/* 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. */
|
|
||||||
|
|
||||||
my_audio_config.achan[0].fix_bits = atoi(optarg);
|
my_audio_config.achan[0].fix_bits = atoi(optarg);
|
||||||
|
|
||||||
if (my_audio_config.achan[0].fix_bits < RETRY_NONE || my_audio_config.achan[0].fix_bits >= RETRY_MAX) {
|
if (my_audio_config.achan[0].fix_bits < RETRY_NONE || my_audio_config.achan[0].fix_bits >= RETRY_MAX) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Invalid Fix Bits level.\n");
|
dw_printf ("Invalid Fix Bits level.\n");
|
||||||
exit (EXIT_FAILURE);
|
exit (1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -376,28 +378,6 @@ int main (int argc, char *argv[])
|
||||||
decode_only = 2;
|
decode_only = 2;
|
||||||
break;
|
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 '?':
|
case '?':
|
||||||
|
|
||||||
/* Unknown option message was already printed. */
|
/* Unknown option message was already printed. */
|
||||||
|
@ -413,124 +393,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]));
|
memcpy (&my_audio_config.achan[1], &my_audio_config.achan[0], sizeof(my_audio_config.achan[0]));
|
||||||
|
|
||||||
|
|
||||||
|
@ -540,21 +402,17 @@ int main (int argc, char *argv[])
|
||||||
usage ();
|
usage ();
|
||||||
}
|
}
|
||||||
|
|
||||||
fx25_init (d_x_opt);
|
|
||||||
il2p_init (d_2_opt);
|
|
||||||
|
|
||||||
start_time = dtime_now();
|
|
||||||
|
|
||||||
while (optind < argc) {
|
|
||||||
|
|
||||||
fp = fopen(argv[optind], "rb");
|
fp = fopen(argv[optind], "rb");
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Couldn't open file for read: %s\n", argv[optind]);
|
dw_printf ("Couldn't open file for read: %s\n", argv[optind]);
|
||||||
//perror ("more info?");
|
//perror ("more info?");
|
||||||
exit (EXIT_FAILURE);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_time = time(NULL);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the file header.
|
* Read the file header.
|
||||||
* Doesn't handle all possible cases but good enough for our purposes.
|
* Doesn't handle all possible cases but good enough for our purposes.
|
||||||
|
@ -579,12 +437,12 @@ int main (int argc, char *argv[])
|
||||||
if (strncmp(chunk.id, "fmt ", 4) != 0) {
|
if (strncmp(chunk.id, "fmt ", 4) != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("WAV file error: Found \"%4.4s\" where \"fmt \" was expected.\n", chunk.id);
|
dw_printf ("WAV file error: Found \"%4.4s\" where \"fmt \" was expected.\n", chunk.id);
|
||||||
exit(EXIT_FAILURE);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (chunk.datasize != 16 && chunk.datasize != 18) {
|
if (chunk.datasize != 16 && chunk.datasize != 18) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("WAV file error: Need fmt chunk datasize of 16 or 18. Found %d.\n", chunk.datasize);
|
dw_printf ("WAV file error: Need fmt chunk datasize of 16 or 18. Found %d.\n", chunk.datasize);
|
||||||
exit(EXIT_FAILURE);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fread (&format, (size_t)chunk.datasize, (size_t)1, fp);
|
err = fread (&format, (size_t)chunk.datasize, (size_t)1, fp);
|
||||||
|
@ -594,56 +452,32 @@ int main (int argc, char *argv[])
|
||||||
if (strncmp(wav_data.data, "data", 4) != 0) {
|
if (strncmp(wav_data.data, "data", 4) != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("WAV file error: Found \"%4.4s\" where \"data\" was expected.\n", wav_data.data);
|
dw_printf ("WAV file error: Found \"%4.4s\" where \"data\" was expected.\n", wav_data.data);
|
||||||
exit(EXIT_FAILURE);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.wformattag != 1) {
|
// TODO: Should have proper message, not abort.
|
||||||
text_color_set(DW_COLOR_ERROR);
|
assert (format.nchannels == 1 || format.nchannels == 2);
|
||||||
dw_printf ("Sorry, I only understand audio format 1 (PCM). This file has %d.\n", format.wformattag);
|
assert (format.wbitspersample == 8 || format.wbitspersample == 16);
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format.nchannels != 1 && format.nchannels != 2) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Sorry, I only understand 1 or 2 channels. This file has %d.\n", format.nchannels);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format.wbitspersample != 8 && format.wbitspersample != 16) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Sorry, I only understand 8 or 16 bits per sample. This file has %d.\n", format.wbitspersample);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
my_audio_config.adev[0].samples_per_sec = format.nsamplespersec;
|
my_audio_config.adev[0].samples_per_sec = format.nsamplespersec;
|
||||||
my_audio_config.adev[0].bits_per_sample = format.wbitspersample;
|
my_audio_config.adev[0].bits_per_sample = format.wbitspersample;
|
||||||
my_audio_config.adev[0].num_channels = format.nchannels;
|
my_audio_config.adev[0].num_channels = format.nchannels;
|
||||||
|
|
||||||
my_audio_config.chan_medium[0] = MEDIUM_RADIO;
|
my_audio_config.achan[0].valid = 1;
|
||||||
if (format.nchannels == 2) {
|
if (format.nchannels == 2) my_audio_config.achan[1].valid = 1;
|
||||||
my_audio_config.chan_medium[1] = MEDIUM_RADIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("%d samples per second. %d bits per sample. %d audio channels.\n",
|
dw_printf ("%d samples per second\n", my_audio_config.adev[0].samples_per_sec);
|
||||||
my_audio_config.adev[0].samples_per_sec,
|
dw_printf ("%d bits per sample\n", my_audio_config.adev[0].bits_per_sample);
|
||||||
my_audio_config.adev[0].bits_per_sample,
|
dw_printf ("%d audio channels\n", my_audio_config.adev[0].num_channels);
|
||||||
my_audio_config.adev[0].num_channels);
|
dw_printf ("%d audio bytes in file\n", (int)(wav_data.datasize));
|
||||||
one_filetime = (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);
|
|
||||||
dw_printf ("Fix Bits level = %d\n", my_audio_config.achan[0].fix_bits);
|
dw_printf ("Fix Bits level = %d\n", my_audio_config.achan[0].fix_bits);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the AFSK demodulator and HDLC decoder.
|
* 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);
|
multi_modem_init (&my_audio_config);
|
||||||
packets_decoded_one = 0;
|
|
||||||
|
|
||||||
|
|
||||||
e_o_f = 0;
|
e_o_f = 0;
|
||||||
|
@ -662,10 +496,8 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
audio_sample = demod_get_sample (ACHAN2ADEV(c));
|
audio_sample = demod_get_sample (ACHAN2ADEV(c));
|
||||||
|
|
||||||
if (audio_sample >= 256 * 256) {
|
if (audio_sample >= 256 * 256)
|
||||||
e_o_f = 1;
|
e_o_f = 1;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == 0) sample_number++;
|
if (c == 0) sample_number++;
|
||||||
|
|
||||||
|
@ -695,34 +527,20 @@ int main (int argc, char *argv[])
|
||||||
dw_printf ("%d\n", count[j]);
|
dw_printf ("%d\n", count[j]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
dw_printf ("%d packets decoded in %d seconds.\n", packets_decoded, (int)(time(NULL) - start_time));
|
||||||
|
|
||||||
dw_printf ("%d from %s\n", packets_decoded_one, argv[optind]);
|
if (error_if_less_than != -1 && packets_decoded < error_if_less_than) {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error_if_less_than != -1 && packets_decoded_total < error_if_less_than) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\n * * * TEST FAILED: number decoded is less than %d * * * \n", error_if_less_than);
|
dw_printf ("\n * * * TEST FAILED: number decoded is less than %d * * * \n", error_if_less_than);
|
||||||
exit (EXIT_FAILURE);
|
exit (1);
|
||||||
}
|
}
|
||||||
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);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\n * * * TEST FAILED: number decoded is greater than %d * * * \n", error_if_greater_than);
|
dw_printf ("\n * * * TEST FAILED: number decoded is greater than %d * * * \n", error_if_greater_than);
|
||||||
exit (EXIT_FAILURE);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit (EXIT_SUCCESS);
|
exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -753,22 +571,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.
|
* 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_append (dlq_type_t type, int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum)
|
||||||
{
|
{
|
||||||
|
|
||||||
char stemp[500];
|
char stemp[500];
|
||||||
unsigned char *pinfo;
|
unsigned char *pinfo;
|
||||||
int info_len;
|
int info_len;
|
||||||
int h;
|
int h;
|
||||||
char heard[2 * AX25_MAX_ADDR_LEN + 20];
|
char heard[AX25_MAX_ADDR_LEN];
|
||||||
char alevel_text[AX25_ALEVEL_TO_TEXT_SIZE];
|
char alevel_text[AX25_ALEVEL_TO_TEXT_SIZE];
|
||||||
|
|
||||||
packets_decoded_one++;
|
packets_decoded++;
|
||||||
if ( ! hdlc_rec_data_detect_any(chan)) dcd_missing_errors++;
|
|
||||||
|
|
||||||
ax25_format_addrs (pp, stemp);
|
ax25_format_addrs (pp, stemp);
|
||||||
|
|
||||||
|
@ -794,7 +632,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
||||||
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf("DECODED[%d] ", packets_decoded_one );
|
dw_printf("DECODED[%d] ", packets_decoded );
|
||||||
|
|
||||||
/* Insert time stamp relative to start of file. */
|
/* Insert time stamp relative to start of file. */
|
||||||
|
|
||||||
|
@ -802,55 +640,32 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
||||||
int min = (int)(sec / 60.);
|
int min = (int)(sec / 60.);
|
||||||
sec -= min * 60;
|
sec -= min * 60;
|
||||||
|
|
||||||
dw_printf ("%d:%06.3f ", min, sec);
|
dw_printf ("%d:%07.4f ", min, sec);
|
||||||
|
|
||||||
if (h != AX25_SOURCE) {
|
if (h != AX25_SOURCE) {
|
||||||
dw_printf ("Digipeater ");
|
dw_printf ("Digipeater ");
|
||||||
}
|
}
|
||||||
ax25_alevel_to_text (alevel, alevel_text);
|
ax25_alevel_to_text (alevel, alevel_text);
|
||||||
|
|
||||||
/* As suggested by KJ4ERJ, if we are receiving from */
|
if (my_audio_config.achan[chan].fix_bits == RETRY_NONE && my_audio_config.achan[chan].passall == 0) {
|
||||||
/* WIDEn-0, it is quite likely (but not guaranteed), that */
|
dw_printf ("%s audio level = %s %s\n", heard, alevel_text, spectrum);
|
||||||
/* 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));
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
switch (fec_type) {
|
dw_printf ("%s audio level = %s [%s] %s\n", heard, alevel_text, retry_text[(int)retries], spectrum);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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.
|
// Display non-APRS packets in a different color.
|
||||||
|
|
||||||
|
@ -880,39 +695,6 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
|
||||||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
ax25_safe_print ((char *)pinfo, info_len, 0);
|
||||||
dw_printf ("\n");
|
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
|
|
||||||
|
|
||||||
#include "decode_aprs.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
if (ax25_is_aprs(pp)) {
|
|
||||||
|
|
||||||
decode_aprs_t A;
|
|
||||||
|
|
||||||
decode_aprs (&A, pp, 0, NULL);
|
|
||||||
|
|
||||||
// Temp experiment to see how different systems set the RR bits in the source and destination.
|
|
||||||
// log_rr_bits (&A, pp);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
|
|
||||||
} /* end fake dlq_append */
|
} /* end fake dlq_append */
|
||||||
|
@ -920,38 +702,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)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,39 +724,23 @@ static void usage (void) {
|
||||||
dw_printf (" atest [ options ] wav-file-in\n");
|
dw_printf (" atest [ options ] wav-file-in\n");
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" -B n Bits/second for data. Proper modem automatically selected for speed.\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 (" 300 baud uses 1600/1800 Hz AFSK.\n");
|
||||||
dw_printf (" 1200 bps uses AFSK tones of 1200 & 2200.\n");
|
dw_printf (" 1200 (default) baud uses 1200/2200 Hz AFSK.\n");
|
||||||
dw_printf (" 2400 bps uses QPSK based on V.26 standard.\n");
|
dw_printf (" 9600 baud uses K9NG/G2RUH 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 ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" -D n Divide audio sample rate by n.\n");
|
dw_printf (" -D n Divide audio sample rate by n.\n");
|
||||||
dw_printf ("\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 (" -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 (" 0 (default) = consider only correct frames. \n");
|
||||||
dw_printf (" 1 = Try to fix only a single bit. \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 (" more = Try modifying more bits to get a good CRC.\n");
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" -d x Debug information for FX.25. Repeat for more detail.\n");
|
dw_printf (" -P m Select the demodulator type such as A, B, C, D (default for 300 baud),\n");
|
||||||
dw_printf ("\n");
|
dw_printf (" E (default for 1200 baud), F, A+, B+, C+, D+, E+, F+.\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 ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" -0 Use channel 0 (left) of stereo audio (default).\n");
|
dw_printf (" -0 Use channel 0 (left) of stereo audio (default).\n");
|
||||||
dw_printf (" -1 use channel 1 (right) of stereo audio.\n");
|
dw_printf (" -1 use channel 1 (right) of stereo audio.\n");
|
||||||
dw_printf (" -2 decode both channels of stereo audio.\n");
|
dw_printf (" -1 decode both channels of stereo audio.\n");
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" wav-file-in is a WAV format audio file.\n");
|
dw_printf (" wav-file-in is a WAV format audio file.\n");
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
@ -1025,11 +759,11 @@ static void usage (void) {
|
||||||
dw_printf (" bits per second.\n");
|
dw_printf (" bits per second.\n");
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf (" atest 02_Track_2.wav\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 -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 ("\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");
|
dw_printf (" performance.\n");
|
||||||
|
|
||||||
exit (1);
|
exit (1);
|
|
@ -60,7 +60,6 @@
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -75,19 +74,21 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
|
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#elif USE_SNDIO
|
#else
|
||||||
#include <sndio.h>
|
#include <errno.h>
|
||||||
#include <poll.h>
|
#ifdef __OpenBSD__
|
||||||
|
#include <soundcard.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "audio_stats.h"
|
#include "audio_stats.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
|
@ -110,9 +111,6 @@ static struct adev_s {
|
||||||
|
|
||||||
int bytes_per_frame; /* number of bytes for a sample from all channels. */
|
int bytes_per_frame; /* number of bytes for a sample from all channels. */
|
||||||
/* e.g. 4 for stereo 16 bit. */
|
/* e.g. 4 for stereo 16 bit. */
|
||||||
#elif USE_SNDIO
|
|
||||||
struct sio_hdl *sndio_in_handle;
|
|
||||||
struct sio_hdl *sndio_out_handle;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
int oss_audio_device_fd; /* Single device, both directions. */
|
int oss_audio_device_fd; /* Single device, both directions. */
|
||||||
|
@ -143,9 +141,6 @@ static struct adev_s {
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *name, char *dir);
|
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);
|
//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
|
#else
|
||||||
static int set_oss_params (int a, int fd, struct audio_s *pa);
|
static int set_oss_params (int a, int fd, struct audio_s *pa);
|
||||||
#endif
|
#endif
|
||||||
|
@ -206,7 +201,7 @@ static int calcbufsize(int rate, int chans, int bits)
|
||||||
* more restrictive in its capabilities.
|
* more restrictive in its capabilities.
|
||||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
* 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
|
* that the device is supplying, that could be different
|
||||||
* than what the user specified.
|
* 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)
|
int audio_open (struct audio_s *pa)
|
||||||
{
|
{
|
||||||
#if !USE_SNDIO
|
|
||||||
int err;
|
int err;
|
||||||
#endif
|
|
||||||
int chan;
|
int chan;
|
||||||
int a;
|
int a;
|
||||||
char audio_in_name[30];
|
char audio_in_name[30];
|
||||||
|
@ -231,11 +224,7 @@ int audio_open (struct audio_s *pa)
|
||||||
memset (adev, 0, sizeof(adev));
|
memset (adev, 0, sizeof(adev));
|
||||||
|
|
||||||
for (a=0; a<MAX_ADEVS; a++) {
|
for (a=0; a<MAX_ADEVS; a++) {
|
||||||
#if USE_ALSA
|
#ifndef 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
|
|
||||||
adev[a].oss_audio_device_fd = -1;
|
adev[a].oss_audio_device_fd = -1;
|
||||||
#endif
|
#endif
|
||||||
adev[a].udp_sock = -1;
|
adev[a].udp_sock = -1;
|
||||||
|
@ -354,33 +343,11 @@ int audio_open (struct audio_s *pa)
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not open audio device %s for input\n%s\n",
|
dw_printf ("Could not open audio device %s for input\n%s\n",
|
||||||
audio_in_name, snd_strerror(err));
|
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);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
adev[a].inbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_in_handle, pa, audio_in_name, "input");
|
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
|
#else // OSS
|
||||||
adev[a].oss_audio_device_fd = open (pa->adev[a].adevice_in, O_RDWR);
|
adev[a].oss_audio_device_fd = open (pa->adev[a].adevice_in, O_RDWR);
|
||||||
|
|
||||||
|
@ -408,8 +375,8 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
{
|
{
|
||||||
struct sockaddr_in si_me;
|
struct sockaddr_in si_me;
|
||||||
//int slen=sizeof(si_me);
|
int slen=sizeof(si_me);
|
||||||
//int data_size = 0;
|
int data_size = 0;
|
||||||
|
|
||||||
//Create UDP Socket
|
//Create UDP Socket
|
||||||
if ((adev[a].udp_sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
|
if ((adev[a].udp_sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
|
||||||
|
@ -463,10 +430,6 @@ int audio_open (struct audio_s *pa)
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not open audio device %s for output\n%s\n",
|
dw_printf ("Could not open audio device %s for output\n%s\n",
|
||||||
audio_out_name, snd_strerror(err));
|
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);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,27 +439,6 @@ int audio_open (struct audio_s *pa)
|
||||||
return (-1);
|
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
|
#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 */
|
} /* 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
|
#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.
|
* This was long ago under different conditions.
|
||||||
* Should study this again some day.
|
* Should study this again some day.
|
||||||
*
|
*
|
||||||
* Your mileage may vary.
|
* Your milage may vary.
|
||||||
*/
|
*/
|
||||||
err = ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &ossbuf_size_in_bytes);
|
err = ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &ossbuf_size_in_bytes);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
@ -1006,9 +842,7 @@ __attribute__((hot))
|
||||||
int audio_get (int a)
|
int audio_get (int a)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
#if USE_ALSA
|
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if STATISTICS
|
#if STATISTICS
|
||||||
/* Gather numbers for read from audio device. */
|
/* Gather numbers for read from audio device. */
|
||||||
|
@ -1087,24 +921,11 @@ int audio_get (int a)
|
||||||
/* Error */
|
/* Error */
|
||||||
// TODO: Needs more study and testing.
|
// TODO: Needs more study and testing.
|
||||||
|
|
||||||
// Only expected error conditions:
|
// TODO: print n. should snd_strerror use n or errno?
|
||||||
// -EBADFD PCM is not in the right state (SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING)
|
// Audio input device error: Unknown error
|
||||||
// -EPIPE an overrun occurred
|
|
||||||
// -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery)
|
|
||||||
|
|
||||||
// Data overrun is displayed as "broken pipe" which seems a little misleading.
|
|
||||||
// Add our own message which says something about CPU being too slow.
|
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Audio input device %d error code %d: %s\n", a, n, snd_strerror(n));
|
dw_printf ("Audio input device %d error: %s\n", a, snd_strerror(n));
|
||||||
|
|
||||||
if (n == (-EPIPE)) {
|
|
||||||
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,
|
audio_stats (a,
|
||||||
save_audio_config_p->adev[a].num_channels,
|
save_audio_config_p->adev[a].num_channels,
|
||||||
|
@ -1138,28 +959,7 @@ int audio_get (int a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif USE_SNDIO
|
#else /* end ALSA, begin OSS */
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
/* Fixed in 1.2. This was formerly outside of the switch */
|
/* Fixed in 1.2. This was formerly outside of the switch */
|
||||||
/* so the OSS version did not process stdin or UDP. */
|
/* so the OSS version did not process stdin or UDP. */
|
||||||
|
@ -1203,7 +1003,7 @@ int audio_get (int a)
|
||||||
case AUDIO_IN_TYPE_SDR_UDP:
|
case AUDIO_IN_TYPE_SDR_UDP:
|
||||||
|
|
||||||
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
||||||
int res;
|
int ch, res,i;
|
||||||
|
|
||||||
assert (adev[a].udp_sock > 0);
|
assert (adev[a].udp_sock > 0);
|
||||||
res = recv(adev[a].udp_sock, adev[a].inbuf_ptr, adev[a].inbuf_size_in_bytes, 0);
|
res = recv(adev[a].udp_sock, adev[a].inbuf_ptr, adev[a].inbuf_size_in_bytes, 0);
|
||||||
|
@ -1238,8 +1038,7 @@ int audio_get (int a)
|
||||||
case AUDIO_IN_TYPE_STDIN:
|
case AUDIO_IN_TYPE_STDIN:
|
||||||
|
|
||||||
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
while (adev[a].inbuf_next >= adev[a].inbuf_len) {
|
||||||
//int ch, res,i;
|
int ch, res,i;
|
||||||
int res;
|
|
||||||
|
|
||||||
res = read(STDIN_FILENO, adev[a].inbuf_ptr, (size_t)adev[a].inbuf_size_in_bytes);
|
res = read(STDIN_FILENO, adev[a].inbuf_ptr, (size_t)adev[a].inbuf_size_in_bytes);
|
||||||
if (res <= 0) {
|
if (res <= 0) {
|
||||||
|
@ -1335,7 +1134,7 @@ int audio_flush (int a)
|
||||||
{
|
{
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
int k;
|
int k;
|
||||||
unsigned char *psound;
|
char *psound;
|
||||||
int retries = 10;
|
int retries = 10;
|
||||||
snd_pcm_status_t *status;
|
snd_pcm_status_t *status;
|
||||||
|
|
||||||
|
@ -1393,17 +1192,6 @@ int audio_flush (int a)
|
||||||
|
|
||||||
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
|
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) {
|
else if (k < 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Audio write error: %s\n", snd_strerror(k));
|
dw_printf ("Audio write error: %s\n", snd_strerror(k));
|
||||||
|
@ -1411,10 +1199,7 @@ int audio_flush (int a)
|
||||||
/* Some other error condition. */
|
/* Some other error condition. */
|
||||||
/* Try again. What do we have to lose? */
|
/* Try again. What do we have to lose? */
|
||||||
|
|
||||||
k = snd_pcm_prepare (adev[a].audio_out_handle);
|
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
|
||||||
if(k < 0) {
|
|
||||||
dw_printf ("Error preparing after error: %s\n", snd_strerror(k));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) {
|
else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -1439,37 +1224,6 @@ int audio_flush (int a)
|
||||||
adev[a].outbuf_len = 0;
|
adev[a].outbuf_len = 0;
|
||||||
return (-1);
|
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 */
|
#else /* OSS */
|
||||||
|
|
||||||
int k;
|
int k;
|
||||||
|
@ -1540,7 +1294,7 @@ int audio_flush (int a)
|
||||||
* (3) Call this function, which might or might not wait long enough.
|
* (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.
|
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||||
* (5) Take difference between current time and desired PPT off time
|
* (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 +1325,6 @@ void audio_wait (int a)
|
||||||
* Either way, the caller will now compensate for it.
|
* Either way, the caller will now compensate for it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#elif USE_SNDIO
|
|
||||||
|
|
||||||
poll_sndio (adev[a].sndio_out_handle, POLLOUT);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
assert (adev[a].oss_audio_device_fd > 0);
|
assert (adev[a].oss_audio_device_fd > 0);
|
||||||
|
@ -1620,22 +1370,7 @@ int audio_close (void)
|
||||||
|
|
||||||
snd_pcm_close (adev[a].audio_in_handle);
|
snd_pcm_close (adev[a].audio_in_handle);
|
||||||
snd_pcm_close (adev[a].audio_out_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
|
#else
|
||||||
|
|
||||||
if (adev[a].oss_audio_device_fd > 0) {
|
if (adev[a].oss_audio_device_fd > 0) {
|
|
@ -0,0 +1,342 @@
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Module: audio.h
|
||||||
|
*
|
||||||
|
* Purpose: Interface to audio device commonly called a "sound card"
|
||||||
|
* for historical reasons.
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AUDIO_H
|
||||||
|
#define AUDIO_H 1
|
||||||
|
|
||||||
|
#ifdef USE_HAMLIB
|
||||||
|
#include <hamlib/rig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "direwolf.h" /* for MAX_CHANS used throughout the application. */
|
||||||
|
#include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PTT control.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ptt_method_e {
|
||||||
|
PTT_METHOD_NONE, /* VOX or no transmit. */
|
||||||
|
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
|
||||||
|
PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */
|
||||||
|
PTT_METHOD_LPT, /* Parallel printer port, Linux only. */
|
||||||
|
PTT_METHOD_HAMLIB }; /* HAMLib, Linux only. */
|
||||||
|
|
||||||
|
typedef enum ptt_method_e ptt_method_t;
|
||||||
|
|
||||||
|
enum ptt_line_e { PTT_LINE_NONE = 0, PTT_LINE_RTS = 1, PTT_LINE_DTR = 2 }; // Important: 0 for neither.
|
||||||
|
typedef enum ptt_line_e ptt_line_t;
|
||||||
|
|
||||||
|
enum audio_in_type_e {
|
||||||
|
AUDIO_IN_TYPE_SOUNDCARD,
|
||||||
|
AUDIO_IN_TYPE_SDR_UDP,
|
||||||
|
AUDIO_IN_TYPE_STDIN };
|
||||||
|
|
||||||
|
/* For option to try fixing frames with bad CRC. */
|
||||||
|
|
||||||
|
typedef enum retry_e {
|
||||||
|
RETRY_NONE=0,
|
||||||
|
RETRY_INVERT_SINGLE=1,
|
||||||
|
RETRY_INVERT_DOUBLE=2,
|
||||||
|
RETRY_INVERT_TRIPLE=3,
|
||||||
|
RETRY_INVERT_TWO_SEP=4,
|
||||||
|
RETRY_MAX = 5} retry_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct audio_s {
|
||||||
|
|
||||||
|
/* Previously we could handle only a single audio device. */
|
||||||
|
/* In version 1.2, we generalize this to handle multiple devices. */
|
||||||
|
/* This means we can now have more than 2 radio channels. */
|
||||||
|
|
||||||
|
struct adev_param_s {
|
||||||
|
|
||||||
|
/* Properites of the sound device. */
|
||||||
|
|
||||||
|
int defined; /* Was device defined? */
|
||||||
|
/* First one defaults to yes. */
|
||||||
|
|
||||||
|
char adevice_in[80]; /* Name of the audio input device (or file?). */
|
||||||
|
/* TODO: Can be "-" to read from stdin. */
|
||||||
|
|
||||||
|
char adevice_out[80]; /* Name of the audio output device (or file?). */
|
||||||
|
|
||||||
|
int num_channels; /* Should be 1 for mono or 2 for stereo. */
|
||||||
|
int samples_per_sec; /* Audio sampling rate. Typically 11025, 22050, or 44100. */
|
||||||
|
int bits_per_sample; /* 8 (unsigned char) or 16 (signed short). */
|
||||||
|
|
||||||
|
} adev[MAX_ADEVS];
|
||||||
|
|
||||||
|
|
||||||
|
/* Common to all channels. */
|
||||||
|
|
||||||
|
char tts_script[80]; /* Script for text to speech. */
|
||||||
|
|
||||||
|
int statistics_interval; /* Number of seconds between the audio */
|
||||||
|
/* statistics reports. This is set by */
|
||||||
|
/* the "-a" option. 0 to disable feature. */
|
||||||
|
|
||||||
|
/* Properties for each audio channel, common to receive and transmit. */
|
||||||
|
/* Can be different for each radio channel. */
|
||||||
|
|
||||||
|
|
||||||
|
struct achan_param_s {
|
||||||
|
|
||||||
|
int valid; /* Is this channel valid? */
|
||||||
|
|
||||||
|
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_OFF } modem_type;
|
||||||
|
|
||||||
|
/* Usual AFSK. */
|
||||||
|
/* Baseband signal. Not used yet. */
|
||||||
|
/* Scrambled http://www.amsat.org/amsat/articles/g3ruh/109/fig03.gif */
|
||||||
|
/* No modem. Might want this for DTMF only channel. */
|
||||||
|
|
||||||
|
|
||||||
|
enum dtmf_decode_t { DTMF_DECODE_OFF, DTMF_DECODE_ON } dtmf_decode;
|
||||||
|
|
||||||
|
/* Originally the DTMF ("Touch Tone") decoder was always */
|
||||||
|
/* enabled because it took a negligible amount of CPU. */
|
||||||
|
/* There were complaints about the false positives when */
|
||||||
|
/* hearing other modulation schemes on HF SSB so now it */
|
||||||
|
/* is enabled only when needed. */
|
||||||
|
|
||||||
|
/* "On" will send special "t" packet to attached applications */
|
||||||
|
/* and process as APRStt. Someday we might want to separate */
|
||||||
|
/* these but for now, we have a single off/on. */
|
||||||
|
|
||||||
|
int decimate; /* Reduce AFSK sample rate by this factor to */
|
||||||
|
/* decrease computational requirements. */
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
int baud; /* Data bits (more accurately, symbols) per second. */
|
||||||
|
/* Standard rates are 1200 for VHF and 300 for HF. */
|
||||||
|
|
||||||
|
/* Next 3 come from config file or command line. */
|
||||||
|
|
||||||
|
char profiles[16]; /* zero or more of ABC etc, optional + */
|
||||||
|
|
||||||
|
int num_freq; /* Number of different frequency pairs for decoders. */
|
||||||
|
|
||||||
|
int offset; /* Spacing between filter frequencies. */
|
||||||
|
|
||||||
|
int num_slicers; /* Number of different threshold points to decide */
|
||||||
|
/* between mark or space. */
|
||||||
|
|
||||||
|
/* This is derived from above by demod_init. */
|
||||||
|
|
||||||
|
int num_subchan; /* Total number of modems for each channel. */
|
||||||
|
|
||||||
|
|
||||||
|
/* These are for dealing with imperfect frames. */
|
||||||
|
|
||||||
|
enum retry_e fix_bits; /* Level of effort to recover from */
|
||||||
|
/* a bad FCS on the frame. */
|
||||||
|
/* 0 = no effort */
|
||||||
|
/* 1 = try fixing a single bit */
|
||||||
|
/* 2... = more techniques... */
|
||||||
|
|
||||||
|
enum sanity_e sanity_test; /* Sanity test to apply when finding a good */
|
||||||
|
/* CRC after making a change. */
|
||||||
|
/* Must look like APRS, AX.25, or anything. */
|
||||||
|
|
||||||
|
int passall; /* Allow thru even with bad CRC. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Additional properties for transmit. */
|
||||||
|
|
||||||
|
/* Originally we had control outputs only for PTT. */
|
||||||
|
/* In version 1.2, we generalize this to allow others such as DCD. */
|
||||||
|
/* Index following structure by one of these: */
|
||||||
|
|
||||||
|
|
||||||
|
#define OCTYPE_PTT 0
|
||||||
|
#define OCTYPE_DCD 1
|
||||||
|
#define OCTYPE_FUTURE 2
|
||||||
|
|
||||||
|
#define NUM_OCTYPES 4 /* number of values above */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
|
||||||
|
ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB. */
|
||||||
|
|
||||||
|
char ptt_device[20]; /* Serial device name for PTT. e.g. COM1 or /dev/ttyS0 */
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
int ptt_gpio; /* GPIO number. */
|
||||||
|
|
||||||
|
int ptt_lpt_bit; /* Bit number for parallel printer port. */
|
||||||
|
/* Bit 0 = pin 2, ..., bit 7 = pin 9. */
|
||||||
|
|
||||||
|
int ptt_invert; /* Invert the output. */
|
||||||
|
int ptt_invert2; /* Invert the secondary output. */
|
||||||
|
|
||||||
|
#ifdef USE_HAMLIB
|
||||||
|
int ptt_rig; /* HAMLib rig. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} octrl[NUM_OCTYPES];
|
||||||
|
|
||||||
|
#define ICTYPE_TXINH 0
|
||||||
|
|
||||||
|
#define NUM_ICTYPES 1
|
||||||
|
|
||||||
|
struct {
|
||||||
|
ptt_method_t method; /* none, serial port, GPIO, LPT. */
|
||||||
|
int gpio; /* GPIO number */
|
||||||
|
int invert; /* 1 = active low */
|
||||||
|
} ictrl[NUM_ICTYPES];
|
||||||
|
|
||||||
|
/* Transmit timing. */
|
||||||
|
|
||||||
|
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 persistance algorithm. */
|
||||||
|
/* Typical value is 10 meaning 100 milliseconds. */
|
||||||
|
|
||||||
|
int persist; /* Sets probability for transmitting after each */
|
||||||
|
/* slot time delay. Transmit if a random number */
|
||||||
|
/* in range of 0 - 255 <= persist value. */
|
||||||
|
/* Otherwise wait another slot time and try again. */
|
||||||
|
/* Default value is 63 for 25% probability. */
|
||||||
|
|
||||||
|
int txdelay; /* After turning on the transmitter, */
|
||||||
|
/* send "flags" for txdelay * 10 mS. */
|
||||||
|
/* Default value is 30 meaning 300 milliseconds. */
|
||||||
|
|
||||||
|
int txtail; /* Amount of time to keep transmitting after we */
|
||||||
|
/* are done sending the data. This is to avoid */
|
||||||
|
/* dropping PTT too soon and chopping off the end */
|
||||||
|
/* of the frame. Again 10 mS units. */
|
||||||
|
/* At this point, I'm thinking of 10 as the default. */
|
||||||
|
|
||||||
|
} achan[MAX_CHANS];
|
||||||
|
|
||||||
|
#ifdef USE_HAMLIB
|
||||||
|
int rigs; /* Total number of configured rigs */
|
||||||
|
RIG *rig[MAX_RIGS]; /* HAMLib rig instances */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__ || __APPLE__
|
||||||
|
#define DEFAULT_ADEVICE "" /* Windows: Empty string = default audio device. */
|
||||||
|
#else
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UDP audio receiving port. Couldn't find any standard or usage precedent.
|
||||||
|
* Got the number from this example: http://gqrx.dk/doc/streaming-audio-over-udp
|
||||||
|
* Any better suggestions?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEFAULT_UDP_AUDIO_PORT 7355
|
||||||
|
|
||||||
|
|
||||||
|
// Maximum size of the UDP buffer (for allowing IP routing, udp packets are often limited to 1472 bytes)
|
||||||
|
|
||||||
|
#define SDR_UDP_BUF_MAXLEN 2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_NUM_CHANNELS 1
|
||||||
|
#define DEFAULT_SAMPLES_PER_SEC 44100 /* Very early observations. Might no longer be valid. */
|
||||||
|
/* 22050 works a lot better than 11025. */
|
||||||
|
/* 44100 works a little better than 22050. */
|
||||||
|
/* If you have a reasonable machine, use the highest rate. */
|
||||||
|
#define MIN_SAMPLES_PER_SEC 8000
|
||||||
|
#define MAX_SAMPLES_PER_SEC 48000 /* Formerly 44100. */
|
||||||
|
/* Software defined radio often uses 48000. */
|
||||||
|
|
||||||
|
#define DEFAULT_BITS_PER_SAMPLE 16
|
||||||
|
|
||||||
|
#define DEFAULT_FIX_BITS RETRY_INVERT_SINGLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standard for AFSK on VHF FM.
|
||||||
|
* Reversing mark and space makes no difference because
|
||||||
|
* NRZI encoding only cares about change or lack of change
|
||||||
|
* between the two tones.
|
||||||
|
*
|
||||||
|
* HF SSB uses 300 baud and 200 Hz shift.
|
||||||
|
* 1600 & 1800 Hz is a popular tone pair, sometimes
|
||||||
|
* called the KAM tones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEFAULT_MARK_FREQ 1200
|
||||||
|
#define DEFAULT_SPACE_FREQ 2200
|
||||||
|
#define DEFAULT_BAUD 1200
|
||||||
|
|
||||||
|
/* Used for sanity checking in config file and command line options. */
|
||||||
|
/* 9600 is known to work. */
|
||||||
|
/* TODO: Is 19200 possible with a soundcard at 44100 samples/sec? */
|
||||||
|
|
||||||
|
#define MIN_BAUD 100
|
||||||
|
#define MAX_BAUD 10000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Typical transmit timings for VHF.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEFAULT_DWAIT 0
|
||||||
|
#define DEFAULT_SLOTTIME 10
|
||||||
|
#define DEFAULT_PERSIST 63
|
||||||
|
#define DEFAULT_TXDELAY 30
|
||||||
|
#define DEFAULT_TXTAIL 10
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that we have two versions of these in audio.c and audio_win.c.
|
||||||
|
* Use one or the other depending on the platform.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int audio_open (struct audio_s *pa);
|
||||||
|
|
||||||
|
int audio_get (int a); /* a = audio device, 0 for first */
|
||||||
|
|
||||||
|
int audio_put (int a, int c);
|
||||||
|
|
||||||
|
int audio_flush (int a);
|
||||||
|
|
||||||
|
void audio_wait (int a);
|
||||||
|
|
||||||
|
int audio_close (void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ifdef AUDIO_H */
|
||||||
|
|
||||||
|
|
||||||
|
/* end audio.h */
|
||||||
|
|
|
@ -37,8 +37,6 @@
|
||||||
|
|
||||||
#if defined(USE_PORTAUDIO)
|
#if defined(USE_PORTAUDIO)
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -56,6 +54,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "audio_stats.h"
|
#include "audio_stats.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
|
@ -156,7 +155,7 @@ static int calcbufsize(int rate, int chans, int bits)
|
||||||
* the same device name for more then one connected device
|
* the same device name for more then one connected device
|
||||||
* (ie two SignaLinks). Appending a Portaudio device index to the
|
* (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
|
* 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)
|
static int searchPADevice(struct adev_s *dev, char *_devName, int reqDeviceNo, int io_flag)
|
||||||
{
|
{
|
||||||
|
@ -213,21 +212,7 @@ static int pa_devNN(char *deviceStr, char *_devName, size_t length, int *_devNo)
|
||||||
while(*cPtr) {
|
while(*cPtr) {
|
||||||
cVal = *cPtr++;
|
cVal = *cPtr++;
|
||||||
if(cVal == ':') break;
|
if(cVal == ':') break;
|
||||||
|
if(((cVal >= ' ') && (cVal <= '~')) && (count < length)) {
|
||||||
// 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) {
|
|
||||||
_devName[count++] = cVal;
|
_devName[count++] = cVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +512,7 @@ static int paOutput16CB( const void *inputBuffer, void *outputBuffer,
|
||||||
* more restrictive in its capabilities.
|
* more restrictive in its capabilities.
|
||||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
* 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
|
* that the device is supplying, that could be different
|
||||||
* than what the user specified.
|
* than what the user specified.
|
||||||
*
|
*
|
||||||
|
@ -1163,7 +1148,7 @@ int audio_put (int a, int c)
|
||||||
static double start = 0, end = 0, diff = 0;
|
static double start = 0, end = 0, diff = 0;
|
||||||
|
|
||||||
if(adev[a].outbuf_len == 0)
|
if(adev[a].outbuf_len == 0)
|
||||||
start = dtime_monotonic();
|
start = dtime_now();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(c >= 0) {
|
if(c >= 0) {
|
||||||
|
@ -1192,7 +1177,7 @@ int audio_put (int a, int c)
|
||||||
#ifdef __TIMED__
|
#ifdef __TIMED__
|
||||||
count += frames;
|
count += frames;
|
||||||
if(c < 0) { // When the Ax25 frames are flushed.
|
if(c < 0) { // When the Ax25 frames are flushed.
|
||||||
end = dtime_monotonic();
|
end = dtime_now();
|
||||||
diff = end - start;
|
diff = end - start;
|
||||||
if(count)
|
if(count)
|
||||||
dw_printf ("Transfer Time:%3.9f No of Frames:%d Per frame:%3.9f speed:%f\n",
|
dw_printf ("Transfer Time:%3.9f No of Frames:%d Per frame:%3.9f speed:%f\n",
|
||||||
|
@ -1260,7 +1245,7 @@ int audio_flush (int a)
|
||||||
* (3) Call this function, which might or might not wait long enough.
|
* (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.
|
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||||
* (5) Take difference between current time and desired PPT off time
|
* (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.
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------*/
|
*----------------------------------------------------------------*/
|
||||||
|
|
|
@ -50,9 +50,6 @@
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -60,11 +57,11 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "audio_stats.h"
|
#include "audio_stats.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
|
#include "dtime_now.h"
|
||||||
#include "demod.h" /* for alevel_t & demod_get_audio_level() */
|
#include "demod.h" /* for alevel_t & demod_get_audio_level() */
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,6 @@
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include "direwolf.h" // Sets _WIN32_WINNT for XP API level needed by ws2tcpip.h
|
|
||||||
// Also includes windows.h.
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -52,6 +48,7 @@
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
|
|
||||||
#ifndef WAVE_FORMAT_96M16
|
#ifndef WAVE_FORMAT_96M16
|
||||||
|
@ -60,9 +57,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h> // _WIN32_WINNT must be set to 0x0501 before including this
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "audio_stats.h"
|
#include "audio_stats.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
|
@ -84,7 +83,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
|
* 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.
|
* it was really about 50 mS per buffer or about 20 per second.
|
||||||
|
@ -209,7 +208,7 @@ static struct adev_s {
|
||||||
* more restrictive in its capabilities.
|
* more restrictive in its capabilities.
|
||||||
* It might say, the best I can do is mono, 8 bit, 8000/sec.
|
* 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
|
* that the device is supplying, that could be different
|
||||||
* than what the user specified.
|
* than what the user specified.
|
||||||
*
|
*
|
||||||
|
@ -222,8 +221,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 in_callback (HWAVEIN handle, UINT msg, DWORD instance, DWORD param1, DWORD param2);
|
||||||
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);
|
||||||
|
|
||||||
int audio_open (struct audio_s *pa)
|
int audio_open (struct audio_s *pa)
|
||||||
{
|
{
|
||||||
|
@ -287,7 +286,7 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
A->udp_sock = INVALID_SOCKET;
|
A->udp_sock = INVALID_SOCKET;
|
||||||
|
|
||||||
in_dev_no[a] = WAVE_MAPPER; /* = ((UINT)-1) in mmsystem.h */
|
in_dev_no[a] = WAVE_MAPPER; /* = -1 */
|
||||||
out_dev_no[a] = WAVE_MAPPER;
|
out_dev_no[a] = WAVE_MAPPER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -313,28 +312,23 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
/* Does config file have a number? */
|
/* Does config file have a number? */
|
||||||
/* If so, it is an index into list of devices. */
|
/* If so, it is an index into list of devices. */
|
||||||
/* Originally only a single digit was recognized. */
|
|
||||||
/* v 1.5 also recognizes two digits. (Issue 116) */
|
|
||||||
|
|
||||||
if (strlen(pa->adev[a].adevice_in) == 1 && isdigit(pa->adev[a].adevice_in[0])) {
|
if (strlen(pa->adev[a].adevice_in) == 1 && isdigit(pa->adev[a].adevice_in[0])) {
|
||||||
in_dev_no[a] = atoi(pa->adev[a].adevice_in);
|
in_dev_no[a] = atoi(pa->adev[a].adevice_in);
|
||||||
}
|
}
|
||||||
else if (strlen(pa->adev[a].adevice_in) == 2 && isdigit(pa->adev[a].adevice_in[0]) && isdigit(pa->adev[a].adevice_in[1])) {
|
|
||||||
in_dev_no[a] = atoi(pa->adev[a].adevice_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, does it have search string? */
|
/* Otherwise, does it have search string? */
|
||||||
|
|
||||||
if ((UINT)(in_dev_no[a]) == WAVE_MAPPER && strlen(pa->adev[a].adevice_in) >= 1) {
|
if (in_dev_no[a] == WAVE_MAPPER && strlen(pa->adev[a].adevice_in) >= 1) {
|
||||||
num_devices = waveInGetNumDevs();
|
num_devices = waveInGetNumDevs();
|
||||||
for (n=0 ; n<num_devices && (UINT)(in_dev_no[a]) == WAVE_MAPPER ; n++) {
|
for (n=0 ; n<num_devices && in_dev_no[a] == WAVE_MAPPER ; n++) {
|
||||||
if ( ! waveInGetDevCaps(n, &wic, sizeof(WAVEINCAPS))) {
|
if ( ! waveInGetDevCaps(n, &wic, sizeof(WAVEINCAPS))) {
|
||||||
if (strstr(wic.szPname, pa->adev[a].adevice_in) != NULL) {
|
if (strstr(wic.szPname, pa->adev[a].adevice_in) != NULL) {
|
||||||
in_dev_no[a] = n;
|
in_dev_no[a] = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((UINT)(in_dev_no[a]) == WAVE_MAPPER) {
|
if (in_dev_no[a] == WAVE_MAPPER) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\"%s\" doesn't match any of the input devices.\n", pa->adev[a].adevice_in);
|
dw_printf ("\"%s\" doesn't match any of the input devices.\n", pa->adev[a].adevice_in);
|
||||||
}
|
}
|
||||||
|
@ -349,20 +343,17 @@ int audio_open (struct audio_s *pa)
|
||||||
if (strlen(pa->adev[a].adevice_out) == 1 && isdigit(pa->adev[a].adevice_out[0])) {
|
if (strlen(pa->adev[a].adevice_out) == 1 && isdigit(pa->adev[a].adevice_out[0])) {
|
||||||
out_dev_no[a] = atoi(pa->adev[a].adevice_out);
|
out_dev_no[a] = atoi(pa->adev[a].adevice_out);
|
||||||
}
|
}
|
||||||
else if (strlen(pa->adev[a].adevice_out) == 2 && isdigit(pa->adev[a].adevice_out[0]) && isdigit(pa->adev[a].adevice_out[1])) {
|
|
||||||
out_dev_no[a] = atoi(pa->adev[a].adevice_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((UINT)(out_dev_no[a]) == WAVE_MAPPER && strlen(pa->adev[a].adevice_out) >= 1) {
|
if (out_dev_no[a] == WAVE_MAPPER && strlen(pa->adev[a].adevice_out) >= 1) {
|
||||||
num_devices = waveOutGetNumDevs();
|
num_devices = waveOutGetNumDevs();
|
||||||
for (n=0 ; n<num_devices && (UINT)(out_dev_no[a]) == WAVE_MAPPER ; n++) {
|
for (n=0 ; n<num_devices && out_dev_no[a] == WAVE_MAPPER ; n++) {
|
||||||
if ( ! waveOutGetDevCaps(n, &woc, sizeof(WAVEOUTCAPS))) {
|
if ( ! waveOutGetDevCaps(n, &woc, sizeof(WAVEOUTCAPS))) {
|
||||||
if (strstr(woc.szPname, pa->adev[a].adevice_out) != NULL) {
|
if (strstr(woc.szPname, pa->adev[a].adevice_out) != NULL) {
|
||||||
out_dev_no[a] = n;
|
out_dev_no[a] = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((UINT)(out_dev_no[a]) == WAVE_MAPPER) {
|
if (out_dev_no[a] == WAVE_MAPPER) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\"%s\" doesn't match any of the output devices.\n", pa->adev[a].adevice_out);
|
dw_printf ("\"%s\" doesn't match any of the output devices.\n", pa->adev[a].adevice_out);
|
||||||
}
|
}
|
||||||
|
@ -561,8 +552,6 @@ int audio_open (struct audio_s *pa)
|
||||||
*/
|
*/
|
||||||
case AUDIO_IN_TYPE_SOUNDCARD:
|
case AUDIO_IN_TYPE_SOUNDCARD:
|
||||||
|
|
||||||
// Use InitializeCriticalSectionAndSpinCount to avoid exceptions in low memory situations?
|
|
||||||
|
|
||||||
InitializeCriticalSection (&(A->in_cs));
|
InitializeCriticalSection (&(A->in_cs));
|
||||||
|
|
||||||
err = waveInOpen (&(A->audio_in_handle), in_dev_no[a], &wf, (DWORD_PTR)in_callback, a, CALLBACK_FUNCTION);
|
err = waveInOpen (&(A->audio_in_handle), in_dev_no[a], &wf, (DWORD_PTR)in_callback, a, CALLBACK_FUNCTION);
|
||||||
|
@ -686,25 +675,24 @@ int audio_open (struct audio_s *pa)
|
||||||
* Called when input audio block is ready.
|
* 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;
|
int a = instance;
|
||||||
|
|
||||||
|
//dw_printf ("in_callback, handle = %d, a = %d\n", (int)handle, a);
|
||||||
|
|
||||||
assert (a >= 0 && a < MAX_ADEVS);
|
assert (a >= 0 && a < MAX_ADEVS);
|
||||||
struct adev_s *A = &(adev[a]);
|
struct adev_s *A = &(adev[a]);
|
||||||
|
|
||||||
|
|
||||||
if (msg == WIM_DATA) {
|
if (msg == WIM_DATA) {
|
||||||
|
|
||||||
WAVEHDR *p = (WAVEHDR*)param1;
|
WAVEHDR *p = (WAVEHDR*)param1;
|
||||||
|
|
||||||
p->dwUser = 0x5a5a5a5a; /* needs to be unprepared. */
|
p->dwUser = -1; /* needs to be unprepared. */
|
||||||
/* dwUser can be 32 or 64 bit unsigned int. */
|
|
||||||
p->lpNext = NULL;
|
p->lpNext = NULL;
|
||||||
|
|
||||||
// dw_printf ("dwBytesRecorded = %ld\n", p->dwBytesRecorded);
|
|
||||||
|
|
||||||
EnterCriticalSection (&(A->in_cs));
|
EnterCriticalSection (&(A->in_cs));
|
||||||
|
|
||||||
if (A->in_headp == NULL) {
|
if (A->in_headp == NULL) {
|
||||||
|
@ -729,7 +717,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) {
|
if (msg == WOM_DONE) {
|
||||||
|
|
||||||
|
@ -810,7 +798,7 @@ int audio_get (int a)
|
||||||
|
|
||||||
p = (WAVEHDR*)(A->in_headp); /* no need to be volatile at this point */
|
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 == -1) {
|
||||||
waveInUnprepareHeader(A->audio_in_handle, p, sizeof(WAVEHDR));
|
waveInUnprepareHeader(A->audio_in_handle, p, sizeof(WAVEHDR));
|
||||||
p->dwUser = 0; /* Index for next byte. */
|
p->dwUser = 0; /* Index for next byte. */
|
||||||
|
|
||||||
|
@ -853,7 +841,7 @@ int audio_get (int a)
|
||||||
|
|
||||||
assert (A->udp_sock > 0);
|
assert (A->udp_sock > 0);
|
||||||
|
|
||||||
res = SOCK_RECV (A->udp_sock, A->stream_data, SDR_UDP_BUF_MAXLEN);
|
res = recv (A->udp_sock, A->stream_data, SDR_UDP_BUF_MAXLEN, 0);
|
||||||
if (res <= 0) {
|
if (res <= 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Can't read from udp socket, errno %d", WSAGetLastError());
|
dw_printf ("Can't read from udp socket, errno %d", WSAGetLastError());
|
||||||
|
@ -923,7 +911,7 @@ int audio_get (int a)
|
||||||
* c - One byte in range of 0 - 255.
|
* 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.
|
* Returns: Normally non-negative.
|
||||||
* -1 for any type of error.
|
* -1 for any type of error.
|
||||||
|
@ -954,15 +942,7 @@ int audio_put (int a, int c)
|
||||||
timeout--;
|
timeout--;
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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 ("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 ();
|
ptt_term ();
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
@ -979,11 +959,11 @@ int audio_put (int a, int c)
|
||||||
/* Should never be full at this point. */
|
/* Should never be full at this point. */
|
||||||
|
|
||||||
assert (p->dwBufferLength >= 0);
|
assert (p->dwBufferLength >= 0);
|
||||||
assert (p->dwBufferLength < (DWORD)(A->outbuf_size));
|
assert (p->dwBufferLength < A->outbuf_size);
|
||||||
|
|
||||||
p->lpData[p->dwBufferLength++] = c;
|
p->lpData[p->dwBufferLength++] = c;
|
||||||
|
|
||||||
if (p->dwBufferLength == (DWORD)(A->outbuf_size)) {
|
if (p->dwBufferLength == A->outbuf_size) {
|
||||||
return (audio_flush(a));
|
return (audio_flush(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,7 +1054,7 @@ int audio_flush (int a)
|
||||||
* (3) Call this function, which might or might not wait long enough.
|
* (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.
|
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||||
* (5) Take difference between current time and desired PPT off time
|
* (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.
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------*/
|
*----------------------------------------------------------------*/
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
|
|
||||||
#define AX25_MAX_REPEATERS 8
|
#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_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */
|
||||||
|
|
||||||
#define AX25_DESTINATION 0 /* Address positions in frame. */
|
#define AX25_DESTINATION 0 /* Address positions in frame. */
|
||||||
|
@ -64,10 +64,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define AX25_UI_FRAME 3 /* Control field value. */
|
#define AX25_UI_FRAME 3 /* Control field value. */
|
||||||
|
#define AX25_NO_LAYER_3 0xf0 /* protocol ID */
|
||||||
|
|
||||||
#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */
|
|
||||||
#define AX25_PID_SEGMENTATION_FRAGMENT 0x08
|
|
||||||
#define AX25_PID_ESCAPE_CHARACTER 0xff
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */
|
#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */
|
||||||
|
@ -98,12 +96,11 @@ struct packet_s {
|
||||||
*
|
*
|
||||||
* Bits: H R R SSID 0
|
* 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.
|
* Changed to 1 when position has been used.
|
||||||
*
|
*
|
||||||
* for source & destination it is called
|
* for source & destination it is called
|
||||||
* command/response. Normally both 1 for APRS.
|
* command/response and is normally 1.
|
||||||
* They should be opposites for connected mode.
|
|
||||||
*
|
*
|
||||||
* R R Reserved. Normally set to 1 1.
|
* R R Reserved. Normally set to 1 1.
|
||||||
*
|
*
|
||||||
|
@ -112,7 +109,6 @@ struct packet_s {
|
||||||
* 0 Usually 0 but 1 for last address.
|
* 0 Usually 0 but 1 for last address.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define SSID_H_MASK 0x80
|
#define SSID_H_MASK 0x80
|
||||||
#define SSID_H_SHIFT 7
|
#define SSID_H_SHIFT 7
|
||||||
|
|
||||||
|
@ -127,15 +123,6 @@ struct packet_s {
|
||||||
|
|
||||||
int frame_len; /* Frame length without CRC. */
|
int frame_len; /* Frame length without CRC. */
|
||||||
|
|
||||||
int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */
|
|
||||||
/* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */
|
|
||||||
/* control bytes. Unfortunately, we can't determine this by looking */
|
|
||||||
/* at an isolated frame. We need to know about the context. If we */
|
|
||||||
/* are part of the conversation, we would know. But if we are */
|
|
||||||
/* just listening to others, this would be more difficult to determine. */
|
|
||||||
|
|
||||||
/* For U frames: set to 0 - not applicable */
|
|
||||||
/* For I & S frames: 8 or 128 if known. 0 if unknown. */
|
|
||||||
|
|
||||||
unsigned char frame_data[AX25_MAX_PACKET_LEN+1];
|
unsigned char frame_data[AX25_MAX_PACKET_LEN+1];
|
||||||
/* Raw frame contents, without the CRC. */
|
/* Raw frame contents, without the CRC. */
|
||||||
|
@ -158,53 +145,30 @@ struct packet_s {
|
||||||
|
|
||||||
typedef struct packet_s *packet_t;
|
typedef struct packet_s *packet_t;
|
||||||
|
|
||||||
typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t;
|
|
||||||
|
|
||||||
|
|
||||||
extern packet_t ax25_new (void);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */
|
#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */
|
||||||
|
|
||||||
|
extern packet_t ax25_new (void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* APRS always has one control octet of 0x03 but the more
|
* APRS always has one control octet of 0x03 but the more
|
||||||
* general AX.25 case is one or two control bytes depending on
|
* general AX.25 case is one or two control bytes depending on
|
||||||
* whether "modulo 128 operation" is in effect.
|
* "modulo 128 operation" is in effect. Unfortunately, it seems
|
||||||
|
* this can be determined only by examining the XID frames and
|
||||||
|
* keeping this information for each connection.
|
||||||
|
* We can assume 1 for our current purposes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#define DEBUGX 1
|
|
||||||
|
|
||||||
static inline int ax25_get_control_offset (packet_t this_p)
|
static inline int ax25_get_control_offset (packet_t this_p)
|
||||||
{
|
{
|
||||||
|
//return (0);
|
||||||
return (this_p->num_addr*7);
|
return (this_p->num_addr*7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ax25_get_num_control (packet_t this_p)
|
static inline int ax25_get_num_control (packet_t this_p)
|
||||||
{
|
{
|
||||||
int c;
|
return (1); // TODO: always be 1 for U frame. More complicated for I and S.
|
||||||
|
|
||||||
c = this_p->frame_data[ax25_get_control_offset(this_p)];
|
|
||||||
|
|
||||||
if ( (c & 0x01) == 0 ) { /* I xxxx xxx0 */
|
|
||||||
#if DEBUGX
|
|
||||||
dw_printf ("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
|
|
||||||
#endif
|
|
||||||
return ((this_p->modulo == 128) ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (c & 0x03) == 1 ) { /* S xxxx xx01 */
|
|
||||||
#if DEBUGX
|
|
||||||
dw_printf ("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
|
|
||||||
#endif
|
|
||||||
return ((this_p->modulo == 128) ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUGX
|
|
||||||
dw_printf ("ax25_get_num_control, %02x is U frame, always returns 1.\n", c);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (1); /* U xxxx xx11 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,17 +194,11 @@ static int ax25_get_num_pid (packet_t this_p)
|
||||||
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
|
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
|
||||||
|
|
||||||
pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
|
pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
|
||||||
#if DEBUGX
|
if (pid == 0xff) {
|
||||||
dw_printf ("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid==AX25_PID_ESCAPE_CHARACTER) ? 2 : 1);
|
|
||||||
#endif
|
|
||||||
if (pid == AX25_PID_ESCAPE_CHARACTER) {
|
|
||||||
return (2); /* pid 1111 1111 means another follows. */
|
return (2); /* pid 1111 1111 means another follows. */
|
||||||
}
|
}
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
#if DEBUGX
|
|
||||||
dw_printf ("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c);
|
|
||||||
#endif
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,14 +217,10 @@ static int ax25_get_num_pid (packet_t this_p)
|
||||||
|
|
||||||
static inline int ax25_get_info_offset (packet_t this_p)
|
static inline int ax25_get_info_offset (packet_t this_p)
|
||||||
{
|
{
|
||||||
int offset = ax25_get_control_offset (this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p);
|
return (ax25_get_control_offset (this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p));
|
||||||
#if DEBUGX
|
|
||||||
dw_printf ("ax25_get_info_offset, returns %d\n", offset);
|
|
||||||
#endif
|
|
||||||
return (offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ax25_get_num_info (packet_t this_p)
|
static int ax25_get_num_info (packet_t this_p)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -283,11 +237,11 @@ static inline int ax25_get_num_info (packet_t this_p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t;
|
typedef enum ax25_modulo_e { modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t;
|
||||||
|
|
||||||
typedef enum ax25_frame_type_e {
|
typedef enum ax25_frame_type_e {
|
||||||
|
|
||||||
frame_type_I = 0, // Information
|
frame_type_I, // Information
|
||||||
|
|
||||||
frame_type_S_RR, // Receive Ready - System Ready To Receive
|
frame_type_S_RR, // Receive Ready - System Ready To Receive
|
||||||
frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full
|
frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full
|
||||||
|
@ -306,8 +260,6 @@ typedef enum ax25_frame_type_e {
|
||||||
frame_type_U, // other Unnumbered, not used by AX.25.
|
frame_type_U, // other Unnumbered, not used by AX.25.
|
||||||
|
|
||||||
frame_not_AX25 // Could not get control byte from frame.
|
frame_not_AX25 // Could not get control byte from frame.
|
||||||
// This must be last because value plus 1 is
|
|
||||||
// for the size of an array.
|
|
||||||
|
|
||||||
} ax25_frame_type_t;
|
} ax25_frame_type_t;
|
||||||
|
|
||||||
|
@ -394,11 +346,7 @@ extern int ax25_get_heard(packet_t this_p);
|
||||||
|
|
||||||
extern int ax25_get_first_not_repeated(packet_t pp);
|
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 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);
|
extern void ax25_set_nextp (packet_t this_p, packet_t next_p);
|
||||||
|
|
||||||
|
@ -409,36 +357,28 @@ extern packet_t ax25_get_nextp (packet_t this_p);
|
||||||
extern void ax25_set_release_time (packet_t this_p, double release_time);
|
extern void ax25_set_release_time (packet_t this_p, double release_time);
|
||||||
extern double ax25_get_release_time (packet_t this_p);
|
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_addrs (packet_t pp, char *);
|
||||||
extern void ax25_format_via_path (packet_t this_p, char *result, size_t result_size);
|
|
||||||
|
|
||||||
extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
|
extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
|
||||||
|
|
||||||
extern ax25_frame_type_t ax25_frame_type (packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns);
|
extern ax25_frame_type_t ax25_frame_type (packet_t this_p, ax25_modulo_t modulo, char *desc, int *pf, int *nr, int *ns);
|
||||||
|
|
||||||
extern void ax25_hex_dump (packet_t this_p);
|
extern void ax25_hex_dump (packet_t this_p);
|
||||||
|
|
||||||
extern int ax25_is_aprs (packet_t pp);
|
extern int ax25_is_aprs (packet_t pp);
|
||||||
extern int ax25_is_null_frame (packet_t this_p);
|
|
||||||
|
|
||||||
extern int ax25_get_control (packet_t this_p);
|
extern int ax25_get_control (packet_t this_p);
|
||||||
extern int ax25_get_c2 (packet_t this_p);
|
extern int ax25_get_c2 (packet_t this_p);
|
||||||
|
|
||||||
extern int ax25_get_pid (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);
|
extern unsigned short ax25_dedupe_crc (packet_t pp);
|
||||||
|
|
||||||
extern unsigned short ax25_m_m_crc (packet_t pp);
|
extern unsigned short ax25_m_m_crc (packet_t pp);
|
||||||
|
|
||||||
extern void ax25_safe_print (char *, int, int ascii_only);
|
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]);
|
extern int ax25_alevel_to_text (alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011, 2013, 2014, 2015, 2016, 2017 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2013, 2014, 2015 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
//#define DEBUG 1
|
//#define DEBUG 1
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -42,6 +40,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "ax25_pad.h"
|
#include "ax25_pad.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
@ -56,7 +55,26 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "dlq.h"
|
#include "dlq.h"
|
||||||
#include "aprs_tt.h" // for dw_run_cmd - should relocate someday.
|
#include "aprs_tt.h" // for dw_run_cmd - should relocate someday.
|
||||||
#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
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -65,7 +83,6 @@
|
||||||
|
|
||||||
static struct audio_s *g_modem_config_p;
|
static struct audio_s *g_modem_config_p;
|
||||||
static struct misc_config_s *g_misc_config_p;
|
static struct misc_config_s *g_misc_config_p;
|
||||||
static struct igate_config_s *g_igate_config_p;
|
|
||||||
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
@ -101,10 +118,6 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo);
|
||||||
* Used only to find valid channels.
|
* Used only to find valid channels.
|
||||||
*
|
*
|
||||||
* pconfig - misc. configuration from config file.
|
* pconfig - misc. configuration from config file.
|
||||||
* Beacon stuff ended up here.
|
|
||||||
*
|
|
||||||
* pigate - IGate configuration.
|
|
||||||
* Need this for calculating IGate statistics.
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Outputs: Remember required information for future use.
|
* Outputs: Remember required information for future use.
|
||||||
|
@ -118,10 +131,9 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct igate_config_s *pigate)
|
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig)
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm tm;
|
|
||||||
int j;
|
int j;
|
||||||
int count;
|
int count;
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
@ -144,7 +156,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
*/
|
*/
|
||||||
g_modem_config_p = pmodem;
|
g_modem_config_p = pmodem;
|
||||||
g_misc_config_p = pconfig;
|
g_misc_config_p = pconfig;
|
||||||
g_igate_config_p = pigate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precompute the packet contents so any errors are
|
* Precompute the packet contents so any errors are
|
||||||
|
@ -152,20 +163,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
|
* If a serious error is found, set type to BEACON_IGNORE and that
|
||||||
* table entry should be ignored later on.
|
* 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++) {
|
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||||
int chan = g_misc_config_p->beacon[j].sendto_chan;
|
int chan = g_misc_config_p->beacon[j].sendto_chan;
|
||||||
|
|
||||||
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
|
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 ||
|
if (g_modem_config_p->achan[chan].valid) {
|
||||||
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) {
|
|
||||||
|
|
||||||
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 &&
|
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 &&
|
||||||
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 &&
|
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 &&
|
||||||
|
@ -195,18 +198,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||||
continue;
|
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;
|
break;
|
||||||
|
|
||||||
case BEACON_TRACKER:
|
case BEACON_TRACKER:
|
||||||
|
@ -221,29 +212,8 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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);
|
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;
|
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;
|
break;
|
||||||
|
|
||||||
case BEACON_CUSTOM:
|
case BEACON_CUSTOM:
|
||||||
|
@ -258,22 +228,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BEACON_IGATE:
|
|
||||||
|
|
||||||
/* Doesn't make sense if IGate is not configured. */
|
|
||||||
|
|
||||||
if (strlen(g_igate_config_p->t2_server_name) == 0 ||
|
|
||||||
strlen(g_igate_config_p->t2_login) == 0 ||
|
|
||||||
strlen(g_igate_config_p->t2_passcode) == 0) {
|
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Config file, line %d: Doesn't make sense to use IBEACON without IGate Configured.\n", g_misc_config_p->beacon[j].lineno);
|
|
||||||
dw_printf ("IBEACON has been disabled.\n");
|
|
||||||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BEACON_IGNORE:
|
case BEACON_IGNORE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -292,71 +246,21 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate first time for each beacon from the 'slot' or 'delay' value.
|
* Calculate first time for each beacon from the 'delay' value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
localtime_r (&now, &tm);
|
|
||||||
|
|
||||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||||
struct beacon_s *bp = & (g_misc_config_p->beacon[j]);
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("beacon[%d] chan=%d, delay=%d, slot=%d, every=%d\n",
|
dw_printf ("beacon[%d] chan=%d, delay=%d, every=%d\n",
|
||||||
j,
|
j,
|
||||||
bp->sendto_chan,
|
g_misc_config_p->beacon[j].sendto_chan,
|
||||||
bp->delay,
|
g_misc_config_p->beacon[j].delay,
|
||||||
bp->slot,
|
g_misc_config_p->beacon[j].every);
|
||||||
bp->every);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* If timeslots, there must be a full number of beacon intervals per hour.
|
|
||||||
*/
|
|
||||||
#define IS_GOOD(x) ((3600/(x))*(x) == 3600)
|
|
||||||
|
|
||||||
if (bp->slot != G_UNKNOWN) {
|
|
||||||
|
|
||||||
if ( ! IS_GOOD(bp->every)) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Config file, line %d: When using timeslots, there must be a whole number of beacon intervals per hour.\n", bp->lineno);
|
|
||||||
|
|
||||||
// Try to make it valid by adjusting up or down.
|
|
||||||
|
|
||||||
int n;
|
|
||||||
for (n=1; ; n++) {
|
|
||||||
int e;
|
|
||||||
e = bp->every + n;
|
|
||||||
if (e > 3600) {
|
|
||||||
bp->every = 3600;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (IS_GOOD(e)) {
|
|
||||||
bp->every = e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
e = bp->every - n;
|
|
||||||
if (e < 1) {
|
|
||||||
bp->every = 1; // Impose a larger minimum?
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (IS_GOOD(e)) {
|
|
||||||
bp->every = e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Config file, line %d: Time between slotted beacons has been adjusted to %d seconds.\n", bp->lineno, bp->every);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Determine when next slot time will arrive.
|
|
||||||
*/
|
|
||||||
bp->delay = bp->slot - (tm.tm_min * 60 + tm.tm_sec);
|
|
||||||
while (bp->delay > bp->every) bp->delay -= bp->every;
|
|
||||||
while (bp->delay < 5) bp->delay += bp->every;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].delay;
|
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +288,7 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
||||||
#else
|
#else
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
e = pthread_create (&beacon_tid, NULL, beacon_thread, NULL);
|
e = pthread_create (&beacon_tid, NULL, beacon_thread, (void *)0);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror("Could not create beacon thread");
|
perror("Could not create beacon thread");
|
||||||
|
@ -563,12 +467,10 @@ static void * beacon_thread (void *arg)
|
||||||
*/
|
*/
|
||||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||||
|
|
||||||
struct beacon_s *bp = & (g_misc_config_p->beacon[j]);
|
if (g_misc_config_p->beacon[j].btype == BEACON_IGNORE)
|
||||||
|
|
||||||
if (bp->btype == BEACON_IGNORE)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bp->next <= now) {
|
if (g_misc_config_p->beacon[j].next <= now) {
|
||||||
|
|
||||||
/* Send the beacon. */
|
/* Send the beacon. */
|
||||||
|
|
||||||
|
@ -577,20 +479,13 @@ static void * beacon_thread (void *arg)
|
||||||
/* Calculate when the next one should be sent. */
|
/* Calculate when the next one should be sent. */
|
||||||
/* Easy for fixed interval. SmartBeaconing takes more effort. */
|
/* Easy for fixed interval. SmartBeaconing takes more effort. */
|
||||||
|
|
||||||
if (bp->btype == BEACON_TRACKER) {
|
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||||
|
|
||||||
if (gpsinfo.fix < DWFIX_2D) {
|
if (gpsinfo.fix < DWFIX_2D) {
|
||||||
/* Fix not available so beacon was not sent. */
|
/* Fix not available so beacon was not sent. */
|
||||||
|
/* Try again in a couple seconds. */
|
||||||
|
|
||||||
if (g_misc_config_p->sb_configured) {
|
g_misc_config_p->beacon[j].next = now + 2;
|
||||||
/* Try again in a couple seconds. */
|
|
||||||
bp->next = now + 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Stay with the schedule. */
|
|
||||||
/* Important for slotted. Might reconsider otherwise. */
|
|
||||||
bp->next += bp->every;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (g_misc_config_p->sb_configured) {
|
else if (g_misc_config_p->sb_configured) {
|
||||||
|
|
||||||
|
@ -600,37 +495,18 @@ static void * beacon_thread (void *arg)
|
||||||
sb_prev_time = now;
|
sb_prev_time = now;
|
||||||
sb_prev_course = gpsinfo.track;
|
sb_prev_course = gpsinfo.track;
|
||||||
|
|
||||||
bp->next = sb_calculate_next_time (now,
|
g_misc_config_p->beacon[j].next = sb_calculate_next_time (now,
|
||||||
DW_KNOTS_TO_MPH(gpsinfo.speed_knots), gpsinfo.track,
|
DW_KNOTS_TO_MPH(gpsinfo.speed_knots), gpsinfo.track,
|
||||||
sb_prev_time, sb_prev_course);
|
sb_prev_time, sb_prev_course);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Tracker beacon, fixed spacing. */
|
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||||
bp->next += bp->every;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Non-tracker beacon, fixed spacing. */
|
/* non-tracker beacons are at fixed spacing. */
|
||||||
/* Increment by 'every' so slotted times come out right. */
|
|
||||||
/* i.e. Don't take relative to now in case there was some delay. */
|
|
||||||
|
|
||||||
bp->next += bp->every;
|
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].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 */
|
} /* if time to send it */
|
||||||
|
@ -782,7 +658,6 @@ static time_t sb_calculate_next_time (time_t now,
|
||||||
static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct beacon_s *bp = & (g_misc_config_p->beacon[j]);
|
|
||||||
|
|
||||||
int strict = 1; /* Strict packet checking because they will go over air. */
|
int strict = 1; /* Strict packet checking because they will go over air. */
|
||||||
char stemp[20];
|
char stemp[20];
|
||||||
|
@ -805,19 +680,13 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
*/
|
*/
|
||||||
strlcpy (mycall, "NOCALL", sizeof(mycall));
|
strlcpy (mycall, "NOCALL", sizeof(mycall));
|
||||||
|
|
||||||
assert (bp->sendto_chan >= 0);
|
assert (g_misc_config_p->beacon[j].sendto_chan >= 0);
|
||||||
|
|
||||||
if (g_modem_config_p->chan_medium[bp->sendto_chan] == MEDIUM_IGATE) { // ICHANNEL uses chan 0 mycall.
|
strlcpy (mycall, g_modem_config_p->achan[g_misc_config_p->beacon[j].sendto_chan].mycall, sizeof(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));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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", g_misc_config_p->beacon[j].lineno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,25 +696,20 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
* src > dest [ , via ]
|
* src > dest [ , via ]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (bp->source != NULL) {
|
strlcpy (beacon_text, mycall, sizeof(beacon_text));
|
||||||
strlcpy (beacon_text, bp->source, sizeof(beacon_text));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strlcpy (beacon_text, mycall, sizeof(beacon_text));
|
|
||||||
}
|
|
||||||
strlcat (beacon_text, ">", sizeof(beacon_text));
|
strlcat (beacon_text, ">", sizeof(beacon_text));
|
||||||
|
|
||||||
if (bp->dest != NULL) {
|
if (g_misc_config_p->beacon[j].dest != NULL) {
|
||||||
strlcat (beacon_text, bp->dest, sizeof(beacon_text));
|
strlcat (beacon_text, g_misc_config_p->beacon[j].dest, sizeof(beacon_text));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf (stemp, sizeof(stemp), "%s%1d%1d", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION);
|
snprintf (stemp, sizeof(stemp), "%s%1d%1d", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION);
|
||||||
strlcat (beacon_text, stemp, sizeof(beacon_text));
|
strlcat (beacon_text, stemp, sizeof(beacon_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bp->via != NULL) {
|
if (g_misc_config_p->beacon[j].via != NULL) {
|
||||||
strlcat (beacon_text, ",", sizeof(beacon_text));
|
strlcat (beacon_text, ",", sizeof(beacon_text));
|
||||||
strlcat (beacon_text, bp->via, sizeof(beacon_text));
|
strlcat (beacon_text, g_misc_config_p->beacon[j].via, sizeof(beacon_text));
|
||||||
}
|
}
|
||||||
strlcat (beacon_text, ":", sizeof(beacon_text));
|
strlcat (beacon_text, ":", sizeof(beacon_text));
|
||||||
|
|
||||||
|
@ -858,23 +722,23 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
// TODO: test & document.
|
// TODO: test & document.
|
||||||
|
|
||||||
strlcpy (super_comment, "", sizeof(super_comment));
|
strlcpy (super_comment, "", sizeof(super_comment));
|
||||||
if (bp->comment != NULL) {
|
if (g_misc_config_p->beacon[j].comment != NULL) {
|
||||||
strlcpy (super_comment, bp->comment, sizeof(super_comment));
|
strlcpy (super_comment, g_misc_config_p->beacon[j].comment, sizeof(super_comment));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bp->commentcmd != NULL) {
|
if (g_misc_config_p->beacon[j].commentcmd != NULL) {
|
||||||
char var_comment[AX25_MAX_INFO_LEN];
|
char var_comment[AX25_MAX_INFO_LEN];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
/* Run given command to get variable part of comment. */
|
/* Run given command to get variable part of comment. */
|
||||||
|
|
||||||
k = dw_run_cmd (bp->commentcmd, 2, var_comment, sizeof(var_comment));
|
k = dw_run_cmd (g_misc_config_p->beacon[j].commentcmd, 2, var_comment, sizeof(var_comment));
|
||||||
if (k > 0) {
|
if (k > 0) {
|
||||||
strlcat (super_comment, var_comment, sizeof(super_comment));
|
strlcat (super_comment, var_comment, sizeof(super_comment));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("xBEACON, config file line %d, COMMENTCMD failure.\n", bp->lineno);
|
dw_printf ("xBEACON, config file line %d, COMMENTCMD failure.\n", g_misc_config_p->beacon[j].lineno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,17 +746,17 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
/*
|
/*
|
||||||
* Add the info part depending on beacon type.
|
* Add the info part depending on beacon type.
|
||||||
*/
|
*/
|
||||||
switch (bp->btype) {
|
switch (g_misc_config_p->beacon[j].btype) {
|
||||||
|
|
||||||
case BEACON_POSITION:
|
case BEACON_POSITION:
|
||||||
|
|
||||||
encode_position (bp->messaging, bp->compress,
|
encode_position (g_misc_config_p->beacon[j].messaging, g_misc_config_p->beacon[j].compress,
|
||||||
bp->lat, bp->lon, bp->ambiguity,
|
g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon, 0,
|
||||||
(int)roundf(DW_METERS_TO_FEET(bp->alt_m)),
|
(int)roundf(DW_METERS_TO_FEET(g_misc_config_p->beacon[j].alt_m)),
|
||||||
bp->symtab, bp->symbol,
|
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||||
bp->power, bp->height, bp->gain, bp->dir,
|
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||||
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
||||||
bp->freq, bp->tone, bp->offset,
|
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset,
|
||||||
super_comment,
|
super_comment,
|
||||||
info, sizeof(info));
|
info, sizeof(info));
|
||||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||||
|
@ -900,11 +764,11 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
|
|
||||||
case BEACON_OBJECT:
|
case BEACON_OBJECT:
|
||||||
|
|
||||||
encode_object (bp->objname, bp->compress, 0, bp->lat, bp->lon, bp->ambiguity,
|
encode_object (g_misc_config_p->beacon[j].objname, g_misc_config_p->beacon[j].compress, 0, g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon, 0,
|
||||||
bp->symtab, bp->symbol,
|
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||||
bp->power, bp->height, bp->gain, bp->dir,
|
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||||
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
||||||
bp->freq, bp->tone, bp->offset, super_comment,
|
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset, super_comment,
|
||||||
info, sizeof(info));
|
info, sizeof(info));
|
||||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||||
break;
|
break;
|
||||||
|
@ -921,7 +785,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
/* transmission of altitude from GPS. */
|
/* transmission of altitude from GPS. */
|
||||||
|
|
||||||
my_alt_ft = G_UNKNOWN;
|
my_alt_ft = G_UNKNOWN;
|
||||||
if (gpsinfo->fix >= 3 && gpsinfo->altitude != G_UNKNOWN && bp->alt_m > 0) {
|
if (gpsinfo->fix >= 3 && gpsinfo->altitude != G_UNKNOWN && g_misc_config_p->beacon[j].alt_m > 0) {
|
||||||
my_alt_ft = (int)roundf(DW_METERS_TO_FEET(gpsinfo->altitude));
|
my_alt_ft = (int)roundf(DW_METERS_TO_FEET(gpsinfo->altitude));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,12 +794,12 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
coarse = (int)roundf(gpsinfo->track);
|
coarse = (int)roundf(gpsinfo->track);
|
||||||
}
|
}
|
||||||
|
|
||||||
encode_position (bp->messaging, bp->compress,
|
encode_position (g_misc_config_p->beacon[j].messaging, g_misc_config_p->beacon[j].compress,
|
||||||
gpsinfo->dlat, gpsinfo->dlon, bp->ambiguity, my_alt_ft,
|
gpsinfo->dlat, gpsinfo->dlon, 0, my_alt_ft,
|
||||||
bp->symtab, bp->symbol,
|
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||||
bp->power, bp->height, bp->gain, bp->dir,
|
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||||
coarse, (int)roundf(gpsinfo->speed_knots),
|
coarse, (int)roundf(gpsinfo->speed_knots),
|
||||||
bp->freq, bp->tone, bp->offset,
|
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset,
|
||||||
super_comment,
|
super_comment,
|
||||||
info, sizeof(info));
|
info, sizeof(info));
|
||||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||||
|
@ -957,8 +821,8 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
A.g_dcs = G_UNKNOWN;
|
A.g_dcs = G_UNKNOWN;
|
||||||
|
|
||||||
strlcpy (A.g_src, mycall, sizeof(A.g_src));
|
strlcpy (A.g_src, mycall, sizeof(A.g_src));
|
||||||
A.g_symbol_table = bp->symtab;
|
A.g_symbol_table = g_misc_config_p->beacon[j].symtab;
|
||||||
A.g_symbol_code = bp->symbol;
|
A.g_symbol_code = g_misc_config_p->beacon[j].symbol;
|
||||||
A.g_lat = gpsinfo->dlat;
|
A.g_lat = gpsinfo->dlat;
|
||||||
A.g_lon = gpsinfo->dlon;
|
A.g_lon = gpsinfo->dlon;
|
||||||
A.g_speed_mph = DW_KNOTS_TO_MPH(gpsinfo->speed_knots);
|
A.g_speed_mph = DW_KNOTS_TO_MPH(gpsinfo->speed_knots);
|
||||||
|
@ -977,25 +841,25 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
|
|
||||||
case BEACON_CUSTOM:
|
case BEACON_CUSTOM:
|
||||||
|
|
||||||
if (bp->custom_info != NULL) {
|
if (g_misc_config_p->beacon[j].custom_info != NULL) {
|
||||||
|
|
||||||
/* Fixed handcrafted text. */
|
/* Fixed handcrafted text. */
|
||||||
|
|
||||||
strlcat (beacon_text, bp->custom_info, sizeof(beacon_text));
|
strlcat (beacon_text, g_misc_config_p->beacon[j].custom_info, sizeof(beacon_text));
|
||||||
}
|
}
|
||||||
else if (bp->custom_infocmd != NULL) {
|
else if (g_misc_config_p->beacon[j].custom_infocmd != NULL) {
|
||||||
char info_part[AX25_MAX_INFO_LEN];
|
char info_part[AX25_MAX_INFO_LEN];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
/* Run given command to obtain the info part for packet. */
|
/* Run given command to obtain the info part for packet. */
|
||||||
|
|
||||||
k = dw_run_cmd (bp->custom_infocmd, 2, info_part, sizeof(info_part));
|
k = dw_run_cmd (g_misc_config_p->beacon[j].custom_infocmd, 2, info_part, sizeof(info_part));
|
||||||
if (k > 0) {
|
if (k > 0) {
|
||||||
strlcat (beacon_text, info_part, sizeof(beacon_text));
|
strlcat (beacon_text, info_part, sizeof(beacon_text));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("CBEACON, config file line %d, INFOCMD failure.\n", bp->lineno);
|
dw_printf ("CBEACON, config file line %d, INFOCMD failure.\n", g_misc_config_p->beacon[j].lineno);
|
||||||
strlcpy (beacon_text, "", sizeof(beacon_text)); // abort!
|
strlcpy (beacon_text, "", sizeof(beacon_text)); // abort!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1006,25 +870,6 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BEACON_IGATE:
|
|
||||||
|
|
||||||
{
|
|
||||||
int last_minutes = 30;
|
|
||||||
char stuff[256];
|
|
||||||
|
|
||||||
snprintf (stuff, sizeof(stuff), "<IGATE,MSG_CNT=%d,PKT_CNT=%d,DIR_CNT=%d,LOC_CNT=%d,RF_CNT=%d,UPL_CNT=%d,DNL_CNT=%d",
|
|
||||||
igate_get_msg_cnt(),
|
|
||||||
igate_get_pkt_cnt(),
|
|
||||||
mheard_count(0,last_minutes),
|
|
||||||
mheard_count(g_igate_config_p->max_digi_hops,last_minutes),
|
|
||||||
mheard_count(8,last_minutes),
|
|
||||||
igate_get_upl_cnt(),
|
|
||||||
igate_get_dnl_cnt());
|
|
||||||
|
|
||||||
strlcat (beacon_text, stuff, sizeof(beacon_text));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BEACON_IGNORE:
|
case BEACON_IGNORE:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1047,35 +892,35 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
alevel_t alevel;
|
alevel_t alevel;
|
||||||
|
|
||||||
|
|
||||||
switch (bp->sendto_type) {
|
switch (g_misc_config_p->beacon[j].sendto_type) {
|
||||||
|
|
||||||
case SENDTO_IGATE:
|
case SENDTO_IGATE:
|
||||||
|
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[ig] %s\n", beacon_text);
|
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);
|
ax25_delete (pp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SENDTO_XMIT:
|
case SENDTO_XMIT:
|
||||||
default:
|
default:
|
||||||
|
|
||||||
tq_append (bp->sendto_chan, TQ_PRIO_1_LO, pp);
|
tq_append (g_misc_config_p->beacon[j].sendto_chan, TQ_PRIO_1_LO, pp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SENDTO_RECV:
|
case SENDTO_RECV:
|
||||||
|
|
||||||
/* Simulated reception from radio. */
|
/* Simulated reception. */
|
||||||
|
|
||||||
memset (&alevel, 0xff, sizeof(alevel));
|
memset (&alevel, 0xff, sizeof(alevel));
|
||||||
dlq_rec_frame (bp->sendto_chan, 0, 0, pp, alevel, 0, 0, "");
|
dlq_append (DLQ_REC_FRAME, g_misc_config_p->beacon[j].sendto_chan, 0, 0, pp, alevel, 0, "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Config file: Failed to parse packet constructed from line %d.\n", bp->lineno);
|
dw_printf ("Config file: Failed to parse packet constructed from line %d.\n", g_misc_config_p->beacon[j].lineno);
|
||||||
dw_printf ("%s\n", beacon_text);
|
dw_printf ("%s\n", beacon_text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
/* beacon.h */
|
/* beacon.h */
|
||||||
|
|
||||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct igate_config_s *pigate);
|
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig);
|
||||||
|
|
||||||
void beacon_tracker_set_debug (int level);
|
void beacon_tracker_set_debug (int level);
|
|
@ -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,36 +0,0 @@
|
||||||
# Normally, all of /dev/hidraw* are accessible only by root.
|
|
||||||
#
|
|
||||||
# $ 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.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# If all went well with installation, the /etc/udev/rules.d directory should contain a file called
|
|
||||||
# 99-direwolf-cmedia.rules containing:
|
|
||||||
#
|
|
||||||
|
|
||||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0d8c", GROUP="audio", MODE="0660"
|
|
||||||
|
|
||||||
#
|
|
||||||
# I used the "audio" group, mimicking the permissions on the sound side of the device.
|
|
||||||
#
|
|
||||||
# $ ls -l /dev/snd/pcm*
|
|
||||||
# crw-rw----+ 1 root audio 116, 16 Sep 24 09:40 /dev/snd/pcmC0D0p
|
|
||||||
# crw-rw----+ 1 root audio 116, 17 Sep 24 09:40 /dev/snd/pcmC0D1p
|
|
||||||
#
|
|
||||||
# You should see something similar to this where someone in the "audio" group has read-write access.
|
|
||||||
#
|
|
||||||
# $ ls -l /dev/hidraw*
|
|
||||||
# crw-rw---- 1 root audio 247, 0 Oct 6 19:24 /dev/hidraw0
|
|
||||||
#
|
|
||||||
# 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"
|
|
|
@ -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
|
@ -0,0 +1,168 @@
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: config.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H 1
|
||||||
|
|
||||||
|
#include "audio.h" /* for struct audio_s */
|
||||||
|
#include "digipeater.h" /* for struct digi_config_s */
|
||||||
|
#include "aprs_tt.h" /* for struct tt_config_s */
|
||||||
|
#include "igate.h" /* for struct igate_config_s */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All the leftovers.
|
||||||
|
* This wasn't thought out. It just happened.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum beacon_type_e { BEACON_IGNORE, BEACON_POSITION, BEACON_OBJECT, BEACON_TRACKER, BEACON_CUSTOM };
|
||||||
|
|
||||||
|
enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_BEACONS 30
|
||||||
|
|
||||||
|
struct misc_config_s {
|
||||||
|
|
||||||
|
int agwpe_port; /* Port number for the "AGW TCPIP Socket Interface" */
|
||||||
|
int kiss_port; /* Port number for the "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. */
|
||||||
|
|
||||||
|
char nullmodem[20]; /* Serial port name for our end of the */
|
||||||
|
/* virtual null modem for native Windows apps. */
|
||||||
|
|
||||||
|
char gpsnmea_port[20]; /* Serial port name for reading NMEA sentences from GPS. */
|
||||||
|
/* e.g. COM22, /dev/ttyACM0 */
|
||||||
|
|
||||||
|
char gpsd_host[20]; /* Host for gpsd server. */
|
||||||
|
/* e.g. localhost, 192.168.1.2 */
|
||||||
|
|
||||||
|
int gpsd_port; /* Port number for gpsd server. */
|
||||||
|
/* Default is 2947. */
|
||||||
|
|
||||||
|
/* e.g. COM22, /dev/ttyACM0 */
|
||||||
|
char nmea_port[20]; /* Serial port name for NMEA communication with GPS */
|
||||||
|
/* receiver and/or mapping application. Change this. */
|
||||||
|
|
||||||
|
char logdir[80]; /* Directory for saving activity logs. */
|
||||||
|
|
||||||
|
int sb_configured; /* TRUE if SmartBeaconing is configured. */
|
||||||
|
int sb_fast_speed; /* MPH */
|
||||||
|
int sb_fast_rate; /* seconds */
|
||||||
|
int sb_slow_speed; /* MPH */
|
||||||
|
int sb_slow_rate; /* seconds */
|
||||||
|
int sb_turn_time; /* seconds */
|
||||||
|
int sb_turn_angle; /* degrees */
|
||||||
|
int sb_turn_slope; /* degrees * MPH */
|
||||||
|
|
||||||
|
|
||||||
|
int num_beacons; /* Number of beacons defined. */
|
||||||
|
|
||||||
|
struct beacon_s {
|
||||||
|
|
||||||
|
enum beacon_type_e btype; /* Position or object. */
|
||||||
|
|
||||||
|
int lineno; /* Line number from config file for later error messages. */
|
||||||
|
|
||||||
|
enum sendto_type_e sendto_type;
|
||||||
|
|
||||||
|
/* SENDTO_XMIT - Usually beacons go to a radio transmitter. */
|
||||||
|
/* chan, below is the channel number. */
|
||||||
|
/* SENDTO_IGATE - Send to IGate, probably to announce my position */
|
||||||
|
/* rather than relying on someone else to hear */
|
||||||
|
/* me on the radio and report me. */
|
||||||
|
/* SENDTO_RECV - Pretend this was heard on the specified */
|
||||||
|
/* radio channel. Mostly for testing. It is a */
|
||||||
|
/* convenient way to send packets to attached apps. */
|
||||||
|
|
||||||
|
int sendto_chan; /* Transmit or simulated receive channel for above. Should be 0 for IGate. */
|
||||||
|
|
||||||
|
int delay; /* Seconds to delay before first transmission. */
|
||||||
|
|
||||||
|
int every; /* Time between transmissions, seconds. */
|
||||||
|
/* Remains fixed for PBEACON and OBEACON. */
|
||||||
|
/* Dynamically adjusted for TBEACON. */
|
||||||
|
|
||||||
|
time_t next; /* Unix time to transmit next one. */
|
||||||
|
|
||||||
|
char *dest; /* NULL or explicit AX.25 destination to use */
|
||||||
|
/* instead of the software version such as APDW11. */
|
||||||
|
|
||||||
|
int compress; /* Use more compact form? */
|
||||||
|
|
||||||
|
char objname[10]; /* Object name. Any printable characters. */
|
||||||
|
|
||||||
|
char *via; /* Path, e.g. "WIDE1-1,WIDE2-1" or NULL. */
|
||||||
|
|
||||||
|
char *custom_info; /* Info part for handcrafted custom beacon. */
|
||||||
|
/* Ignore the rest below if this is set. */
|
||||||
|
|
||||||
|
char *custom_infocmd; /* Command to generate info part. */
|
||||||
|
/* Again, other options below are then ignored. */
|
||||||
|
|
||||||
|
int messaging; /* Set messaging attribute for position report. */
|
||||||
|
/* i.e. Data Type Indicator of '=' rather than '!' */
|
||||||
|
|
||||||
|
double lat; /* Latitude and longitude. */
|
||||||
|
double lon;
|
||||||
|
float alt_m; /* Altitude in meters. */
|
||||||
|
|
||||||
|
char symtab; /* Symbol table: / or \ or overlay character. */
|
||||||
|
char symbol; /* Symbol code. */
|
||||||
|
|
||||||
|
float power; /* For PHG. */
|
||||||
|
float height;
|
||||||
|
float gain; /* Original protocol spec was unclear. */
|
||||||
|
/* Addendum 1.1 clarifies it is dBi not dBd. */
|
||||||
|
|
||||||
|
char dir[3]; /* 1 or 2 of N,E,W,S, or empty for omni. */
|
||||||
|
|
||||||
|
float freq; /* MHz. */
|
||||||
|
float tone; /* Hz. */
|
||||||
|
float offset; /* MHz. */
|
||||||
|
|
||||||
|
char *comment; /* Comment or NULL. */
|
||||||
|
char *commentcmd; /* Command to append more to Comment or NULL. */
|
||||||
|
|
||||||
|
|
||||||
|
} beacon[MAX_BEACONS];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MIN_IP_PORT_NUMBER 1024
|
||||||
|
#define MAX_IP_PORT_NUMBER 49151
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_AGWPE_PORT 8000 /* Like everyone else. */
|
||||||
|
#define DEFAULT_KISS_PORT 8001 /* Above plus 1. */
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_NULLMODEM "COM3" /* should be equiv. to /dev/ttyS2 on Cygwin */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern void config_init (char *fname, struct audio_s *p_modem,
|
||||||
|
struct digi_config_s *digi_config,
|
||||||
|
struct tt_config_s *p_tt_config,
|
||||||
|
struct igate_config_s *p_igate_config,
|
||||||
|
struct misc_config_s *misc_config);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_H */
|
||||||
|
|
||||||
|
/* end config.h */
|
||||||
|
|
||||||
|
|
|
@ -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,9 @@ typedef struct decode_aprs_s {
|
||||||
|
|
||||||
int g_quiet; /* Suppress error messages when decoding. */
|
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
|
char g_src[AX25_MAX_ADDR_LEN];
|
||||||
// header, this is the encapsulated source.
|
|
||||||
|
|
||||||
char g_dest[AX25_MAX_ADDR_LEN];
|
char g_msg_type[60]; /* Message type. Telemetry descriptions get pretty long. */
|
||||||
|
|
||||||
char g_data_type_desc[100]; /* APRS data type description. Telemetry descriptions get pretty long. */
|
|
||||||
|
|
||||||
char g_symbol_table; /* The Symbol Table Identifier character selects one */
|
char g_symbol_table; /* The Symbol Table Identifier character selects one */
|
||||||
/* of the two Symbol Tables, or it may be used as */
|
/* of the two Symbol Tables, or it may be used as */
|
||||||
|
@ -67,62 +64,21 @@ typedef struct decode_aprs_s {
|
||||||
/* Also for Directed Station Query which is a */
|
/* Also for Directed Station Query which is a */
|
||||||
/* special case of message. */
|
/* 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,
|
|
||||||
message_subtype_telem_bits,
|
|
||||||
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. */
|
|
||||||
|
|
||||||
float g_speed_mph; /* Speed in MPH. */
|
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. */
|
float g_course; /* 0 = North, 90 = East, etc. */
|
||||||
|
|
||||||
int g_power; /* Transmitter power in watts. */
|
int g_power; /* Transmitter power in watts. */
|
||||||
|
|
||||||
int g_height; /* Antenna height above average terrain, feet. */
|
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 */
|
char g_directivity[12]; /* Direction of max signal strength */
|
||||||
|
|
||||||
float g_range; /* Precomputed radio range in miles. */
|
float g_range; /* Precomputed radio range in miles. */
|
||||||
|
|
||||||
float g_altitude_ft; /* Feet above median sea level. */
|
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. */
|
char g_mfr[80]; /* Manufacturer or application. */
|
||||||
|
|
||||||
|
@ -164,9 +120,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);
|
extern void decode_aprs_print (decode_aprs_t *A);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -96,7 +96,6 @@
|
||||||
|
|
||||||
#define DEDUPE_C
|
#define DEDUPE_C
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// 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 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,6 +18,14 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// #define DEBUG1 1 /* display debugging info */
|
||||||
|
|
||||||
|
// #define DEBUG3 1 /* print carrier detect changes. */
|
||||||
|
|
||||||
|
// #define DEBUG4 1 /* capture AFSK demodulator output to log files */
|
||||||
|
|
||||||
|
// #define DEBUG5 1 /* capture 9600 output to log files */
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
@ -31,7 +39,6 @@
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -42,16 +49,17 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "demod.h"
|
#include "demod.h"
|
||||||
#include "tune.h"
|
#include "tune.h"
|
||||||
#include "fsk_demod_state.h"
|
#include "fsk_demod_state.h"
|
||||||
#include "fsk_gen_filter.h"
|
#include "fsk_gen_filter.h"
|
||||||
|
#include "fsk_fast_filter.h"
|
||||||
#include "hdlc_rec.h"
|
#include "hdlc_rec.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
#include "demod_9600.h"
|
#include "demod_9600.h"
|
||||||
#include "demod_afsk.h"
|
#include "demod_afsk.h"
|
||||||
#include "demod_psk.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,12 +68,13 @@
|
||||||
static struct audio_s *save_audio_config_p;
|
static struct audio_s *save_audio_config_p;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Current state of all the decoders.
|
// Current state of all the decoders.
|
||||||
|
|
||||||
static struct demodulator_state_s demodulator_state[MAX_CHANS][MAX_SUBCHANS];
|
static struct demodulator_state_s demodulator_state[MAX_CHANS][MAX_SUBCHANS];
|
||||||
|
|
||||||
|
|
||||||
|
#define UPSAMPLE 2
|
||||||
|
|
||||||
static int sample_sum[MAX_CHANS][MAX_SUBCHANS];
|
static int sample_sum[MAX_CHANS][MAX_SUBCHANS];
|
||||||
static int sample_count[MAX_CHANS][MAX_SUBCHANS];
|
static int sample_count[MAX_CHANS][MAX_SUBCHANS];
|
||||||
|
|
||||||
|
@ -89,6 +98,7 @@ static int sample_count[MAX_CHANS][MAX_SUBCHANS];
|
||||||
|
|
||||||
int demod_init (struct audio_s *pa)
|
int demod_init (struct audio_s *pa)
|
||||||
{
|
{
|
||||||
|
//int j;
|
||||||
int chan; /* Loop index over number of radio channels. */
|
int chan; /* Loop index over number of radio channels. */
|
||||||
char profile;
|
char profile;
|
||||||
|
|
||||||
|
@ -102,7 +112,7 @@ int demod_init (struct audio_s *pa)
|
||||||
|
|
||||||
for (chan = 0; chan < MAX_CHANS; chan++) {
|
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 *p;
|
||||||
char just_letters[16];
|
char just_letters[16];
|
||||||
|
@ -116,6 +126,7 @@ int demod_init (struct audio_s *pa)
|
||||||
* This can be increased by:
|
* This can be increased by:
|
||||||
* Multiple frequencies.
|
* Multiple frequencies.
|
||||||
* Multiple letters (not sure if I will continue this).
|
* Multiple letters (not sure if I will continue this).
|
||||||
|
* New interleaved decoders.
|
||||||
*
|
*
|
||||||
* num_slicers is set to max by the "+" option.
|
* num_slicers is set to max by the "+" option.
|
||||||
*/
|
*/
|
||||||
|
@ -129,20 +140,6 @@ int demod_init (struct audio_s *pa)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODEM_AFSK:
|
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:
|
* Tear apart the profile and put it back together in a normalized form:
|
||||||
|
@ -191,60 +188,48 @@ int demod_init (struct audio_s *pa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (num_letters == (int)(strlen(just_letters)));
|
assert (num_letters == strlen(just_letters));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick a good default demodulator if none specified.
|
* 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+".
|
|
||||||
*/
|
*/
|
||||||
if (num_letters == 0) {
|
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 (save_audio_config_p->achan[chan].baud < 600) {
|
||||||
// If not explicitly turned off.
|
|
||||||
}
|
/* 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
|
#endif
|
||||||
|
}
|
||||||
/*
|
num_letters = 1;
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert (num_letters == strlen(just_letters));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put it back together again.
|
* Put it back together again.
|
||||||
*/
|
*/
|
||||||
assert (num_letters == (int)(strlen(just_letters)));
|
|
||||||
|
|
||||||
/* At this point, have_plus can have 3 values: */
|
/* At this point, have_plus can have 3 values: */
|
||||||
/* 1 = turned on, either explicitly or by applied default */
|
/* 1 = turned on, either explicitly or by applied default */
|
||||||
|
@ -293,7 +278,7 @@ int demod_init (struct audio_s *pa)
|
||||||
|
|
||||||
if (save_audio_config_p->achan[chan].decimate == 0) {
|
if (save_audio_config_p->achan[chan].decimate == 0) {
|
||||||
save_audio_config_p->achan[chan].decimate = 1;
|
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;
|
save_audio_config_p->achan[chan].decimate = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,6 +318,48 @@ int demod_init (struct audio_s *pa)
|
||||||
|
|
||||||
save_audio_config_p->achan[chan].num_subchan = num_letters;
|
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) {
|
if (save_audio_config_p->achan[chan].num_subchan != num_letters) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n",
|
dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n",
|
||||||
|
@ -361,7 +388,7 @@ int demod_init (struct audio_s *pa)
|
||||||
dw_printf (" %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
|
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,
|
save_audio_config_p->achan[chan].baud,
|
||||||
mark,
|
mark,
|
||||||
space,
|
space,
|
||||||
|
@ -376,11 +403,11 @@ int demod_init (struct audio_s *pa)
|
||||||
D->num_slicers = MAX_SLICERS;
|
D->num_slicers = MAX_SLICERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
/* For siginal level reporting, we want a longer term view. */
|
||||||
// TODO: Should probably move this into the init functions.
|
// TODO: Should probably move this into the init functions.
|
||||||
|
|
||||||
D->quick_attack = D->agc_fast_attack * 0.2f;
|
D->quick_attack = D->agc_fast_attack * 0.2;
|
||||||
D->sluggish_decay = D->agc_slow_decay * 0.2f;
|
D->sluggish_decay = D->agc_slow_decay * 0.2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (have_plus) {
|
else if (have_plus) {
|
||||||
|
@ -432,10 +459,10 @@ int demod_init (struct audio_s *pa)
|
||||||
D->num_slicers = MAX_SLICERS;
|
D->num_slicers = MAX_SLICERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
/* For siginal level reporting, we want a longer term view. */
|
||||||
|
|
||||||
D->quick_attack = D->agc_fast_attack * 0.2f;
|
D->quick_attack = D->agc_fast_attack * 0.2;
|
||||||
D->sluggish_decay = D->agc_slow_decay * 0.2f;
|
D->sluggish_decay = D->agc_slow_decay * 0.2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int d;
|
int d;
|
||||||
|
@ -485,257 +512,38 @@ int demod_init (struct audio_s *pa)
|
||||||
D->num_slicers = MAX_SLICERS;
|
D->num_slicers = MAX_SLICERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
/* For siginal level reporting, we want a longer term view. */
|
||||||
|
|
||||||
D->quick_attack = D->agc_fast_attack * 0.2f;
|
D->quick_attack = D->agc_fast_attack * 0.2;
|
||||||
D->sluggish_decay = D->agc_slow_decay * 0.2f;
|
D->sluggish_decay = D->agc_slow_decay * 0.2;
|
||||||
|
|
||||||
} /* for each freq pair */
|
} /* for each freq pair */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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) {
|
|
||||||
//#if __arm__
|
|
||||||
// strlcpy (save_audio_config_p->achan[chan].profiles, "R", sizeof(save_audio_config_p->achan[chan].profiles));
|
|
||||||
//#else
|
|
||||||
strlcpy (save_audio_config_p->achan[chan].profiles, "PQRS", sizeof(save_audio_config_p->achan[chan].profiles));
|
|
||||||
//#endif
|
|
||||||
}
|
|
||||||
save_audio_config_p->achan[chan].num_subchan = strlen(save_audio_config_p->achan[chan].profiles);
|
|
||||||
|
|
||||||
save_audio_config_p->achan[chan].decimate = 1; // think about this later.
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
|
||||||
dw_printf ("Channel %d: %d bps, QPSK, %s, %d sample rate",
|
|
||||||
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);
|
|
||||||
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");
|
|
||||||
|
|
||||||
int d;
|
|
||||||
for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
|
|
||||||
|
|
||||||
assert (d >= 0 && d < MAX_SUBCHANS);
|
|
||||||
struct demodulator_state_s *D;
|
|
||||||
D = &demodulator_state[chan][d];
|
|
||||||
profile = save_audio_config_p->achan[chan].profiles[d];
|
|
||||||
|
|
||||||
//text_color_set(DW_COLOR_DEBUG);
|
|
||||||
//dw_printf ("About to call demod_psk_init for Q-PSK case, modem_type=%d, profile='%c'\n",
|
|
||||||
// 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,
|
|
||||||
D);
|
|
||||||
|
|
||||||
//text_color_set(DW_COLOR_DEBUG);
|
|
||||||
//dw_printf ("Returned from demod_psk_init\n");
|
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
|
||||||
/* Guesses based on 9600. Maybe revisit someday. */
|
|
||||||
|
|
||||||
D->quick_attack = 0.080 * 0.2;
|
|
||||||
D->sluggish_decay = 0.00012 * 0.2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MODEM_8PSK: // New for 1.4
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
//#if __arm__
|
|
||||||
// strlcpy (save_audio_config_p->achan[chan].profiles, "V", sizeof(save_audio_config_p->achan[chan].profiles));
|
|
||||||
//#else
|
|
||||||
strlcpy (save_audio_config_p->achan[chan].profiles, "TUVW", sizeof(save_audio_config_p->achan[chan].profiles));
|
|
||||||
//#endif
|
|
||||||
}
|
|
||||||
save_audio_config_p->achan[chan].num_subchan = strlen(save_audio_config_p->achan[chan].profiles);
|
|
||||||
|
|
||||||
save_audio_config_p->achan[chan].decimate = 1; // think about this later
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
|
||||||
dw_printf ("Channel %d: %d bps, 8PSK, %s, %d sample rate",
|
|
||||||
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);
|
|
||||||
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].dtmf_decode != DTMF_DECODE_OFF)
|
|
||||||
dw_printf (", DTMF decoder enabled");
|
|
||||||
dw_printf (".\n");
|
|
||||||
|
|
||||||
//int d;
|
|
||||||
for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
|
|
||||||
|
|
||||||
assert (d >= 0 && d < MAX_SUBCHANS);
|
|
||||||
struct demodulator_state_s *D;
|
|
||||||
D = &demodulator_state[chan][d];
|
|
||||||
profile = save_audio_config_p->achan[chan].profiles[d];
|
|
||||||
|
|
||||||
//text_color_set(DW_COLOR_DEBUG);
|
|
||||||
//dw_printf ("About to call demod_psk_init for 8-PSK case, modem_type=%d, profile='%c'\n",
|
|
||||||
// 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,
|
|
||||||
D);
|
|
||||||
|
|
||||||
//text_color_set(DW_COLOR_DEBUG);
|
|
||||||
//dw_printf ("Returned from demod_psk_init\n");
|
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
|
||||||
/* Guesses based on 9600. Maybe revisit someday. */
|
|
||||||
|
|
||||||
D->quick_attack = 0.080 * 0.2;
|
|
||||||
D->sluggish_decay = 0.00012 * 0.2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//TODO: how about MODEM_OFF case?
|
//TODO: how about MODEM_OFF case?
|
||||||
|
|
||||||
case MODEM_BASEBAND:
|
case MODEM_BASEBAND:
|
||||||
case MODEM_SCRAMBLE:
|
case MODEM_SCRAMBLE:
|
||||||
case MODEM_AIS:
|
|
||||||
default: /* Not AFSK */
|
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) {
|
if (strcmp(save_audio_config_p->achan[chan].profiles, "") == 0) {
|
||||||
|
|
||||||
/* Apply default if not set earlier. */
|
/* Apply default if not set earlier. */
|
||||||
/* Not sure if it should be on for ARM too. */
|
/* Not sure if it should be on for ARM too. */
|
||||||
/* Need to take a look at CPU usage and performance difference. */
|
/* Need to take a look at CPU usage and performance difference. */
|
||||||
|
|
||||||
/* Version 1.5: Remove special case for ARM. */
|
#ifndef __arm__
|
||||||
/* We want higher performance to be the default. */
|
|
||||||
/* "MODEM 9600 -" can be used on very slow CPU if necessary. */
|
|
||||||
|
|
||||||
strlcpy (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TUNE_UPSAMPLE
|
|
||||||
save_audio_config_p->achan[chan].upsample = TUNE_UPSAMPLE;
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("Channel %d: %d baud, %s, %s, %d sample rate x %d",
|
dw_printf ("Channel %d: %d baud, K9NG/G3RUH, %s, %d sample rate x %d",
|
||||||
chan,
|
chan, save_audio_config_p->achan[chan].baud,
|
||||||
save_audio_config_p->achan[chan].baud,
|
|
||||||
save_audio_config_p->achan[chan].modem_type == MODEM_AIS ? "AIS" : "K9NG/G3RUH",
|
|
||||||
save_audio_config_p->achan[chan].profiles,
|
save_audio_config_p->achan[chan].profiles,
|
||||||
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
|
save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, UPSAMPLE);
|
||||||
save_audio_config_p->achan[chan].upsample);
|
|
||||||
if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
|
if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
|
||||||
dw_printf (", DTMF decoder enabled");
|
dw_printf (", DTMF decoder enabled");
|
||||||
dw_printf (".\n");
|
dw_printf (".\n");
|
||||||
|
@ -743,7 +551,6 @@ int demod_init (struct audio_s *pa)
|
||||||
struct demodulator_state_s *D;
|
struct demodulator_state_s *D;
|
||||||
D = &demodulator_state[chan][0]; // first subchannel
|
D = &demodulator_state[chan][0]; // first subchannel
|
||||||
|
|
||||||
|
|
||||||
save_audio_config_p->achan[chan].num_subchan = 1;
|
save_audio_config_p->achan[chan].num_subchan = 1;
|
||||||
save_audio_config_p->achan[chan].num_slicers = 1;
|
save_audio_config_p->achan[chan].num_slicers = 1;
|
||||||
|
|
||||||
|
@ -755,36 +562,7 @@ int demod_init (struct audio_s *pa)
|
||||||
save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
|
save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
demod_9600_init (UPSAMPLE * save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, save_audio_config_p->achan[chan].baud, D);
|
||||||
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,
|
|
||||||
save_audio_config_p->achan[chan].baud,
|
|
||||||
(double)ratio);
|
|
||||||
if (ratio < 3) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("There is little hope of success with such a low ratio. Use a higher sample rate.\n");
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
else if (ratio > 15) {
|
|
||||||
dw_printf ("Sample rate is more than adequate. You might lower it if CPU load is a concern.\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {
|
if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {
|
||||||
|
|
||||||
|
@ -795,32 +573,19 @@ int demod_init (struct audio_s *pa)
|
||||||
D->num_slicers = MAX_SLICERS;
|
D->num_slicers = MAX_SLICERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For signal level reporting, we want a longer term view. */
|
/* For siginal level reporting, we want a longer term view. */
|
||||||
|
|
||||||
D->quick_attack = D->agc_fast_attack * 0.2f;
|
D->quick_attack = D->agc_fast_attack * 0.2;
|
||||||
D->sluggish_decay = D->agc_slow_decay * 0.2f;
|
D->sluggish_decay = D->agc_slow_decay * 0.2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} /* switch on modulation type. */
|
} /* switch on modulation type. */
|
||||||
|
|
||||||
} /* if channel medium is radio */
|
} /* if channel number is valid */
|
||||||
|
|
||||||
// FIXME dw_printf ("-------- end of loop for chn %d \n", chan);
|
|
||||||
|
|
||||||
} /* for chan ... */
|
} /* 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);
|
return (0);
|
||||||
|
|
||||||
|
@ -832,7 +597,7 @@ int demod_init (struct audio_s *pa)
|
||||||
*
|
*
|
||||||
* Name: demod_get_sample
|
* 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.
|
* Inputs: a - Index for audio device. 0 = first.
|
||||||
*
|
*
|
||||||
|
@ -842,7 +607,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
|
* 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.
|
* 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
|
* When processing stereo, the caller will call this
|
||||||
* at twice the normal rate to obtain alternating left
|
* at twice the normal rate to obtain alternating left
|
||||||
|
@ -852,15 +617,17 @@ int demod_init (struct audio_s *pa)
|
||||||
|
|
||||||
#define FSK_READ_ERR (256*256)
|
#define FSK_READ_ERR (256*256)
|
||||||
|
|
||||||
|
|
||||||
__attribute__((hot))
|
__attribute__((hot))
|
||||||
int demod_get_sample (int a)
|
int demod_get_sample (int a)
|
||||||
{
|
{
|
||||||
int x1, x2;
|
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);
|
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) {
|
if (save_audio_config_p->adev[a].bits_per_sample == 8) {
|
||||||
|
|
||||||
x1 = audio_get(a);
|
x1 = audio_get(a);
|
||||||
|
@ -927,38 +694,27 @@ 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))
|
__attribute__((hot))
|
||||||
void demod_process_sample (int chan, int subchan, int sam)
|
void demod_process_sample (int chan, int subchan, int sam)
|
||||||
{
|
{
|
||||||
float fsam;
|
float fsam;
|
||||||
//int k;
|
//float abs_fsam;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG4
|
||||||
|
static FILE *demod_log_fp = NULL;
|
||||||
|
static int seq = 0; /* for log file name */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//int j;
|
||||||
|
//int demod_data;
|
||||||
struct demodulator_state_s *D;
|
struct demodulator_state_s *D;
|
||||||
|
|
||||||
assert (chan >= 0 && chan < MAX_CHANS);
|
assert (chan >= 0 && chan < MAX_CHANS);
|
||||||
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
||||||
|
|
||||||
if (mute_input[chan]) {
|
|
||||||
sam = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
D = &demodulator_state[chan][subchan];
|
D = &demodulator_state[chan][subchan];
|
||||||
|
|
||||||
|
|
||||||
|
@ -1006,7 +762,6 @@ void demod_process_sample (int chan, int subchan, int sam)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODEM_AFSK:
|
case MODEM_AFSK:
|
||||||
case MODEM_EAS:
|
|
||||||
|
|
||||||
if (save_audio_config_p->achan[chan].decimate > 1) {
|
if (save_audio_config_p->achan[chan].decimate > 1) {
|
||||||
|
|
||||||
|
@ -1019,34 +774,58 @@ void demod_process_sample (int chan, int subchan, int sam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
demod_afsk_process_sample (chan, subchan, sam, D);
|
demod_afsk_process_sample (chan, subchan, sam, D);
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MODEM_QPSK:
|
|
||||||
case MODEM_8PSK:
|
|
||||||
|
|
||||||
if (save_audio_config_p->achan[chan].decimate > 1) {
|
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Invalid combination of options. Exiting.\n");
|
|
||||||
// Would probably work but haven't thought about it or tested yet.
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
demod_psk_process_sample (chan, subchan, sam, D);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MODEM_BASEBAND:
|
case MODEM_BASEBAND:
|
||||||
case MODEM_SCRAMBLE:
|
case MODEM_SCRAMBLE:
|
||||||
case MODEM_AIS:
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
demod_9600_process_sample (chan, sam, save_audio_config_p->achan[chan].upsample, D);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} /* switch modem_type */
|
#define ZEROSTUFF 1
|
||||||
|
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} /* end demod_process_sample */
|
} /* end demod_process_sample */
|
||||||
|
@ -1083,18 +862,14 @@ 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);
|
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 ||
|
if (save_audio_config_p->achan[chan].modem_type == MODEM_AFSK) {
|
||||||
save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
|
|
||||||
|
|
||||||
/* For AFSK, we have mark and space amplitudes. */
|
/* For AFSK, we have mark and space amplitudes. */
|
||||||
|
|
||||||
alevel.mark = (int) ((D->alevel_mark_peak ) * 100.0f + 0.5f);
|
alevel.mark = (int) ((D->alevel_mark_peak ) * 100.0f + 0.5f);
|
||||||
alevel.space = (int) ((D->alevel_space_peak ) * 100.0f + 0.5f);
|
alevel.space = (int) ((D->alevel_space_peak ) * 100.0f + 0.5f);
|
||||||
}
|
|
||||||
else if (save_audio_config_p->achan[chan].modem_type == MODEM_QPSK ||
|
//alevel.ms_ratio = D->alevel_mark_peak / D->alevel_space_peak; // TODO: remove after temp test
|
||||||
save_audio_config_p->achan[chan].modem_type == MODEM_8PSK) {
|
|
||||||
alevel.mark = -1;
|
|
||||||
alevel.space = -1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -8,13 +8,10 @@
|
||||||
|
|
||||||
int demod_init (struct audio_s *pa);
|
int demod_init (struct audio_s *pa);
|
||||||
|
|
||||||
void demod_mute_input (int chan, int mute);
|
|
||||||
|
|
||||||
int demod_get_sample (int a);
|
int demod_get_sample (int a);
|
||||||
|
|
||||||
void demod_process_sample (int chan, int subchan, int sam);
|
void demod_process_sample (int chan, int subchan, int sam);
|
||||||
|
|
||||||
void demod_print_agc (int chan, int subchan);
|
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);
|
||||||
|
|
|
@ -0,0 +1,517 @@
|
||||||
|
//
|
||||||
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// 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/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// #define DEBUG5 1 /* capture 9600 output to log files */
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Module: demod_9600.c
|
||||||
|
*
|
||||||
|
* Purpose: Demodulator for scrambled baseband encoding.
|
||||||
|
*
|
||||||
|
* Input: Audio samples from either a file or the "sound card."
|
||||||
|
*
|
||||||
|
* Outputs: Calls hdlc_rec_bit() for each bit demodulated.
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
|
#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];
|
||||||
|
|
||||||
|
|
||||||
|
/* Add sample to buffer and shift the rest down. */
|
||||||
|
|
||||||
|
__attribute__((hot)) __attribute__((always_inline))
|
||||||
|
static inline void push_sample (float val, float *buff, int size)
|
||||||
|
{
|
||||||
|
memmove(buff+1,buff,(size-1)*sizeof(float));
|
||||||
|
buff[0] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FIR filter kernel. */
|
||||||
|
|
||||||
|
__attribute__((hot)) __attribute__((always_inline))
|
||||||
|
static inline float convolve (const float *__restrict__ data, const float *__restrict__ filter, int filter_size)
|
||||||
|
{
|
||||||
|
float sum = 0.0f;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// As suggested here, http://locklessinc.com/articles/vectorize/
|
||||||
|
// Unfortunately, older compilers don't recognize it.
|
||||||
|
|
||||||
|
// Get more information by using -ftree-vectorizer-verbose=5
|
||||||
|
|
||||||
|
float *d = __builtin_assume_aligned(data, 16);
|
||||||
|
float *f = __builtin_assume_aligned(filter, 16);
|
||||||
|
|
||||||
|
#pragma GCC ivdep
|
||||||
|
for (j=0; j<filter_size; j++) {
|
||||||
|
sum += f[j] * d[j];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#pragma GCC ivdep // ignored until gcc 4.9
|
||||||
|
for (j=0; j<filter_size; j++) {
|
||||||
|
sum += filter[j] * data[j];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Automatic gain control. */
|
||||||
|
/* Result should settle down to 1 unit peak to peak. i.e. -0.5 to +0.5 */
|
||||||
|
|
||||||
|
__attribute__((hot)) __attribute__((always_inline))
|
||||||
|
static inline float agc (float in, float fast_attack, float slow_decay, float *ppeak, float *pvalley)
|
||||||
|
{
|
||||||
|
if (in >= *ppeak) {
|
||||||
|
*ppeak = in * fast_attack + *ppeak * (1. - fast_attack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*ppeak = in * slow_decay + *ppeak * (1. - slow_decay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in <= *pvalley) {
|
||||||
|
*pvalley = in * fast_attack + *pvalley * (1. - fast_attack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*pvalley = in * slow_decay + *pvalley * (1. - slow_decay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ppeak > *pvalley) {
|
||||||
|
return ((in - 0.5 * (*ppeak + *pvalley)) / (*ppeak - *pvalley));
|
||||||
|
}
|
||||||
|
return (0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: demod_9600_init
|
||||||
|
*
|
||||||
|
* Purpose: Initialize the 9600 baud demodulator.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* D - Address of demodulator state.
|
||||||
|
*
|
||||||
|
* Returns: None
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void demod_9600_init (int samples_per_sec, int baud, struct demodulator_state_s *D)
|
||||||
|
{
|
||||||
|
float fc;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
memset (D, 0, sizeof(struct demodulator_state_s));
|
||||||
|
D->num_slicers = 1;
|
||||||
|
|
||||||
|
//dw_printf ("demod_9600_init(rate=%d, baud=%d, D ptr)\n", samples_per_sec, baud);
|
||||||
|
|
||||||
|
D->pll_step_per_sample =
|
||||||
|
(int) round(TICKS_PER_PLL_CYCLE * (double) baud / (double)samples_per_sec);
|
||||||
|
|
||||||
|
D->lp_filter_len_bits = 72 * 9600.0 / (44100.0 * 2.0);
|
||||||
|
D->lp_filter_size = (int) (( D->lp_filter_len_bits * (float)samples_per_sec / baud) + 0.5);
|
||||||
|
D->lp_window = BP_WINDOW_HAMMING;
|
||||||
|
D->lpf_baud = 0.59;
|
||||||
|
|
||||||
|
D->agc_fast_attack = 0.080;
|
||||||
|
D->agc_slow_decay = 0.00012;
|
||||||
|
|
||||||
|
D->pll_locked_inertia = 0.88;
|
||||||
|
D->pll_searching_inertia = 0.67;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TUNE_LP_WINDOW
|
||||||
|
D->lp_window = TUNE_LP_WINDOW;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TUNE_LP_FILTER_SIZE
|
||||||
|
D->lp_filter_size = TUNE_LP_FILTER_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TUNE_LPF_BAUD
|
||||||
|
D->lpf_baud = TUNE_LPF_BAUD;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TUNE_AGC_FAST
|
||||||
|
D->agc_fast_attack = TUNE_AGC_FAST;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TUNE_AGC_SLOW
|
||||||
|
D->agc_slow_decay = TUNE_AGC_SLOW;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TUNE_PLL_LOCKED) && defined(TUNE_PLL_SEARCHING)
|
||||||
|
D->pll_locked_inertia = TUNE_PLL_LOCKED;
|
||||||
|
D->pll_searching_inertia = TUNE_PLL_SEARCHING;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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->lp_filter, D->lp_filter_size, D->lp_window);
|
||||||
|
|
||||||
|
/* Version 1.2: Experiment with different slicing levels. */
|
||||||
|
|
||||||
|
for (j = 0; j < MAX_SUBCHANS; j++) {
|
||||||
|
slice_point[j] = 0.02 * (j - 0.5 * (MAX_SUBCHANS-1));
|
||||||
|
//dw_printf ("slice_point[%d] = %+5.2f\n", j, slice_point[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end fsk_demod_init */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: demod_9600_process_sample
|
||||||
|
*
|
||||||
|
* Purpose: (1) Filter & slice the signal.
|
||||||
|
* (2) Descramble it.
|
||||||
|
* (2) Recover clock and data.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Audio channel. 0 for left, 1 for right.
|
||||||
|
*
|
||||||
|
* sam - One sample of audio.
|
||||||
|
* Should be in range of -32768 .. 32767.
|
||||||
|
*
|
||||||
|
* Returns: None
|
||||||
|
*
|
||||||
|
* Descripion: "9600 baud" packet is FSK for an FM voice transceiver.
|
||||||
|
* By the time it gets here, it's really a baseband signal.
|
||||||
|
* At one extreme, we could have a 4800 Hz square wave.
|
||||||
|
* A the other extreme, we could go a considerable number
|
||||||
|
* of bit times without any transitions.
|
||||||
|
*
|
||||||
|
* The trick is to extract the digital data which has
|
||||||
|
* been distorted by going thru voice transceivers not
|
||||||
|
* intended to pass this sort of "audio" signal.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* to recover the clock and pick out data bits at
|
||||||
|
* the proper rate.
|
||||||
|
*
|
||||||
|
* For each recovered data bit, we call:
|
||||||
|
*
|
||||||
|
* hdlc_rec (channel, demodulated_bit);
|
||||||
|
*
|
||||||
|
* to decode HDLC frames from the stream of bits.
|
||||||
|
*
|
||||||
|
* Future: This could be generalized by passing in the name
|
||||||
|
* of the function to be called for each bit recovered
|
||||||
|
* from the demodulator. For now, it's simply hard-coded.
|
||||||
|
*
|
||||||
|
* References: 9600 Baud Packet Radio Modem Design
|
||||||
|
* http://www.amsat.org/amsat/articles/g3ruh/109.html
|
||||||
|
*
|
||||||
|
* The KD2BD 9600 Baud Modem
|
||||||
|
* http://www.amsat.org/amsat/articles/kd2bd/9k6modem/
|
||||||
|
*
|
||||||
|
* 9600 Baud Packet Handbook
|
||||||
|
* ftp://ftp.tapr.org/general/9600baud/96man2x0.txt
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void inline nudge_pll (int chan, int subchan, int slice, int demod_data, struct demodulator_state_s *D);
|
||||||
|
|
||||||
|
__attribute__((hot))
|
||||||
|
void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D)
|
||||||
|
{
|
||||||
|
|
||||||
|
float fsam;
|
||||||
|
//float abs_fsam;
|
||||||
|
float amp;
|
||||||
|
float demod_out;
|
||||||
|
|
||||||
|
#if DEBUG5
|
||||||
|
static FILE *demod_log_fp = NULL;
|
||||||
|
static int seq = 0; /* for log file name */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//int j;
|
||||||
|
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 = sam / 16384.0;
|
||||||
|
|
||||||
|
push_sample (fsam, D->raw_cb, D->lp_filter_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Low pass filter to reduce noise yet pass the data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
amp = convolve (D->raw_cb, D->lp_filter, D->lp_filter_size);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 1.2: Capture the post-filtering amplitude for display.
|
||||||
|
* This is similar to the AGC without the normalization step.
|
||||||
|
* We want decay to be substantially slower to get a longer
|
||||||
|
* range idea of the received audio.
|
||||||
|
* For AFSK, we keep mark and space amplitudes.
|
||||||
|
* Here we keep + and - peaks because there could be a DC bias.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (amp >= D->alevel_mark_peak) {
|
||||||
|
D->alevel_mark_peak = amp * D->quick_attack + D->alevel_mark_peak * (1. - D->quick_attack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
D->alevel_mark_peak = amp * D->sluggish_decay + D->alevel_mark_peak * (1. - D->sluggish_decay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amp <= D->alevel_space_peak) {
|
||||||
|
D->alevel_space_peak = amp * D->quick_attack + D->alevel_space_peak * (1. - D->quick_attack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
D->alevel_space_peak = amp * D->sluggish_decay + D->alevel_space_peak * (1. - D->sluggish_decay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The input level can vary greatly.
|
||||||
|
* More importantly, there could be a DC bias which we need to remove.
|
||||||
|
*
|
||||||
|
* Normalize the signal with automatic gain control (AGC).
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 amp=%.2f norm=%.2f\n", D->m_peak, D->m_valley, amp, norm);
|
||||||
|
|
||||||
|
/* Throw in a little Hysteresis??? */
|
||||||
|
/* (Not to be confused with Hysteria.) */
|
||||||
|
/* Doesn't seem to have any value. */
|
||||||
|
/* Using a level of .02 makes things worse. */
|
||||||
|
/* Might want to experiment with this again someday. */
|
||||||
|
|
||||||
|
|
||||||
|
// if (demod_out > 0.03) {
|
||||||
|
// demod_data = 1;
|
||||||
|
// }
|
||||||
|
// else if (demod_out < -0.03) {
|
||||||
|
// demod_data = 0;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// demod_data = D->slicer[subchan].prev_demod_data;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (D->num_slicers <= 1) {
|
||||||
|
|
||||||
|
/* Normal case of one demodulator to one HDLC decoder. */
|
||||||
|
/* Demodulator output is difference between response from two filters. */
|
||||||
|
/* AGC should generally keep this around -1 to +1 range. */
|
||||||
|
|
||||||
|
demod_data = demod_out > 0;
|
||||||
|
nudge_pll (chan, subchan, 0, demod_data, D);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int slice;
|
||||||
|
|
||||||
|
/* Multiple slicers each feeding its own HDLC decoder. */
|
||||||
|
|
||||||
|
for (slice=0; slice<D->num_slicers; slice++) {
|
||||||
|
demod_data = demod_out > slice_point[slice];
|
||||||
|
nudge_pll (chan, subchan, slice, demod_data, D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end demod_9600_process_sample */
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((hot))
|
||||||
|
static void inline nudge_pll (int chan, int subchan, int slice, int demod_data, struct demodulator_state_s *D)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Next, 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
|
||||||
|
* sample a data bit from the demodulated signal.
|
||||||
|
*
|
||||||
|
* Ideally, the the demodulated signal transitions should be near
|
||||||
|
* zero we we sample mid way between the transitions.
|
||||||
|
*
|
||||||
|
* Nudge the PLL by removing some small fraction from the value of
|
||||||
|
* data_clock_pll, pushing it closer to zero.
|
||||||
|
*
|
||||||
|
* This adjustment will never change the sign so it won't cause
|
||||||
|
* any erratic data bit sampling.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* I don't think the optimal value will depend on the audio sample rate
|
||||||
|
* because this happens for each transition from the demodulator.
|
||||||
|
*
|
||||||
|
* This was optimized for 1200 baud AFSK. There might be some opportunity
|
||||||
|
* for improvement here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
D->slicer[slice].prev_d_c_pll = D->slicer[slice].data_clock_pll;
|
||||||
|
D->slicer[slice].data_clock_pll += D->pll_step_per_sample;
|
||||||
|
|
||||||
|
if (D->slicer[slice].data_clock_pll < 0 && D->slicer[slice].prev_d_c_pll > 0) {
|
||||||
|
|
||||||
|
/* Overflow. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point, we need to descramble the data as
|
||||||
|
* in hardware based designs by G3RUH and K9NG.
|
||||||
|
*
|
||||||
|
* Future Idea: allow unscrambled baseband data.
|
||||||
|
*
|
||||||
|
* http://www.amsat.org/amsat/articles/g3ruh/109/fig03.gif
|
||||||
|
*/
|
||||||
|
// Warning: 'descram' set but not used.
|
||||||
|
// It's used in conditional debug code below.
|
||||||
|
// descram =
|
||||||
|
descramble (demod_data, &(D->slicer[slice].lfsr));
|
||||||
|
|
||||||
|
hdlc_rec_bit (chan, subchan, slice, demod_data, 1, D->slicer[slice].lfsr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (demod_data != D->slicer[slice].prev_demod_data) {
|
||||||
|
|
||||||
|
// Note: Test for this demodulator, not overall for channel.
|
||||||
|
|
||||||
|
if (hdlc_rec_gathering (chan, subchan, slice)) {
|
||||||
|
D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_locked_inertia);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_searching_inertia);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG5
|
||||||
|
|
||||||
|
//if (chan == 0) {
|
||||||
|
if (hdlc_rec_gathering (chan,subchan,slice)) {
|
||||||
|
|
||||||
|
char fname[30];
|
||||||
|
|
||||||
|
|
||||||
|
if (demod_log_fp == NULL) {
|
||||||
|
seq++;
|
||||||
|
snprintf (fname, sizeof(fname), "demod96/%04d.csv", seq);
|
||||||
|
if (seq == 1) mkdir ("demod96"
|
||||||
|
#ifndef __WIN32__
|
||||||
|
, 0777
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
demod_log_fp = fopen (fname, "w");
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("Starting 9600 decoder log file %s\n", fname);
|
||||||
|
fprintf (demod_log_fp, "Audio, Peak, Valley, Demod, SData, Descram, Clock\n");
|
||||||
|
}
|
||||||
|
fprintf (demod_log_fp, "%.3f, %.3f, %.3f, %.3f, %.2f, %.2f, %.2f\n",
|
||||||
|
0.5 * fsam + 3.5,
|
||||||
|
0.5 * D->m_peak + 3.5,
|
||||||
|
0.5 * D->m_valley + 3.5,
|
||||||
|
0.5 * demod_out + 2.0,
|
||||||
|
demod_data ? 1.35 : 1.0,
|
||||||
|
descram ? .9 : .55,
|
||||||
|
(D->data_clock_pll & 0x80000000) ? .1 : .45);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (demod_log_fp != NULL) {
|
||||||
|
fclose (demod_log_fp);
|
||||||
|
demod_log_fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember demodulator output (pre-descrambling) so we can compare next time
|
||||||
|
* for the DPLL sync.
|
||||||
|
*/
|
||||||
|
D->slicer[slice].prev_demod_data = demod_data;
|
||||||
|
|
||||||
|
} /* end nudge_pll */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* end demod_9600.c */
|
|
@ -6,9 +6,9 @@
|
||||||
#include "fsk_demod_state.h"
|
#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
|
@ -23,7 +23,6 @@
|
||||||
* Name: digipeater.c
|
* Name: digipeater.c
|
||||||
*
|
*
|
||||||
* Purpose: Act as an APRS digital repeater.
|
* Purpose: Act as an APRS digital repeater.
|
||||||
* Similar cdigipeater.c is for connected mode.
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Description: Decide whether the specified packet should
|
* Description: Decide whether the specified packet should
|
||||||
|
@ -49,13 +48,11 @@
|
||||||
* Preemptive Digipeating (new in version 0.8)
|
* Preemptive Digipeating (new in version 0.8)
|
||||||
*
|
*
|
||||||
* http://www.aprs.org/aprs12/preemptive-digipeating.txt
|
* http://www.aprs.org/aprs12/preemptive-digipeating.txt
|
||||||
* I ignored the part about the RR bits.
|
*
|
||||||
*
|
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define DIGIPEATER_C
|
#define DIGIPEATER_C
|
||||||
|
|
||||||
#include "direwolf.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -63,8 +60,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h> /* for isdigit, isupper */
|
#include <ctype.h> /* for isdigit, isupper */
|
||||||
#include "regex.h"
|
#include "regex.h"
|
||||||
#include <unistd.h>
|
#include <sys/unistd.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
#include "ax25_pad.h"
|
#include "ax25_pad.h"
|
||||||
#include "digipeater.h"
|
#include "digipeater.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
|
@ -74,7 +72,9 @@
|
||||||
|
|
||||||
|
|
||||||
static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, char *mycall_xmit,
|
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);
|
||||||
|
|
||||||
|
//static int filter_by_type (char *source, char *infop, char *type_filter);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -87,18 +87,6 @@ static struct audio_s *save_audio_config_p;
|
||||||
static struct digi_config_s *save_digi_config_p;
|
static struct digi_config_s *save_digi_config_p;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maintain count of packets digipeated for each combination of from/to channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int digi_count[MAX_CHANS][MAX_CHANS];
|
|
||||||
|
|
||||||
int digipeater_get_count (int from_chan, int to_chan) {
|
|
||||||
return (digi_count[from_chan][to_chan]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: digipeater_init
|
* Name: digipeater_init
|
||||||
|
@ -150,49 +138,18 @@ void digipeater (int from_chan, packet_t pp)
|
||||||
|
|
||||||
// dw_printf ("digipeater()\n");
|
// dw_printf ("digipeater()\n");
|
||||||
|
|
||||||
|
assert (from_chan >= 0 && from_chan < MAX_CHANS);
|
||||||
|
|
||||||
|
if ( ! save_audio_config_p->achan[from_chan].valid) {
|
||||||
// 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)) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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.
|
* First pass: Look at packets being digipeated to same channel.
|
||||||
*
|
*
|
||||||
* We want these to get out quickly, bypassing the usual random wait time.
|
* We want these to get out quickly.
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) {
|
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) {
|
||||||
|
@ -204,12 +161,10 @@ void digipeater (int from_chan, packet_t pp)
|
||||||
save_audio_config_p->achan[to_chan].mycall,
|
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],
|
&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],
|
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]);
|
save_digi_config_p->filter_str[from_chan][to_chan]);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
dedupe_remember (pp, to_chan);
|
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,12 +186,10 @@ void digipeater (int from_chan, packet_t pp)
|
||||||
save_audio_config_p->achan[to_chan].mycall,
|
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],
|
&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],
|
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]);
|
save_digi_config_p->filter_str[from_chan][to_chan]);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
dedupe_remember (pp, to_chan);
|
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 +227,6 @@ void digipeater (int from_chan, packet_t pp)
|
||||||
*
|
*
|
||||||
* preempt - Option for "preemptive" digipeating.
|
* 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.
|
* filter_str - Filter expression string or NULL.
|
||||||
*
|
*
|
||||||
* Returns: Packet object for transmission or NULL.
|
* Returns: Packet object for transmission or NULL.
|
||||||
|
@ -293,11 +243,28 @@ void digipeater (int from_chan, packet_t pp)
|
||||||
*
|
*
|
||||||
*------------------------------------------------------------------------------*/
|
*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
|
||||||
static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, char *mycall_xmit,
|
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;
|
int ssid;
|
||||||
int r;
|
int r;
|
||||||
char repeater[AX25_MAX_ADDR_LEN];
|
char repeater[AX25_MAX_ADDR_LEN];
|
||||||
|
@ -307,9 +274,19 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
/*
|
/*
|
||||||
* First check if filtering has been configured.
|
* First check if filtering has been configured.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (filter_str != NULL) {
|
if (filter_str != NULL) {
|
||||||
|
|
||||||
if (pfilter(from_chan, to_chan, filter_str, pp, 1) != 1) {
|
if (pfilter(from_chan, to_chan, filter_str, pp) != 1) {
|
||||||
|
|
||||||
|
// TODO1.2: take out debug message
|
||||||
|
// Actually it turns out to be useful.
|
||||||
|
// Maybe add a quiet option to suppress it although no one has complained about it yet.
|
||||||
|
//#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("Packet was rejected for digipeating from channel %d to %d by filter: %s\n", from_chan, to_chan, filter_str);
|
||||||
|
//#endif
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,6 +310,11 @@ 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.
|
* Otherwise we don't want to modify the input because this could be called multiple times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
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. */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the first repeater station which doesn't have "has been repeated" set.
|
* Find the first repeater station which doesn't have "has been repeated" set.
|
||||||
|
@ -355,13 +337,10 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check for explicit use of my call, including SSID.
|
* First check for explicit use of my call.
|
||||||
* Someone might explicitly specify a particular path for testing purposes.
|
|
||||||
* This will bypass the usual checks for duplicates and my call in the source.
|
|
||||||
*
|
|
||||||
* In this case, we don't check the history so it would be possible
|
* In this case, we don't check the history so it would be possible
|
||||||
* to have a loop (of limited size) if someone constructed the digipeater paths
|
* to have a loop (of limited size) if someone constructed the digipeater paths
|
||||||
* correctly. I would expect it only for testing purposes.
|
* correctly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strcmp(repeater, mycall_rec) == 0) {
|
if (strcmp(repeater, mycall_rec) == 0) {
|
||||||
|
@ -377,24 +356,13 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't digipeat my own. Fixed in 1.4 dev H.
|
|
||||||
* Alternatively we might feed everything transmitted into
|
|
||||||
* dedupe_remember rather than only frames out of digipeater.
|
|
||||||
*/
|
|
||||||
ax25_get_addr_with_ssid(pp, AX25_SOURCE, source);
|
|
||||||
if (strcmp(source, mycall_rec) == 0) {
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next try to avoid retransmitting redundant information.
|
* Next try to avoid retransmitting redundant information.
|
||||||
* Duplicates are detected by comparing only:
|
* Duplicates are detected by comparing only:
|
||||||
* - source
|
* - source
|
||||||
* - destination
|
* - destination
|
||||||
* - info part
|
* - info part
|
||||||
* - but not the via path. (digipeater addresses)
|
* - but none of the digipeaters
|
||||||
* A history is kept for some amount of time, typically 30 seconds.
|
* A history is kept for some amount of time, typically 30 seconds.
|
||||||
* For efficiency, only a checksum, rather than the complete fields
|
* For efficiency, only a checksum, rather than the complete fields
|
||||||
* might be kept but the result is the same.
|
* might be kept but the result is the same.
|
||||||
|
@ -403,6 +371,7 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (dedupe_check(pp, to_chan)) {
|
if (dedupe_check(pp, to_chan)) {
|
||||||
//#if DEBUG
|
//#if DEBUG
|
||||||
/* Might be useful if people are wondering why */
|
/* Might be useful if people are wondering why */
|
||||||
|
@ -416,10 +385,7 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the alias pattern, we unconditionally digipeat it once.
|
* For the alias pattern, we unconditionally digipeat it once.
|
||||||
* i.e. Just replace it with MYCALL.
|
* i.e. Just replace it with MYCALL don't even look at the ssid.
|
||||||
*
|
|
||||||
* My call should be an implied member of this set.
|
|
||||||
* In this implementation, we already caught it further up.
|
|
||||||
*/
|
*/
|
||||||
err = regexec(alias,repeater,0,NULL,0);
|
err = regexec(alias,repeater,0,NULL,0);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
|
@ -441,10 +407,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
|
* If preemptive digipeating is enabled, try matching my call
|
||||||
* and aliases against all remaining unused digipeaters.
|
* 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) {
|
if (preempt != PREEMPT_OFF) {
|
||||||
|
@ -470,22 +432,13 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
|
|
||||||
switch (preempt) {
|
switch (preempt) {
|
||||||
case PREEMPT_DROP: /* remove all prior */
|
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) {
|
while (r2 > AX25_REPEATER_1) {
|
||||||
ax25_remove_addr (result, r2-1);
|
ax25_remove_addr (result, r2-1);
|
||||||
r2--;
|
r2--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREEMPT_MARK: // TODO: deprecate this option. Result is misleading.
|
case PREEMPT_MARK:
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
r2--;
|
r2--;
|
||||||
while (r2 >= AX25_REPEATER_1 && ax25_get_h(result,r2) == 0) {
|
while (r2 >= AX25_REPEATER_1 && ax25_get_h(result,r2) == 0) {
|
||||||
ax25_set_h (result, r2);
|
ax25_set_h (result, r2);
|
||||||
|
@ -493,12 +446,7 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PREEMPT_TRACE: /* My enhancement - remove prior unused digis. */
|
case PREEMPT_TRACE: /* remove prior unused */
|
||||||
/* 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?
|
|
||||||
default:
|
default:
|
||||||
while (r2 > AX25_REPEATER_1 && ax25_get_h(result,r2-1) == 0) {
|
while (r2 > AX25_REPEATER_1 && ax25_get_h(result,r2-1) == 0) {
|
||||||
ax25_remove_addr (result, r2-1);
|
ax25_remove_addr (result, r2-1);
|
||||||
|
@ -507,16 +455,6 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Idea: Here is an interesting idea for a new option. REORDER?
|
|
||||||
// The preemptive digipeater could move its call after the (formerly) last used digi field
|
|
||||||
// and preserve all the unused fields after that. The list of used addresses would
|
|
||||||
// accurately record the journey taken by the packet.
|
|
||||||
|
|
||||||
// https://groups.yahoo.com/neo/groups/aprsisce/conversations/topics/31935
|
|
||||||
|
|
||||||
// > I was wishing for a non-marking preemptive digipeat so that the original packet would be left intact
|
|
||||||
// > or maybe something like WIDE1-1,WIDE2-1,KJ4OVQ-9 becoming KJ4OVQ-9*,WIDE1-1,WIDE2-1.
|
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,40 +467,6 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
||||||
err = regexec(wide,repeater,0,NULL,0);
|
err = regexec(wide,repeater,0,NULL,0);
|
||||||
if (err == 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
|
* If ssid == 1, we simply replace the repeater with my call and
|
||||||
* mark it as being used.
|
* mark it as being used.
|
||||||
|
@ -661,7 +565,7 @@ void digi_regen (int from_chan, packet_t pp)
|
||||||
*
|
*
|
||||||
* Name: main
|
* Name: main
|
||||||
*
|
*
|
||||||
* Purpose: Standalone test case for this functionality.
|
* Purpose: Standalone test case for this funtionality.
|
||||||
*
|
*
|
||||||
* Usage: make -f Makefile.<platform> dtest
|
* Usage: make -f Makefile.<platform> dtest
|
||||||
* ./dtest
|
* ./dtest
|
||||||
|
@ -670,7 +574,7 @@ void digi_regen (int from_chan, packet_t pp)
|
||||||
|
|
||||||
#if DIGITEST
|
#if DIGITEST
|
||||||
|
|
||||||
static char mycall[12];
|
static char mycall[] = "WB2OSZ-9";
|
||||||
|
|
||||||
static regex_t alias_re;
|
static regex_t alias_re;
|
||||||
|
|
||||||
|
@ -680,12 +584,13 @@ static int failed;
|
||||||
|
|
||||||
static enum preempt_e preempt = PREEMPT_OFF;
|
static enum preempt_e preempt = PREEMPT_OFF;
|
||||||
|
|
||||||
static char config_atgp[AX25_MAX_ADDR_LEN] = "HOP";
|
static char typefilter[20] = "";
|
||||||
|
|
||||||
|
|
||||||
static void test (char *in, char *out)
|
static void test (char *in, char *out)
|
||||||
{
|
{
|
||||||
packet_t pp, result;
|
packet_t pp, result;
|
||||||
|
//int should_repeat;
|
||||||
char rec[256];
|
char rec[256];
|
||||||
char xmit[256];
|
char xmit[256];
|
||||||
unsigned char *pinfo;
|
unsigned char *pinfo;
|
||||||
|
@ -694,7 +599,6 @@ static void test (char *in, char *out)
|
||||||
int frame_len;
|
int frame_len;
|
||||||
alevel_t alevel;
|
alevel_t alevel;
|
||||||
|
|
||||||
|
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -706,7 +610,6 @@ static void test (char *in, char *out)
|
||||||
|
|
||||||
ax25_format_addrs (pp, rec);
|
ax25_format_addrs (pp, rec);
|
||||||
info_len = ax25_get_info (pp, &pinfo);
|
info_len = ax25_get_info (pp, &pinfo);
|
||||||
(void)info_len;
|
|
||||||
strlcat (rec, (char*)pinfo, sizeof(rec));
|
strlcat (rec, (char*)pinfo, sizeof(rec));
|
||||||
|
|
||||||
if (strcmp(in, rec) != 0) {
|
if (strcmp(in, rec) != 0) {
|
||||||
|
@ -744,9 +647,9 @@ static void test (char *in, char *out)
|
||||||
text_color_set(DW_COLOR_REC);
|
text_color_set(DW_COLOR_REC);
|
||||||
dw_printf ("Rec\t%s\n", rec);
|
dw_printf ("Rec\t%s\n", rec);
|
||||||
|
|
||||||
//TODO: Add filtering to test.
|
//TODO: Add filtering to test.
|
||||||
// V
|
// V
|
||||||
result = digipeat_match (0, pp, mycall, mycall, &alias_re, &wide_re, 0, preempt, config_atgp, NULL);
|
result = digipeat_match (0, pp, mycall, mycall, &alias_re, &wide_re, 0, preempt, NULL);
|
||||||
|
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
|
|
||||||
|
@ -781,7 +684,6 @@ int main (int argc, char *argv[])
|
||||||
int e;
|
int e;
|
||||||
failed = 0;
|
failed = 0;
|
||||||
char message[256];
|
char message[256];
|
||||||
strlcpy(mycall, "WB2OSZ-9", sizeof(mycall));
|
|
||||||
|
|
||||||
dedupe_init (4);
|
dedupe_init (4);
|
||||||
|
|
||||||
|
@ -796,7 +698,7 @@ int main (int argc, char *argv[])
|
||||||
exit (1);
|
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) {
|
if (e != 0) {
|
||||||
regerror (e, &wide_re, message, sizeof(message));
|
regerror (e, &wide_re, message, sizeof(message));
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -882,11 +784,10 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change destination SSID to normal digipeater if none specified. (Obsolete, removed.)
|
* Change destination SSID to normal digipeater if none specified.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
test ( "W1ABC>TEST-3:",
|
test ( "W1ABC>TEST-3:",
|
||||||
"");
|
"W1ABC>TEST,WB2OSZ-9*,WIDE3-2:");
|
||||||
|
|
||||||
test ( "W1DEF>TEST-3,WIDE2-2:",
|
test ( "W1DEF>TEST-3,WIDE2-2:",
|
||||||
"W1DEF>TEST-3,WB2OSZ-9*,WIDE2-1:");
|
"W1DEF>TEST-3,WB2OSZ-9*,WIDE2-1:");
|
||||||
|
@ -894,22 +795,17 @@ int main (int argc, char *argv[])
|
||||||
/*
|
/*
|
||||||
* Drop duplicates within specified time interval.
|
* Drop duplicates within specified time interval.
|
||||||
* Only the first 1 of 3 should be retransmitted.
|
* Only the first 1 of 3 should be retransmitted.
|
||||||
* The 4th case might be controversial.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
test ( "W1XYZ>TESTD,R1*,WIDE3-2:info1",
|
test ( "W1XYZ>TEST,R1*,WIDE3-2:info1",
|
||||||
"W1XYZ>TESTD,R1,WB2OSZ-9*,WIDE3-1: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");
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow same thing after adequate time.
|
* Allow same thing after adequate time.
|
||||||
*/
|
*/
|
||||||
|
@ -967,72 +863,72 @@ int main (int argc, char *argv[])
|
||||||
"");
|
"");
|
||||||
|
|
||||||
|
|
||||||
/*
|
#if 0 /* changed strategy */
|
||||||
* Did I miss any cases?
|
/*
|
||||||
* Yes. Don't retransmit my own. 1.4H
|
* New in version 1.2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
test ( "WB2OSZ-7>TEST14,WIDE1-1,WIDE1-1:stuff",
|
|
||||||
"WB2OSZ-7>TEST14,WB2OSZ-9*,WIDE1-1:stuff");
|
|
||||||
|
|
||||||
test ( "WB2OSZ-9>TEST14,WIDE1-1,WIDE1-1:from myself",
|
// no filter.
|
||||||
|
if (filter_by_type ("CWAPID", ":NWS-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", "") != 1)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 1\n"); failed++; }
|
||||||
|
|
||||||
|
// message should not match psqt
|
||||||
|
if (filter_by_type ("CWAPID", ":NWS-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", "pqst") != 0)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 2\n"); failed++; }
|
||||||
|
|
||||||
|
// This should match position
|
||||||
|
if (filter_by_type ("N3LEE-7", "`cHDl <0x1c>[/\"5j}", "qstp") != 1)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 3\n"); failed++; }
|
||||||
|
|
||||||
|
// This should match nws
|
||||||
|
if (filter_by_type ("CWAPID", ":NWS-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", "n") != 1)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 4\n"); failed++; }
|
||||||
|
|
||||||
|
// But not this.
|
||||||
|
if (filter_by_type ("CWAPID", ":zzz-TTTTT:DDHHMMz,ADVISETYPE,zcs{seq#", "n") != 0)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 5\n"); failed++; }
|
||||||
|
|
||||||
|
// This should match nws
|
||||||
|
if (filter_by_type ("CWAPID", ";CWAttttz *DDHHMMzLATLONICONADVISETYPE{seq#", "n") != 1)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 6\n"); failed++; }
|
||||||
|
|
||||||
|
// But not this due do addressee prefix mismatch
|
||||||
|
if (filter_by_type ("CWAPID", ";NWSttttz *DDHHMMzLATLONICONADVISETYPE{seq#", "n") != 0)
|
||||||
|
{ text_color_set(DW_COLOR_ERROR); dw_printf ("filter_by_type case 7\n"); failed++; }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filtering integrated with rest of process...
|
||||||
|
*/
|
||||||
|
|
||||||
|
strlcpy (typefilter, "w", sizeof(typefilter));
|
||||||
|
|
||||||
|
test ( "N8VIM>APN391,WIDE2-1:$ULTW00000000010E097D2884FFF389DC000102430002033400000000",
|
||||||
|
"N8VIM>APN391,WB2OSZ-9*:$ULTW00000000010E097D2884FFF389DC000102430002033400000000");
|
||||||
|
|
||||||
|
test ( "AB1OC-10>APWW10,WIDE1-1,WIDE2-1:>FN42er/# Hollis, NH iGate Operational",
|
||||||
|
"");
|
||||||
|
|
||||||
|
strlcpy (typefilter, "s", sizeof(typefilter));
|
||||||
|
|
||||||
|
test ( "AB1OC-10>APWW10,WIDE1-1,WIDE2-1:>FN42er/# Hollis, NH iGate Operational",
|
||||||
|
"AB1OC-10>APWW10,WB2OSZ-9*,WIDE2-1:>FN42er/# Hollis, NH iGate Operational");
|
||||||
|
|
||||||
|
test ( "K1ABC-9>TR4R8R,WIDE1-1:`c6LlIb>/`\"4K}_%",
|
||||||
"");
|
"");
|
||||||
|
|
||||||
test ( "WB2OSZ-9>TEST14,WIDE1-1*,WB2OSZ-9:from myself but explicit routing",
|
strlcpy (typefilter, "up", sizeof(typefilter));
|
||||||
"WB2OSZ-9>TEST14,WIDE1-1,WB2OSZ-9*:from myself but explicit routing");
|
|
||||||
|
|
||||||
test ( "WB2OSZ-15>TEST14,WIDE1-1,WIDE1-1:stuff",
|
test ( "K1ABC-9>TR4R8R,WIDE1-1:`c6LlIb>/`\"4K}_%",
|
||||||
"WB2OSZ-15>TEST14,WB2OSZ-9*,WIDE1-1:stuff");
|
"K1ABC-9>TR4R8R,WB2OSZ-9*:`c6LlIb>/`\"4K}_%");
|
||||||
|
|
||||||
// New in 1.7 - ATGP Hack
|
strlcpy (typefilter, "", sizeof(typefilter));
|
||||||
|
#endif
|
||||||
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*:");
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Did I miss any cases?
|
||||||
|
*/
|
||||||
|
|
||||||
if (failed == 0) {
|
if (failed == 0) {
|
||||||
dw_printf ("SUCCESS -- All digipeater tests passed.\n");
|
dw_printf ("SUCCESS -- All digipeater tests passed.\n");
|
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
#ifndef DIGIPEATER_H
|
#ifndef DIGIPEATER_H
|
||||||
#define DIGIPEATER_H 1
|
#define DIGIPEATER_H 1
|
||||||
|
|
||||||
|
@ -37,10 +38,7 @@ struct digi_config_s {
|
||||||
|
|
||||||
enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS];
|
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.
|
//char type_filter[MAX_CHANS][MAX_CHANS][20]; // TODO1.2: remove this
|
||||||
// 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];
|
char *filter_str[MAX_CHANS+1][MAX_CHANS+1];
|
||||||
// NULL or optional Packet Filter strings such as "t/m".
|
// NULL or optional Packet Filter strings such as "t/m".
|
||||||
|
@ -67,11 +65,6 @@ extern void digipeater (int from_chan, packet_t pp);
|
||||||
void digi_regen (int from_chan, packet_t pp);
|
void digi_regen (int from_chan, packet_t pp);
|
||||||
|
|
||||||
|
|
||||||
/* Make statistics available. */
|
|
||||||
|
|
||||||
int digipeater_get_count (int from_chan, int to_chan);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* end digipeater.h */
|
/* end digipeater.h */
|
Binary file not shown.
Before Width: | Height: | Size: 31 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,229 @@
|
||||||
|
|
||||||
|
#ifndef DIREWOLF_H
|
||||||
|
#define DIREWOLF_H 1
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_ADEVS 3
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of radio channels.
|
||||||
|
* Note that there could be gaps.
|
||||||
|
* Suppose audio device 0 was in mono mode and audio device 1 was stereo.
|
||||||
|
* The channels available would be:
|
||||||
|
*
|
||||||
|
* ADevice 0: channel 0
|
||||||
|
* ADevice 1: left = 2, right = 3
|
||||||
|
*
|
||||||
|
* TODO1.2: Look for any places that have
|
||||||
|
* for (ch=0; ch<MAX_CHANS; ch++) ...
|
||||||
|
* and make sure they handle undefined channels correctly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_CHANS ((MAX_ADEVS) * 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of rigs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_HAMLIB
|
||||||
|
#define MAX_RIGS MAX_CHANS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get audio device number for given channel.
|
||||||
|
* and first channel for given device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ACHAN2ADEV(n) ((n)>>1)
|
||||||
|
#define ADEVFIRSTCHAN(n) ((n) * 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of modems per channel.
|
||||||
|
* I called them "subchannels" (in the code) because
|
||||||
|
* it is short and unambiguous.
|
||||||
|
* Nothing magic about the number. Could be larger
|
||||||
|
* but CPU demands might be overwhelming.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_SUBCHANS 9
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each one of these can have multiple slicers, at
|
||||||
|
* different levels, to compensate for different
|
||||||
|
* amplitudes of the AFSK tones.
|
||||||
|
* Intially used same number as subchannels but
|
||||||
|
* we could probably trim this down a little
|
||||||
|
* without impacting performance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_SLICERS 9
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
#include <windows.h>
|
||||||
|
#define SLEEP_SEC(n) Sleep((n)*1000)
|
||||||
|
#define SLEEP_MS(n) Sleep(n)
|
||||||
|
#else
|
||||||
|
#define SLEEP_SEC(n) sleep(n)
|
||||||
|
#define SLEEP_MS(n) usleep((n)*1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
#define PTW32_STATIC_LIB
|
||||||
|
//#include "pthreads/pthread.h"
|
||||||
|
#define gmtime_r( _clock, _result ) \
|
||||||
|
( *(_result) = *gmtime( (_clock) ), \
|
||||||
|
(_result) )
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Not sure where to put these. */
|
||||||
|
|
||||||
|
/* Prefix with DW_ because /usr/include/gps.h uses a couple of these names. */
|
||||||
|
|
||||||
|
#ifndef G_UNKNOWN
|
||||||
|
#include "latlong.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#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_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)
|
||||||
|
#define DW_MPH_TO_KNOTS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.868976)
|
||||||
|
#define DW_MPH_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.44704)
|
||||||
|
|
||||||
|
#define DW_MBAR_TO_INHG(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.0295333727)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
|
typedef CRITICAL_SECTION dw_mutex_t;
|
||||||
|
|
||||||
|
#define dw_mutex_init(x) \
|
||||||
|
InitializeCriticalSection (x)
|
||||||
|
|
||||||
|
/* This one waits for lock. */
|
||||||
|
|
||||||
|
#define dw_mutex_lock(x) \
|
||||||
|
EnterCriticalSection (x)
|
||||||
|
|
||||||
|
/* Returns non-zero if lock was obtained. */
|
||||||
|
|
||||||
|
#define dw_mutex_try_lock(x) \
|
||||||
|
TryEnterCriticalSection (x)
|
||||||
|
|
||||||
|
#define dw_mutex_unlock(x) \
|
||||||
|
LeaveCriticalSection (x)
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef pthread_mutex_t dw_mutex_t;
|
||||||
|
|
||||||
|
#define dw_mutex_init(x) pthread_mutex_init (x, NULL)
|
||||||
|
|
||||||
|
/* this one will wait. */
|
||||||
|
|
||||||
|
#define dw_mutex_lock(x) \
|
||||||
|
{ \
|
||||||
|
int err; \
|
||||||
|
err = pthread_mutex_lock (x); \
|
||||||
|
if (err != 0) { \
|
||||||
|
text_color_set(DW_COLOR_ERROR); \
|
||||||
|
dw_printf ("INTERNAL ERROR %s %d pthread_mutex_lock returned %d", __FILE__, __LINE__, err); \
|
||||||
|
exit (1); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This one returns true if lock successful, false if not. */
|
||||||
|
/* pthread_mutex_trylock returns 0 for success. */
|
||||||
|
|
||||||
|
#define dw_mutex_try_lock(x) \
|
||||||
|
({ \
|
||||||
|
int err; \
|
||||||
|
err = pthread_mutex_trylock (x); \
|
||||||
|
if (err != 0 && err != EBUSY) { \
|
||||||
|
text_color_set(DW_COLOR_ERROR); \
|
||||||
|
dw_printf ("INTERNAL ERROR %s %d pthread_mutex_trylock returned %d", __FILE__, __LINE__, err); \
|
||||||
|
exit (1); \
|
||||||
|
} ; \
|
||||||
|
! err; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define dw_mutex_unlock(x) \
|
||||||
|
{ \
|
||||||
|
int err; \
|
||||||
|
err = pthread_mutex_unlock (x); \
|
||||||
|
if (err != 0) { \
|
||||||
|
text_color_set(DW_COLOR_ERROR); \
|
||||||
|
dw_printf ("INTERNAL ERROR %s %d pthread_mutex_unlock returned %d", __FILE__, __LINE__, err); \
|
||||||
|
exit (1); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Platform differences for string functions. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
char *strsep(char **stringp, const char *delim);
|
||||||
|
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#if __WIN32__
|
||||||
|
char *strcasestr(const char *S, const char *FIND);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||||
|
|
||||||
|
// strlcpy and strlcat should be in string.h and the C library.
|
||||||
|
|
||||||
|
#else // Use our own copy
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG_STRL 1
|
||||||
|
|
||||||
|
#if DEBUG_STRL
|
||||||
|
|
||||||
|
#define strlcpy(dst,src,siz) strlcpy_debug(dst,src,siz,__FILE__,__func__,__LINE__)
|
||||||
|
#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 /* BSD or Apple */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ifndef DIREWOLF_H */
|
|
@ -0,0 +1,62 @@
|
||||||
|
Name: direwolf
|
||||||
|
Version: 1.1b1
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: Soundcard based AX.25 TNC
|
||||||
|
|
||||||
|
Group: Applications/Communications
|
||||||
|
License: GPLv2
|
||||||
|
URL: http://home.comcast.net/~wb2osz
|
||||||
|
Source0: http://home.comcast.net/~wb2osz/Version%201.1/direwolf-%{version}.tgz
|
||||||
|
Packager: David Ranch (KI6ZHD) <dranch@trinnet.net>
|
||||||
|
Distribution: RedHat Linux
|
||||||
|
|
||||||
|
Patch0: direwolf-makefile7.patch
|
||||||
|
|
||||||
|
BuildRequires: automake
|
||||||
|
BuildRequires: alsa-lib-devel
|
||||||
|
|
||||||
|
|
||||||
|
%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 tocalls-symbols
|
||||||
|
make %{?_smp_mflags} -f Makefile.linux
|
||||||
|
|
||||||
|
|
||||||
|
%install
|
||||||
|
make -f Makefile.linux install DESTDIR=$RPM_BUILD_ROOT
|
||||||
|
make -f Makefile.linux install-conf DESTDIR=$RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
# Install icon
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/pixmaps/
|
||||||
|
cp dw-icon.png ${RPM_BUILD_ROOT}%{_datadir}/pixmaps/
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%{_sysconfdir}/ax25/direwolf.conf
|
||||||
|
%{_bindir}/*
|
||||||
|
%{_datadir}/pixmaps/dw-icon.png
|
||||||
|
%{_datadir}/applications/%{name}.desktop
|
||||||
|
%{_datadir}/direwolf/*
|
||||||
|
%{_docdir}/%{name}/*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Sat Dec 20 2014 David Ranch <dranch@trinnet.net> - 1.1b1-1
|
||||||
|
- new spec file
|
|
@ -0,0 +1,532 @@
|
||||||
|
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#NULLMODEM 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 option with the transmit channel number and a VIA path.
|
||||||
|
C
|
||||||
|
C#IGTXVIA 0 WIDE1-1
|
||||||
|
C
|
||||||
|
C# You might want to apply a filter for what packets will be obtained from the server.
|
||||||
|
C# Read about filters 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# That is known as a server-side filter. It is processed by the IGate server.
|
||||||
|
C# You can also apply local filtering to limit what will be transmitted on the
|
||||||
|
C# RF side. For example, transmit only "messages" on channel 0 and weather
|
||||||
|
C# reports on channel 1.
|
||||||
|
C
|
||||||
|
C#FILTER IG 0 t/m
|
||||||
|
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
|
|
@ -0,0 +1,646 @@
|
||||||
|
|
||||||
|
//
|
||||||
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
|
//
|
||||||
|
// Copyright (C) 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
|
||||||
|
// 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/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Module: dlq.c
|
||||||
|
*
|
||||||
|
* Purpose: Received frame queue.
|
||||||
|
*
|
||||||
|
* Description: In previous versions, the main thread read from the
|
||||||
|
* audio device and performed the receive demodulation/decoding.
|
||||||
|
* In version 1.2 we now have a seprate receive thread
|
||||||
|
* for each audio device. This queue is used to collect
|
||||||
|
* received frames from all channels and process them
|
||||||
|
* serially.
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
|
#include "ax25_pad.h"
|
||||||
|
#include "textcolor.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "dlq.h"
|
||||||
|
#include "dedupe.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* The queue is a linked list of these. */
|
||||||
|
|
||||||
|
struct dlq_item_s {
|
||||||
|
|
||||||
|
struct dlq_item_s *nextp; /* Next item in queue. */
|
||||||
|
|
||||||
|
dlq_type_t type; /* Type of item. */
|
||||||
|
/* Only received frames at this time. */
|
||||||
|
|
||||||
|
int chan; /* Radio channel of origin. */
|
||||||
|
|
||||||
|
int subchan; /* Winning "subchannel" when using multiple */
|
||||||
|
/* decoders on one channel. */
|
||||||
|
/* Special case, -1 means DTMF decoder. */
|
||||||
|
/* Maybe we should have a different type in this case? */
|
||||||
|
|
||||||
|
int slice; /* Winning slicer. */
|
||||||
|
|
||||||
|
packet_t pp; /* Pointer to frame structure. */
|
||||||
|
|
||||||
|
alevel_t alevel; /* Audio level. */
|
||||||
|
|
||||||
|
retry_t retries; /* Effort expended to get a valid CRC. */
|
||||||
|
|
||||||
|
char spectrum[MAX_SUBCHANS*MAX_SLICERS+1]; /* "Spectrum" display for multi-decoders. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct dlq_item_s *queue_head = NULL; /* Head of linked list for queue. */
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
|
// TODO1.2: use dw_mutex_t
|
||||||
|
|
||||||
|
static CRITICAL_SECTION dlq_cs; /* Critical section for updating queues. */
|
||||||
|
|
||||||
|
static HANDLE wake_up_event; /* Notify received packet processing thread when queue not empty. */
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static pthread_mutex_t dlq_mutex; /* Critical section for updating queues. */
|
||||||
|
|
||||||
|
static pthread_cond_t wake_up_cond; /* Notify received packet processing thread when queue not empty. */
|
||||||
|
|
||||||
|
static pthread_mutex_t wake_up_mutex; /* Required by cond_wait. */
|
||||||
|
|
||||||
|
static int recv_thread_is_waiting = 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int dlq_is_empty (void);
|
||||||
|
|
||||||
|
static int was_init = 0; /* was initialization performed? */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_init
|
||||||
|
*
|
||||||
|
* Purpose: Initialize the queue.
|
||||||
|
*
|
||||||
|
* Inputs: None.
|
||||||
|
*
|
||||||
|
* Outputs:
|
||||||
|
*
|
||||||
|
* Description: Initialize the queue to be empty and set up other
|
||||||
|
* mechanisms for sharing it between different threads.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
void dlq_init (void)
|
||||||
|
{
|
||||||
|
int c, p;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_init ( )\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
queue_head = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_init: pthread_mutex_init...\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
InitializeCriticalSection (&dlq_cs);
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_init (&wake_up_mutex, NULL);
|
||||||
|
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 (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_init: pthread_cond_init...\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
|
wake_up_event = CreateEvent (NULL, 0, 0, NULL);
|
||||||
|
|
||||||
|
if (wake_up_event == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_init: pthread_cond_init: can't create receive wake up event");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
err = pthread_cond_init (&wake_up_cond, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_init: pthread_cond_init returns %d\n", err);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_init: pthread_cond_init err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_thread_is_waiting = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
was_init = 1;
|
||||||
|
|
||||||
|
} /* end dlq_init */
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_append
|
||||||
|
*
|
||||||
|
* Purpose: Add a packet to the end of the specified receive queue.
|
||||||
|
*
|
||||||
|
* Inputs: type - One of the following:
|
||||||
|
*
|
||||||
|
* DLQ_REC_FRAME - Frame received from radio.
|
||||||
|
*
|
||||||
|
* chan - Channel, 0 is first.
|
||||||
|
*
|
||||||
|
* subchan - Which modem caught it.
|
||||||
|
* Special case -1 for APRStt gateway.
|
||||||
|
*
|
||||||
|
* slice - Which slice we picked.
|
||||||
|
*
|
||||||
|
* pp - Address of packet object.
|
||||||
|
* Caller should NOT make any references to
|
||||||
|
* it after this point because it could
|
||||||
|
* be deleted at any time.
|
||||||
|
*
|
||||||
|
* alevel - Audio level, range of 0 - 100.
|
||||||
|
* (Special case, use negative to skip
|
||||||
|
* display of audio level line.
|
||||||
|
* Use -2 to indicate DTMF message.)
|
||||||
|
*
|
||||||
|
* retries - Level of bit correction used.
|
||||||
|
*
|
||||||
|
* spectrum - Display of how well multiple decoders did.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Outputs: Information is appended to queue.
|
||||||
|
*
|
||||||
|
* Description: Add item to end of linked list.
|
||||||
|
* Signal the receive processing thread if the queue was formerly empty.
|
||||||
|
*
|
||||||
|
* IMPORTANT! Don't make an further references to the packet object after
|
||||||
|
* giving it to dlq_append.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void dlq_append (dlq_type_t type, int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct dlq_item_s *pnew;
|
||||||
|
struct dlq_item_s *plast;
|
||||||
|
int err;
|
||||||
|
int queue_length = 0;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_append (type=%d, chan=%d, pp=%p, ...)\n", type, chan, pp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ! was_init) {
|
||||||
|
dlq_init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (chan >= 0 && chan < MAX_CHANS);
|
||||||
|
|
||||||
|
if (pp == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("INTERNAL ERROR: dlq_append NULL packet pointer. Please report this!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AX25MEMDEBUG
|
||||||
|
|
||||||
|
if (ax25memdebug_get()) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_append (type=%d, chan=%d.%d, seq=%d, ...)\n", type, chan, subchan, ax25memdebug_seq(pp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Allocate a new queue item. */
|
||||||
|
|
||||||
|
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||||
|
|
||||||
|
pnew->nextp = NULL;
|
||||||
|
pnew->type = type;
|
||||||
|
pnew->chan = chan;
|
||||||
|
pnew->slice = slice;
|
||||||
|
pnew->subchan = subchan;
|
||||||
|
pnew->pp = pp;
|
||||||
|
pnew->alevel = alevel;
|
||||||
|
pnew->retries = retries;
|
||||||
|
if (spectrum == NULL)
|
||||||
|
strlcpy(pnew->spectrum, "", sizeof(pnew->spectrum));
|
||||||
|
else
|
||||||
|
strlcpy(pnew->spectrum, spectrum, sizeof(pnew->spectrum));
|
||||||
|
|
||||||
|
#if DEBUG1
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_append: enter critical section\n");
|
||||||
|
#endif
|
||||||
|
#if __WIN32__
|
||||||
|
EnterCriticalSection (&dlq_cs);
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_lock (&dlq_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_append: pthread_mutex_lock err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (queue_head == NULL) {
|
||||||
|
queue_head = pnew;
|
||||||
|
queue_length = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
queue_length = 2; /* head + new one */
|
||||||
|
plast = queue_head;
|
||||||
|
while (plast->nextp != NULL) {
|
||||||
|
plast = plast->nextp;
|
||||||
|
queue_length++;
|
||||||
|
}
|
||||||
|
plast->nextp = pnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
LeaveCriticalSection (&dlq_cs);
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_unlock (&dlq_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_append: pthread_mutex_unlock err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if DEBUG1
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_append: left critical section\n");
|
||||||
|
dw_printf ("dlq_append (): about to wake up recv processing thread.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bug: June 2015, version 1.2
|
||||||
|
*
|
||||||
|
* It has long been known that we will eventually block trying to write to a
|
||||||
|
* pseudo terminal if nothing is reading from the other end. There is even
|
||||||
|
* a warning at start up time:
|
||||||
|
*
|
||||||
|
* Virtual KISS TNC is available on /dev/pts/2
|
||||||
|
* WARNING - Dire Wolf will hang eventually if nothing is reading from it.
|
||||||
|
* Created symlink /tmp/kisstnc -> /dev/pts/2
|
||||||
|
*
|
||||||
|
* In earlier versions, where the audio input and demodulation was in the main
|
||||||
|
* thread, that would stop and it was pretty obvious something was wrong.
|
||||||
|
* In version 1.2, the audio in / demodulating was moved to a device specific
|
||||||
|
* thread. Packet objects are appended to this queue.
|
||||||
|
*
|
||||||
|
* The main thread should wake up and process them which includes printing and
|
||||||
|
* forwarding to clients over multiple protocols and transport methods.
|
||||||
|
* Just before the 1.2 release someone reported a memory leak which only showed
|
||||||
|
* up after about 20 hours. It happened to be on a Cubie Board 2, which shouldn't
|
||||||
|
* make a difference unless there was some operating system difference.
|
||||||
|
* (cubieez 2.0 is based on Debian wheezy, just like Raspian.)
|
||||||
|
*
|
||||||
|
* The debug output revealed:
|
||||||
|
*
|
||||||
|
* It was using AX.25 for Linux (not APRS).
|
||||||
|
* The pseudo terminal KISS interface was being used.
|
||||||
|
* Transmitting was continuing fine. (So something must be writing to the other end.)
|
||||||
|
* Frames were being received and appended to this queue.
|
||||||
|
* They were not coming out of the queue.
|
||||||
|
*
|
||||||
|
* My theory is that writing to the the pseudo terminal is blocking so the
|
||||||
|
* main thread is stopped. It's not taking anything from this queue and we detect
|
||||||
|
* it as a memory leak.
|
||||||
|
*
|
||||||
|
* Add a new check here and complain if the queue is growing too large.
|
||||||
|
* That will get us a step closer to the root cause.
|
||||||
|
* This has been documented in the User Guide and the CHANGES.txt file which is
|
||||||
|
* a minimal version of Release Notes.
|
||||||
|
* The proper fix will be somehow avoiding or detecting the pseudo terminal filling up
|
||||||
|
* and blocking on a write.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (queue_length > 10) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Received frame queue is out of control. Length=%d.\n", queue_length);
|
||||||
|
dw_printf ("Reader thread is probably frozen.\n");
|
||||||
|
dw_printf ("This can be caused by using a pseudo terminal (direwolf -p) where another\n");
|
||||||
|
dw_printf ("application is not reading the frames from the other side.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
SetEvent (wake_up_event);
|
||||||
|
#else
|
||||||
|
if (recv_thread_is_waiting) {
|
||||||
|
|
||||||
|
err = pthread_mutex_lock (&wake_up_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_append: pthread_mutex_lock wu err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pthread_cond_signal (&wake_up_cond);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_append: pthread_cond_signal err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pthread_mutex_unlock (&wake_up_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_append: pthread_mutex_unlock wu err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_wait_while_empty
|
||||||
|
*
|
||||||
|
* Purpose: Sleep while the received data queue is empty rather than
|
||||||
|
* polling periodically.
|
||||||
|
*
|
||||||
|
* Inputs: None.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
void dlq_wait_while_empty (void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG1
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_wait_while_empty () \n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ! was_init) {
|
||||||
|
dlq_init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (queue_head == NULL) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_wait_while_empty (): prepare to SLEEP - about to call cond wait\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
WaitForSingleObject (wake_up_event, INFINITE);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_wait_while_empty (): returned from wait\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_lock (&wake_up_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_wait_while_empty: pthread_mutex_lock wu err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_thread_is_waiting = 1;
|
||||||
|
err = pthread_cond_wait (&wake_up_cond, &wake_up_mutex);
|
||||||
|
recv_thread_is_waiting = 0;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_wait_while_empty (): WOKE UP - returned from cond wait, err = %d\n", err);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_wait_while_empty: pthread_cond_wait err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pthread_mutex_unlock (&wake_up_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_wait_while_empty: pthread_mutex_unlock wu err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_wait_while_empty () returns\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_remove
|
||||||
|
*
|
||||||
|
* Purpose: Remove an item from the head of the queue.
|
||||||
|
*
|
||||||
|
* Inputs: None.
|
||||||
|
*
|
||||||
|
* Outputs: type - type of queue entry.
|
||||||
|
*
|
||||||
|
* chan - channel of received frame.
|
||||||
|
* subchan - which demodulator caught it.
|
||||||
|
* slice - which slicer caught it.
|
||||||
|
*
|
||||||
|
* pp - pointer to packet object when type is DLQ_REC_FRAME.
|
||||||
|
* Caller should destroy it with ax25_delete when finished with it.
|
||||||
|
*
|
||||||
|
* Returns: 1 for success.
|
||||||
|
* 0 if queue is empty.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, int *slice, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum, size_t spectrumsize)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct dlq_item_s *phead;
|
||||||
|
int result;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#if DEBUG1
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_remove() enter critical section\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ! was_init) {
|
||||||
|
dlq_init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
EnterCriticalSection (&dlq_cs);
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_lock (&dlq_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_remove: pthread_mutex_lock err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (queue_head == NULL) {
|
||||||
|
|
||||||
|
*type = -1;
|
||||||
|
*chan = -1;
|
||||||
|
*subchan = -1;
|
||||||
|
*slice = -1;
|
||||||
|
*pp = NULL;
|
||||||
|
|
||||||
|
memset (alevel, 0xff, sizeof(*alevel));
|
||||||
|
|
||||||
|
*retries = -1;
|
||||||
|
strlcpy(spectrum, "", spectrumsize);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
phead = queue_head;
|
||||||
|
queue_head = queue_head->nextp;
|
||||||
|
|
||||||
|
*type = phead->type;
|
||||||
|
*chan = phead->chan;
|
||||||
|
*subchan = phead->subchan;
|
||||||
|
*slice = phead->slice;
|
||||||
|
*pp = phead->pp;
|
||||||
|
*alevel = phead->alevel;
|
||||||
|
*retries = phead->retries;
|
||||||
|
strlcpy (spectrum, phead->spectrum, spectrumsize);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
LeaveCriticalSection (&dlq_cs);
|
||||||
|
#else
|
||||||
|
err = pthread_mutex_unlock (&dlq_mutex);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("dlq_remove: pthread_mutex_unlock err=%d", err);
|
||||||
|
perror ("");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_remove() returns type=%d, chan=%d\n", (int)(*type), *chan);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if AX25MEMDEBUG
|
||||||
|
|
||||||
|
if (ax25memdebug_get() && result) {
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_remove (type=%d, chan=%d.%d, seq=%d, ...)\n", *type, *chan, *subchan, ax25memdebug_seq(*pp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (result) {
|
||||||
|
free (phead);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_is_empty
|
||||||
|
*
|
||||||
|
* Purpose: Test whether queue is empty.
|
||||||
|
*
|
||||||
|
* Inputs: None
|
||||||
|
*
|
||||||
|
* Returns: True if nothing in the queue.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int dlq_is_empty (void)
|
||||||
|
{
|
||||||
|
if (queue_head == NULL) {
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
} /* end dlq_is_empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* end dlq.c */
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Module: dlq.h
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef DLQ_H
|
||||||
|
#define DLQ_H 1
|
||||||
|
|
||||||
|
#include "ax25_pad.h"
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
|
||||||
|
void dlq_init (void);
|
||||||
|
|
||||||
|
/* Types of things that can be in queue. */
|
||||||
|
|
||||||
|
typedef enum dlq_type_e {DLQ_REC_FRAME} dlq_type_t;
|
||||||
|
|
||||||
|
void dlq_append (dlq_type_t type, int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, char *spectrum);
|
||||||
|
|
||||||
|
void dlq_wait_while_empty (void);
|
||||||
|
|
||||||
|
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, int *slice, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum, size_t spectrumsize);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* end dlq.h */
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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})
|
|
Binary file not shown.
121
doc/README.md
121
doc/README.md
|
@ -1,21 +1,13 @@
|
||||||
# Documentation for Dire Wolf #
|
# Documentation for Dire Wolf #
|
||||||
|
|
||||||
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 ##
|
## Essential Reading ##
|
||||||
|
|
||||||
- [**User Guide**](User-Guide.pdf) [ [*download*](../../../raw/master/doc/User-Guide.pdf) ]
|
- [User Guide](User-Guide.pdf)
|
||||||
|
|
||||||
This is your primary source of information about installation, operation, and configuration.
|
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)
|
||||||
|
|
||||||
The Raspberry Pi has some special considerations that
|
The Raspberry Pi has some special considerations that
|
||||||
make it different from other generic Linux systems.
|
make it different from other generic Linux systems.
|
||||||
|
@ -27,102 +19,36 @@ 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.
|
These dive into more detail for specialized topics or typical usage scenarios.
|
||||||
|
|
||||||
|
|
||||||
|
- [APRStt Implementation Notes](APRStt-Implementation-Notes.pdf)
|
||||||
- [**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) ]
|
|
||||||
|
|
||||||
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) ]
|
|
||||||
|
|
||||||
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.
|
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.
|
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)
|
||||||
|
|
||||||
This example illustrates how APRStt can be integrated with other applications such as SARTrack, APRSISCE/32, YAAC, or Xastir.
|
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)
|
||||||
|
|
||||||
|
|
||||||
WB4APR described a useful application for the [QIKCOM-2 Satallite Transponder](http://www.tapr.org/pipermail/aprssig/2015-November/045035.html).
|
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.
|
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 SDR IGate](Raspberry-Pi-SDR-IGate.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) ]
|
|
||||||
|
|
||||||
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.
|
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)
|
||||||
|
|
||||||
Describes scripts and methods to generate telemetry.
|
Describes scripts and methods to generate telemetry.
|
||||||
Includes a complete example of attaching an analog to
|
Includes a complete example of attaching an analog to
|
||||||
digital converter to a Raspberry Pi and transmitting
|
digital converter to a Raspberry Pi and transmitting
|
||||||
a measured voltage.
|
a measured voltage.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- [**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) ]
|
|
||||||
|
|
||||||
|
|
||||||
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) ]
|
|
||||||
|
|
||||||
|
|
||||||
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 ##
|
## Miscellaneous ##
|
||||||
|
|
||||||
- **[Ham Radio of Things (HRoT)](https://github.com/wb2osz/hrot)**
|
|
||||||
|
|
||||||
|
- [A Better APRS Packet Demodulator, part 1, 1200 baud](A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf)
|
||||||
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) ]
|
|
||||||
|
|
||||||
Sometimes it's a little mystifying why an
|
Sometimes it's a little mystifying why an
|
||||||
APRS / AX.25 Packet TNC will decode some signals
|
APRS / AX.25 Packet TNC will decode some signals
|
||||||
|
@ -134,7 +60,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)
|
||||||
|
|
||||||
In the first part of this series we discussed 1200 baud audio frequency shift keying (AFSK). The mismatch
|
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
|
between FM transmitter pre-emphasis and the
|
||||||
|
@ -143,36 +69,13 @@ and a couple things that can be done about it.
|
||||||
This makes it more difficult to demodulate them accurately.
|
This makes it more difficult to demodulate them accurately.
|
||||||
9600 baud operation is an entirely different animal. ...
|
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)
|
||||||
|
|
||||||
How can we compare how well the TNCs perform under real world conditions?
|
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).
|
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.
|
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)
|
||||||
|
|
||||||
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.
|
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.
|
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)
|
|
||||||
|
|
||||||
- [Raspberry Pi 4 Ham Radio](https://groups.io/g/RaspberryPi-4-HamRadio)
|
|
||||||
|
|
||||||
- [linuxham](https://groups.io/g/linuxham)
|
|
||||||
|
|
||||||
- [TAPR aprssig](http://www.tapr.org/pipermail/aprssig/)
|
|
||||||
|
|
||||||
|
|
||||||
The github "issues" section is for reporting software defects and enhancement requests. It is NOT a place to ask questions or have general discussions. Please use one of the locations above.
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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