mirror of https://github.com/wb2osz/direwolf.git
Merge branch 'dev' into bugfix/ThirsPartyType
This commit is contained in:
commit
33cda1f447
|
@ -0,0 +1,170 @@
|
|||
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: ''
|
||||
}
|
||||
- {
|
||||
name: 'Ubuntu 18.04',
|
||||
os: ubuntu-18.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@v2
|
||||
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
|
|
@ -0,0 +1,73 @@
|
|||
# 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"
|
||||
|
||||
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', '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@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# 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@v1
|
||||
|
||||
# ℹ️ 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@v1
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
### New Features: ###
|
||||
|
||||
- Additional documentation location to slow down growth of main repository. [https://github.com/wb2osz/direwolf-doc](https://github.com/wb2osz/direwolf-doc)
|
||||
|
||||
- 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.
|
||||
|
||||
|
|
|
@ -167,15 +167,16 @@ elseif(APPLE)
|
|||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_MACOS_DNSSD")
|
||||
|
||||
elseif (WIN32)
|
||||
if(NOT VS2015 AND NOT VS2017)
|
||||
message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler")
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
if (C_CLANG OR C_GCC)
|
||||
|
|
|
@ -5,7 +5,9 @@ elseif(NOT DEFINED C_GCC AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|||
set(C_GCC 1)
|
||||
elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(C_MSVC 1)
|
||||
if(MSVC_VERSION GREATER 1910 AND MSVC_VERSION LESS 1919)
|
||||
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)
|
||||
|
|
|
@ -365,7 +365,7 @@ static void * tnc_listen_thread (void *arg)
|
|||
}
|
||||
|
||||
/*
|
||||
* Call to/from fields are 10 bytes but contents must not exceeed 9 characters.
|
||||
* Call to/from fields are 10 bytes but contents must not exceed 9 characters.
|
||||
* It's not guaranteed that unused bytes will contain 0 so we
|
||||
* don't issue error message in this case.
|
||||
*/
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <getopt.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define ATEST_C 1
|
||||
|
|
|
@ -1532,7 +1532,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additoinal time if required.
|
||||
* and wait for additional time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ struct audio_s {
|
|||
|
||||
struct adev_param_s {
|
||||
|
||||
/* Properites of the sound device. */
|
||||
/* Properties of the sound device. */
|
||||
|
||||
int defined; /* Was device defined? */
|
||||
/* First one defaults to yes. */
|
||||
|
@ -102,7 +102,7 @@ struct audio_s {
|
|||
/* This is the probability, in per cent, of randomly corrupting it. */
|
||||
/* Normally this is 0. 25 would mean corrupt it 25% of the time. */
|
||||
|
||||
int recv_error_rate; /* Similar but the % probablity of dropping a received frame. */
|
||||
int recv_error_rate; /* Similar but the % probability of dropping a received frame. */
|
||||
|
||||
float recv_ber; /* Receive Bit Error Rate (BER). */
|
||||
/* Probability of inverting a bit coming out of the modem. */
|
||||
|
|
|
@ -1260,7 +1260,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additoinal time if required.
|
||||
* and wait for additional time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ static struct audio_s *save_audio_config_p;
|
|||
*/
|
||||
|
||||
/*
|
||||
* Originally, we had an abitrary buf time of 40 mS.
|
||||
* Originally, we had an arbitrary buf time of 40 mS.
|
||||
*
|
||||
* For mono, the buffer size was rounded up from 3528 to 4k so
|
||||
* it was really about 50 mS per buffer or about 20 per second.
|
||||
|
@ -1074,7 +1074,7 @@ int audio_flush (int a)
|
|||
* (3) Call this function, which might or might not wait long enough.
|
||||
* (4) Add (1) and (2) resulting in when PTT should be turned off.
|
||||
* (5) Take difference between current time and desired PPT off time
|
||||
* and wait for additoinal time if required.
|
||||
* and wait for additional time if required.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -347,7 +347,7 @@ typedef struct ax25_dlsm_s {
|
|||
// Sometimes the flow chart has SAT instead of SRT.
|
||||
// I think that is a typographical error.
|
||||
|
||||
float t1v; // How long to wait for an acknowlegement before resending.
|
||||
float t1v; // How long to wait for an acknowledgement before resending.
|
||||
// Value used when starting timer T1, in seconds.
|
||||
// "FRACK" parameter in some implementations.
|
||||
// Typically it might be 3 seconds after frame has been
|
||||
|
@ -6049,7 +6049,7 @@ static void check_need_for_response (ax25_dlsm_t *S, ax25_frame_type_t frame_typ
|
|||
*
|
||||
* Outputs: S->srt New smoothed roundtrip time.
|
||||
*
|
||||
* S->t1v How long to wait for an acknowlegement before resending.
|
||||
* S->t1v How long to wait for an acknowledgement before resending.
|
||||
* Value used when starting timer T1, in seconds.
|
||||
* Here it is dynamically adjusted.
|
||||
*
|
||||
|
|
|
@ -1866,7 +1866,7 @@ packet_t ax25_get_nextp (packet_t this_p)
|
|||
*
|
||||
* Inputs: this_p - Current packet object.
|
||||
*
|
||||
* release_time - Time as returned by dtime_now().
|
||||
* release_time - Time as returned by dtime_monotonic().
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -2923,7 +2923,9 @@ int ax25_alevel_to_text (alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE])
|
|||
|
||||
snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d(%+d/%+d)", alevel.rec, alevel.mark, alevel.space);
|
||||
}
|
||||
else if (alevel.mark == -1 && alevel.space == -1) { /* PSK - single number. */
|
||||
else if ((alevel.mark == -1 && alevel.space == -1) || /* PSK */
|
||||
(alevel.mark == -99 && alevel.space == -99)) { /* v. 1.7 "B" FM demodulator. */
|
||||
// ?? Where does -99 come from?
|
||||
|
||||
snprintf (text, AX25_ALEVEL_TO_TEXT_SIZE, "%d", alevel.rec);
|
||||
}
|
||||
|
|
14
src/beacon.c
14
src/beacon.c
|
@ -162,6 +162,7 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
int chan = g_misc_config_p->beacon[j].sendto_chan;
|
||||
|
||||
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
|
||||
if (chan >= MAX_CHANS) chan = 0; // For ICHANNEL, use channel 0 call.
|
||||
|
||||
if (g_modem_config_p->chan_medium[chan] == MEDIUM_RADIO ||
|
||||
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) {
|
||||
|
@ -621,6 +622,7 @@ static void * beacon_thread (void *arg)
|
|||
// 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 */
|
||||
|
@ -805,11 +807,17 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
|
||||
assert (bp->sendto_chan >= 0);
|
||||
|
||||
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall));
|
||||
if (g_modem_config_p->chan_medium[bp->sendto_chan] == MEDIUM_IGATE) { // ICHANNEL uses chan 0 mycall.
|
||||
// TODO: Maybe it should be allowed to have own.
|
||||
strlcpy (mycall, g_modem_config_p->achan[0].mycall, sizeof(mycall));
|
||||
}
|
||||
else {
|
||||
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall));
|
||||
}
|
||||
|
||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("MYCALL not set for beacon in config file line %d.\n", bp->lineno);
|
||||
dw_printf ("MYCALL not set for beacon to chan %d in config file line %d.\n", bp->sendto_chan, bp->lineno);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1046,7 +1054,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
|||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[ig] %s\n", beacon_text);
|
||||
|
||||
igate_send_rec_packet (0, pp);
|
||||
igate_send_rec_packet (-1, pp); // Channel -1 to avoid RF>IS filtering.
|
||||
ax25_delete (pp);
|
||||
break;
|
||||
|
||||
|
|
38
src/config.c
38
src/config.c
|
@ -5594,7 +5594,8 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
}
|
||||
else if (value[0] == 'r' || value[0] == 'R') {
|
||||
int n = atoi(value+1);
|
||||
if ( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) {
|
||||
if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||
&& p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n);
|
||||
continue;
|
||||
|
@ -5604,7 +5605,8 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
}
|
||||
else if (value[0] == 't' || value[0] == 'T' || value[0] == 'x' || value[0] == 'X') {
|
||||
int n = atoi(value+1);
|
||||
if ( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) {
|
||||
if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||
&& p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n);
|
||||
continue;
|
||||
|
@ -5615,7 +5617,8 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
}
|
||||
else {
|
||||
int n = atoi(value);
|
||||
if ( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) {
|
||||
if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||
&& p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n);
|
||||
continue;
|
||||
|
@ -5829,7 +5832,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
/*
|
||||
* Process symbol now that we have any later overlay.
|
||||
*
|
||||
* FIXME: Someone who used this was surprized to end up with Solar Powser (S-).
|
||||
* FIXME: Someone who used this was surprised to end up with Solar Powser (S-).
|
||||
* overlay=S symbol="/-"
|
||||
* We should complain if overlay used with symtab other than \.
|
||||
*/
|
||||
|
@ -5864,19 +5867,32 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
|
||||
if (b->sendto_type == SENDTO_XMIT) {
|
||||
|
||||
if ( b->sendto_chan < 0 || b->sendto_chan >= MAX_CHANS || p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_NONE) {
|
||||
if (( b->sendto_chan < 0 || b->sendto_chan >= MAX_CHANS || p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_NONE)
|
||||
&& p_audio_config->chan_medium[b->sendto_chan] != MEDIUM_IGATE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 ||
|
||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 ||
|
||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) {
|
||||
if (p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_IGATE) { // Prevent subscript out of bounds.
|
||||
// Will be using call from chan 0 later.
|
||||
if ( strcmp(p_audio_config->achan[0].mycall, "") == 0 ||
|
||||
strcmp(p_audio_config->achan[0].mycall, "NOCALL") == 0 ||
|
||||
strcmp(p_audio_config->achan[0].mycall, "N0CALL") == 0 ) {
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", b->sendto_chan);
|
||||
return (0);
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", 0);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 ||
|
||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 ||
|
||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) {
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", b->sendto_chan);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -858,6 +858,32 @@ static void aprs_ll_pos (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
|
||||
strlcpy (A->g_data_type_desc, "Weather Report", sizeof(A->g_data_type_desc));
|
||||
weather_data (A, p->comment, TRUE);
|
||||
/*
|
||||
Here is an interesting case.
|
||||
The protocol spec states that a position report with symbol _ is a special case
|
||||
and the information part must contain wxnow.txt format weather data.
|
||||
But, here we see it being generated like a normal position report.
|
||||
|
||||
N8VIM>BEACON,AB1OC-10*,WIDE2-1:!4240.85N/07133.99W_PHG72604/ Pepperell, MA. WX. 442.9+ PL100<0x0d>
|
||||
Didn't find wind direction in form c999.
|
||||
Didn't find wind speed in form s999.
|
||||
Didn't find wind gust in form g999.
|
||||
Didn't find temperature in form t999.
|
||||
Weather Report, WEATHER Station (blue)
|
||||
N 42 40.8500, W 071 33.9900
|
||||
, "PHG72604/ Pepperell, MA. WX. 442.9+ PL100"
|
||||
|
||||
It seems, to me, that this is a violation of the protocol spec.
|
||||
Then, immediately following, we have a positionless weather report in Ultimeter format.
|
||||
|
||||
N8VIM>APN391,AB1OC-10*,WIDE2-1:$ULTW006F00CA01421C52275800008A00000102FA000F04A6000B002A<0x0d><0x0a>
|
||||
Ultimeter, Kantronics KPC-3 rom versions
|
||||
wind 6.9 mph, direction 284, temperature 32.2, barometer 29.75, humidity 76
|
||||
|
||||
aprs.fi merges these two together. Is that anywhere in the protocol spec or
|
||||
just a heuristic added after noticing a pair of packets like this?
|
||||
*/
|
||||
|
||||
}
|
||||
else {
|
||||
/* Regular position report. */
|
||||
|
@ -1375,7 +1401,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
}
|
||||
}
|
||||
|
||||
/* 6th character of destintation indicates east / west. */
|
||||
/* 6th character of destination indicates east / west. */
|
||||
|
||||
/*
|
||||
* Example of apparently invalid encoding. 6th character missing.
|
||||
|
@ -1579,7 +1605,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
* Purpose: Decode "Message Format."
|
||||
* The word message is used loosely all over the place, but it has a very specific meaning here.
|
||||
*
|
||||
* Inputs: info - Pointer to Information field. Be carefull not to modify it here!
|
||||
* Inputs: info - Pointer to Information field. Be careful not to modify it here!
|
||||
* ilen - Information field length.
|
||||
* quiet - suppress error messages.
|
||||
*
|
||||
|
@ -2372,6 +2398,20 @@ static void aprs_status_report (decode_aprs_t *A, char *info, int ilen)
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
https://groups.io/g/direwolf/topic/95961245#7357
|
||||
|
||||
What APRS queries should DireWolf respond to? Well, it should be configurable whether it responds to queries at all, in case some other application is using DireWolf as a dumb TNC (KISS or AGWPE style) and wants to handle the queries itself.
|
||||
|
||||
Assuming query responding is enabled, the following broadcast queries should be supported (if the corresponding data is configured in DireWolf):
|
||||
|
||||
?APRS (I am an APRS station)
|
||||
?IGATE (I am operating as a I-gate)
|
||||
?WX (I am providing local weather data in my beacon)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static void aprs_general_query (decode_aprs_t *A, char *info, int ilen, int quiet)
|
||||
{
|
||||
char *q2;
|
||||
|
@ -2524,6 +2564,28 @@ static void aprs_general_query (decode_aprs_t *A, char *info, int ilen, int quie
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
https://groups.io/g/direwolf/topic/95961245#7357
|
||||
|
||||
The following directed queries (sent as bodies of APRS text messages) would also be useful (if corresponding data configured):
|
||||
|
||||
?APRSP (force my current beacon)
|
||||
?APRST and ?PING (trace my path to requestor)
|
||||
?APRSD (all stations directly heard [no digipeat hops] by local station)
|
||||
?APRSO (any Objects/Items originated by this station)
|
||||
?APRSH (how often or how many times the specified 3rd station was heard by the queried station)
|
||||
?APRSS (immediately send the Status message if configured) (can DireWolf do Status messages?)
|
||||
|
||||
Lynn KJ4ERJ and I have implemented a non-standard query which might be useful:
|
||||
|
||||
?VER (send the human-readable software version of the queried station)
|
||||
|
||||
Hope this is useful. It's just my $.02.
|
||||
|
||||
Andrew, KA2DDO
|
||||
author of YAAC
|
||||
*/
|
||||
|
||||
static void aprs_directed_station_query (decode_aprs_t *A, char *addressee, char *query, int quiet)
|
||||
{
|
||||
//char query_type[20]; /* Does the query type always need to be exactly 5 characters? */
|
||||
|
|
|
@ -832,7 +832,7 @@ int demod_init (struct audio_s *pa)
|
|||
*
|
||||
* Name: demod_get_sample
|
||||
*
|
||||
* Purpose: Get one audio sample fromt the specified sound input source.
|
||||
* Purpose: Get one audio sample from the specified sound input source.
|
||||
*
|
||||
* Inputs: a - Index for audio device. 0 = first.
|
||||
*
|
||||
|
|
|
@ -309,10 +309,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
|
|||
D->lp_window = BP_WINDOW_TRUNCATED;
|
||||
}
|
||||
|
||||
D->agc_fast_attack = 0.820;
|
||||
D->agc_slow_decay = 0.000214;
|
||||
D->agc_fast_attack = 0.45;
|
||||
D->agc_slow_decay = 0.000195;
|
||||
D->agc_fast_attack = 0.70;
|
||||
D->agc_slow_decay = 0.000090;
|
||||
|
||||
|
@ -372,10 +368,16 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
|
|||
// For scaling phase shift into normallized -1 to +1 range for mark and space.
|
||||
D->u.afsk.normalize_rpsam = 1.0 / (0.5 * abs(mark_freq - space_freq) * 2 * M_PI / samples_per_sec);
|
||||
|
||||
// New "B" demodulator does not use AGC but demod.c needs this to derive "quick" and
|
||||
// "sluggish" values for overall signal amplitude. That probably should be independent
|
||||
// of these values.
|
||||
D->agc_fast_attack = 0.70;
|
||||
D->agc_slow_decay = 0.000090;
|
||||
|
||||
D->pll_locked_inertia = 0.74;
|
||||
D->pll_searching_inertia = 0.50;
|
||||
|
||||
D->alevel_mark_peak = -1; // FIXME: disable display
|
||||
D->alevel_mark_peak = -1; // Disable received signal (m/s) display.
|
||||
D->alevel_space_peak = -1;
|
||||
break;
|
||||
|
||||
|
@ -868,6 +870,7 @@ static void nudge_pll (int chan, int subchan, int slice, float demod_out, struct
|
|||
{
|
||||
D->slicer[slice].prev_d_c_pll = D->slicer[slice].data_clock_pll;
|
||||
|
||||
|
||||
// Perform the add as unsigned to avoid signed overflow error.
|
||||
D->slicer[slice].data_clock_pll = (signed)((unsigned)(D->slicer[slice].data_clock_pll) + (unsigned)(D->pll_step_per_sample));
|
||||
|
||||
|
@ -901,7 +904,15 @@ static void nudge_pll (int chan, int subchan, int slice, float demod_out, struct
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
hdlc_rec_bit (chan, subchan, slice, demod_out > 0, 0, quality);
|
||||
#else // TODO: new feature to measure data speed error.
|
||||
// Maybe hdlc_rec_bit could provide indication when frame starts.
|
||||
hdlc_rec_bit_new (chan, subchan, slice, demod_out > 0, 0, quality,
|
||||
&(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count));
|
||||
D->slicer[slice].pll_symbol_count++;
|
||||
#endif
|
||||
pll_dcd_each_symbol2 (D, chan, subchan, slice);
|
||||
}
|
||||
|
||||
|
@ -912,12 +923,14 @@ static void nudge_pll (int chan, int subchan, int slice, float demod_out, struct
|
|||
|
||||
pll_dcd_signal_transition2 (D, slice, D->slicer[slice].data_clock_pll);
|
||||
|
||||
// TODO: signed int before = (signed int)(D->slicer[slice].data_clock_pll); // Treat as signed.
|
||||
if (D->slicer[slice].data_detect) {
|
||||
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);
|
||||
}
|
||||
// TODO: D->slicer[slice].pll_nudge_total += (int64_t)((signed int)(D->slicer[slice].data_clock_pll)) - (int64_t)before;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1053,7 +1053,7 @@ int main (int argc, char *argv[])
|
|||
audio_config.achan[x_opt_chan].mark_freq,
|
||||
x_opt_chan);
|
||||
while (n-- > 0) {
|
||||
tone_gen_put_bit(x_opt_chan, 0);
|
||||
tone_gen_put_bit(x_opt_chan, 1);
|
||||
}
|
||||
break;
|
||||
case 's': // "Space" tone: -x s
|
||||
|
@ -1061,7 +1061,7 @@ int main (int argc, char *argv[])
|
|||
audio_config.achan[x_opt_chan].space_freq,
|
||||
x_opt_chan);
|
||||
while (n-- > 0) {
|
||||
tone_gen_put_bit(x_opt_chan, 1);
|
||||
tone_gen_put_bit(x_opt_chan, 0);
|
||||
}
|
||||
break;
|
||||
case 'p': // Silence - set PTT only: -x p
|
||||
|
|
113
src/dtime_now.c
113
src/dtime_now.c
|
@ -25,9 +25,9 @@
|
|||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Name: dtime_now
|
||||
* Name: dtime_realtime
|
||||
*
|
||||
* Purpose: Return current time as double precision.
|
||||
* Purpose: Return current wall clock time as double precision.
|
||||
*
|
||||
* Input: none
|
||||
*
|
||||
|
@ -40,11 +40,24 @@
|
|||
* part of a second, and having extra calculations everywhere,
|
||||
* simply use double precision floating point to make usage
|
||||
* easier.
|
||||
*
|
||||
*
|
||||
* NOTE: This is not a good way to calculate elapsed time because
|
||||
* it can jump forward or backware via NTP or other manual setting.
|
||||
*
|
||||
* Use the monotonic version for measuring elapsed time.
|
||||
*
|
||||
* History: Originally I called this dtime_now. We ran into issues where
|
||||
* we really cared about elapsed time, rather than wall clock time.
|
||||
* The wall clock time could be wrong at start up time if there
|
||||
* is no realtime clock or Internet access. It can then jump
|
||||
* when GPS time or Internet access becomes available.
|
||||
* All instances of dtime_now should be replaced by dtime_realtime
|
||||
* if we want wall clock time, or dtime_monotonic if it is to be
|
||||
* used for measuring elapsed time, such as between becons.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
|
||||
double dtime_now (void)
|
||||
double dtime_realtime (void)
|
||||
{
|
||||
double result;
|
||||
|
||||
|
@ -55,7 +68,7 @@ double dtime_now (void)
|
|||
|
||||
GetSystemTimeAsFileTime (&ft);
|
||||
|
||||
result = ((( (double)ft.dwHighDateTime * (256. * 256. * 256. * 256.) +
|
||||
result = ((( (double)ft.dwHighDateTime * (256. * 256. * 256. * 256.) +
|
||||
(double)ft.dwLowDateTime ) / 10000000.) - 11644473600.);
|
||||
#else
|
||||
/* tv_sec is seconds from Jan 1, 1970. */
|
||||
|
@ -63,6 +76,10 @@ double dtime_now (void)
|
|||
struct timespec ts;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// Why didn't I use clock_gettime?
|
||||
// Not available before Max OSX 10.12? https://github.com/gambit/gambit/issues/293
|
||||
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
ts.tv_nsec = tp.tv_usec * 1000;
|
||||
|
@ -75,6 +92,83 @@ double dtime_now (void)
|
|||
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dtime_realtime() returns %.3f\n", result );
|
||||
#endif
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Name: dtime_monotonic
|
||||
*
|
||||
* Purpose: Return montonically increasing time, which is not influenced
|
||||
* by the wall clock changing. e.g. leap seconds, NTP adjustments.
|
||||
*
|
||||
* Input: none
|
||||
*
|
||||
* Returns: Time as double precision, so we can get resolution
|
||||
* finer than one second.
|
||||
*
|
||||
* Description: Use this when calculating elapsed time.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
double dtime_monotonic (void)
|
||||
{
|
||||
double result;
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
// FIXME:
|
||||
// This is still returning wall clock time.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64
|
||||
// GetTickCount64 would be ideal but it requires Vista or Server 2008.
|
||||
// As far as I know, the current version of direwolf still works on XP.
|
||||
//
|
||||
// As a work-around, GetTickCount could be used if we add extra code to deal
|
||||
// with the wrap around after about 49.7 days.
|
||||
// Resolution is only about 10 or 16 milliseconds. Is that good enough?
|
||||
|
||||
/* 64 bit integer is number of 100 nanosecond intervals from Jan 1, 1601. */
|
||||
|
||||
FILETIME ft;
|
||||
|
||||
GetSystemTimeAsFileTime (&ft);
|
||||
|
||||
result = ((( (double)ft.dwHighDateTime * (256. * 256. * 256. * 256.) +
|
||||
(double)ft.dwLowDateTime ) / 10000000.) - 11644473600.);
|
||||
#else
|
||||
/* tv_sec is seconds from Jan 1, 1970. */
|
||||
|
||||
struct timespec ts;
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// FIXME: Does MacOS have a monotonically increasing time?
|
||||
// https://stackoverflow.com/questions/41509505/clock-gettime-on-macos
|
||||
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
ts.tv_nsec = tp.tv_usec * 1000;
|
||||
ts.tv_sec = tp.tv_sec;
|
||||
#else
|
||||
|
||||
// This is the only case handled properly.
|
||||
// Probably the only one that matters.
|
||||
// It is common to have a Raspberry Pi, without Internet,
|
||||
// starting up direwolf before GPS/NTP adjusts the time.
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &ts);
|
||||
#endif
|
||||
|
||||
result = ((double)(ts.tv_sec) + (double)(ts.tv_nsec) * 0.000000001);
|
||||
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dtime_now() returns %.3f\n", result );
|
||||
|
@ -84,6 +178,7 @@ double dtime_now (void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Name: timestamp_now
|
||||
|
@ -104,7 +199,7 @@ double dtime_now (void)
|
|||
|
||||
void timestamp_now (char *result, int result_size, int show_ms)
|
||||
{
|
||||
double now = dtime_now();
|
||||
double now = dtime_realtime();
|
||||
time_t t = (int)now;
|
||||
struct tm tm;
|
||||
|
||||
|
@ -150,7 +245,7 @@ void timestamp_now (char *result, int result_size, int show_ms)
|
|||
|
||||
void timestamp_user_format (char *result, int result_size, char *user_format)
|
||||
{
|
||||
double now = dtime_now();
|
||||
double now = dtime_realtime();
|
||||
time_t t = (int)now;
|
||||
struct tm tm;
|
||||
|
||||
|
@ -191,7 +286,7 @@ void timestamp_user_format (char *result, int result_size, char *user_format)
|
|||
|
||||
void timestamp_filename (char *result, int result_size)
|
||||
{
|
||||
double now = dtime_now();
|
||||
double now = dtime_realtime();
|
||||
time_t t = (int)now;
|
||||
struct tm tm;
|
||||
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
|
||||
|
||||
extern double dtime_now (void);
|
||||
extern double dtime_realtime (void);
|
||||
|
||||
extern double dtime_monotonic (void);
|
||||
|
||||
|
||||
void timestamp_now (char *result, int result_size, int show_ms);
|
||||
|
||||
void timestamp_user_format (char *result, int result_size, char *user_format);
|
||||
|
||||
void timestamp_filename (char *result, int result_size);
|
||||
void timestamp_filename (char *result, int result_size);
|
||||
|
||||
|
||||
// FIXME: remove temp workaround.
|
||||
// Needs many scattered updates.
|
||||
|
||||
#define dtime_now dtime_realtime
|
||||
|
|
50
src/dwgpsd.c
50
src/dwgpsd.c
|
@ -57,18 +57,36 @@
|
|||
|
||||
|
||||
|
||||
// An incompatibility was introduced with version 7
|
||||
// and again with 9 and again with 10.
|
||||
// An API incompatibility was introduced with API version 7.
|
||||
// and again with 9.
|
||||
// and again with 10.
|
||||
// We deal with it by using a bunch of conditional code such as:
|
||||
// #if GPSD_API_MAJOR_VERSION >= 9
|
||||
|
||||
// release lib version API Raspberry Pi OS
|
||||
// 3.22 28 11 bullseye
|
||||
// 3.23 29 12
|
||||
// 3.24 14 Not tested yet.
|
||||
|
||||
#if GPSD_API_MAJOR_VERSION < 5 || GPSD_API_MAJOR_VERSION > 12
|
||||
#error libgps API version might be incompatible.
|
||||
// release lib version API Raspberry Pi OS Testing status
|
||||
// 3.22 28 11 bullseye OK.
|
||||
// 3.23 29 12 OK.
|
||||
// 3.25 30 14 OK, Jan. 2023
|
||||
|
||||
|
||||
// Previously the compilation would fail if the API version was later
|
||||
// than the last one tested. Now it is just a warning because it changes so
|
||||
// often but more recent versions have not broken backward compatibility.
|
||||
|
||||
#define MAX_TESTED_VERSION 14
|
||||
|
||||
#if (GPSD_API_MAJOR_VERSION < 5) || (GPSD_API_MAJOR_VERSION > MAX_TESTED_VERSION)
|
||||
#pragma message "Your version of gpsd might be incompatible with this application."
|
||||
#pragma message "The libgps application program interface (API) often"
|
||||
#pragma message "changes to be incompatible with earlier versions."
|
||||
// I could not figure out how to do value substitution here.
|
||||
#pragma message "You have libgpsd API version GPSD_API_MAJOR_VERSION."
|
||||
#pragma message "The last that has been tested is MAX_TESTED_VERSION."
|
||||
#pragma message "Even if this builds successfully, it might not run properly."
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Information for interface to gpsd daemon.
|
||||
*/
|
||||
|
@ -168,6 +186,22 @@ static void * read_gpsd_thread (void *arg);
|
|||
* can't find it there. Solution is to define environment variable:
|
||||
*
|
||||
* export LD_LIBRARY_PATH=/use/local/lib
|
||||
*
|
||||
* January 2023: Now using 64 bit Raspberry Pi OS, bullseye.
|
||||
* See https://gitlab.com/gpsd/gpsd/-/blob/master/build.adoc
|
||||
* Try to install in proper library place so we don't have to mess with LD_LIBRARY_PATH.
|
||||
*
|
||||
* (Remove any existing gpsd first so we are not mixing mismatched pieces.)
|
||||
*
|
||||
* sudo apt-get install libncurses5-dev
|
||||
* sudo apt-get install gtk+-3.0
|
||||
*
|
||||
* git clone https://gitlab.com/gpsd/gpsd.git gpsd-gitlab
|
||||
* cd gpsd-gitlab
|
||||
* scons prefix=/usr libdir=lib/aarch64-linux-gnu
|
||||
* [ scons check ]
|
||||
* sudo scons udev-install
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ struct demodulator_state_s
|
|||
// Add a sample to the total when putting it in our array of recent samples.
|
||||
// Subtract it from the total when it gets pushed off the end.
|
||||
// We can also eliminate the need to shift them all down by using a circular buffer.
|
||||
// This only works with integers because float would have cummulated round off errors.
|
||||
// This only works with integers because float would have cumulated round off errors.
|
||||
|
||||
cic_t cic_center1;
|
||||
cic_t cic_above;
|
||||
|
|
75
src/igate.c
75
src/igate.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013, 2014, 2015, 2016 John Langner, WB2OSZ
|
||||
// Copyright (C) 2013, 2014, 2015, 2016, 2023 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -328,7 +328,7 @@ static int stats_uplink_packets; /* Number of packets passed along to the IGate
|
|||
/* server after filtering. */
|
||||
|
||||
static int stats_uplink_bytes; /* Total number of bytes sent to IGate server */
|
||||
/* including login, packets, and hearbeats. */
|
||||
/* including login, packets, and heartbeats. */
|
||||
|
||||
static int stats_downlink_bytes; /* Total number of bytes from IGate server including */
|
||||
/* packets, heartbeats, other messages. */
|
||||
|
@ -855,6 +855,9 @@ static void * connnect_thread (void *arg)
|
|||
* Purpose: Send a packet to the IGate server
|
||||
*
|
||||
* Inputs: chan - Radio channel it was received on.
|
||||
* This is required for the RF>IS filtering.
|
||||
* Beaconing (sendto=ig, chan=-1) and a client app sending
|
||||
* to ICHANNEL should bypass the filtering.
|
||||
*
|
||||
* recv_pp - Pointer to packet object.
|
||||
* *** CALLER IS RESPONSIBLE FOR DELETING IT! **
|
||||
|
@ -902,7 +905,12 @@ void igate_send_rec_packet (int chan, packet_t recv_pp)
|
|||
* In that case, the payload will have TCPIP in the path and it will be dropped.
|
||||
*/
|
||||
|
||||
if (save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) {
|
||||
// Apply RF>IS filtering only if it same from a radio channel.
|
||||
// Beacon will be channel -1.
|
||||
// Client app to ICHANNEL is outside of radio channel range.
|
||||
|
||||
if (chan >= 0 && chan < MAX_CHANS && // in radio channel range
|
||||
save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) {
|
||||
|
||||
if (pfilter(chan, MAX_CHANS, save_digi_config_p->filter_str[chan][MAX_CHANS], recv_pp, 1) != 1) {
|
||||
|
||||
|
@ -1221,7 +1229,7 @@ static void send_packet_to_server (packet_t pp, int chan)
|
|||
* Name: send_msg_to_server
|
||||
*
|
||||
* Purpose: Send something to the IGate server.
|
||||
* This one function should be used for login, hearbeats,
|
||||
* This one function should be used for login, heartbeats,
|
||||
* and packets.
|
||||
*
|
||||
* Inputs: imsg - Message. We will add CR/LF here.
|
||||
|
@ -1517,32 +1525,36 @@ static void * igate_recv_thread (void *arg)
|
|||
|
||||
int ichan = save_audio_config_p->igate_vchannel;
|
||||
|
||||
// Try to parse it into a packet object.
|
||||
// This will contain "q constructs" and we might see an address
|
||||
// with two alphnumeric characters in the SSID so we must use
|
||||
// the non-strict parsing.
|
||||
// My original poorly thoughtout idea was to parse it into a packet object,
|
||||
// using the non-strict option, and send to the client app.
|
||||
//
|
||||
// A lot of things can go wrong with that approach.
|
||||
|
||||
// Possible problem: Up to 8 digipeaters are allowed in radio format.
|
||||
// There is a potential of finding a larger number here.
|
||||
// (1) Up to 8 digipeaters are allowed in radio format.
|
||||
// There is a potential of finding a larger number here.
|
||||
//
|
||||
// (2) The via path can have names that are not valid in the radio format.
|
||||
// e.g. qAC, T2HAKATA, N5JXS-F1.
|
||||
// Non-strict parsing would force uppercase, truncate names too long,
|
||||
// and drop unacceptable SSIDs.
|
||||
//
|
||||
// (3) The source address could be invalid for the RF address format.
|
||||
// e.g. WHO-IS>APJIW4,TCPIP*,qAC,AE5PL-JF::ZL1JSH-9 :Charles Beadfield/New Zealand{583
|
||||
// That is essential information that we absolutely need to preserve.
|
||||
//
|
||||
// I think the only correct solution is to apply a third party header
|
||||
// wrapper so the original contents are preserved. This will be a little
|
||||
// more work for the application developer. Search for ":}" and use only
|
||||
// the part after that. At this point, I don't see any value in encoding
|
||||
// information in the source/destination so I will just use "X>X:}" as a prefix
|
||||
|
||||
packet_t pp3 = ax25_from_text((char*)message, 0); // 0 means not strict
|
||||
char stemp[AX25_MAX_INFO_LEN];
|
||||
strlcpy (stemp, "X>X:}", sizeof(stemp));
|
||||
strlcat (stemp, (char*)message, sizeof(stemp));
|
||||
|
||||
packet_t pp3 = ax25_from_text(stemp, 0); // 0 means not strict
|
||||
if (pp3 != NULL) {
|
||||
|
||||
// Should we remove the VIA path?
|
||||
|
||||
// For example, we might get something like this from the server.
|
||||
// Lower case 'q' and non-numeric SSID are not valid for AX.25 over the air.
|
||||
// K1USN-1>APWW10,TCPIP*,qAC,N5JXS-F1:T#479,100,048,002,500,000,10000000
|
||||
|
||||
// Should we try to retain all information and pass that along, to the best of our ability,
|
||||
// to the client app, or should we remove the via path so it looks like this?
|
||||
// K1USN-1>APWW10:T#479,100,048,002,500,000,10000000
|
||||
|
||||
// For now, keep it intact and see if it causes problems. Easy to remove like this:
|
||||
// while (ax25_get_num_repeaters(pp3) > 0) {
|
||||
// ax25_remove_addr (pp3, AX25_REPEATER_1);
|
||||
// }
|
||||
|
||||
alevel_t alevel;
|
||||
memset (&alevel, 0, sizeof(alevel));
|
||||
alevel.mark = -2; // FIXME: Do we want some other special case?
|
||||
|
@ -1831,8 +1843,19 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan)
|
|||
* If we recently transmitted a 'message' from some station,
|
||||
* send the position of the message sender when it comes along later.
|
||||
*
|
||||
* Some refer to this as a courtesy posit report but I don't
|
||||
* think that is an official term.
|
||||
*
|
||||
* If we have a position report, look up the sender and see if we should
|
||||
* bypass the normal filtering.
|
||||
*
|
||||
* Reference: https://www.aprs-is.net/IGating.aspx
|
||||
*
|
||||
* "Passing all message packets also includes passing the sending station's position
|
||||
* along with the message. When APRS-IS was small, we did this using historical position
|
||||
* packets. This has become problematic as it introduces historical data on to RF.
|
||||
* The IGate should note the station(s) it has gated messages to RF for and pass
|
||||
* the next position packet seen for that station(s) to RF."
|
||||
*/
|
||||
|
||||
// TODO: Not quite this simple. Should have a function to check for position.
|
||||
|
|
|
@ -437,7 +437,7 @@ packet_t il2p_decode_header_type_1 (unsigned char *hdr, int num_sym_changed)
|
|||
// However, I have seen cases, where the error rate is very high, where the RS decoder
|
||||
// thinks it found a valid code block by changing one symbol but it was the wrong one.
|
||||
// The result is trash. This shows up as address fields like 'R&G4"A' and 'TEW\ !'.
|
||||
// I added a sanity check here to catch characters other than uppper case letters and digits.
|
||||
// I added a sanity check here to catch characters other than upper case letters and digits.
|
||||
// The frame should be rejected in this case. The question is whether to discard it
|
||||
// silently or print a message so the user can see that something strange is happening?
|
||||
// My current thinking is that it should be silently ignored if the header has been
|
||||
|
|
|
@ -194,7 +194,7 @@ int il2p_encode_payload (unsigned char *payload, int payload_size, int max_fec,
|
|||
* Purpose: Extract original data from encoded payload.
|
||||
*
|
||||
* Inputs: received Array of bytes. Size is unknown but in practice it
|
||||
* must not exceeed IL2P_MAX_ENCODED_SIZE.
|
||||
* must not exceed IL2P_MAX_ENCODED_SIZE.
|
||||
* payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE)
|
||||
* Expected result size based on header.
|
||||
* max_fec true for 16 parity symbols, false for automatic.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013, 2014, 2017 John Langner, WB2OSZ
|
||||
// Copyright (C) 2013, 2014, 2017, 2023 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -611,7 +611,8 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct
|
|||
/* Verify that the radio channel number is valid. */
|
||||
/* Any sort of medium should be OK here. */
|
||||
|
||||
if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) {
|
||||
if ((chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE)
|
||||
&& save_audio_config_p->chan_medium[chan] != MEDIUM_IGATE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan);
|
||||
dw_printf ("\n");
|
||||
|
|
|
@ -1421,7 +1421,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
}
|
||||
|
||||
/*
|
||||
* Call to/from fields are 10 bytes but contents must not exceeed 9 characters.
|
||||
* Call to/from fields are 10 bytes but contents must not exceed 9 characters.
|
||||
* It's not guaranteed that unused bytes will contain 0 so we
|
||||
* don't issue error message in this case.
|
||||
*/
|
||||
|
|
|
@ -681,7 +681,7 @@ void symbols_from_dest_or_src (char dti, char *src, char *dest, char *symtab, ch
|
|||
|
||||
// The position and object formats all contain a proper symbol and table.
|
||||
// There doesn't seem to be much reason to have a symbol for something without
|
||||
// a postion because it would not show up on a map.
|
||||
// a position because it would not show up on a map.
|
||||
// This just seems to be a remnant of something used long ago and no longer needed.
|
||||
// The protocol spec mentions a "MIM tracker" but I can't find any references to it.
|
||||
|
||||
|
|
47
src/tq.c
47
src/tq.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2014, 2015, 2016 John Langner, WB2OSZ
|
||||
// Copyright (C) 2011, 2012, 2014, 2015, 2016, 2023 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -50,7 +50,8 @@
|
|||
#include "audio.h"
|
||||
#include "tq.h"
|
||||
#include "dedupe.h"
|
||||
|
||||
#include "igate.h"
|
||||
#include "dtime_now.h"
|
||||
|
||||
|
||||
|
||||
|
@ -195,6 +196,9 @@ void tq_init (struct audio_s *audio_config_p)
|
|||
*
|
||||
* Inputs: chan - Channel, 0 is first.
|
||||
*
|
||||
* New in 1.7:
|
||||
* Channel can be assigned to IGate rather than a radio.
|
||||
*
|
||||
* prio - Priority, use TQ_PRIO_0_HI for digipeated or
|
||||
* TQ_PRIO_1_LO for normal.
|
||||
*
|
||||
|
@ -247,6 +251,43 @@ void tq_append (int chan, int prio, packet_t pp)
|
|||
}
|
||||
#endif
|
||||
|
||||
// New in 1.7 - A channel can be assigned to the IGate rather than a radio.
|
||||
|
||||
#ifndef DIGITEST // avoid dtest link error
|
||||
|
||||
if (save_audio_config_p->chan_medium[chan] == MEDIUM_IGATE) {
|
||||
|
||||
char ts[100]; // optional time stamp.
|
||||
|
||||
if (strlen(save_audio_config_p->timestamp_format) > 0) {
|
||||
char tstmp[100];
|
||||
timestamp_user_format (tstmp, sizeof(tstmp), save_audio_config_p->timestamp_format);
|
||||
strlcpy (ts, " ", sizeof(ts)); // space after channel.
|
||||
strlcat (ts, tstmp, sizeof(ts));
|
||||
}
|
||||
else {
|
||||
strlcpy (ts, "", sizeof(ts));
|
||||
}
|
||||
|
||||
char stemp[256]; // Formated addresses.
|
||||
ax25_format_addrs (pp, stemp);
|
||||
unsigned char *pinfo;
|
||||
int info_len = ax25_get_info (pp, &pinfo);
|
||||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[%d>is%s] ", chan, ts);
|
||||
dw_printf ("%s", stemp); /* stations followed by : */
|
||||
ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
|
||||
dw_printf ("\n");
|
||||
|
||||
igate_send_rec_packet (chan, pp);
|
||||
ax25_delete(pp);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Normal case - put in queue for radio transmission.
|
||||
// Error if trying to transmit to a radio channel which was not configured.
|
||||
|
||||
if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan);
|
||||
|
@ -281,8 +322,6 @@ void tq_append (int chan, int prio, packet_t pp)
|
|||
* The check would allow an unlimited number of other types.
|
||||
*
|
||||
* Limit was 20. Changed to 100 in version 1.2 as a workaround.
|
||||
*
|
||||
* Implementing the 6PACK protocol is probably the proper solution.
|
||||
*/
|
||||
|
||||
if (ax25_is_aprs(pp) && tq_count(chan,prio,"","",0) > 100) {
|
||||
|
|
|
@ -882,7 +882,7 @@ static void xmit_object_report (int i, int first_time)
|
|||
* IGate.
|
||||
*
|
||||
* When transmitting over the radio, it gets sent multiple times, to help
|
||||
* probablity of being heard, with increasing delays between.
|
||||
* probability of being heard, with increasing delays between.
|
||||
*
|
||||
* The other methods are reliable so we only want to send it once.
|
||||
*/
|
||||
|
|
|
@ -298,7 +298,7 @@ void waypoint_send_sentence (char *name_in, double dlat, double dlong, char symt
|
|||
dw_printf ("waypoint_send_sentence (\"%s\", \"%c%c\")\n", name_in, symtab, symbol);
|
||||
#endif
|
||||
|
||||
// Don't waste time if no destintations specified.
|
||||
// Don't waste time if no destinations specified.
|
||||
|
||||
if (s_waypoint_serial_port_fd == MYFDERROR &&
|
||||
s_waypoint_udp_sock_fd == -1) {
|
||||
|
|
|
@ -600,7 +600,7 @@ static void * xmit_thread (void *arg)
|
|||
// I don't know if this in some official specification
|
||||
// somewhere, but it is generally agreed that APRS digipeaters
|
||||
// should send only one frame at a time rather than
|
||||
// bunding multiple frames into a single transmission.
|
||||
// bundling multiple frames into a single transmission.
|
||||
// Discussion here: http://lists.tapr.org/pipermail/aprssig_lists.tapr.org/2021-September/049034.html
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue