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: ### | ### 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. | - 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") |   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_MACOS_DNSSD") | ||||||
| 
 | 
 | ||||||
| elseif (WIN32) | elseif (WIN32) | ||||||
|   if(NOT VS2015 AND NOT VS2017) |   if(C_MSVC) | ||||||
|     message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler") |     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() | ||||||
| 
 |  | ||||||
|   # 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() | ||||||
| 
 | 
 | ||||||
| if (C_CLANG OR C_GCC) | 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) |   set(C_GCC 1) | ||||||
| elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC") | elseif(NOT DEFINED C_MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC") | ||||||
|   set(C_MSVC 1) |   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) |     set(VS2017 ON) | ||||||
|   elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910) |   elseif(MSVC_VERSION GREATER 1899 AND MSVC_VERSION LESS 1910) | ||||||
|     set(VS2015 ON) |     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 |  * It's not guaranteed that unused bytes will contain 0 so we | ||||||
|  * don't issue error message in this case.  |  * don't issue error message in this case.  | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -68,6 +68,7 @@ | ||||||
| #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 | ||||||
|  |  | ||||||
|  | @ -1532,7 +1532,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 additoinal time if required. |  *			and wait for additional time if required. | ||||||
|  * |  * | ||||||
|  *----------------------------------------------------------------*/ |  *----------------------------------------------------------------*/ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ struct audio_s { | ||||||
| 
 | 
 | ||||||
| 	struct adev_param_s { | 	struct adev_param_s { | ||||||
| 
 | 
 | ||||||
| 	    /* Properites of the sound device. */ | 	    /* Properties of the sound device. */ | ||||||
| 
 | 
 | ||||||
| 	    int defined;		/* Was device defined? */ | 	    int defined;		/* Was device defined? */ | ||||||
| 					/* First one defaults to yes. */ | 					/* First one defaults to yes. */ | ||||||
|  | @ -102,7 +102,7 @@ struct audio_s { | ||||||
| 					/* This is the probability, in per cent, of randomly corrupting it. */ | 					/* This is the probability, in per cent, of randomly corrupting it. */ | ||||||
| 					/* Normally this is 0.  25 would mean corrupt it 25% of the time. */ | 					/* 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). */ | 	float recv_ber;			/* Receive Bit Error Rate (BER). */ | ||||||
| 					/* Probability of inverting a bit coming out of the modem. */ | 					/* 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. |  *		(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 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 |  * 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. | ||||||
|  | @ -1074,7 +1074,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 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.
 | 						// Sometimes the flow chart has SAT instead of SRT.
 | ||||||
| 						// I think that is a typographical error.
 | 						// 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.
 | 						// Value used when starting timer T1, in seconds.
 | ||||||
| 						// "FRACK" parameter in some implementations.
 | 						// "FRACK" parameter in some implementations.
 | ||||||
| 						// Typically it might be 3 seconds after frame has been
 | 						// 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. |  * 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. |  *					Value used when starting timer T1, in seconds. | ||||||
|  *					Here it is dynamically adjusted. |  *					Here it is dynamically adjusted. | ||||||
|  * |  * | ||||||
|  |  | ||||||
|  | @ -1866,7 +1866,7 @@ packet_t ax25_get_nextp (packet_t this_p) | ||||||
|  * |  * | ||||||
|  * Inputs:	this_p		- Current packet object. |  * 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); | 	  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); | 	  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; | 	  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->chan_medium[chan] == MEDIUM_RADIO || | ||||||
| 	      g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) { | 	      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.
 | 	        // On reboot, the time is in the past.
 | ||||||
| 	        // After time gets set from GPS, all beacons from that interval are sent.
 | 	        // After time gets set from GPS, all beacons from that interval are sent.
 | ||||||
| 	        // FIXME:  This will surely break time slotted scheduling.
 | 	        // 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) */ | 	        /* 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 */ | 	        /* 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); | 	      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) { | 	      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 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; | 		return; | ||||||
| 	      } | 	      } | ||||||
| 
 | 
 | ||||||
|  | @ -1046,7 +1054,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo) | ||||||
| 	  	    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 (0, pp); | 		    igate_send_rec_packet (-1, pp);	// Channel -1 to avoid RF>IS filtering.
 | ||||||
| 		    ax25_delete (pp); | 		    ax25_delete (pp); | ||||||
| 	            break; | 	            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') { | 	    else if (value[0] == 'r' || value[0] == 'R') { | ||||||
| 	       int n = atoi(value+1); | 	       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); | 	         text_color_set(DW_COLOR_ERROR); | ||||||
| 	         dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n); | 	         dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n); | ||||||
| 	         continue; | 	         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') { | 	    else if (value[0] == 't' || value[0] == 'T' || value[0] == 'x' || value[0] == 'X') { | ||||||
| 	      int n = atoi(value+1); | 	      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); | 	        text_color_set(DW_COLOR_ERROR); | ||||||
| 	        dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); | 	        dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); | ||||||
| 	        continue; | 	        continue; | ||||||
|  | @ -5615,7 +5617,8 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ | ||||||
| 	    } | 	    } | ||||||
| 	    else { | 	    else { | ||||||
| 	       int n = atoi(value); | 	       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); | 	         text_color_set(DW_COLOR_ERROR); | ||||||
| 	         dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); | 	         dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); | ||||||
| 	         continue; | 	         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. |  * 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="/-" |  *	overlay=S symbol="/-" | ||||||
|  * We should complain if overlay used with symtab other than \. |  * 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_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); | 	    text_color_set(DW_COLOR_ERROR); | ||||||
| 	    dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan); | 	    dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan); | ||||||
| 	    return (0); | 	    return (0); | ||||||
| 	  } | 	  } | ||||||
| 
 | 
 | ||||||
| 	  if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 ||  | 	  if (p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_IGATE) {  // Prevent subscript out of bounds.
 | ||||||
| 	       strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 ||  | 									     // Will be using call from chan 0 later.
 | ||||||
| 	       strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) { | 	    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); | 	      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);  | 	      dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", 0);  | ||||||
| 	    return (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)); | 	    strlcpy (A->g_data_type_desc, "Weather Report", sizeof(A->g_data_type_desc)); | ||||||
| 	    weather_data (A, p->comment, TRUE); | 	    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 { | 	  else { | ||||||
| 	    /* Regular position report. */ | 	    /* 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. |  * 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." |  * Purpose:	Decode "Message Format." | ||||||
|  *		The word message is used loosely all over the place, but it has a very specific meaning here. |  *		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. |  *		ilen 	- Information field length. | ||||||
|  *		quiet	- suppress error messages. |  *		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)  | static void aprs_general_query (decode_aprs_t *A, char *info, int ilen, int quiet)  | ||||||
| { | { | ||||||
| 	char *q2; | 	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) | 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? */
 | 	//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 |  * 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. |  * 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->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_fast_attack = 0.70;		 | ||||||
| 	    D->agc_slow_decay = 0.000090; | 	    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.
 | 	    // 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); | 	    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_locked_inertia = 0.74; | ||||||
| 	    D->pll_searching_inertia = 0.50; | 	    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; | 	    D->alevel_space_peak = -1; | ||||||
| 	    break; | 	    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; | 	D->slicer[slice].prev_d_c_pll = D->slicer[slice].data_clock_pll; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	// Perform the add as unsigned to avoid signed overflow error.
 | 	// 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)); | 	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 | #endif | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #if 1 | ||||||
| 	  hdlc_rec_bit (chan, subchan, slice, demod_out > 0, 0, quality); | 	  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); | 	  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); | 	  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) { | 	  if (D->slicer[slice].data_detect) { | ||||||
| 	    D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_locked_inertia); | 	    D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_locked_inertia); | ||||||
| 	  } | 	  } | ||||||
| 	  else { | 	  else { | ||||||
| 	    D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_searching_inertia); | 	    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, | 						audio_config.achan[x_opt_chan].mark_freq, | ||||||
| 						x_opt_chan); | 						x_opt_chan); | ||||||
| 				while (n-- > 0) { | 				while (n-- > 0) { | ||||||
| 					tone_gen_put_bit(x_opt_chan, 0); | 					tone_gen_put_bit(x_opt_chan, 1); | ||||||
| 				} | 				} | ||||||
| 				break; | 				break; | ||||||
| 			case 's':  // "Space" tone: -x s
 | 			case 's':  // "Space" tone: -x s
 | ||||||
|  | @ -1061,7 +1061,7 @@ int main (int argc, char *argv[]) | ||||||
| 						audio_config.achan[x_opt_chan].space_freq, | 						audio_config.achan[x_opt_chan].space_freq, | ||||||
| 						x_opt_chan); | 						x_opt_chan); | ||||||
| 				while (n-- > 0) { | 				while (n-- > 0) { | ||||||
| 					tone_gen_put_bit(x_opt_chan, 1); | 					tone_gen_put_bit(x_opt_chan, 0); | ||||||
| 				} | 				} | ||||||
| 				break; | 				break; | ||||||
| 			case 'p':  // Silence - set PTT only: -x p
 | 			case 'p':  // Silence - set PTT only: -x p
 | ||||||
|  |  | ||||||
							
								
								
									
										109
									
								
								src/dtime_now.c
								
								
								
								
							
							
						
						
									
										109
									
								
								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 |  * Input:	none | ||||||
|  * |  * | ||||||
|  | @ -41,10 +41,23 @@ | ||||||
|  *		simply use double precision floating point to make usage |  *		simply use double precision floating point to make usage | ||||||
|  *		easier. |  *		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_realtime (void) | ||||||
| double dtime_now (void) |  | ||||||
| { | { | ||||||
| 	double result; | 	double result; | ||||||
| 
 | 
 | ||||||
|  | @ -63,6 +76,10 @@ double dtime_now (void) | ||||||
| 	struct timespec ts; | 	struct timespec ts; | ||||||
| 
 | 
 | ||||||
| #ifdef __APPLE__ | #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; | 	struct timeval tp; | ||||||
| 	gettimeofday(&tp, NULL); | 	gettimeofday(&tp, NULL); | ||||||
| 	ts.tv_nsec = tp.tv_usec * 1000; | 	ts.tv_nsec = tp.tv_usec * 1000; | ||||||
|  | @ -75,6 +92,83 @@ double dtime_now (void) | ||||||
| 	 | 	 | ||||||
| #endif | #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	 | #if DEBUG	 | ||||||
| 	text_color_set(DW_COLOR_DEBUG); | 	text_color_set(DW_COLOR_DEBUG); | ||||||
| 	dw_printf ("dtime_now() returns %.3f\n", result ); | 	dw_printf ("dtime_now() returns %.3f\n", result ); | ||||||
|  | @ -84,6 +178,7 @@ double dtime_now (void) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /*------------------------------------------------------------------
 | /*------------------------------------------------------------------
 | ||||||
|  * |  * | ||||||
|  * Name:	timestamp_now |  * Name:	timestamp_now | ||||||
|  | @ -104,7 +199,7 @@ double dtime_now (void) | ||||||
| 
 | 
 | ||||||
| void timestamp_now (char *result, int result_size, int show_ms) | void timestamp_now (char *result, int result_size, int show_ms) | ||||||
| { | { | ||||||
| 	double now = dtime_now(); | 	double now = dtime_realtime(); | ||||||
| 	time_t t = (int)now; | 	time_t t = (int)now; | ||||||
| 	struct tm tm; | 	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) | 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; | 	time_t t = (int)now; | ||||||
| 	struct tm tm; | 	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) | void timestamp_filename (char *result, int result_size) | ||||||
| { | { | ||||||
| 	double now = dtime_now(); | 	double now = dtime_realtime(); | ||||||
| 	time_t t = (int)now; | 	time_t t = (int)now; | ||||||
| 	struct tm tm; | 	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_now (char *result, int result_size, int show_ms); | ||||||
| 
 | 
 | ||||||
| void timestamp_user_format (char *result, int result_size, char *user_format); | 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
 | // An API incompatibility was introduced with API version 7.
 | ||||||
| // and again with 9 and again with 10.
 | // 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 | // release	lib version	API	Raspberry Pi OS		Testing status
 | ||||||
| #error libgps API version might be incompatible. | // 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 | #endif | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Information for interface to gpsd daemon. |  * 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: |  *	can't find it there.  Solution  is to define environment variable: | ||||||
|  * |  * | ||||||
|  *	export LD_LIBRARY_PATH=/use/local/lib |  *	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.
 | 		// 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.
 | 		// 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.
 | 		// 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_center1; | ||||||
| 		cic_t cic_above; | 		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.
 | //    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
 | //    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
 | ||||||
|  | @ -328,7 +328,7 @@ static int stats_uplink_packets;	/* Number of packets passed along to the IGate | ||||||
| 					/* server after filtering. */ | 					/* server after filtering. */ | ||||||
| 
 | 
 | ||||||
| static int stats_uplink_bytes;		/* Total number of bytes sent to IGate server */ | 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 */ | static int stats_downlink_bytes;	/* Total number of bytes from IGate server including */ | ||||||
| 					/* packets, heartbeats, other messages. */ | 					/* packets, heartbeats, other messages. */ | ||||||
|  | @ -855,6 +855,9 @@ static void * connnect_thread (void *arg) | ||||||
|  * Purpose:     Send a packet to the IGate server |  * Purpose:     Send a packet to the IGate server | ||||||
|  * |  * | ||||||
|  * Inputs:	chan	- Radio channel it was received on. |  * 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. |  *		recv_pp	- Pointer to packet object. | ||||||
|  *			  *** CALLER IS RESPONSIBLE FOR DELETING IT! ** |  *			  *** 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. |  * 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) { | 	  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 |  * Name:        send_msg_to_server | ||||||
|  * |  * | ||||||
|  * Purpose:     Send something to the IGate 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. |  *		and packets. | ||||||
|  * |  * | ||||||
|  * Inputs:	imsg	- Message.  We will add CR/LF here. |  * 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; | 	      int ichan = save_audio_config_p->igate_vchannel; | ||||||
| 
 | 
 | ||||||
| 	      // Try to parse it into a packet object.
 | 	      // My original poorly thoughtout idea was to parse it into a packet object,
 | ||||||
| 	      // This will contain "q constructs" and we might see an address
 | 	      // using the non-strict option, and send to the client app.
 | ||||||
| 	      // with two alphnumeric characters in the SSID so we must use
 | 	      //
 | ||||||
| 	      // the non-strict parsing.
 | 	      // A lot of things can go wrong with that approach.
 | ||||||
| 
 | 
 | ||||||
| 	      // Possible problem:  Up to 8 digipeaters are allowed in radio format.
 | 	      // (1)  Up to 8 digipeaters are allowed in radio format.
 | ||||||
| 	      // There is a potential of finding a larger number here.
 | 	      //      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) { | 	      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; | 	        alevel_t alevel; | ||||||
| 	        memset (&alevel, 0, sizeof(alevel)); | 	        memset (&alevel, 0, sizeof(alevel)); | ||||||
| 	        alevel.mark = -2;	// FIXME: Do we want some other special case?
 | 	        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, |  * If we recently transmitted a 'message' from some station, | ||||||
|  * send the position of the message sender when it comes along later. |  * 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 |  * If we have a position report, look up the sender and see if we should | ||||||
|  * bypass the normal filtering. |  * 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.
 | // 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
 | // 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.
 | // 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\ !'.
 | // 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
 | // 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?
 | // 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
 | // 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. |  * Purpose:	Extract original data from encoded payload. | ||||||
|  * |  * | ||||||
|  * Inputs:	received	Array of bytes.  Size is unknown but in practice it |  * 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) |  *		payload_size	0 to 1023.  (IL2P_MAX_PAYLOAD_SIZE) | ||||||
|  *				Expected result size based on header. |  *				Expected result size based on header. | ||||||
|  *		max_fec		true for 16 parity symbols, false for automatic. |  *		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.
 | //    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
 | //    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
 | ||||||
|  | @ -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. */ | 	    /* Verify that the radio channel number is valid. */ | ||||||
| 	    /* Any sort of medium should be OK here. */ | 	    /* 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); | 	      text_color_set(DW_COLOR_ERROR); | ||||||
| 	      dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan); | 	      dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan); | ||||||
| 	      dw_printf ("\n"); | 	      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 |  * It's not guaranteed that unused bytes will contain 0 so we | ||||||
|  * don't issue error message in this case.  |  * 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.
 | // 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
 | // 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.
 | // 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.
 | // 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.
 | //    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
 | //    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
 | ||||||
|  | @ -50,7 +50,8 @@ | ||||||
| #include "audio.h" | #include "audio.h" | ||||||
| #include "tq.h" | #include "tq.h" | ||||||
| #include "dedupe.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. |  * 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 |  *		prio	- Priority, use TQ_PRIO_0_HI for digipeated or | ||||||
|  *				TQ_PRIO_1_LO for normal. |  *				TQ_PRIO_1_LO for normal. | ||||||
|  * |  * | ||||||
|  | @ -247,6 +251,43 @@ void tq_append (int chan, int prio, packet_t pp) | ||||||
| 	} | 	} | ||||||
| #endif | #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) { | 	if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) { | ||||||
| 	  text_color_set(DW_COLOR_ERROR); | 	  text_color_set(DW_COLOR_ERROR); | ||||||
| 	  dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); | 	  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. |  * The check would allow an unlimited number of other types. | ||||||
|  * |  * | ||||||
|  * Limit was 20.  Changed to 100 in version 1.2 as a workaround. |  * 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) { | 	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. |  * 	IGate. | ||||||
|  * |  * | ||||||
|  * When transmitting over the radio, it gets sent multiple times, to help |  * 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. |  * 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); | 	dw_printf ("waypoint_send_sentence (\"%s\", \"%c%c\")\n", name_in, symtab, symbol); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| // Don't waste time if no destintations specified.
 | // Don't waste time if no destinations specified.
 | ||||||
| 
 | 
 | ||||||
| 	if (s_waypoint_serial_port_fd == MYFDERROR && | 	if (s_waypoint_serial_port_fd == MYFDERROR && | ||||||
| 	    s_waypoint_udp_sock_fd == -1) { | 	    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
 | 					// I don't know if this in some official specification
 | ||||||
| 					// somewhere, but it is generally agreed that APRS digipeaters
 | 					// somewhere, but it is generally agreed that APRS digipeaters
 | ||||||
| 					// should send only one frame at a time rather than
 | 					// 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
 | 					// Discussion here:  http://lists.tapr.org/pipermail/aprssig_lists.tapr.org/2021-September/049034.html
 | ||||||
| 	            break; | 	            break; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue