Compare commits

..
314 Commits
Author SHA1 Message Date
Jonathan Naylor 046e1df161 Merge pull request #362 from n0mjs710/link-audio-fidelity
FM link-mode network audio: anti-alias/reconstruction filtering
2026-08-16 17:36:20 +01:00
Cort Buffington d70ab85bae Copy-construct the ds/us filters from m_filterStage1/2/3
Same coefficients, no need to retype them. CFMDirectFormI's copy ctor
already copies coefficients and (zeroed, at this point) state.
2026-08-13 13:52:06 -05:00
Cort Buffington 384c5d559d Reconstruction filter after ext-audio upsampling in FM mode
CFMUpSampler zero-stuffs 8kHz to 24kHz with no lowpass after it,
leaving imaging artifacts in the reconstructed ext audio. Filter it
with a second, separately-stated pass of the same 300-2700Hz design
already used for TX shaping, right where it comes out of the upsampler.
2026-08-12 07:43:23 -05:00
Cort Buffington 4c7e8fbe46 Anti-alias filter before RF->network downsampling in FM mode
The 24kHz->8kHz decimation in CFMDownSampler had no lowpass ahead of
it, aliasing everything above 4kHz back into the audio band. Reuse
the existing 300-2700Hz filter design (separate instance/state) ahead
of all three addSample() call sites in FM.cpp.

Also: reset() wasn't clearing the ring buffer or in-progress sample
pack, so stale audio could bleed into the next transmission. And
addSample() packed samples into 12 bits with no saturation, so an
out-of-range value corrupted the neighbouring sample.
2026-08-11 09:57:47 -05:00
Jonathan Naylor 894ba76432 Merge pull request #361 from n0mjs710/link-mode-ext-gap
Link mode ext audio gap
2026-08-11 15:02:32 +01:00
Cort Buffington 8a89804fda Refactor FM_LINK_EXT_GAP_MS and improve comments
Updated the FM_LINK_EXT_GAP_MS constant declaration and added comments for clarity.
2026-08-11 08:55:22 -05:00
Cort Buffington 8bd467598c Debounce link-mode external-audio underrun before dropping PTT
Under [FM] LinkMode=1, linkStateMachine() set m_extSignal false the
instant a single ext-audio sample went missing, with no debounce --
unlike the non-link duplex/simplex paths, which already tolerate a
brief gap via the RELAYING_EXT -> RELAYING_WAIT_EXT / m_ackDelayTimer
pattern before declaring a real loss. Since IO::process() drops PTT
the moment the downstream TX buffer runs dry, that zero-debounce cutoff
meant even a very brief, late-but-recoverable gap from the gateway
(scheduling jitter, a late UDP frame, etc.) could cascade into a full
PTT drop-and-rekey cycle -- far more audible than the underlying gap
itself.

Adds m_extGapTimer, mirroring the existing pattern: on the first missed
sample, start the timer instead of immediately clearing m_extSignal; a
gap that recovers before FM_LINK_EXT_GAP_MS (default 60ms) expires
never affects m_extSignal at all, so the transmitter never notices.
Only a gap that outlasts the timer is treated as a genuine end of
transmission, exactly as before.

linkSamples()'s currentExtSample is now zero-initialized, since
m_extSignal can now stay true for a few samples past an underrun --
silence, not stack garbage, must be what gets played out to the modem
during that window.
2026-08-09 11:42:20 -05:00
Jonathan Naylor 715d3f5839 Merge pull request #359 from chancellor1101/bugfixes
Fix several small bugs: STM UART repeater port, FM noise squelch, Due FM LED, DMR trunking state
2026-07-13 12:07:39 +01:00
Clint Chance 68252f15f5 Fix the FM 25kHz calibration debug message.
It said 10kHz, a copy and paste from the case above.
2026-07-12 16:45:24 -05:00
Clint Chance 96061a6013 Make DMR trunking state handling order-independent.
The CSBK slot type was only encoded into the ALOHA frame inside
setColorCode(), so it took effect only if a reconfigure happened after
an ALOHA frame had already been received; on the usual command ordering
(SET_CONFIG then ALOHA) the transmitted slot type depended entirely on
the host-supplied bytes. Remember the colour code and stamp the slot
type in writeAloha() as well.

Also clear m_controlChannel when trunking is disabled, so the host has
a way to stop control channel transmission other than rebooting, and
fix a stray tab introduced in createCACH().
2026-07-12 16:45:24 -05:00
Clint Chance 90220cbb9d Fix the FM mode LED pin guard on the Arduino Due.
The pinMode() call for PIN_FM was guarded by USE_ALTERNATE_POCSAG_LEDS
instead of USE_ALTERNATE_FM_LEDS, a copy and paste error. The Teensy
version and the setFMInt() implementation in this file both use the FM
macro.
2026-07-12 16:42:58 -05:00
Clint Chance 2eb6f7fd06 Initialise and reset the FM noise squelch invalid counter.
m_invalidCount was missing from the constructor initialiser list and was
read uninitialised in process(), making the squelch behaviour after
power-up indeterminate. reset() also cleared neither hysteresis counter,
so state leaked across squelch resets.
2026-07-12 16:42:58 -05:00
Clint Chance a1794b44ed Fix RX interrupt flag being cleared on the wrong USART in STMUART.
handleIRQ() hardcoded USART1 when clearing the RXNE pending bit, so on
boards where the repeater/display UART is not USART1 (Nucleo, Discovery,
F767, UART5-based boards) the flag was cleared on the wrong peripheral.
Use the m_usart member, matching the TXE handling below.

Also fix flush(): it passed a flag constant to USART_GetITStatus and
span while TXE was set, which returns immediately since TXE indicates
the data register is already empty. Wait for the software TX FIFO to
drain and then for the TC flag, which indicates the shift register has
actually emptied.
2026-07-12 16:42:47 -05:00
Jonathan Naylor 57e692ad8c Small cleanups of the DMR trunking code. 2026-04-24 16:54:23 +01:00
Jonathan Naylor 841d7505c2 Merge pull request #358 from qradiolink/trunking_patches
Add support for DMR tier III trunking
2026-04-24 14:50:28 +01:00
adrian 549dfd7258 Change DMR ALOHA header to 0x17 2026-04-19 11:32:07 +03:00
adrian 30ba4c4c55 Fix merge gone wrong in DMRTX.cpp 2026-04-19 11:12:37 +03:00
adrian a696fd454c DMR trunking patches to DMRTX and SerialPort 2026-04-18 11:29:48 +03:00
Jonathan Naylor 3fd84d5ed4 Fix merge compilation issue. 2026-02-19 15:59:46 +00:00
Jonathan Naylor 78216afbb7 Clean up the ring buffer. 2026-02-18 13:40:05 +00:00
Jonathan Naylor 0308bfc6c7 Merge branch 'master' into mqtt 2026-02-18 13:36:22 +00:00
Jonathan Naylor 278c69152a Merge pull request #356 from F4FXL/C++11-Flags 2026-01-20 20:31:18 +00:00
Geoffrey Merck 8e144e81d0 Add C++11 standard flag to compiler flags
Debian Trixie ships with arm-none-eabi-g++ v14.2.1 which defaults to c++17, this forces compilation with c++11
2026-01-20 20:29:04 +01:00
Jonathan Naylor 5dd59fc473 Merge branch 'master' into mqtt 2025-08-28 17:00:21 +01:00
Jonathan Naylor 5fb5986d50 Remove M17 and AX.25 2025-08-27 18:35:30 +01:00
Jonathan Naylor 824c9b9852 Widened the size of serial data going into M17 and FM. 2025-01-13 15:05:28 +00:00
Jonathan Naylor f324f96db7 Increase the number of frames before YSF declares a signal to be lost. 2024-11-21 17:50:15 +00:00
Jonathan Naylor 15227d9cec Merge branch 'master' into mqtt 2024-10-02 16:10:09 +01:00
Jonathan Naylor c3246dbcb7 Merge branch 'master' of https://github.com/g4klx/MMDVM 2024-10-02 16:05:48 +01:00
Jonathan Naylor 65c51bf849 Merge branch 'master' into mqtt 2024-08-01 12:55:06 +01:00
Jonathan Naylor edd60caad3 Remove the deprecated register keyword. 2024-07-31 19:25:59 +01:00
Jonathan Naylor b8a0f7b1cf Merge pull request #343 from mytechguyri/master
Added option to configure Serial Repeater baud rate
2024-03-10 18:28:44 +00:00
John Tetreault 28e564738e Added option to configure Serial Repeater baud rate so end user can set to 115,200 for high speed Nextion display 2024-03-10 14:19:21 -04:00
Jonathan Naylor a7fddc37e1 Don't send a status when the FM repeater is reset, it causes a loop. 2023-11-18 16:45:36 +00:00
Jonathan Naylor a8bf99037e Merge branch 'master' into mqtt 2023-11-09 19:13:12 +00:00
Jonathan Naylor 029e6df4b9 Remove support for STM32F1* boards, they're just too slow. 2023-11-09 19:08:15 +00:00
Jonathan Naylor 85d3086d4c Restart the RSSI ADC conversion in the STM32 interrupt to match the signal ADC. 2023-10-10 20:06:50 +01:00
Jonathan Naylor ccf3b7301e Make the type correct for silence frames. 2023-10-10 20:03:01 +01:00
Jonathan Naylor 6b3a811ae7 Simplify the serial repeater code. 2023-10-05 19:49:17 +01:00
Jonathan Naylor 508018c89c Add the MMDVM serial protocol document from December 2015. 2023-09-22 16:51:03 +01:00
Jonathan Naylor 3e079f58ad Add RSSI reporting to FM and AX.25 2023-08-02 17:34:52 +01:00
Jonathan Naylor 7ef0d992d9 Improve the status reporting for FM mode. 2023-01-18 14:30:02 +00:00
Jonathan Naylor bf23a94038 Merge pull request #334 from n0mjs710/master 2023-01-09 15:17:17 +00:00
Cort Buffington b2755864ef Adding support for WA0EDA STM32-DVM-MTR2K v2.0d with FM LED, and a (commented) line to compile for 500000 serial port speed to support the WA0EDA MODEMs and others that use Armbian + AllWinner H2/H3 SOC that does not support 4600800. 2023-01-09 07:06:42 -06:00
Jonathan Naylor 7276ca3929 Update Version.h 2022-11-21 19:14:24 +00:00
Jonathan Naylor d14b9dede3 Update Version.h 2022-11-21 19:14:14 +00:00
Jonathan Naylor de87d77ad6 Merge pull request #330 from spongegovo/pocsagax25_fix
Fixed Serial protocol issue where MMDVMHost could not send POCSAG or AX25 to the MMDVM
2022-11-21 19:13:21 +00:00
spongegovo 2626ad5580 Update SerialPort.cpp 2022-11-20 09:15:59 +11:00
Jonathan Naylor 031b078e76 Merge pull request #327 from shawnchain/fix_ax25_dac_overflow_error 2022-09-13 14:09:12 +01:00
Shawn Chain 5d987969a9 The AX25 sine value ranges from 0-4095, and inside io.write() will perform the calculation (value * q15_t(txLevel) >> 15) which may exceed 4096 and cause the DAC Overflow error 2022-09-13 20:18:03 +08:00
Jonathan Naylor f898390956 Bump the version date. 2021-12-20 23:00:13 +00:00
Jonathan Naylor f8d1cc7aed Fix crash on long data frames. 2021-12-20 22:57:40 +00:00
Jonathan Naylor cf9fa93cb9 Include the ARM copyright in the README file. 2021-12-18 22:38:26 +00:00
Jonathan Naylor 69adaf2ebb Update SerialTeensy.cpp 2021-12-18 22:34:24 +00:00
Jonathan Naylor 7f4ae790ba Update STM32Utils.h 2021-12-18 22:31:48 +00:00
Jonathan Naylor 416fc8fc8b Update the README. 2021-12-13 10:31:10 +00:00
Jonathan Naylor 5b79356ddb Merge pull request #324 from 1tilen/master
Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23
2021-11-14 19:51:29 +00:00
Tilen 26fc87aca6 Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23 2021-11-14 19:21:35 +01:00
Jonathan Naylor 54745130c2 Add the transmit function. 2021-10-27 21:28:43 +01:00
Jonathan Naylor f65d52bf2f Add M17 calibration mode. 2021-10-27 19:37:58 +01:00
Jonathan Naylor 5800b33f21 Split the DMR and YSF filtering 2021-10-26 20:51:21 +01:00
Jonathan Naylor 105dba2c27 Merge branch 'master' of github.com:g4klx/MMDVM 2021-10-26 17:43:51 +01:00
Jonathan Naylor 777cc9f2ea Fix typo 2021-10-26 17:43:34 +01:00
Jonathan Naylor e879b4615a Merge branch 'master' of https://github.com/g4klx/MMDVM 2021-10-25 20:03:36 +01:00
Jonathan Naylor 8d69fc59be Update the README file 2021-10-25 20:03:17 +01:00
Jonathan Naylor 2f4e9cc269 Remove unused configuration option 2021-10-25 19:47:31 +01:00
Jonathan Naylor ee07f76bd5 Split the repeater and link mode audio paths. 2021-09-30 18:16:51 +01:00
Jonathan Naylor d063a1da1e Change the EOT handling on TX. 2021-09-19 14:25:12 +01:00
Jonathan Naylor 6a4dad4c44 Change the LinkMode state machine. 2021-09-06 22:50:40 +01:00
Jonathan Naylor ed6bd66fab Rename SimpleMode to LinkMode. 2021-09-06 21:53:01 +01:00
Jonathan Naylor 1a07a6f0d1 Add more details to the simple FM state machine. 2021-09-05 19:46:01 +01:00
Jonathan Naylor 70bf47f93e Add a bery simple FM mode for internet gatewaying. 2021-09-05 19:06:56 +01:00
Jonathan Naylor a5eaafc7e0 Change a method name. 2021-08-26 17:39:52 +01:00
Jonathan Naylor 2200945857 Change the EOF sync pattern for simplicity. 2021-08-26 16:50:18 +01:00
Jonathan Naylor 63a8e61a45 Update to send and receive the new EOF marker. 2021-08-25 21:11:09 +01:00
Jonathan Naylor 7275f65e44 Reset the transmit levels to be correct. 2021-08-23 21:07:17 +01:00
Jonathan Naylor 2aabdb61ab Remove the last traces of M17 packet mode and fix a buffer overrun bug. 2021-08-08 18:55:09 +01:00
Jonathan Naylor 96c0e5b141 Fix compiler warnings when building for POG style boards. 2021-07-19 21:20:57 +01:00
Jonathan Naylor 9c883cfafd Revert "Restore SerialRB for POG builds."
This reverts commit 8a1ab88c3a.
2021-07-01 22:58:59 +01:00
Jonathan Naylor 8a1ab88c3a Restore SerialRB for POG builds. 2021-07-01 22:28:59 +01:00
Jonathan Naylor f4e1c0b401 Fix a potential issue with reporting the wrong command type in ACK and NAK messages. 2021-06-17 16:55:59 +01:00
Jonathan Naylor 43b53fe2fc Add a dummy return for the setting of the FM parameters when FM is not enabled. 2021-05-08 23:48:52 +01:00
Jonathan Naylor 6517229f87 Bump the version date. 2021-05-08 23:24:36 +01:00
Jonathan Naylor d0557ab723 Fix merge mistake which disabled serial access to the RB V5 board. 2021-05-08 23:22:25 +01:00
Jonathan Naylor b5d106dcb6 Merge branch 'master' into M17_AX25_FM 2021-05-05 21:01:19 +01:00
Jonathan Naylor 34cbff41c9 Merge pull request #317 from N4IRS/master 2021-05-02 15:00:12 +01:00
Steve N4IRS 752e13821f Add STM32F7-DVM board 2021-05-02 07:19:24 -04:00
Jonathan Naylor 86b45c15eb Merge branch 'master' into M17_AX25_FM 2021-04-20 20:38:14 +01:00
Jonathan Naylor 4fa0e052f8 Merge pull request #316 from N4IRS/master
RB STM32_DVM_F7 support
2021-04-20 12:51:10 +01:00
Steve N4IRS 0736a5cbe8 RB STM32_DVM_F7 support 2021-04-18 09:50:46 -04:00
Jonathan Naylor 6ffb68450c Allow for hex dumps of modem data by the host. 2021-04-11 18:15:19 +01:00
Jonathan Naylor 1ad20fd4a0 Disable packet mode in M17. 2021-04-07 19:02:04 +01:00
Jonathan Naylor 34f6dfc5bb Simplification of the M17 receiver. 2021-03-14 18:24:30 +00:00
Jonathan Naylor 1e065ba17f Fix and simplify the M17 receiver. 2021-03-14 17:53:28 +00:00
Jonathan Naylor 1df7d7a7fc Change the FM serial block size to 80. 2021-03-07 19:01:46 +00:00
Jonathan Naylor 7e919b12f7 Clean up the M17 synchronisation logic. 2021-01-02 12:24:11 +00:00
Jonathan Naylor bada4d9285 Add M17 packet mode support. 2021-01-01 13:17:02 +00:00
Jonathan Naylor 9ae4a5376d Merge branch 'master' into M17_AX25_FM 2021-01-01 13:01:56 +00:00
Jonathan Naylor 8038ce9c9c Merge pull request #308 from shawnchain/drcc_dvm_hhp_board_support
Add DRCC_DVM_HHP446 board support
2021-01-01 12:32:01 +00:00
Shawn Chain 842dcdb5c5 Add DRCC_DVM_HHP446 board support 2021-01-01 19:48:07 +08:00
Jonathan Naylor f7ead5cc0e Update the M17 sync vectors. 2020-12-26 12:42:16 +00:00
Jonathan Naylor b155597693 Merge branch 'master' into M17_AX25_FM 2020-12-14 09:53:38 +00:00
Jonathan Naylor 7148cf9f7d Add I2C support. 2020-12-14 09:46:53 +00:00
Jonathan Naylor 9440b43114 Simplify the D-Star fast data support. 2020-12-14 09:45:53 +00:00
Jonathan Naylor c06a83660f Merge pull request #306 from timclassic/dstar-match-full-last-data-frame
Detect full 48 bits of last data frame in a D-Star transmission
2020-12-14 09:37:05 +00:00
Tim Stewart 657e71238d Detect full 48 bits of last data frame in a transmission
While testing new support for DV Fast Data, I ran across a particular
image that reliably generated a bit sequence that the MDMVM firmware
interpreted as an end-of-transmission.  I dug a bit and discovered
that MMDVM only matches on 32 bits of the last data frame instead of
the full 48 bits.

See http://www.arrl.org/files/file/D-STAR.pdf section 2.1.2, item (6)
for details.
2020-12-05 13:37:06 -05:00
Jonathan Naylor 510d433906 Merge pull request #305 from dg0tm/M17_AX25_FM
Fixing Arduino Unique Identifier byte order
2020-11-28 15:27:16 +00:00
Christoph Kottke ff39a9031b Fixing Arduino Unique Identifier byte order 2020-11-28 16:25:08 +01:00
Jonathan Naylor 4f3aa8b7e1 Merge pull request #304 from dg0tm/M17_AX25_FM
Fixing Arduino UUID support
2020-11-28 12:13:35 +00:00
Christoph Kottke a35b8f929a Fixing Arduino UUID support 2020-11-28 08:51:58 +01:00
Jonathan Naylor 6d0335b357 Update for latest M17 specification. 2020-11-26 10:03:54 +00:00
Jonathan Naylor 54f4dcabf0 Increase serial speed to 460800. 2020-11-24 16:22:14 +00:00
Jonathan Naylor 19e2ccf150 Bump the version date. 2020-11-20 10:36:45 +00:00
Jonathan Naylor 0c4f49fa68 Add FM LED pin definition for the Repeater Builder V4 board. 2020-11-20 10:35:19 +00:00
Jonathan Naylor 98ebefe84b Update module pointers. 2020-11-20 10:31:11 +00:00
Jonathan Naylor 029e7eef4a Fix bugs. 2020-11-18 20:35:07 +00:00
Jonathan Naylor ca4fff2ba6 Remove unused I2C code and fix buffer handling bugs. 2020-11-17 10:36:00 +00:00
Jonathan Naylor 23ba73cabd Disable I2C in M17_AX25_FM. 2020-11-13 15:22:35 +00:00
Jonathan Naylor 519af80ac4 Add the beginnings of I2C support. 2020-11-13 15:20:54 +00:00
Jonathan Naylor c5b542f438 Allow serial data to be sent back to the host. 2020-11-13 12:09:10 +00:00
Jonathan Naylor 3503e0cc2a Merge branch 'master' into M17_AX25_FM 2020-11-12 09:15:40 +00:00
Jonathan Naylor 955578789d Make the M17 receiver less sensitive to noise. 2020-11-11 18:30:49 +00:00
Andy CA6JAU 061e10e395 Fixing deploy-pi and deploy-pi-f7 (M0VSE advice) 2020-11-11 15:23:14 -03:00
Jonathan Naylor fa9040fdf0 Fix compile issue for the serial repeater. 2020-11-11 17:14:05 +00:00
Jonathan Naylor 8240225371 Set the Config.h defaults correctly for the ZUM v0.9 board. 2020-11-11 17:11:22 +00:00
Jonathan Naylor f2c7c19444 Strip the version out of SerialPort.cpp 2020-11-09 17:29:55 +00:00
Jonathan Naylor 2e5f174cdd Add the modem capabilities data to the version message. 2020-11-09 16:22:44 +00:00
Jonathan Naylor d144ce6f1c Small changes to the serial protocol. 2020-11-09 14:23:43 +00:00
Jonathan Naylor 31744a237a Use the D-Star correlator receiver. 2020-11-09 11:50:02 +00:00
Jonathan Naylor 46c0958704 Add the boxcar filter as an option for NXDN. 2020-11-09 11:25:03 +00:00
Jonathan Naylor 99d2a0d822 Add UDID support. 2020-11-09 10:23:57 +00:00
Jonathan Naylor 81518bf74c Make AX.25, DMR, P25, NXDN and FM selectable at compile time. 2020-11-08 22:23:27 +00:00
Jonathan Naylor dd5a465a39 Make D-Star, System Fusion, M17, and POCSAG optional. 2020-11-08 21:28:26 +00:00
Jonathan Naylor a345586ee9 Update the protocol version. 2020-11-06 15:14:02 +00:00
Jonathan Naylor 55c89a4413 Merge branch 'AX25_FM' into M17_AX25_FM 2020-11-06 15:06:00 +00:00
Jonathan Naylor 60f87072ba Rescale the TX filter for M17. 2020-10-15 09:40:35 +01:00
Jonathan Naylor f2d2033733 Add the sync and RRC 0.5 data and code. 2020-10-14 13:29:23 +01:00
Jonathan Naylor 0334b5a791 Handle the M17 mode LED pins(-ish) 2020-10-14 11:55:31 +01:00
Jonathan Naylor a62fd814ae Begin M17 support. 2020-10-14 10:52:30 +01:00
Jonathan Naylor 02000c8049 Merge branch 'master' into AX25_FM 2020-09-01 13:27:57 +01:00
Jonathan Naylor 2509ab5ba1 Fix the self-test LEDs. 2020-09-01 13:27:29 +01:00
Jonathan Naylor 2de9e4d533 Merge branch 'master' into AX25_FM 2020-09-01 09:59:31 +01:00
Jonathan Naylor fda1e3dcf4 More LED fixes. 2020-09-01 09:57:49 +01:00
Jonathan Naylor cb3ed795d0 Merge branch 'master' into AX25_FM 2020-08-31 16:09:44 +01:00
Jonathan Naylor 632ddda68b Change the handling of the mode LEDs. 2020-08-31 16:06:59 +01:00
Jonathan Naylor b6093406ad Fix missing AX25 class definition. 2020-08-11 16:39:19 +01:00
Jonathan Naylor 8d9b49bdb0 Merge pull request #297 from F4FXL/AX25_FM
Add some delay to squelch
2020-08-05 22:16:37 +01:00
Geoffrey Merck 625ec93af8 Remove unused variable 2020-08-05 21:17:05 +02:00
Geoffrey Merck b2111553c6 Correct comment 2020-08-05 21:15:03 +02:00
Geoffrey Merck 252d54a484 Add some delay to squelch 2020-08-05 21:11:32 +02:00
Jonathan Naylor 1ad9799123 Merge branch 'AX25' into AX25_FM 2020-08-03 13:09:15 +01:00
Jonathan Naylor 2a001f491d Simplify the CTCSS and Noise Squelch decoders and logic. 2020-07-31 09:20:55 +01:00
Jonathan Naylor b5ba384495 Fix a couple of minor bugs. 2020-07-28 14:24:51 +01:00
Jonathan Naylor d8f138066e Add an experimental noise squelch. 2020-07-28 13:55:50 +01:00
Jonathan Naylor 6964251122 Merge branch 'AX25' into AX25_FM 2020-07-28 12:40:42 +01:00
Jonathan Naylor 9ff59570c7 Merge branch 'AX25' into AX25_FM 2020-07-15 10:42:43 +01:00
Jonathan Naylor 5960fb97f3 Merge branch 'AX25' into AX25_FM 2020-07-12 15:28:00 +01:00
Jonathan Naylor d29a0bc3a6 Merge branch 'AX25' into AX25_FM 2020-07-12 10:48:43 +01:00
Jonathan Naylor ad77fd60fd Remove KerchunkTX. 2020-07-07 17:57:31 +01:00
Jonathan Naylor aab8f5469f Add timeouts to the FM simplex state machine. 2020-07-06 10:56:35 +01:00
Jonathan Naylor f1d6a8b36e Add DCD LED control. 2020-07-06 10:03:48 +01:00
Jonathan Naylor 843997ccad Merge pull request #293 from F4FXL/AX25_FM
Fix wrong frame type
2020-07-06 06:52:50 +01:00
Geoffrey Merck d5f2d1c382 Fix wrong frame type 2020-07-04 12:15:33 +02:00
Jonathan Naylor c99f50575d Add a simpe simplex FM controller state machine. 2020-07-01 13:02:14 +01:00
Jonathan Naylor 29c8cf9414 Add AX.25 Slot Time and P-Persist processing for simplex work. 2020-07-01 12:33:08 +01:00
Jonathan Naylor 2c6e2c2a11 Remove unneeded zeroes from the band pass FIR filter. 2020-06-30 17:09:09 +01:00
Jonathan Naylor 8d10555dc9 Reduce the low pass filter a little. 2020-06-30 15:35:58 +01:00
Jonathan Naylor 14d5098018 Rename FMDownsampler to FMDownSampler. 2020-06-30 12:44:02 +01:00
Jonathan Naylor 52a351d0f1 Slight tweak to the mark and space. 2020-06-29 16:11:56 +01:00
Jonathan Naylor 43f84ae968 Simplify the pre-emphasis code for AX.25. 2020-06-29 15:59:46 +01:00
Jonathan Naylor a73376671c Fix preamble and NRZI. 2020-06-28 15:27:58 +01:00
Jonathan Naylor 759efd1da4 Merge pull request #292 from F4FXL/AX25_FM
correct preamble and NRZI
2020-06-28 15:25:45 +01:00
Geoffrey Merck ea0c1953cc correct preamble and NRZI 2020-06-28 11:22:10 +02:00
Jonathan Naylor a29cb23a75 Remove TX Twist. 2020-06-27 22:55:16 +01:00
Jonathan Naylor bb66c72ef3 Merge branch 'FM_Ext' into AX25_FM 2020-06-25 10:41:48 +01:00
Jonathan Naylor 0ea732780d Implement Kerchunk TX option. 2020-06-20 21:03:11 +01:00
Jonathan Naylor 1309ad9326 Merge pull request #286 from F4FXL/FM_Ext
Add forgotten file for large frame handling
2020-06-01 09:55:25 +01:00
Geoffrey Merck 411d439d78 Add forgotten file for large frame handling 2020-06-01 10:29:05 +02:00
Jonathan Naylor ec9428d63e Merge pull request #285 from F4FXL/FM_Ext
Habdle full frame length
2020-05-31 21:14:35 +01:00
Geoffrey Merck 2a4b28c35e return space as number of bytes 2020-05-31 22:11:28 +02:00
Geoffrey Merck 4f060c0047 Esnure frame size is 84 samples, correctly report space as number of frames 2020-05-31 21:50:06 +02:00
Jonathan Naylor 1ed3a4c9d5 Merge pull request #284 from F4FXL/FM_Ext
Avoid Buffer underruns
2020-05-31 11:26:27 +01:00
Geoffrey Merck f414288c9b Update speed comments 2020-05-31 11:45:17 +02:00
Geoffrey Merck 72cd2ce03e Ensure we have at least 75ms of audio before transmitting 2020-05-30 20:05:34 +02:00
Jonathan Naylor 9137af8e3f Merge pull request #281 from F4FXL/FM_Ext
Speed improvements and fixes for FM Ext
2020-05-24 07:56:45 +01:00
Geoffrey Merck cdfe3d0ec9 Clean up includes 2020-05-24 08:20:03 +02:00
Geoffrey Merck 4dfab06a50 Revert to GPIO_Fast_Speed 2020-05-24 08:11:32 +02:00
Geoffrey Merck 47649171fc Fix sample unpacking 2020-05-24 08:01:59 +02:00
Geoffrey Merck 0bd79fa440 Fix sample packing 2020-05-24 07:45:50 +02:00
Geoffrey Merck 26d055a67b Update filter generation script 2020-05-24 07:44:38 +02:00
Geoffrey Merck 5db1adb5ea #defines for serial speeds 2020-05-23 21:01:21 +02:00
Geoffrey Merck f86b5435bb Remove unneeded include 2020-05-23 15:30:00 +02:00
Geoffrey Merck 31f0e24588 Make serial speed a compile option 2020-05-23 08:57:30 +02:00
Geoffrey Merck 04d0b15545 Remove UART habndling Copy/Paste code 2020-05-23 08:28:23 +02:00
Geoffrey Merck f14222e77d Make sure buffer is continuously filled 2020-05-23 08:25:51 +02:00
Jonathan Naylor 5039dfbe68 Merge pull request #280 from F4FXL/FM_Ext
Fix Callsign at end and simplify Samples
2020-05-20 22:19:36 +01:00
Jonathan Naylor f9f81b9b8e Try and make the closing callsign appear.
(cherry picked from commit 063b21f999)
2020-05-20 23:11:22 +02:00
Geoffrey Merck 3cc5d67696 check acks 2020-05-20 22:51:22 +02:00
Geoffrey Merck 3f960f9fc5 Fix Callsignatend and simplify Samples 2020-05-20 22:30:55 +02:00
Jonathan Naylor 489853f200 Fix the TX Hang. 2020-05-20 15:27:16 +01:00
Jonathan Naylor 96e1a765f9 Merge pull request #279 from F4FXL/FM_Ext
Remove SerialUSB for Arduino and remove uneeded class
2020-05-20 10:17:33 +01:00
Geoffrey Merck 04982c25c0 Remove SerialUSB for Arduino 2020-05-20 11:06:02 +02:00
Geoffrey Merck a3ffa9ed36 Remove no longer needed SerialRB class 2020-05-20 08:08:22 +02:00
Jonathan Naylor e7a22482db Set the COS LED on incoming RF transmissions. 2020-05-19 13:45:17 +01:00
Jonathan Naylor 625749a546 Fixed up the use of the writeFMEOT method. 2020-05-16 13:15:21 +01:00
Jonathan Naylor d75042dc4c Merge pull request #276 from F4FXL/FM_Ext
Add FM EOT
2020-05-16 12:57:33 +01:00
Geoffrey Merck 296ac88842 Correct length 2020-05-16 12:08:26 +02:00
Geoffrey Merck 48e863d1d0 Sent EOT on rf timeout 2020-05-15 21:19:26 +02:00
Geoffrey Merck 7b915f9cac Only send EOT when EXT is enabled 2020-05-15 21:06:16 +02:00
Geoffrey Merck e330c9f52a Fix typo 2020-05-15 21:05:57 +02:00
Geoffrey Merck 9470b1d6d3 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-15 20:21:12 +02:00
Geoffrey Merck 388620b182 Add FM EOT 2020-05-15 18:53:34 +02:00
Jonathan Naylor 72e45177f3 Merge pull request #275 from F4FXL/FM_Ext
Minor fix, reduce memory usage
2020-05-14 22:19:27 +01:00
Geoffrey Merck 90b82621f2 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-14 22:02:47 +02:00
Geoffrey Merck cfcb7ed852 Really fix TX Buffer ovrflows,, reduce delay buffer memory footprint 2020-05-14 09:10:11 +02:00
Geoffrey Merck b245be464f Fix txbuffer overflows and bring back elegant while loop 2020-05-13 22:57:42 +02:00
Jonathan Naylor 139003d4c7 Merge pull request #274 from F4FXL/FM_Ext
Add define to use native USB port on Arduino
2020-05-13 20:19:41 +01:00
Geoffrey Merck c47eacd010 Add define to use native port on Arduino 2020-05-13 21:02:19 +02:00
Jonathan Naylor 6b01f12602 Merge branch 'FM' into FM_Ext 2020-05-13 12:03:12 +01:00
Jonathan Naylor 4f93c6022c Merge pull request #273 from F4FXL/FM_Ext
Send unsigned data and simplify downdampling code
2020-05-13 11:44:37 +01:00
Geoffrey Merck 81f6b6be53 Send usigned data and simplify downdamplign code 2020-05-13 12:42:14 +02:00
Jonathan Naylor fa9f89700f Merge pull request #272 from F4FXL/FM_Ext
Fix compiler warnings
2020-05-13 11:10:04 +01:00
Geoffrey Merck 9023b6ae13 Correct indentation 2020-05-13 12:03:52 +02:00
Geoffrey Merck df23e15c91 Fix compilation warnings 2020-05-13 11:52:59 +02:00
Jonathan Naylor 51e5e7b851 Merge branch 'FM' into FM_Ext 2020-05-13 10:31:17 +01:00
Jonathan Naylor 056dd908b3 Merge pull request #269 from F4FXL/FM_Ext
Fix crash when writing to serial, Tighten handling of incomign data
2020-05-13 07:41:39 +01:00
Geoffrey Merck 62f239ccc9 Fix modem crash while writing to serial, Split IO write and serial write to 2 separate loops. 2020-05-13 08:31:59 +02:00
Geoffrey Merck 994226e4b1 Tighten incoming data, Add FM UpSampler 2020-05-12 22:06:26 +02:00
Jonathan Naylor 2cc6c1f68f Merge pull request #267 from F4FXL/FM_Ext
Write Audio to serial
2020-05-12 19:00:09 +01:00
Geoffrey Merck 8e8cf35b19 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-12 17:55:41 +02:00
Geoffrey Merck 66de35b6d8 Move downsamplig call back to samples 2020-05-12 17:55:24 +02:00
Jonathan Naylor 7dc420c8ff Add the FM controller status to the FM Status message. 2020-05-12 15:58:54 +01:00
Jonathan Naylor df0a9ebe72 Merge branch 'FM' into FM_Ext 2020-05-12 15:51:41 +01:00
Jonathan Naylor e957f0154e Merge pull request #264 from F4FXL/FM_Ext
Fix Silence
2020-05-12 15:25:27 +01:00
Geoffrey Merck b10c72fd78 Merge branch 'FM_Ext' of https://github.com/F4FXL/MMDVM into FM_Ext 2020-05-12 16:22:54 +02:00
Geoffrey Merck 496afcb40e Fix silence 2020-05-12 16:21:24 +02:00
Geoffrey Merck 9467b10e5c Fix silence 2020-05-12 16:19:19 +02:00
Jonathan Naylor 13c5f7b0b4 Merge pull request #263 from F4FXL/FM_Ext
Fix FM not transmitting, remove silence for testing
2020-05-12 15:07:17 +01:00
Geoffrey Merck b64712f657 Restore silence 2020-05-12 14:45:03 +02:00
Geoffrey Merck d23c0900c1 Fix compilation 2020-05-12 14:18:27 +02:00
Geoffrey Merck a0a3080da2 Make sure downsampler always buffers 22 samples at a time 2020-05-12 14:15:04 +02:00
Geoffrey Merck 0fad84b46d Remove silence 2020-05-12 09:29:01 +02:00
Geoffrey Merck 1b40044a23 Re-enable write audio to serial 2020-05-12 09:28:24 +02:00
Geoffrey Merck a671263398 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-12 08:37:10 +02:00
Geoffrey Merck ca1cc7096a Fix modem not goign on transmit, still some cleansing to be done 2020-05-12 08:36:38 +02:00
Geoffrey Merck a5aabd8fac Update TX ON/OFF debug info 2020-05-12 08:35:48 +02:00
Jonathan Naylor 6d0e57ea88 Merge pull request #262 from F4FXL/FM_Ext
Still some work in progress to fix no TX
2020-05-11 23:39:05 +01:00
Geoffrey Merck 1d04c1e903 Typo 2020-05-11 22:35:46 +02:00
Geoffrey Merck 042c26b3bb Trying to fix no tx, WIP 2020-05-11 22:32:24 +02:00
Geoffrey Merck b4a125a759 Add debug info TX switching 2020-05-11 22:31:50 +02:00
Geoffrey Merck 8ecf80ff8f Merge branch 'FM_Ext' of https://github.com/F4FXL/MMDVM into FM_Ext 2020-05-11 19:02:24 +02:00
Geoffrey Merck 6786b9b6b1 Temporary revert to previous code 2020-05-11 19:02:08 +02:00
Geoffrey Merck 86ffc69b30 Add getData 2020-05-11 19:02:08 +02:00
Geoffrey Merck 5d4df6ffd9 Write larger chunks of data to IO 2020-05-11 19:02:08 +02:00
Geoffrey Merck eac2aa4ac1 Write larger chunks of FM audio to the serial port 2020-05-11 19:02:08 +02:00
Geoffrey Merck 8cbd52aa72 Update to SAM 1.6.12 2020-05-11 19:02:08 +02:00
Jonathan Naylor 99b853a976 Stop the status timer when leaving TX. 2020-05-11 15:00:53 +01:00
Jonathan Naylor 15bc1a4027 Merge branch 'FM' into FM_Ext 2020-05-11 13:42:14 +01:00
Jonathan Naylor 1836ba928e Merge branch 'FM' into FM_Ext 2020-05-11 13:36:38 +01:00
Jonathan Naylor 4a5a260c28 Perform FM mode changing in a more conventional manner. 2020-05-11 13:15:13 +01:00
Geoffrey Merck 4bcc1e88c4 Update to SAM 1.6.12 2020-05-11 07:53:21 +02:00
Jonathan Naylor 89458a2c93 Release to STATE_IDLE under simpler conditions. 2020-05-10 21:25:10 +01:00
Jonathan Naylor c91a42f53d Merge pull request #260 from F4FXL/FM_Ext
Write audio to serial port, blank too ext high audio, really ignore ext audio when ext is disabled
2020-05-10 21:04:22 +01:00
Geoffrey Merck 470a070d96 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-10 21:59:57 +02:00
Geoffrey Merck 36537c981c Write audio to serial port, blank to high audio, really ignore ext aduio when ext is disabled 2020-05-10 21:59:14 +02:00
Jonathan Naylor c85978a4e3 Rescale the FM calibration level. 2020-05-10 17:33:50 +01:00
Jonathan Naylor 3ad443dc2a Remove the delay when using COS. 2020-05-10 17:13:10 +01:00
Jonathan Naylor da16ee277c Merge pull request #258 from F4FXL/FM_Ext
Fix repeater stuck on transmit
2020-05-10 17:06:57 +01:00
Geoffrey Merck 0f51ddd0bd Fix repeater stuck on transmit 2020-05-10 17:18:59 +02:00
Jonathan Naylor aaa72e769f Merge pull request #257 from F4FXL/FM_Ext
Only use one RingBuffer plus some bug fixes
2020-05-10 08:14:08 +01:00
Geoffrey Merck 0e8fdb381a Fix State machine not changing state 2020-05-10 09:07:21 +02:00
Geoffrey Merck 0b31c40c2b Made Get volatile 2020-05-10 08:01:10 +02:00
Geoffrey Merck 2b3df4e901 Merge remote-tracking branch 'upstream/FM_Ext' into FM_Ext 2020-05-10 07:01:21 +02:00
Geoffrey Merck 807f01ba72 Get rid of annoying PI warning 2020-05-10 07:00:58 +02:00
Geoffrey Merck 03f18451f7 Remove CSerialBuffer, use CRingBuffer 2020-05-10 06:50:35 +02:00
Geoffrey Merck 16c3d418eb Buffer no longer volatile, not needed 2020-05-10 00:03:32 +02:00
Geoffrey Merck 55df5fe04c Remove useless stuff 2020-05-10 00:03:05 +02:00
Geoffrey Merck b0ba3b5dd8 SerialRB now inherits from RingBuffer 2020-05-09 19:57:40 +02:00
Geoffrey Merck 05d21c0a14 TX Buffer now using Templae RB 2020-05-09 17:44:44 +02:00
Geoffrey Merck 26a703c68c IO RXbuffer now uses template RingBuffer 2020-05-09 17:35:38 +02:00
Geoffrey Merck 6c3dd265ab No more need to specify each types for ringBuffer 2020-05-09 14:14:53 +02:00
Jonathan Naylor c04e207821 Insert the missing silence. 2020-05-09 13:10:02 +01:00
Jonathan Naylor 67e0bf02e2 Merge branch 'FM' into FM_Ext 2020-05-09 13:06:32 +01:00
Geoffrey Merck 7302dc8bd7 Replace RSSI RB with template RB 2020-05-09 11:08:18 +02:00
Jonathan Naylor bb7383a301 Merge pull request #256 from F4FXL/FM_Ext
Add missing files
2020-05-09 10:03:04 +01:00
Geoffrey Merck 61a69d8536 Add missing file 2020-05-09 11:01:28 +02:00
Jonathan Naylor 5a11fcea5b Merge pull request #255 from F4FXL/FM_Ext
Add RingBuffer Template
2020-05-09 09:59:57 +01:00
Geoffrey Merck 05775f0bfa Add RingBuffer Template 2020-05-09 10:57:16 +02:00
Jonathan Naylor 973a1391d7 Merge pull request #254 from F4FXL/FM_Ext
Handle Incoming external audio
2020-05-09 07:36:32 +01:00
Geoffrey Merck 5d45649096 Simplify code 2020-05-09 08:29:31 +02:00
Geoffrey Merck e91c4417cb Handle incoming audio 2020-05-09 08:23:02 +02:00
Geoffrey Merck ff3e6feeb6 Use more explicit names 2020-05-09 08:00:24 +02:00
Geoffrey Merck 0e2a83bc7b Add incoming network data buffer 2020-05-09 07:57:45 +02:00
Jonathan Naylor c84dbd02e5 Merge pull request #253 from F4FXL/FM_Ext
FM into FM_Ext
2020-05-08 21:07:46 +01:00
Geoffrey Merck c0aad5effa Add mising initilizer 2020-05-08 21:47:03 +02:00
Geoffrey Merck e0234dfc00 Merge remote-tracking branch 'upstream/FM' into FM_Ext 2020-05-08 21:39:18 +02:00
Jonathan Naylor 7c9385beab Merge pull request #252 from F4FXL/FM_Ext
Use pointer/shift/masking for sample unpacking
2020-05-08 16:53:32 +01:00
Geoffrey Merck 4c6601d778 Merge branch 'FM_Ext' of https://github.com/F4FXL/MMDVM into FM_Ext 2020-05-08 17:43:43 +02:00
Geoffrey Merck e3a951b33b Use pointer/masking/shifting for sample unpacking 2020-05-08 17:43:05 +02:00
Geoffrey Merck 97192602d8 Use pointer/masking/shifting for sample unpacking 2020-05-08 17:41:12 +02:00
Jonathan Naylor 604957b3e2 Merge pull request #251 from F4FXL/FM_Ext
Remove Union for sample packing
2020-05-08 16:30:06 +01:00
Geoffrey Merck bb731e7890 Init pointer with null 2020-05-08 17:15:23 +02:00
Geoffrey Merck c81d13395b Use correct types 2020-05-08 17:13:29 +02:00
Geoffrey Merck 18bc0a75b8 Merge branch 'FM_Ext' of https://github.com/F4FXL/MMDVM into FM_Ext 2020-05-08 16:45:22 +02:00
Geoffrey Merck f1a43ee520 Remove union, use pointer tricks instead 2020-05-08 16:44:53 +02:00
Geoffrey Merck b73bca237d Remove union, use pointer tricks instead 2020-05-08 15:06:08 +02:00
Jonathan Naylor e7ff0d1898 Use const uint8_t instead of non-const. 2020-05-08 13:29:50 +01:00
Jonathan Naylor 880df2536d Add audio packing code. 2020-05-08 12:30:15 +01:00
Jonathan Naylor 09b6929100 Merge pull request #250 from F4FXL/FM_Ext
Merge FM into FM_Ext
2020-05-08 11:04:14 +01:00
Geoffrey Merck 9afcf3acc9 Merge remote-tracking branch 'upstream/FM' into FM_Ext 2020-05-08 12:00:36 +02:00
Jonathan Naylor d7cd7096d0 Add the external audio state machine and the beginnings of the audio
processing.
2020-05-07 22:39:17 +01:00
Jonathan Naylor 5d1b66dde3 Add the missing functions. 2020-05-07 22:07:58 +01:00
Jonathan Naylor 96364dc189 Add the external audio parameters. 2020-05-07 22:01:48 +01:00
Jonathan Naylor a816818e3f Beginnings of external audio for the FM controller. 2020-05-07 16:17:00 +01:00
131 changed files with 4145 additions and 5311 deletions
+2
View File
@@ -1,3 +1,5 @@
.pio
.vscode
*.o *.o
obj/ obj/
bin/ bin/
-3
View File
@@ -4,6 +4,3 @@
[submodule "STM32F7XX_Lib"] [submodule "STM32F7XX_Lib"]
path = STM32F7XX_Lib path = STM32F7XX_Lib
url = https://github.com/juribeparada/STM32F7XX_Lib.git url = https://github.com/juribeparada/STM32F7XX_Lib.git
[submodule "STM32F10X_Lib"]
path = STM32F10X_Lib
url = https://github.com/shawnchain/STM32F10X_Lib.git
-36
View File
@@ -1,36 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(AX25DEFINES_H)
#define AX25DEFINES_H
const uint8_t AX25_RADIO_SYMBOL_LENGTH = 20U; // At 24 kHz sample rate
const uint8_t AX25_FRAME_START = 0x7EU;
const uint8_t AX25_FRAME_END = 0x7EU;
const uint8_t AX25_FRAME_ABORT = 0xFEU;
const uint8_t AX25_MAX_ONES = 5U;
const uint16_t AX25_MIN_FRAME_LENGTH = 17U; // Callsign (7) + Callsign (7) + Control (1) + Checksum (2)
const uint16_t AX25_MAX_FRAME_LENGTH = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) +
// Control (1) + PID (1) + Data (256) + Checksum (2)
#endif
-266
View File
@@ -1,266 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright 2015-2019 Mobilinkd LLC <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "AX25Demodulator.h"
#include "AX25Defines.h"
const float32_t SAMPLE_RATE = 24000.0F;
const float32_t SYMBOL_RATE = 1200.0F;
const uint16_t DELAY_LEN = 11U;
const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE;
const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F;
const uint32_t LPF_FILTER_LEN = 96U;
q15_t LPF_FILTER_COEFFS[] = {
0, 0, 0, 1, 2, 5, 8, 12, 18, 23,
29, 33, 36, 36, 33, 25, 13, -5, -28, -57,
-89, -123, -159, -194, -225, -249, -264, -267, -254, -224,
-175, -104, -12, 102, 236, 389, 557, 738, 926, 1117,
1306, 1486, 1654, 1802, 1927, 2025, 2092, 2126, 2126, 2092,
2025, 1927, 1802, 1654, 1486, 1306, 1117, 926, 738, 557,
389, 236, 102, -12, -104, -175, -224, -254, -267, -264,
-249, -225, -194, -159, -123, -89, -57, -28, -5, 13,
25, 33, 36, 36, 33, 29, 23, 18, 12, 8,
5, 2, 1, 0, 0, 0
};
// 64 Hz loop filter.
// scipy.signal:
// loop_coeffs = firwin(9, [64.0/(1200/2)], width = None,
// pass_zero = True, scale = True, window='hann')
//
const uint32_t PLL_FILTER_LEN = 7U;
float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F};
CAX25Demodulator::CAX25Demodulator(int8_t n) :
m_frame(),
m_twist(n),
m_lpfFilter(),
m_lpfState(),
m_delayLine(NULL),
m_delayPos(0U),
m_nrziState(false),
m_pllFilter(),
m_pllState(),
m_pllLast(false),
m_pllBits(1U),
m_pllCount(0.0F),
m_hdlcOnes(0U),
m_hdlcFlag(false),
m_hdlcBuffer(0U),
m_hdlcBits(0U),
m_hdlcState(AX25_IDLE)
{
m_delayLine = new bool[DELAY_LEN];
m_lpfFilter.numTaps = LPF_FILTER_LEN;
m_lpfFilter.pState = m_lpfState;
m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS;
m_pllFilter.numTaps = PLL_FILTER_LEN;
m_pllFilter.pState = m_pllState;
m_pllFilter.pCoeffs = PLL_FILTER_COEFFS;
}
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
{
bool result = false;
q15_t fa[RX_BLOCK_SIZE];
m_twist.process(samples, fa, RX_BLOCK_SIZE);
int16_t buffer[RX_BLOCK_SIZE];
for (uint8_t i = 0; i < length; i++) {
bool level = (fa[i] >= 0);
bool delayed = delay(level);
buffer[i] = (int16_t(level ^ delayed) << 1) - 1;
}
q15_t fc[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
for (uint8_t i = 0; i < length; i++) {
bool bit = fc[i] >= 0;
bool sample = PLL(bit);
if (sample) {
// We will only ever get one frame because there are
// not enough bits in a block for more than one.
if (result) {
HDLC(NRZI(bit));
} else {
result = HDLC(NRZI(bit));
if (result) {
// Copy the frame data.
::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN);
frame.m_length = m_frame.m_length;
frame.m_fcs = m_frame.m_fcs;
m_frame.m_length = 0U;
}
}
}
}
return result;
}
bool CAX25Demodulator::delay(bool b)
{
bool r = m_delayLine[m_delayPos];
m_delayLine[m_delayPos++] = b;
if (m_delayPos >= DELAY_LEN)
m_delayPos = 0U;
return r;
}
bool CAX25Demodulator::NRZI(bool b)
{
bool result = (b == m_nrziState);
m_nrziState = b;
return result;
}
bool CAX25Demodulator::PLL(bool input)
{
bool sample = false;
if (input != m_pllLast || m_pllBits > 16U) {
// Record transition.
m_pllLast = input;
if (m_pllCount > PLL_LIMIT)
m_pllCount -= SAMPLES_PER_SYMBOL;
float32_t offset = m_pllCount / float32_t(m_pllBits);
float32_t jitter;
::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U);
m_pllCount -= jitter / 2.0F;
m_pllBits = 1U;
} else {
if (m_pllCount > PLL_LIMIT) {
sample = true;
m_pllCount -= SAMPLES_PER_SYMBOL;
m_pllBits++;
}
}
m_pllCount += 1.0F;
return sample;
}
bool CAX25Demodulator::HDLC(bool b)
{
if (m_hdlcOnes == AX25_MAX_ONES) {
if (b) {
// flag byte
m_hdlcFlag = true;
} else {
// bit stuffing...
m_hdlcFlag = false;
m_hdlcOnes = 0U;
return false;
}
}
m_hdlcBuffer >>= 1;
m_hdlcBuffer |= b ? 128U : 0U;
m_hdlcBits++; // Free-running until Sync byte.
if (b)
m_hdlcOnes++;
else
m_hdlcOnes = 0U;
if (m_hdlcFlag) {
bool result = false;
switch (m_hdlcBuffer) {
case AX25_FRAME_END:
if (m_frame.m_length >= AX25_MIN_FRAME_LENGTH) {
result = m_frame.checkCRC();
if (!result)
m_frame.m_length = 0U;
} else {
m_frame.m_length = 0U;
}
m_hdlcState = AX25_SYNC;
m_hdlcFlag = false;
m_hdlcBits = 0U;
break;
case AX25_FRAME_ABORT:
// Frame aborted
m_frame.m_length = 0U;
m_hdlcState = AX25_IDLE;
m_hdlcFlag = false;
m_hdlcBits = 0U;
break;
default:
break;
}
return result;
}
switch (m_hdlcState) {
case AX25_IDLE:
break;
case AX25_SYNC:
if (m_hdlcBits == 8U) { // 8th bit.
// Start of frame data.
m_hdlcState = AX25_RECEIVE;
m_frame.append(m_hdlcBuffer);
m_hdlcBits = 0U;
}
break;
case AX25_RECEIVE:
if (m_hdlcBits == 8U) { // 8th bit.
m_frame.append(m_hdlcBuffer);
m_hdlcBits = 0U;
}
break;
default:
break;
}
return false;
}
void CAX25Demodulator::setTwist(int8_t n)
{
m_twist.setTwist(n);
}
-67
View File
@@ -1,67 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(AX25Demodulator_H)
#define AX25Demodulator_H
#include "Config.h"
#include "AX25Frame.h"
#include "AX25Twist.h"
enum AX25_STATE {
AX25_IDLE,
AX25_SYNC,
AX25_RECEIVE
};
class CAX25Demodulator {
public:
CAX25Demodulator(int8_t n);
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
void setTwist(int8_t n);
private:
CAX25Frame m_frame;
CAX25Twist m_twist;
arm_fir_instance_q15 m_lpfFilter;
q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 20 - 1 plus some spare
bool* m_delayLine;
uint16_t m_delayPos;
bool m_nrziState;
arm_fir_instance_f32 m_pllFilter;
float32_t m_pllState[20U]; // NoTaps + BlockSize - 1, 7 + 1 - 1 plus some spare
bool m_pllLast;
uint8_t m_pllBits;
float32_t m_pllCount;
uint16_t m_hdlcOnes;
bool m_hdlcFlag;
uint16_t m_hdlcBuffer;
uint16_t m_hdlcBits;
AX25_STATE m_hdlcState;
bool delay(bool b);
bool NRZI(bool b);
bool PLL(bool b);
bool HDLC(bool b);
};
#endif
-122
View File
@@ -1,122 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "AX25Frame.h"
const uint16_t CCITT_TABLE[] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 };
CAX25Frame::CAX25Frame(const uint8_t* data, uint16_t length) :
m_data(),
m_length(0U),
m_fcs(0U)
{
for (uint16_t i = 0U; i < length && i < (AX25_MAX_PACKET_LEN - 2U); i++)
m_data[m_length++] = data[i];
}
CAX25Frame::CAX25Frame() :
m_data(),
m_length(0U),
m_fcs(0U)
{
}
bool CAX25Frame::append(uint16_t c)
{
if (m_length == AX25_MAX_PACKET_LEN)
return false;
m_data[m_length++] = uint8_t(c);
return true;
}
bool CAX25Frame::checkCRC()
{
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0xFFFFU;
for (uint16_t i = 0U; i < (m_length - 2U); i++)
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
crc16 = ~crc16;
if (crc8[0U] == m_data[m_length - 2U] && crc8[1U] == m_data[m_length - 1U]) {
m_fcs = crc16;
return true;
} else {
return false;
}
}
void CAX25Frame::addCRC()
{
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0xFFFFU;
for (uint16_t i = 0U; i < m_length; i++)
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
crc16 = ~crc16;
m_fcs = crc16;
m_data[m_length++] = crc8[0U];
m_data[m_length++] = crc8[1U];
}
-120
View File
@@ -1,120 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "AX25RX.h"
/*
* Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass,
* Hann window, starting and ending 0 value coefficients removed.
*
* np.array(
* firwin2(152,
* [
* 0.0,
* 1000.0/(sample_rate/2),
* 1100.0/(sample_rate/2),
* 2350.0/(sample_rate/2),
* 2500.0/(sample_rate/2),
* 1.0
* ],
* [0,0,1,1,0,0],
* antisymmetric = False,
* window='hann') * 32768,
* dtype=int)[10:-10]
*/
const uint32_t FILTER_LEN = 132;
q15_t FILTER_COEFFS[] = {
0, 5, 12, 18, 21, 19, 11, -2, -15, -25,
-27, -21, -11, -3, -5, -19, -43, -69, -83, -73,
-35, 27, 98, 155, 180, 163, 109, 39, -20, -45,
-26, 23, 74, 89, 39, -81, -247, -407, -501, -480,
-334, -92, 175, 388, 479, 429, 275, 99, 5, 68,
298, 626, 913, 994, 740, 115, -791, -1770, -2544, -2847,
-2509, -1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76,
-1527, -2509, -2847, -2544, -1770, -791, 115, 740, 994, 913,
626, 298, 68, 5, 99, 275, 429, 479, 388, 175,
-92, -334, -480, -501, -407, -247, -81, 39, 89, 74,
23, -26, -45, -20, 39, 109, 163, 180, 155, 98,
27, -35, -73, -83, -69, -43, -19, -5, -3, -11,
-21, -27, -25, -15, -2, 11, 19, 21, 18, 12,
5, 0
};
CAX25RX::CAX25RX() :
m_filter(),
m_state(),
m_demod1(3),
m_demod2(6),
m_demod3(9),
m_lastFCS(0U),
m_count(0U)
{
m_filter.numTaps = FILTER_LEN;
m_filter.pState = m_state;
m_filter.pCoeffs = FILTER_COEFFS;
}
void CAX25RX::samples(q15_t* samples, uint8_t length)
{
q15_t output[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
m_count++;
CAX25Frame frame;
bool ret = m_demod1.process(output, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
}
DEBUG1("Decoder 1 reported");
}
ret = m_demod2.process(output, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
}
DEBUG1("Decoder 2 reported");
}
ret = m_demod3.process(output, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
}
DEBUG1("Decoder 3 reported");
}
}
void CAX25RX::setParams(int8_t twist)
{
m_demod1.setTwist(twist - 3);
m_demod2.setTwist(twist);
m_demod3.setTwist(twist + 3);
}
-180
View File
@@ -1,180 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "AX25TX.h"
#include "AX25Defines.h"
#include "AX25Frame.h"
const uint8_t START_FLAG[] = { AX25_FRAME_START };
const uint8_t END_FLAG[] = { AX25_FRAME_END };
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
const uint8_t BIT_MASK_TABLE2[] = { 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U };
#define WRITE_BIT2(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE2[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE2[(i)&7])
#define READ_BIT2(p,i) (p[(i)>>3] & BIT_MASK_TABLE2[(i)&7])
const uint16_t AUDIO_TABLE_LEN = 120U;
const q15_t AUDIO_TABLE_DATA[] = {
0, 214, 428, 641, 851, 1060, 1265, 1468, 1666, 1859, 2048, 2230, 2407, 2577, 2740, 2896, 3043, 3182, 3313, 3434, 3546, 3649,
3741, 3823, 3895, 3955, 4006, 4045, 4073, 4089, 4095, 4089, 4073, 4045, 4006, 3955, 3895, 3823, 3741, 3649, 3546, 3434, 3313,
3182, 3043, 2896, 2740, 2577, 2407, 2230, 2048, 1859, 1666, 1468, 1265, 1060, 851, 641, 428, 214, 0, -214, -428, -641, -851,
-1060, -1265, -1468, -1666, -1859, -2047, -2230, -2407, -2577, -2740, -2896, -3043, -3182, -3313, -3434, -3546, -3649, -3741,
-3823, -3895, -3955, -4006, -4045, -4073, -4089, -4095, -4089, -4073, -4045, -4006, -3955, -3895, -3823, -3741, -3649, -3546,
-3434, -3313, -3182, -3043, -2896, -2740, -2577, -2407, -2230, -2047, -1859, -1666, -1468, -1265, -1060, -851, -641, -428, -214
};
CAX25TX::CAX25TX() :
m_twist(-6),
m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(120U),
m_tablePtr(0U),
m_nrzi(false)
{
}
void CAX25TX::process()
{
if (m_poLen == 0U)
return;
uint16_t space = io.getSpace();
while (space > AX25_RADIO_SYMBOL_LENGTH) {
bool b = READ_BIT1(m_poBuffer, m_poPtr) != 0U;
m_poPtr++;
writeBit(b);
space -= AX25_RADIO_SYMBOL_LENGTH;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
m_poLen = 0U;
return;
}
}
}
uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length)
{
CAX25Frame frame(data, length);
frame.addCRC();
m_poLen = 0U;
m_poPtr = 0U;
m_nrzi = false;
m_tablePtr = 0U;
// Add TX delay (already NRZI)
for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++)
WRITE_BIT1(m_poBuffer, m_poLen, false);
// Add the Start Flag
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
bool b1 = READ_BIT1(START_FLAG, i) != 0U;
bool b2 = NRZI(b1);
WRITE_BIT1(m_poBuffer, m_poLen, b2);
}
uint8_t ones = 0U;
for (uint16_t i = 0U; i < (frame.m_length * 8U); i++) {
bool b1 = READ_BIT2(frame.m_data, i) != 0U;
bool b2 = NRZI(b1);
WRITE_BIT1(m_poBuffer, m_poLen, b2);
m_poLen++;
if (b1) {
ones++;
if (ones == AX25_MAX_ONES) {
// Bit stuffing
bool b = NRZI(false);
WRITE_BIT1(m_poBuffer, m_poLen, b);
m_poLen++;
ones = 0U;
}
} else {
ones = 0U;
}
}
// Add the End Flag
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
bool b1 = READ_BIT1(END_FLAG, i) != 0U;
bool b2 = NRZI(b1);
WRITE_BIT1(m_poBuffer, m_poLen, b2);
}
return 0U;
}
void CAX25TX::writeBit(bool b)
{
q15_t in[AX25_RADIO_SYMBOL_LENGTH];
for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) {
in[i] = AUDIO_TABLE_DATA[m_tablePtr];
if (b)
m_tablePtr += 6U;
else
m_tablePtr += 11U;
if (m_tablePtr >= AUDIO_TABLE_LEN)
m_tablePtr -= AUDIO_TABLE_LEN;
}
q15_t out[AX25_RADIO_SYMBOL_LENGTH];
m_twist.process(in, out, AX25_RADIO_SYMBOL_LENGTH);
io.write(STATE_AX25, out, AX25_RADIO_SYMBOL_LENGTH);
}
void CAX25TX::setParams(int8_t twist)
{
m_twist.setTwist(twist);
}
void CAX25TX::setTXDelay(uint8_t delay)
{
m_txDelay = delay * 12U;
}
uint8_t CAX25TX::getSpace() const
{
return m_poLen == 0U ? 255U : 0U;
}
bool CAX25TX::NRZI(bool b)
{
bool result = (b == m_nrzi);
m_nrzi = b;
return result;
}
-311
View File
@@ -1,311 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "AX25Twist.h"
// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine.
q15_t dB12[] = {
176,
-812,
-3916,
-7586,
23536,
-7586,
-3916,
-812,
176
};
// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine.
q15_t dB11[] = {
121,
-957,
-3959,
-7383,
23871,
-7383,
-3959,
-957,
121
};
// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine.
q15_t dB10[] = {
56,
-1110,
-3987,
-7141,
24254,
-7141,
-3987,
-1110,
56
};
// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine.
q15_t dB9[] = {
-19,
-1268,
-3994,
-6856,
24688,
-6856,
-3994,
-1268,
-19
};
// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine.
q15_t dB8[] = {
-104,
-1424,
-3968,
-6516,
25182,
-6516,
-3968,
-1424,
-104
};
// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine.
q15_t dB7[] = {
-196,
-1565,
-3896,
-6114,
25742,
-6114,
-3896,
-1565,
-196
};
// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine.
q15_t dB6[] = {
-288,
-1676,
-3761,
-5642,
26370,
-5642,
-3761,
-1676,
-288
};
// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine.
q15_t dB5[] = {
-370,
-1735,
-3545,
-5088,
27075,
-5088,
-3545,
-1735,
-370
};
// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine.
q15_t dB4[] = {
-432,
-1715,
-3220,
-4427,
27880,
-4427,
-3220,
-1715,
-432
};
// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine.
q15_t dB3[] = {
-452,
-1582,
-2759,
-3646,
28792,
-3646,
-2759,
-1582,
-452
};
// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine.
q15_t dB2[] = {
-408,
-1295,
-2123,
-2710,
29846,
-2710,
-2123,
-1295,
-408
};
// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine.
q15_t dB1[] = {
-268,
-795,
-1244,
-1546,
31116,
-1546,
-1244,
-795,
-268
};
q15_t dB0[] = {
0,
0,
0,
0,
32767,
0,
0,
0,
0,
};
// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine.
q15_t dB_1[] = {
-419,
-177,
3316,
8650,
11278,
8650,
3316,
-177,
-419
};
// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine.
q15_t dB_2[] = {
-90,
1033,
3975,
7267,
8711,
7267,
3975,
1033,
-90
};
// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine.
q15_t dB_3[] = {
292,
1680,
3752,
5615,
6362,
5615,
3752,
1680,
292
};
// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar.
q15_t dB_4[] = {
917,
3024,
5131,
6684,
7255,
6684,
5131,
3024,
917
};
// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar.
q15_t dB_5[] = {
1620,
3339,
4925,
6042,
6444,
6042,
4925,
3339,
1620
};
// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar.
q15_t dB_6[] = {
2161,
3472,
4605,
5373,
5644,
5373,
4605,
3472,
2161
};
q15_t* coeffs[] = {
dB12,
dB11,
dB10,
dB9,
dB8,
dB7,
dB6,
dB5,
dB4,
dB3,
dB2,
dB1,
dB0,
dB_1,
dB_2,
dB_3,
dB_4,
dB_5,
dB_6
};
CAX25Twist::CAX25Twist(int8_t n) :
m_filter(),
m_state()
{
setTwist(n);
}
void CAX25Twist::process(q15_t* in, q15_t* out, uint8_t length)
{
::arm_fir_fast_q15(&m_filter, in, out, length);
}
void CAX25Twist::setTwist(int8_t n)
{
uint8_t twist = uint8_t(n + 6);
m_filter.numTaps = 9;
m_filter.pState = m_state;
m_filter.pCoeffs = coeffs[twist];
}
+5
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "CalDMR.h" #include "CalDMR.h"
@@ -221,3 +224,5 @@ uint8_t CCalDMR::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(CALDMR_H) #if !defined(CALDMR_H)
#define CALDMR_H #define CALDMR_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
enum DMRCAL1K { enum DMRCAL1K {
@@ -53,3 +56,5 @@ private:
#endif #endif
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX * Copyright (C) 2009-2016,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h" #include "Globals.h"
#include "CalDStarRX.h" #include "CalDStarRX.h"
#include "Utils.h" #include "Utils.h"
@@ -24,7 +27,7 @@
const unsigned int BUFFER_LENGTH = 200U; const unsigned int BUFFER_LENGTH = 200U;
const uint32_t PLLMAX = 0x10000U; const uint32_t PLLMAX = 0x10000U;
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH; const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_SYMBOL_LENGTH;
const uint32_t INC = PLLINC / 32U; const uint32_t INC = PLLINC / 32U;
// D-Star bit order version of 0x55 0x2D 0x16 // D-Star bit order version of 0x55 0x2D 0x16
@@ -126,3 +129,5 @@ void CCalDStarRX::process(q15_t value)
} }
} }
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(CALDSTARRX_H) #if !defined(CALDSTARRX_H)
#define CALDSTARRX_H #define CALDSTARRX_H
#include "Config.h"
#include "DStarDefines.h" #include "DStarDefines.h"
class CCalDStarRX { class CCalDStarRX {
@@ -40,3 +43,5 @@ private:
#endif #endif
#endif
+5
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h" #include "Globals.h"
#include "CalDStarTX.h" #include "CalDStarTX.h"
@@ -181,3 +184,5 @@ uint8_t CCalDStarTX::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+6 -1
View File
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(CALDSTARTX_H) #if !defined(CALDSTARTX_H)
#define CALDSTARTX_H #define CALDSTARTX_H
#include "Config.h"
#include "DStarDefines.h" #include "DStarDefines.h"
class CCalDStarTX { class CCalDStarTX {
@@ -37,3 +40,5 @@ private:
#endif #endif
#endif
+7 -1
View File
@@ -19,6 +19,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "CalFM.h" #include "CalFM.h"
@@ -52,7 +55,7 @@ void CCalFM::process()
{ {
const TONE_TABLE* entry = NULL; const TONE_TABLE* entry = NULL;
if (m_modemState!=m_lastState) if (m_modemState != m_lastState)
{ {
switch (m_modemState) { switch (m_modemState) {
case STATE_FMCAL10K: case STATE_FMCAL10K:
@@ -125,3 +128,6 @@ uint8_t CCalFM::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+6 -2
View File
@@ -18,11 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(CALFM_H) #if !defined(CALFM_H)
#define CALFM_H #define CALFM_H
#include "Config.h"
class CCalFM { class CCalFM {
public: public:
CCalFM(); CCalFM();
@@ -49,3 +51,5 @@ private:
#endif #endif
#endif
+5
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h" #include "Globals.h"
#include "CalNXDN.h" #include "CalNXDN.h"
@@ -93,3 +96,5 @@ uint8_t CCalNXDN::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+6 -2
View File
@@ -17,11 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(CALNXDN_H) #if !defined(CALNXDN_H)
#define CALNXDN_H #define CALNXDN_H
#include "Config.h"
enum NXDNCAL1K { enum NXDNCAL1K {
NXDNCAL1K_IDLE, NXDNCAL1K_IDLE,
NXDNCAL1K_TX NXDNCAL1K_TX
@@ -43,3 +45,5 @@ private:
#endif #endif
#endif
+5
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_P25)
#include "Globals.h" #include "Globals.h"
#include "CalP25.h" #include "CalP25.h"
@@ -96,3 +99,5 @@ uint8_t CCalP25::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_P25)
#if !defined(CALP25_H) #if !defined(CALP25_H)
#define CALP25_H #define CALP25_H
#include "Config.h"
#include "P25Defines.h" #include "P25Defines.h"
enum P25CAL1K { enum P25CAL1K {
@@ -44,3 +47,5 @@ private:
#endif #endif
#endif
+6 -1
View File
@@ -18,10 +18,12 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_POCSAG)
#include "Globals.h" #include "Globals.h"
#include "CalPOCSAG.h" #include "CalPOCSAG.h"
CCalPOCSAG::CCalPOCSAG() : CCalPOCSAG::CCalPOCSAG() :
m_state(POCSAGCAL_IDLE) m_state(POCSAGCAL_IDLE)
{ {
@@ -48,3 +50,6 @@ uint8_t CCalPOCSAG::write(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
#endif
+7 -2
View File
@@ -17,11 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_POCSAG)
#if !defined(CALPOCSAG_H) #if !defined(CALPOCSAG_H)
#define CALPOCSAG_H #define CALPOCSAG_H
#include "Config.h"
enum POCSAGCAL { enum POCSAGCAL {
POCSAGCAL_IDLE, POCSAGCAL_IDLE,
POCSAGCAL_TX POCSAGCAL_TX
@@ -40,3 +42,6 @@ private:
}; };
#endif #endif
#endif
+43 -10
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2025 by Jonathan Naylor G4KLX
* *
* 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
@@ -19,6 +19,31 @@
#if !defined(CONFIG_H) #if !defined(CONFIG_H)
#define CONFIG_H #define CONFIG_H
// Allow for the selection of which modes to compile into the firmware. This is particularly useful for processors
// which have limited code space and processing power.
// Enable D-Star support.
#define MODE_DSTAR
// Enable DMR support.
#define MODE_DMR
// Enable System Fusion support.
#define MODE_YSF
// Enable P25 phase 1 support.
#define MODE_P25
// Enable NXDN support, the boxcar filter sometimes improves the performance of NXDN receive on some systems.
#define MODE_NXDN
#define USE_NXDN_BOXCAR
// Enable POCSAG support.
#define MODE_POCSAG
// Enable FM support.
#define MODE_FM
// Allow for the use of high quality external clock oscillators // Allow for the use of high quality external clock oscillators
// The number is the frequency of the oscillator in Hertz. // The number is the frequency of the oscillator in Hertz.
// //
@@ -35,19 +60,20 @@
// For 19.2 MHz // For 19.2 MHz
// #define EXTERNAL_OSC 19200000 // #define EXTERNAL_OSC 19200000
// Select a baud rate for host communication. The faster speeds are needed for external FM to work.
// #define SERIAL_SPEED 115200 // Suitable for most older boards (Arduino Due, etc). External FM will NOT work with this!
// #define SERIAL_SPEED 230400 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM might work with this
#define SERIAL_SPEED 460800 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM should work with this
//#define SERIAL_SPEED 500000 // Used with newer boards and Armbian on AllWinner SOCs (H2, H3) that do not support 460800
// Use pins to output the current mode via LEDs // Use pins to output the current mode via LEDs
#define MODE_LEDS #define MODE_LEDS
// For the original Arduino Due pin layout // For the original Arduino Due pin layout
// #define ARDUINO_DUE_PAPA // #define ARDUINO_DUE_PAPA
#if defined(STM32F1)
// For the SQ6POG board
#define STM32F1_POG
#else
// For the ZUM V1.0 and V1.0.1 boards pin layout // For the ZUM V1.0 and V1.0.1 boards pin layout
#define ARDUINO_DUE_ZUM_V10 // #define ARDUINO_DUE_ZUM_V10
#endif
// For the SP8NTH board // For the SP8NTH board
// #define ARDUINO_DUE_NTH // #define ARDUINO_DUE_NTH
@@ -63,10 +89,16 @@
// #define VK6MST_TEENSY_PI3_SHIELD_I2C // #define VK6MST_TEENSY_PI3_SHIELD_I2C
// Pass RSSI information to the host // Pass RSSI information to the host
// #define SEND_RSSI_DATA #define SEND_RSSI_DATA
// Use the modem as a serial repeater for Nextion displays // Use the modem as a serial repeater for Nextion displays
// #define SERIAL_REPEATER #define SERIAL_REPEATER
// Set the baud rate of the modem serial repeater for Nextion displays
#define SERIAL_REPEATER_BAUD_RATE 9600
// Use the modem as an I2C repeater for OLED displays
// #define I2C_REPEATER
// To reduce CPU load, you can remove the DC blocker by commenting out the next line // To reduce CPU load, you can remove the DC blocker by commenting out the next line
#define USE_DCBLOCKER #define USE_DCBLOCKER
@@ -79,9 +111,10 @@
// #define USE_ALTERNATE_NXDN_LEDS // #define USE_ALTERNATE_NXDN_LEDS
// Use the D-Star and DMR LEDs for POCSAG // Use the D-Star and DMR LEDs for POCSAG
// #define USE_ALTERNATE_POCSAG_LEDS #define USE_ALTERNATE_POCSAG_LEDS
// Use the D-Star and YSF LEDs for FM // Use the D-Star and YSF LEDs for FM
#define USE_ALTERNATE_FM_LEDS #define USE_ALTERNATE_FM_LEDS
#endif #endif
+7 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRDMORX.h" #include "DMRDMORX.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -423,3 +426,6 @@ void CDMRDMORX::writeRSSIData(uint8_t* frame)
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif #endif
} }
#endif
+8 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRDMORX_H) #if !defined(DMRDMORX_H)
#define DMRDMORX_H #define DMRDMORX_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
@@ -67,3 +70,6 @@ private:
}; };
#endif #endif
#endif
+6 -1
View File
@@ -19,6 +19,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -74,7 +77,7 @@ void CDMRDMOTX::process()
m_poLen = m_txDelay; m_poLen = m_txDelay;
} else { } else {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
m_poBuffer[i] = m_fifo.get(); m_fifo.get(m_poBuffer[i]);
for (unsigned int i = 0U; i < 39U; i++) for (unsigned int i = 0U; i < 39U; i++)
m_poBuffer[i + DMR_FRAME_LENGTH_BYTES] = PR_FILL[i]; m_poBuffer[i + DMR_FRAME_LENGTH_BYTES] = PR_FILL[i];
@@ -161,3 +164,5 @@ void CDMRDMOTX::setTXDelay(uint8_t delay)
m_txDelay = 1200U; m_txDelay = 1200U;
} }
#endif
+8 -3
View File
@@ -17,13 +17,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRDMOTX_H) #if !defined(DMRDMOTX_H)
#define DMRDMOTX_H #define DMRDMOTX_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
#include "SerialRB.h" #include "RingBuffer.h"
class CDMRDMOTX { class CDMRDMOTX {
public: public:
@@ -38,7 +41,7 @@ public:
uint8_t getSpace() const; uint8_t getSpace() const;
private: private:
CSerialRB m_fifo; CRingBuffer<uint8_t> m_fifo;
arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_interpolate_instance_q15 m_modFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
uint8_t m_poBuffer[1200U]; uint8_t m_poBuffer[1200U];
@@ -51,3 +54,5 @@ private:
#endif #endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRIdleRX.h" #include "DMRIdleRX.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -209,3 +212,6 @@ void CDMRIdleRX::setColorCode(uint8_t colorCode)
{ {
m_colorCode = colorCode; m_colorCode = colorCode;
} }
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 by Jonathan Naylor G4KLX * Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRIDLERX_H) #if !defined(DMRIDLERX_H)
#define DMRIDLERX_H #define DMRIDLERX_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
class CDMRIdleRX { class CDMRIdleRX {
@@ -49,3 +52,5 @@ private:
#endif #endif
#endif
+6 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRRX.h" #include "DMRRX.h"
@@ -68,3 +71,5 @@ void CDMRRX::reset()
m_slot2RX.reset(); m_slot2RX.reset();
} }
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRRX_H) #if !defined(DMRRX_H)
#define DMRRX_H #define DMRRX_H
#include "Config.h"
#include "DMRSlotRX.h" #include "DMRSlotRX.h"
class CDMRRX { class CDMRRX {
@@ -40,3 +43,5 @@ private:
#endif #endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRSlotRX.h" #include "DMRSlotRX.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -400,3 +403,6 @@ void CDMRSlotRX::writeRSSIData(uint8_t* frame)
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif #endif
} }
#endif
+8 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRSLOTRX_H) #if !defined(DMRSLOTRX_H)
#define DMRSLOTRX_H #define DMRSLOTRX_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
enum DMRRX_STATE { enum DMRRX_STATE {
@@ -70,3 +73,6 @@ private:
}; };
#endif #endif
#endif
+6 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 by Jonathan Naylor G4KLX * Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -285,3 +288,5 @@ void CDMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) c
frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU); frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
} }
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015 by Jonathan Naylor G4KLX * Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,6 +16,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRSLOTTYPE_H) #if !defined(DMRSLOTTYPE_H)
#define DMRSLOTTYPE_H #define DMRSLOTTYPE_H
@@ -35,3 +39,5 @@ private:
#endif #endif
#endif
+70 -11
View File
@@ -2,6 +2,7 @@
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU * Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2022,2023,2026 by Adrian Musceac YO8RZZ
* *
* 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
@@ -19,6 +20,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h" #include "Globals.h"
#include "DMRSlotType.h" #include "DMRSlotType.h"
@@ -39,6 +43,12 @@ const uint8_t IDLE_DATA[] =
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U};
// DT Terminator with LC, empty
const uint8_t TERMINATOR_DATA[] =
{0x00U, 0xCCU, 0x01U, 0x80U, 0x01U, 0x94U, 0x01U, 0x48U, 0x08U, 0xB0U, 0x08U,
0x80U, 0x04U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x90U,
0x01U, 0x78U, 0x00U, 0xD0U, 0x08U, 0x40U, 0x14U, 0x00U, 0x0DU, 0x80U, 0x15U};
const uint8_t CACH_INTERLEAVE[] = const uint8_t CACH_INTERLEAVE[] =
{ 1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, { 1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U,
25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U, 25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U,
@@ -62,6 +72,7 @@ m_modFilter(),
m_modState(), m_modState(),
m_state(DMRTXSTATE_IDLE), m_state(DMRTXSTATE_IDLE),
m_idle(), m_idle(),
m_aloha(),
m_cachPtr(0U), m_cachPtr(0U),
m_shortLC(), m_shortLC(),
m_newShortLC(), m_newShortLC(),
@@ -71,7 +82,10 @@ m_poLen(0U),
m_poPtr(0U), m_poPtr(0U),
m_frameCount(0U), m_frameCount(0U),
m_abortCount(), m_abortCount(),
m_abort() m_abort(),
m_controlChannel(false),
m_trunking(false),
m_colorCode(0U)
{ {
::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); ::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
@@ -208,6 +222,23 @@ uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint16_t length)
return 0U; return 0U;
} }
uint8_t CDMRTX::writeAloha(const uint8_t* data, uint16_t length)
{
if (length != DMR_FRAME_LENGTH_BYTES)
return 4U;
::memcpy(m_aloha, data, length);
// Stamp the slot type with the current colour code so that the result
// doesn't depend on the ordering of the ALOHA and SET_CONFIG commands.
CDMRSlotType slotType;
slotType.encode(m_colorCode, DT_CSBK, m_aloha);
m_controlChannel = true;
return 0U;
}
uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length) uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length)
{ {
if (length != 1U) if (length != 1U)
@@ -291,16 +322,20 @@ uint8_t CDMRTX::getSpace2() const
void CDMRTX::createData(uint8_t slotIndex) void CDMRTX::createData(uint8_t slotIndex)
{ {
if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) { if ((m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES) && (m_frameCount >= STARTUP_COUNT) && (m_abortCount[slotIndex] >= ABORT_COUNT)) {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = m_fifo[slotIndex].get(); m_fifo[slotIndex].get(m_poBuffer[i]);
m_markBuffer[i] = MARK_NONE; m_markBuffer[i] = MARK_NONE;
} }
} else { } else {
m_abort[slotIndex] = false; m_abort[slotIndex] = false;
// Transmit an idle message // Transmit an idle message
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = m_idle[i]; if ((slotIndex == 0U) && m_controlChannel && m_trunking)
m_poBuffer[i] = m_aloha[i];
else
m_poBuffer[i] = m_idle[i];
m_markBuffer[i] = MARK_NONE; m_markBuffer[i] = MARK_NONE;
} }
} }
@@ -351,10 +386,14 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
m_cachPtr = 0U; m_cachPtr = 0U;
if (m_cachPtr == 0U) { if (m_cachPtr == 0U) {
if (m_fifo[0U].getData() == 0U && m_fifo[1U].getData() == 0U) if ((m_fifo[0U].getData() == 0U) && (m_fifo[1U].getData() == 0U)) {
::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U); if (m_trunking)
else ::memcpy(m_shortLC, m_newShortLC, 12U);
else
::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U);
} else {
::memcpy(m_shortLC, m_newShortLC, 12U); ::memcpy(m_shortLC, m_newShortLC, 12U);
}
} }
::memcpy(m_poBuffer, m_shortLC + m_cachPtr, 3U); ::memcpy(m_poBuffer, m_shortLC + m_cachPtr, 3U);
@@ -364,8 +403,8 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
bool at = false; bool at = false;
if (m_frameCount >= STARTUP_COUNT) if (m_frameCount >= STARTUP_COUNT)
at = m_fifo[rxSlotIndex].getData() > 0U; at = (m_fifo[rxSlotIndex].getData() > 0U);
bool tc = txSlotIndex == 1U; bool tc = (txSlotIndex == 1U);
bool ls0 = true; // For 1 and 2 bool ls0 = true; // For 1 and 2
bool ls1 = true; bool ls1 = true;
@@ -394,10 +433,20 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
void CDMRTX::setColorCode(uint8_t colorCode) void CDMRTX::setColorCode(uint8_t colorCode)
{ {
::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); m_colorCode = colorCode;
if (m_trunking)
::memcpy(m_idle, TERMINATOR_DATA, DMR_FRAME_LENGTH_BYTES);
else
::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES);
CDMRSlotType slotType; CDMRSlotType slotType;
slotType.encode(colorCode, DT_IDLE, m_idle); if (m_trunking) {
slotType.encode(colorCode, DT_TERMINATOR_WITH_LC, m_idle);
slotType.encode(colorCode, DT_CSBK, m_aloha);
} else {
slotType.encode(colorCode, DT_IDLE, m_idle);
}
} }
void CDMRTX::resetFifo1() void CDMRTX::resetFifo1()
@@ -414,3 +463,13 @@ uint32_t CDMRTX::getFrameCount()
{ {
return m_frameCount; return m_frameCount;
} }
void CDMRTX::setTrunking(bool trunking)
{
m_trunking = trunking;
if (!trunking)
m_controlChannel = false;
}
#endif
+14 -3
View File
@@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2026 by Adrian Musceac YO8RZZ
* *
* 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
@@ -17,13 +18,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRTX_H) #if !defined(DMRTX_H)
#define DMRTX_H #define DMRTX_H
#include "Config.h"
#include "DMRDefines.h" #include "DMRDefines.h"
#include "SerialRB.h" #include "RingBuffer.h"
enum DMRTXSTATE { enum DMRTXSTATE {
DMRTXSTATE_IDLE, DMRTXSTATE_IDLE,
@@ -42,10 +46,12 @@ public:
uint8_t writeData2(const uint8_t* data, uint16_t length); uint8_t writeData2(const uint8_t* data, uint16_t length);
uint8_t writeShortLC(const uint8_t* data, uint16_t length); uint8_t writeShortLC(const uint8_t* data, uint16_t length);
uint8_t writeAloha(const uint8_t* data, uint16_t length);
uint8_t writeAbort(const uint8_t* data, uint16_t length); uint8_t writeAbort(const uint8_t* data, uint16_t length);
void setStart(bool start); void setStart(bool start);
void setCal(bool start); void setCal(bool start);
void setTrunking(bool trunking);
void process(); void process();
@@ -59,11 +65,12 @@ public:
void setColorCode(uint8_t colorCode); void setColorCode(uint8_t colorCode);
private: private:
CSerialRB m_fifo[2U]; CRingBuffer<uint8_t> m_fifo[2U];
arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_interpolate_instance_q15 m_modFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
DMRTXSTATE m_state; DMRTXSTATE m_state;
uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; uint8_t m_idle[DMR_FRAME_LENGTH_BYTES];
uint8_t m_aloha[DMR_FRAME_LENGTH_BYTES];
uint8_t m_cachPtr; uint8_t m_cachPtr;
uint8_t m_shortLC[12U]; uint8_t m_shortLC[12U];
uint8_t m_newShortLC[12U]; uint8_t m_newShortLC[12U];
@@ -74,6 +81,9 @@ private:
uint32_t m_frameCount; uint32_t m_frameCount;
uint32_t m_abortCount[2U]; uint32_t m_abortCount[2U];
bool m_abort[2U]; bool m_abort[2U];
bool m_controlChannel;
bool m_trunking;
uint8_t m_colorCode;
void createData(uint8_t slotIndex); void createData(uint8_t slotIndex);
void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex); void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex);
@@ -83,3 +93,4 @@ private:
#endif #endif
#endif
+37 -17
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX * Copyright (C) 2009-2015,2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -19,30 +19,50 @@
#if !defined(DSTARDEFINES_H) #if !defined(DSTARDEFINES_H)
#define DSTARDEFINES_H #define DSTARDEFINES_H
const unsigned int DSTAR_RADIO_BIT_LENGTH = 5U; // At 24 kHz sample rate const unsigned int DSTAR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U; const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U; const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U; const unsigned int DSTAR_FEC_SECTION_LENGTH_SYMBOLS = 660U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U; const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U; const unsigned int DSTAR_DATA_LENGTH_SYMBOLS = DSTAR_DATA_LENGTH_BYTES * 8U;
const unsigned int DSTAR_DATA_LENGTH_SAMPLES = DSTAR_DATA_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_EOT_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const unsigned int DSTAR_END_SYNC_LENGTH_BYTES = 6U;
const unsigned int DSTAR_EOT_LENGTH_BYTES = 6U; const unsigned int DSTAR_END_SYNC_LENGTH_BITS = DSTAR_END_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_EOT_LENGTH_BITS = DSTAR_EOT_LENGTH_BYTES * 8U;
const uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U; const unsigned int DSTAR_FRAME_SYNC_LENGTH_BYTES = 3U;
const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U; const unsigned int DSTAR_FRAME_SYNC_LENGTH_SYMBOLS = DSTAR_FRAME_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SAMPLES = DSTAR_FRAME_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16}; const unsigned int DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
const unsigned int DSTAR_DATA_SYNC_LENGTH_SYMBOLS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_DATA_SYNC_LENGTH_SAMPLES = DSTAR_DATA_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U}; // D-Star bit order version of 0x55 0x6E 0x0A
const uint32_t DSTAR_FRAME_SYNC_DATA = 0x00557650U;
const uint32_t DSTAR_FRAME_SYNC_MASK = 0x00FFFFFFU;
const bool DSTAR_FRAME_SYNC_SYMBOLS[] = {false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, false, false, true, false, true, false, false, false, false};
// D-Star bit order version of 0x55 0x2D 0x16
const uint32_t DSTAR_DATA_SYNC_DATA = 0x00AAB468U;
const uint32_t DSTAR_DATA_SYNC_MASK = 0x00FFFFFFU;
const bool DSTAR_DATA_SYNC_SYMBOLS[] = {true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, false, false, true, true, false, true, false, false, false};
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
const uint32_t DSTAR_END_SYNC_DATA = 0xAAAA135EU;
const uint32_t DSTAR_END_SYNC_MASK = 0xFFFFFFFFU;
const uint8_t DSTAR_END_SYNC_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U};
#endif #endif
+249 -142
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU * Copyright (C) 2017 by Andy Uribe CA6JAU
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -18,31 +18,28 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h" #include "Globals.h"
#include "DStarRX.h" #include "DStarRX.h"
#include "Utils.h" #include "Utils.h"
const unsigned int BUFFER_LENGTH = 200U; const unsigned int MAX_FRAMES = 150U;
const uint32_t PLLMAX = 0x10000U;
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
const uint32_t INC = PLLINC / 32U;
const unsigned int MAX_SYNC_BITS = 100U * DSTAR_DATA_LENGTH_BITS;
// D-Star bit order version of 0x55 0x55 0x6E 0x0A // D-Star bit order version of 0x55 0x55 0x6E 0x0A
const uint32_t FRAME_SYNC_DATA = 0x00557650U; const uint64_t FRAME_SYNC_DATA = 0x0000000000557650U;
const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU; const uint64_t FRAME_SYNC_MASK = 0x0000000000FFFFFFU;
const uint8_t FRAME_SYNC_ERRS = 2U; const uint8_t FRAME_SYNC_ERRS = 2U;
// D-Star bit order version of 0x55 0x2D 0x16 // D-Star bit order version of 0x55 0x2D 0x16
const uint32_t DATA_SYNC_DATA = 0x00AAB468U; const uint64_t DATA_SYNC_DATA = 0x0000000000AAB468U;
const uint32_t DATA_SYNC_MASK = 0x00FFFFFFU; const uint64_t DATA_SYNC_MASK = 0x0000000000FFFFFFU;
const uint8_t DATA_SYNC_ERRS = 2U; const uint8_t DATA_SYNC_ERRS = 2U;
// D-Star bit order version of 0x55 0x55 0xC8 0x7A // D-Star bit order version of 0x55 0x55 0xC8 0x7A
const uint32_t END_SYNC_DATA = 0xAAAA135EU; const uint64_t END_SYNC_DATA = 0x0000AAAAAAAA135EU;
const uint32_t END_SYNC_MASK = 0xFFFFFFFFU; const uint64_t END_SYNC_MASK = 0x0000FFFFFFFFFFFFU;
const uint8_t END_SYNC_ERRS = 1U; const uint8_t END_SYNC_ERRS = 1U;
const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU}; const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU};
@@ -237,14 +234,24 @@ const uint16_t CCITT_TABLE[] = {
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U}; 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
const uint16_t NOENDPTR = 9999U;
CDStarRX::CDStarRX() : CDStarRX::CDStarRX() :
m_pll(0U),
m_prev(false),
m_rxState(DSRXS_NONE), m_rxState(DSRXS_NONE),
m_patternBuffer(0x00U), m_bitBuffer(),
m_rxBuffer(), m_headerBuffer(),
m_rxBufferBits(0U), m_dataBuffer(),
m_dataBits(0U), m_bitPtr(0U),
m_headerPtr(0U),
m_dataPtr(0U),
m_startPtr(NOENDPTR),
m_syncPtr(NOENDPTR),
m_minSyncPtr(NOENDPTR),
m_maxSyncPtr(NOENDPTR),
m_maxFrameCorr(0),
m_maxDataCorr(0),
m_frameCount(0U),
m_countdown(0U),
m_mar(0U), m_mar(0U),
m_pathMetric(), m_pathMetric(),
m_pathMemory0(), m_pathMemory0(),
@@ -259,14 +266,20 @@ m_rssiCount(0U)
void CDStarRX::reset() void CDStarRX::reset()
{ {
m_pll = 0U; m_rxState = DSRXS_NONE;
m_prev = false; m_headerPtr = 0U;
m_rxState = DSRXS_NONE; m_dataPtr = 0U;
m_patternBuffer = 0x00U; m_bitPtr = 0U;
m_rxBufferBits = 0U; m_maxFrameCorr = 0;
m_dataBits = 0U; m_maxDataCorr = 0;
m_rssiAccum = 0U; m_startPtr = NOENDPTR;
m_rssiCount = 0U; m_syncPtr = NOENDPTR;
m_minSyncPtr = NOENDPTR;
m_maxSyncPtr = NOENDPTR;
m_frameCount = 0U;
m_countdown = 0U;
m_rssiAccum = 0U;
m_rssiCount = 0U;
} }
void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length) void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
@@ -275,125 +288,117 @@ void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t lengt
m_rssiAccum += rssi[i]; m_rssiAccum += rssi[i];
m_rssiCount++; m_rssiCount++;
bool bit = samples[i] < 0; q15_t sample = samples[i];
if (bit != m_prev) { m_bitBuffer[m_bitPtr] <<= 1;
if (m_pll < (PLLMAX / 2U)) if (sample < 0)
m_pll += INC; m_bitBuffer[m_bitPtr] |= 0x01U;
else
m_pll -= INC; m_dataBuffer[m_dataPtr] = sample;
switch (m_rxState) {
case DSRXS_HEADER:
processHeader(sample);
break;
case DSRXS_DATA:
processData();
break;
default:
processNone(sample);
break;
} }
m_prev = bit; m_dataPtr++;
if (m_dataPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_pll += PLLINC; m_bitPtr++;
if (m_bitPtr >= DSTAR_RADIO_SYMBOL_LENGTH)
if (m_pll >= PLLMAX) { m_bitPtr = 0U;
m_pll -= PLLMAX;
switch (m_rxState) {
case DSRXS_NONE:
processNone(bit);
break;
case DSRXS_HEADER:
processHeader(bit);
break;
case DSRXS_DATA:
processData(bit);
break;
default:
break;
}
}
} }
} }
void CDStarRX::processNone(bool bit) void CDStarRX::processNone(q15_t sample)
{ {
m_patternBuffer <<= 1;
if (bit)
m_patternBuffer |= 0x01U;
// Fuzzy matching of the frame sync sequence // Fuzzy matching of the frame sync sequence
if (countBits32((m_patternBuffer & FRAME_SYNC_MASK) ^ FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) { bool ret = correlateFrameSync();
DEBUG1("DStarRX: found frame sync in None"); if (ret) {
m_countdown = 5U;
::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES); m_headerBuffer[m_headerPtr] = sample;
m_rxBufferBits = 0U; m_headerPtr++;
m_rssiAccum = 0U; m_rssiAccum = 0U;
m_rssiCount = 0U; m_rssiCount = 0U;
m_rxState = DSRXS_HEADER; m_rxState = DSRXS_HEADER;
return; return;
} }
// Exact matching of the data sync bit sequence // Fuzzy matching of the data sync bit sequence
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) { ret = correlateDataSync();
if (ret) {
DEBUG1("DStarRX: found data sync in None"); DEBUG1("DStarRX: found data sync in None");
io.setDecode(true); io.setDecode(true);
io.setADCDetection(true); io.setADCDetection(true);
// Suppress RSSI on the dummy sync message m_rxState = DSRXS_DATA;
m_rssiAccum = 0U;
m_rssiCount = 0U;
::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
writeRSSIData(m_rxBuffer);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
m_dataBits = MAX_SYNC_BITS;
m_rxState = DSRXS_DATA;
return;
} }
} }
void CDStarRX::processHeader(bool bit) void CDStarRX::processHeader(q15_t sample)
{ {
m_patternBuffer <<= 1; if (m_countdown > 0U) {
if (bit) correlateFrameSync();
m_patternBuffer |= 0x01U; m_countdown--;
}
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit); m_headerBuffer[m_headerPtr] = sample;
m_rxBufferBits++; m_headerPtr++;
// A full FEC header // A full FEC header
if (m_rxBufferBits == DSTAR_FEC_SECTION_LENGTH_BITS) { if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) {
// Process the scrambling, interleaving and FEC, then return if the chcksum was correct uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES];
unsigned char header[DSTAR_HEADER_LENGTH_BYTES]; samplesToBits(m_headerBuffer, DSTAR_RADIO_SYMBOL_LENGTH, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES);
bool ok = rxHeader(m_rxBuffer, header);
if (ok) { // Process the scrambling, interleaving and FEC, then return true if the chcksum was correct
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
bool ok = rxHeader(buffer, header);
if (!ok) {
// The checksum failed, return to looking for syncs
m_rxState = DSRXS_NONE;
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
} else {
io.setDecode(true); io.setDecode(true);
io.setADCDetection(true); io.setADCDetection(true);
writeRSSIHeader(header); writeRSSIHeader(header);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
m_rxState = DSRXS_DATA;
m_dataBits = MAX_SYNC_BITS;
} else {
// The checksum failed, return to looking for syncs
m_rxState = DSRXS_NONE;
} }
} }
// Ready to start the first data section
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH)) {
m_frameCount = 0U;
m_dataPtr = 0U;
m_startPtr = 476U;
m_syncPtr = 471U;
m_maxSyncPtr = 472U;
m_minSyncPtr = 470U;
DEBUG5("DStarRX: calc start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
m_rxState = DSRXS_DATA;
}
} }
void CDStarRX::processData(bool bit) void CDStarRX::processData()
{ {
m_patternBuffer <<= 1;
if (bit)
m_patternBuffer |= 0x01U;
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
m_rxBufferBits++;
// Fuzzy matching of the end frame sequences // Fuzzy matching of the end frame sequences
if (countBits32((m_patternBuffer & END_SYNC_MASK) ^ END_SYNC_DATA) <= END_SYNC_ERRS) { if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= END_SYNC_ERRS) {
DEBUG1("DStarRX: Found end sync in Data"); DEBUG1("DStarRX: Found end sync in Data");
io.setDecode(false); io.setDecode(false);
@@ -401,35 +406,24 @@ void CDStarRX::processData(bool bit)
serial.writeDStarEOT(); serial.writeDStarEOT();
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
m_rxState = DSRXS_NONE; m_rxState = DSRXS_NONE;
return; return;
} }
// Fuzzy matching of the data sync bit sequence // Fuzzy matching of the data sync bit sequence
bool syncSeen = false; if (m_minSyncPtr < m_maxSyncPtr) {
if (m_rxBufferBits >= (DSTAR_DATA_LENGTH_BITS - 3U)) { if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) { correlateDataSync();
m_rxBufferBits = DSTAR_DATA_LENGTH_BITS; } else {
m_dataBits = MAX_SYNC_BITS; if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
syncSeen = true; correlateDataSync();
}
} }
// Check to see if the sync is arriving late // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS && !syncSeen) { if (m_frameCount >= MAX_FRAMES) {
for (uint8_t i = 1U; i <= 3U; i++) {
uint32_t syncMask = DATA_SYNC_MASK >> i;
uint32_t syncData = DATA_SYNC_DATA >> i;
if (countBits32((m_patternBuffer & syncMask) ^ syncData) <= DATA_SYNC_ERRS) {
m_rxBufferBits -= i;
break;
}
}
}
m_dataBits--;
if (m_dataBits == 0U) {
DEBUG1("DStarRX: data sync timed out, lost lock"); DEBUG1("DStarRX: data sync timed out, lost lock");
io.setDecode(false); io.setDecode(false);
@@ -437,24 +431,35 @@ void CDStarRX::processData(bool bit)
serial.writeDStarLost(); serial.writeDStarLost();
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
m_rxState = DSRXS_NONE; m_rxState = DSRXS_NONE;
return; return;
} }
// Send a data frame to the host if the required number of bits have been received, or if a data sync has been seen // Send a data frame to the host if the required number of bits have been received
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS) { if (m_dataPtr == m_maxSyncPtr) {
if (syncSeen) { uint8_t buffer[DSTAR_DATA_LENGTH_BYTES + 2U];
m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U]; samplesToBits(m_dataBuffer, m_startPtr, DSTAR_DATA_LENGTH_SYMBOLS, buffer, DSTAR_DATA_LENGTH_SAMPLES);
m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
writeRSSIData(m_rxBuffer);
} else {
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
}
// Start the next frame if ((m_frameCount % 21U) == 0U) {
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); if (m_frameCount == 0U) {
m_rxBufferBits = 0U; buffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
buffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
buffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
DEBUG5("DStarRX: found start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
}
writeRSSIData(buffer);
} else {
serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES);
}
m_frameCount++;
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
} }
} }
@@ -500,6 +505,105 @@ void CDStarRX::writeRSSIData(unsigned char* data)
m_rssiCount = 0U; m_rssiCount = 0U;
} }
bool CDStarRX::correlateFrameSync()
{
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_FRAME_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
q31_t corr = 0;
for (uint8_t i = 0U; i < DSTAR_FRAME_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_dataBuffer[ptr];
if (DSTAR_FRAME_SYNC_SYMBOLS[i])
corr -= val;
else
corr += val;
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
}
if (corr > m_maxFrameCorr) {
m_maxFrameCorr = corr;
m_headerPtr = 0U;
return true;
}
}
return false;
}
bool CDStarRX::correlateDataSync()
{
uint8_t maxErrs = 0U;
if (m_rxState == DSRXS_DATA)
maxErrs = DATA_SYNC_ERRS;
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= maxErrs) {
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
q31_t corr = 0;
for (uint8_t i = 0U; i < DSTAR_DATA_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_dataBuffer[ptr];
if (DSTAR_DATA_SYNC_SYMBOLS[i])
corr -= val;
else
corr += val;
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
}
if (corr > m_maxDataCorr) {
m_maxDataCorr = corr;
m_frameCount = 0U;
m_syncPtr = m_dataPtr;
m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH;
if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
m_minSyncPtr = m_syncPtr + DSTAR_DATA_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
return true;
}
}
return false;
}
void CDStarRX::samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit)
{
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = inBuffer[start];
if (sample < 0)
WRITE_BIT2(outBuffer, i, true);
else
WRITE_BIT2(outBuffer, i, false);
start += DSTAR_RADIO_SYMBOL_LENGTH;
if (start >= limit)
start -= limit;
}
}
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out) bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
{ {
int i; int i;
@@ -715,3 +819,6 @@ bool CDStarRX::checksum(const uint8_t* header) const
return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U]; return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U];
} }
#endif
+27 -11
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(DSTARRX_H) #if !defined(DSTARRX_H)
#define DSTARRX_H #define DSTARRX_H
#include "Config.h"
#include "DStarDefines.h" #include "DStarDefines.h"
enum DSRX_STATE { enum DSRX_STATE {
@@ -37,13 +40,21 @@ public:
void reset(); void reset();
private: private:
uint32_t m_pll;
bool m_prev;
DSRX_STATE m_rxState; DSRX_STATE m_rxState;
uint32_t m_patternBuffer; uint64_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH];
uint8_t m_rxBuffer[100U]; q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH];
unsigned int m_rxBufferBits; q15_t m_dataBuffer[DSTAR_DATA_LENGTH_SAMPLES];
unsigned int m_dataBits; uint16_t m_bitPtr;
uint16_t m_headerPtr;
uint16_t m_dataPtr;
uint16_t m_startPtr;
uint16_t m_syncPtr;
uint16_t m_minSyncPtr;
uint16_t m_maxSyncPtr;
q31_t m_maxFrameCorr;
q31_t m_maxDataCorr;
uint16_t m_frameCount;
uint8_t m_countdown;
unsigned int m_mar; unsigned int m_mar;
int m_pathMetric[4U]; int m_pathMetric[4U];
unsigned int m_pathMemory0[42U]; unsigned int m_pathMemory0[42U];
@@ -54,9 +65,12 @@ private:
uint32_t m_rssiAccum; uint32_t m_rssiAccum;
uint16_t m_rssiCount; uint16_t m_rssiCount;
void processNone(bool bit); void processNone(q15_t sample);
void processHeader(bool bit); void processHeader(q15_t sample);
void processData(bool bit); void processData();
bool correlateFrameSync();
bool correlateDataSync();
void samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit);
void writeRSSIHeader(unsigned char* header); void writeRSSIHeader(unsigned char* header);
void writeRSSIData(unsigned char* data); void writeRSSIData(unsigned char* data);
bool rxHeader(uint8_t* in, uint8_t* out); bool rxHeader(uint8_t* in, uint8_t* out);
@@ -68,3 +82,5 @@ private:
#endif #endif
#endif
+20 -12
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h" #include "Globals.h"
#include "DStarTX.h" #include "DStarTX.h"
@@ -198,7 +201,7 @@ m_txDelay(60U) // 100ms
{ {
::memset(m_modState, 0x00U, 20U * sizeof(q15_t)); ::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
m_modFilter.L = DSTAR_RADIO_BIT_LENGTH; m_modFilter.L = DSTAR_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN; m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER; m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
m_modFilter.pState = m_modState; m_modFilter.pState = m_modState;
@@ -217,11 +220,12 @@ void CDStarTX::process()
m_poBuffer[m_poLen++] = BIT_SYNC; m_poBuffer[m_poLen++] = BIT_SYNC;
} else { } else {
// Pop the type byte off // Pop the type byte off
m_buffer.get(); uint8_t dummy;
m_buffer.get(dummy);
uint8_t header[DSTAR_HEADER_LENGTH_BYTES]; uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++) for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++)
header[i] = m_buffer.get(); m_buffer.get(header[i]);
uint8_t buffer[86U]; uint8_t buffer[86U];
txHeader(header, buffer + 2U); txHeader(header, buffer + 2U);
@@ -239,21 +243,23 @@ void CDStarTX::process()
if (type == DSTAR_DATA && m_poLen == 0U) { if (type == DSTAR_DATA && m_poLen == 0U) {
// Pop the type byte off // Pop the type byte off
m_buffer.get(); uint8_t dummy;
m_buffer.get(dummy);
for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++) for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++)
m_poBuffer[m_poLen++] = m_buffer.get(); m_buffer.get(m_poBuffer[m_poLen++]);
m_poPtr = 0U; m_poPtr = 0U;
} }
if (type == DSTAR_EOT && m_poLen == 0U) { if (type == DSTAR_EOT && m_poLen == 0U) {
// Pop the type byte off // Pop the type byte off
m_buffer.get(); uint8_t dummy;
m_buffer.get(dummy);
for (uint8_t j = 0U; j < 3U; j++) { for (uint8_t j = 0U; j < 3U; j++) {
for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++) for (uint8_t i = 0U; i < DSTAR_END_SYNC_LENGTH_BYTES; i++)
m_poBuffer[m_poLen++] = DSTAR_EOT_BYTES[i]; m_poBuffer[m_poLen++] = DSTAR_END_SYNC_BYTES[i];
} }
m_poPtr = 0U; m_poPtr = 0U;
@@ -262,11 +268,11 @@ void CDStarTX::process()
if (m_poLen > 0U) { if (m_poLen > 0U) {
uint16_t space = io.getSpace(); uint16_t space = io.getSpace();
while (space > (8U * DSTAR_RADIO_BIT_LENGTH)) { while (space > (8U * DSTAR_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++]; uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c); writeByte(c);
space -= 8U * DSTAR_RADIO_BIT_LENGTH; space -= 8U * DSTAR_RADIO_SYMBOL_LENGTH;
if (m_poPtr >= m_poLen) { if (m_poPtr >= m_poLen) {
m_poPtr = 0U; m_poPtr = 0U;
@@ -412,7 +418,7 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const
void CDStarTX::writeByte(uint8_t c) void CDStarTX::writeByte(uint8_t c)
{ {
q15_t inBuffer[8U]; q15_t inBuffer[8U];
q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U]; q15_t outBuffer[DSTAR_RADIO_SYMBOL_LENGTH * 8U];
uint8_t mask = 0x01U; uint8_t mask = 0x01U;
@@ -427,7 +433,7 @@ void CDStarTX::writeByte(uint8_t c)
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U); ::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U); io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_SYMBOL_LENGTH * 8U);
} }
void CDStarTX::setTXDelay(uint8_t delay) void CDStarTX::setTXDelay(uint8_t delay)
@@ -443,3 +449,5 @@ uint8_t CDStarTX::getSpace() const
return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U); return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U);
} }
#endif
+8 -4
View File
@@ -16,12 +16,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(DSTARTX_H) #if !defined(DSTARTX_H)
#define DSTARTX_H #define DSTARTX_H
#include "Config.h" #include "RingBuffer.h"
#include "SerialRB.h"
class CDStarTX { class CDStarTX {
public: public:
@@ -38,7 +40,7 @@ public:
uint8_t getSpace() const; uint8_t getSpace() const;
private: private:
CSerialRB m_buffer; CRingBuffer<uint8_t> m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_interpolate_instance_q15 m_modFilter;
q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare
uint8_t m_poBuffer[600U]; uint8_t m_poBuffer[600U];
@@ -52,3 +54,5 @@ private:
#endif #endif
#endif
+2 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2021 by Jonathan Naylor G4KLX
* *
* 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
@@ -27,6 +27,7 @@
#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c)) #define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c))
#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d)) #define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d))
#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e)) #define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e))
#define DEBUG_DUMP(a,b) serial.writeDebugDump((a),(b))
#endif #endif
+968 -134
View File
File diff suppressed because it is too large Load Diff
+73 -31
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2020 by Jonathan Naylor G4KLX * Copyright (C) 2020,2021,2023,2025 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,39 +16,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FM_H) #if !defined(FM_H)
#define FM_H #define FM_H
#include "Config.h"
#include "FMBlanking.h" #include "FMBlanking.h"
#include "FMCTCSSRX.h" #include "FMCTCSSRX.h"
#include "FMCTCSSTX.h" #include "FMCTCSSTX.h"
#include "FMTimeout.h" #include "FMTimeout.h"
#include "FMKeyer.h" #include "FMKeyer.h"
#include "FMTimer.h" #include "FMTimer.h"
#include "FMRB.h" #include "RingBuffer.h"
#include "FMDirectForm1.h" #include "FMDirectForm1.h"
#include "FMDownsampler.h" #include "FMDownSampler.h"
#include "FMUpSampler.h"
enum FM_STATE { #include "FMNoiseSquelch.h"
FS_LISTENING,
FS_KERCHUNK,
FS_RELAYING,
FS_RELAYING_WAIT,
FS_TIMEOUT,
FS_TIMEOUT_WAIT,
FS_HANG
};
class CFM { class CFM {
public: public:
CFM(); CFM();
void samples(bool cos, const q15_t* samples, uint8_t length); void samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void process(); void process();
@@ -56,15 +48,22 @@ public:
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch); uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level); uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel); uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
uint8_t getSpace() const;
uint8_t writeData(const uint8_t* data, uint16_t length);
private: private:
CFMKeyer m_callsign; CFMKeyer m_callsign;
CFMKeyer m_rfAck; CFMKeyer m_rfAck;
CFMKeyer m_extAck;
CFMCTCSSRX m_ctcssRX; CFMCTCSSRX m_ctcssRX;
CFMCTCSSTX m_ctcssTX; CFMCTCSSTX m_ctcssTX;
CFMNoiseSquelch m_squelch;
CFMTimeout m_timeoutTone; CFMTimeout m_timeoutTone;
FM_STATE m_state; uint8_t m_state;
bool m_callsignAtStart; bool m_callsignAtStart;
bool m_callsignAtEnd; bool m_callsignAtEnd;
bool m_callsignAtLatch; bool m_callsignAtLatch;
@@ -76,26 +75,66 @@ private:
CFMTimer m_ackDelayTimer; CFMTimer m_ackDelayTimer;
CFMTimer m_hangTimer; CFMTimer m_hangTimer;
CFMTimer m_reverseTimer; CFMTimer m_reverseTimer;
CFMTimer m_extGapTimer; // debounce for link-mode ext-audio underrun, see linkStateMachine()
bool m_needReverse;
CFMDirectFormI m_filterStage1; CFMDirectFormI m_filterStage1;
CFMDirectFormI m_filterStage2; CFMDirectFormI m_filterStage2;
CFMDirectFormI m_filterStage3; CFMDirectFormI m_filterStage3;
CFMDirectFormI m_dsFilterStage1; // anti-alias filter for the downsampler, own state
CFMDirectFormI m_dsFilterStage2;
CFMDirectFormI m_dsFilterStage3;
CFMDirectFormI m_usFilterStage1; // reconstruction filter for the upsampler, own state
CFMDirectFormI m_usFilterStage2;
CFMDirectFormI m_usFilterStage3;
CFMBlanking m_blanking; CFMBlanking m_blanking;
uint8_t m_accessMode; uint8_t m_accessMode;
bool m_linkMode;
bool m_cosInvert; bool m_cosInvert;
bool m_noiseSquelch;
q15_t m_rfAudioBoost; q15_t m_rfAudioBoost;
CFMDownsampler m_downsampler; q15_t m_extAudioBoost;
CFMDownSampler m_downSampler;
bool m_extEnabled;
q15_t m_rxLevel; q15_t m_rxLevel;
CFMRB m_inputRB; CRingBuffer<q15_t> m_inputRFRB;
CFMRB m_outputRB; CRingBuffer<q15_t> m_outputRFRB;
CFMUpSampler m_inputExtRB;
bool m_rfSignal;
bool m_extSignal;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void stateMachine(bool validSignal); void stateMachine(bool validRFSignal, bool validExtSignal);
void listeningState(bool validSignal);
void kerchunkState(bool validSignal); void repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void relayingState(bool validSignal); void linkSamples(bool cos, q15_t* samples, uint8_t length);
void relayingWaitState(bool validSignal);
void timeoutState(bool validSignal); void duplexStateMachine(bool validRFSignal, bool validExtSignal);
void timeoutWaitState(bool validSignal); void listeningStateDuplex(bool validRFSignal, bool validExtSignal);
void hangState(bool validSignal); void kerchunkRFStateDuplex(bool validSignal);
void relayingRFStateDuplex(bool validSignal);
void relayingRFWaitStateDuplex(bool validSignal);
void timeoutRFStateDuplex(bool validSignal);
void timeoutRFWaitStateDuplex(bool validSignal);
void kerchunkExtStateDuplex(bool validSignal);
void relayingExtStateDuplex(bool validSignal);
void relayingExtWaitStateDuplex(bool validSignal);
void timeoutExtStateDuplex(bool validSignal);
void timeoutExtWaitStateDuplex(bool validSignal);
void hangStateDuplex(bool validRFSignal, bool validExtSignal);
void simplexStateMachine(bool validRFSignal, bool validExtSignal);
void listeningStateSimplex(bool validRFSignal, bool validExtSignal);
void relayingRFStateSimplex(bool validSignal);
void relayingRFWaitStateSimplex(bool validSignal);
void timeoutRFStateSimplex(bool validSignal);
void timeoutRFWaitStateSimplex(bool validSignal);
void relayingExtStateSimplex(bool validSignal);
void relayingExtWaitStateSimplex(bool validSignal);
void timeoutExtStateSimplex(bool validSignal);
void timeoutExtWaitStateSimplex(bool validSignal);
void linkStateMachine(bool validRFSignal, bool validExtSignal);
void clock(uint8_t length); void clock(uint8_t length);
@@ -107,3 +146,6 @@ private:
}; };
#endif #endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMBlanking.h" #include "FMBlanking.h"
@@ -80,3 +83,6 @@ q15_t CFMBlanking::process(q15_t sample)
return sample; return sample;
} }
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMBlanking_H) #if !defined(FMBlanking_H)
#define FMBlanking_H #define FMBlanking_H
#include "Config.h"
class CFMBlanking { class CFMBlanking {
public: public:
CFMBlanking(); CFMBlanking();
@@ -39,3 +41,6 @@ private:
}; };
#endif #endif
#endif
+16 -16
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMCTCSSRX.h" #include "FMCTCSSRX.h"
@@ -87,7 +90,7 @@ m_lowThreshold(0),
m_count(0U), m_count(0U),
m_q0(0), m_q0(0),
m_q1(0), m_q1(0),
m_result(CTS_NONE) m_state(false)
{ {
} }
@@ -111,13 +114,11 @@ uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t highThreshold, uint8_t
return 0U; return 0U;
} }
uint8_t CFMCTCSSRX::process(q15_t sample) bool CFMCTCSSRX::process(q15_t sample)
{ {
//get more dynamic into the decoder by multiplying the sample by 1.5 //get more dynamic into the decoder by multiplying the sample by 1.5
q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1); q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1);
m_result &= ~CTS_READY;
q31_t q2 = m_q1; q31_t q2 = m_q1;
m_q1 = m_q0; m_q1 = m_q0;
@@ -149,33 +150,32 @@ uint8_t CFMCTCSSRX::process(q15_t sample)
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2 // value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
q31_t value = t2 + t4 - t9; q31_t value = t2 + t4 - t9;
bool previousCTCSSValid = CTCSS_VALID(m_result); bool previousState = m_state;
q31_t threshold = m_highThreshold; q31_t threshold = m_highThreshold;
if (previousCTCSSValid) if (previousState)
threshold = m_lowThreshold; threshold = m_lowThreshold;
m_result |= CTS_READY; m_state = value >= threshold;
if (value >= threshold)
m_result |= CTS_VALID;
else
m_result &= ~CTS_VALID;
if (previousCTCSSValid != CTCSS_VALID(m_result)) if (previousState != m_state)
DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, CTCSS_VALID(m_result)); DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, m_state);
m_count = 0U; m_count = 0U;
m_q0 = 0; m_q0 = 0;
m_q1 = 0; m_q1 = 0;
} }
return m_result; return m_state;
} }
void CFMCTCSSRX::reset() void CFMCTCSSRX::reset()
{ {
m_q0 = 0; m_q0 = 0;
m_q1 = 0; m_q1 = 0;
m_result = CTS_NONE; m_state = false;
m_count = 0U; m_count = 0U;
} }
#endif
+8 -12
View File
@@ -16,19 +16,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(FMCTCSSRX_H)
#define FMCTCSSRX_H
#include "Config.h" #include "Config.h"
const uint8_t CTS_NONE = 0U; #if defined(MODE_FM)
const uint8_t CTS_READY = 1U;
const uint8_t CTS_VALID = 2U;
#define CTCSS_READY(a) ((a & CTS_READY) != 0) #if !defined(FMCTCSSRX_H)
#define CTCSS_NOT_READY(a) ((a & CTS_READY) == 0) #define FMCTCSSRX_H
#define CTCSS_VALID(a) ((a & CTS_VALID) != 0)
#define CTCSS_NOT_VALID(a) ((a & CTS_VALID) == 0)
class CFMCTCSSRX { class CFMCTCSSRX {
public: public:
@@ -36,7 +29,7 @@ public:
uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold); uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold);
uint8_t process(q15_t sample); bool process(q15_t sample);
void reset(); void reset();
@@ -47,7 +40,10 @@ private:
uint16_t m_count; uint16_t m_count;
q31_t m_q0; q31_t m_q0;
q31_t m_q1; q31_t m_q1;
uint8_t m_result; bool m_state;
}; };
#endif #endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMCTCSSTX.h" #include "FMCTCSSTX.h"
@@ -126,3 +129,6 @@ q15_t CFMCTCSSTX::getAudio(bool reverse)
else else
return sample; return sample;
} }
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMCTCSSTX_H) #if !defined(FMCTCSSTX_H)
#define FMCTCSSTX_H #define FMCTCSSTX_H
#include "Config.h"
class CFMCTCSSTX { class CFMCTCSSTX {
public: public:
CFMCTCSSTX(); CFMCTCSSTX();
@@ -36,3 +38,6 @@ private:
}; };
#endif #endif
#endif
+15 -13
View File
@@ -29,7 +29,11 @@ THE SOFTWARE.
// based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h // based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h
#include "Globals.h" #include "Config.h"
#if defined(MODE_FM)
#include <cstdint>
#ifndef DIRECTFORMI_H_ #ifndef DIRECTFORMI_H_
#define DIRECTFORMI_H_ #define DIRECTFORMI_H_
@@ -38,8 +42,7 @@ class CFMDirectFormI
public: public:
// convenience function which takes the a0 argument but ignores it! // convenience function which takes the a0 argument but ignores it!
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2, CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2, const q31_t, const q31_t a1, const q31_t a2)
const q31_t, const q31_t a1, const q31_t a2)
{ {
// FIR coefficients // FIR coefficients
c_b0 = b0; c_b0 = b0;
@@ -53,21 +56,21 @@ public:
CFMDirectFormI(const CFMDirectFormI &my) CFMDirectFormI(const CFMDirectFormI &my)
{ {
// delay line // delay line
m_x2 = my.m_x2; // x[n-2] m_x2 = my.m_x2; // x[n-2]
m_y2 = my.m_y2; // y[n-2] m_y2 = my.m_y2; // y[n-2]
m_x1 = my.m_x1; // x[n-1] m_x1 = my.m_x1; // x[n-1]
m_y1 = my.m_y1; // y[n-1] m_y1 = my.m_y1; // y[n-1]
// coefficients // coefficients
c_b0 = my.c_b0; c_b0 = my.c_b0;
c_b1 = my.c_b1; c_b1 = my.c_b1;
c_b2 = my.c_b2; // FIR c_b2 = my.c_b2; // FIR
c_a1 = my.c_a1; c_a1 = my.c_a1;
c_a2 = my.c_a2; // IIR c_a2 = my.c_a2; // IIR
} }
void reset () void reset()
{ {
m_x1 = 0; m_x1 = 0;
m_x2 = 0; m_x2 = 0;
@@ -79,11 +82,7 @@ public:
inline q15_t filter(const q15_t in) inline q15_t filter(const q15_t in)
{ {
// calculate the output // calculate the output
register q31_t out_upscaled = c_b0 * in q31_t out_upscaled = c_b0 * in + c_b1 * m_x1 + c_b2 * m_x2 - c_a1 * m_y1 - c_a2 * m_y2;
+ c_b1 * m_x1
+ c_b2 * m_x2
- c_a1 * m_y1
- c_a2 * m_y2;
q15_t out = __SSAT(out_upscaled >> 15, 15); q15_t out = __SSAT(out_upscaled >> 15, 15);
@@ -108,4 +107,7 @@ private:
q31_t c_a1,c_a2; // IIR q31_t c_a1,c_a2; // IIR
}; };
#endif /* DIRECTFORMI_H */ #endif /* DIRECTFORMI_H */
#endif
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#include "FMDownSampler.h"
CFMDownSampler::CFMDownSampler(uint16_t length) :
m_ringBuffer(length),
m_samplePack(0U),
m_samplePackPointer(NULL),
m_sampleIndex(0U)
{
m_samplePackPointer = (uint8_t*)&m_samplePack;
}
void CFMDownSampler::addSample(q15_t sample)
{
sample = __SSAT(sample, 12);//clamp before packing to 12 bits
uint32_t usample = uint32_t(int32_t(sample) + 2048);
//only take one of three samples
switch(m_sampleIndex){
case 0:
m_samplePack = usample << 12;
break;
case 3:{
m_samplePack |= usample;
//we did not use MSB; skip it
TSamplePairPack pair{m_samplePackPointer[0U], m_samplePackPointer[1U], m_samplePackPointer[2U]};
m_ringBuffer.put(pair);
m_samplePack = 0U;//reset the sample pack
}
break;
default:
//Just skip this sample
break;
}
m_sampleIndex++;
if (m_sampleIndex >= 6U)//did we pack two samples ?
m_sampleIndex = 0U;
}
bool CFMDownSampler::getPackedData(TSamplePairPack& data)
{
return m_ringBuffer.get(data);
}
uint16_t CFMDownSampler::getData()
{
return m_ringBuffer.getData();
}
void CFMDownSampler::reset()
{
m_sampleIndex = 0U;
m_samplePack = 0U;
m_ringBuffer.reset();
}
#endif
+22 -13
View File
@@ -17,27 +17,36 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMDOWNSAMPLER_H) #if !defined(FMDOWNSAMPLER_H)
#define FMDOWNSAMPLER_H #define FMDOWNSAMPLER_H
#include "Config.h" #include "RingBuffer.h"
#include "FMDownsampleRB.h" #include "FMSamplePairPack.h"
class CFMDownsampler { class CFMDownSampler {
public: public:
CFMDownsampler(uint16_t length); CFMDownSampler(uint16_t length);
void addSample(q15_t sample); void addSample(q15_t sample);
inline bool getPackedData(uint8_t& data){ return m_ringBuffer.get(data); };
inline bool hasOverflowed() { return m_ringBuffer.hasOverflowed(); }; bool getPackedData(TSamplePairPack& data);
uint16_t getData();
void reset();
private: private:
CFMDownsampleRB m_ringBuffer; CRingBuffer<TSamplePairPack> m_ringBuffer;
union { uint32_t m_samplePack;
int32_t m_samplePack; uint8_t* m_samplePackPointer;
int8_t m_samplePackBytes[4]; uint8_t m_sampleIndex;
};
uint8_t m_packIndex;
uint8_t m_downSampleIndex;
}; };
#endif #endif
#endif
-63
View File
@@ -1,63 +0,0 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "FMDownsampler.h"
CFMDownsampler::CFMDownsampler(uint16_t length) :
m_ringBuffer(length),//length might need tweaking
m_packIndex(0),
m_downSampleIndex(0)
{
m_samplePack = 0;
}
void CFMDownsampler::addSample(q15_t sample)
{
//only take one of three samples
if(m_downSampleIndex == 0) {
switch(m_packIndex){
case 0:
m_samplePack = int32_t(sample) << 12;
break;
case 1:{
m_samplePack |= int32_t(sample);
//we did not use MSB; skip it
m_ringBuffer.put(m_samplePackBytes[1]);
m_ringBuffer.put(m_samplePackBytes[2]);
m_ringBuffer.put(m_samplePackBytes[3]);
m_samplePack = 0;
}
break;
default:
//should never happen
break;
}
m_packIndex++;
if(m_packIndex >= 2)
m_packIndex = 0;
}
m_downSampleIndex++;
if(m_downSampleIndex >= 3)
m_downSampleIndex = 0;
}
+6
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMKeyer.h" #include "FMKeyer.h"
@@ -214,3 +217,6 @@ bool CFMKeyer::isRunning() const
{ {
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U; return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
} }
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMKeyer_H) #if !defined(FMKeyer_H)
#define FMKeyer_H #define FMKeyer_H
#include "Config.h"
class CFMKeyer { class CFMKeyer {
public: public:
CFMKeyer(); CFMKeyer();
@@ -52,3 +54,6 @@ private:
}; };
#endif #endif
#endif
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMNoiseSquelch.h"
// 4500Hz centre frequency
const q31_t COEFF_DIV_TWO = 821806413;
// 400Hz bandwidth
const uint16_t N = 24000U / 400U;
CFMNoiseSquelch::CFMNoiseSquelch() :
m_highThreshold(0),
m_lowThreshold(0),
m_count(0U),
m_q0(0),
m_q1(0),
m_state(false),
m_validCount(0U),
m_invalidCount(0U)
{
}
void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold)
{
m_highThreshold = q31_t(highThreshold);
m_lowThreshold = q31_t(lowThreshold);
}
bool CFMNoiseSquelch::process(q15_t sample)
{
//get more dynamic into the decoder by multiplying the sample by 64
q31_t sample31 = q31_t(sample) << 6; //+ (q31_t(sample) >> 1);
q31_t q2 = m_q1;
m_q1 = m_q0;
// Q31 multiplication, t3 = m_coeffDivTwo * 2 * m_q1
q63_t t1 = COEFF_DIV_TWO * m_q1;
q31_t t2 = __SSAT((t1 >> 31), 31);
q31_t t3 = t2 * 2;
// m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample
m_q0 = t3 - q2 + sample31;
m_count++;
if (m_count == N) {
// Q31 multiplication, t2 = m_q0 * m_q0
q63_t t1 = q63_t(m_q0) * q63_t(m_q0);
q31_t t2 = __SSAT((t1 >> 31), 31);
// Q31 multiplication, t4 = m_q0 * m_q0
q63_t t3 = q63_t(m_q1) * q63_t(m_q1);
q31_t t4 = __SSAT((t3 >> 31), 31);
// Q31 multiplication, t9 = m_q0 * m_q1 * m_coeffDivTwo * 2
q63_t t5 = q63_t(m_q0) * q63_t(m_q1);
q31_t t6 = __SSAT((t5 >> 31), 31);
q63_t t7 = t6 * COEFF_DIV_TWO;
q31_t t8 = __SSAT((t7 >> 31), 31);
q31_t t9 = t8 * 2;
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
q31_t value = t2 + t4 - t9;
bool previousState = m_state;
q31_t threshold = m_highThreshold;
if (previousState)
threshold = m_lowThreshold;
if (!m_state) {
if (value < threshold)
m_validCount++;
else
m_validCount = 0U;
}
if (m_state) {
if (value >= threshold)
m_invalidCount++;
else
m_invalidCount = 0U;
}
m_state = m_validCount >= 10U && m_invalidCount < 10U;
if(previousState && !m_state)
m_invalidCount = 0U;
if (previousState != m_state) {
DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, m_state);
DEBUG3("Valid Count / Invalid Count", m_validCount, m_invalidCount);
}
m_count = 0U;
m_q0 = 0;
m_q1 = 0;
}
return m_state;
}
void CFMNoiseSquelch::reset()
{
m_q0 = 0;
m_q1 = 0;
m_state = false;
m_count = 0U;
m_validCount = 0U;
m_invalidCount = 0U;
}
#endif
+21 -14
View File
@@ -16,28 +16,35 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(AX25Frame_H)
#define AX25Frame_H
#include "Config.h" #include "Config.h"
const uint16_t AX25_MAX_PACKET_LEN = 300U; #if defined(MODE_FM)
class CAX25Frame { #if !defined(FMNOISESQUELCH_H)
#define FMNOISESQUELCH_H
class CFMNoiseSquelch {
public: public:
CAX25Frame(const uint8_t* data, uint16_t length); CFMNoiseSquelch();
CAX25Frame();
bool append(uint16_t c); void setParams(uint8_t highThreshold, uint8_t lowThreshold);
bool process(q15_t sample);
bool checkCRC(); void reset();
void addCRC(); private:
q31_t m_highThreshold;
uint8_t m_data[AX25_MAX_PACKET_LEN]; q31_t m_lowThreshold;
uint16_t m_length; uint16_t m_count;
uint16_t m_fcs; q31_t m_q0;
q31_t m_q1;
bool m_state;
uint8_t m_validCount;
uint8_t m_invalidCount;
}; };
#endif #endif
#endif
-110
View File
@@ -1,110 +0,0 @@
/*
TX fifo control - Copyright (C) KI6ZUM 2015
Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "FMRB.h"
CFMRB::CFMRB(uint16_t length) :
m_length(length),
m_head(0U),
m_tail(0U),
m_full(false),
m_overflow(false)
{
m_samples = new q15_t[length];
}
uint16_t CFMRB::getSpace() const
{
uint16_t n = 0U;
if (m_tail == m_head)
n = m_full ? 0U : m_length;
else if (m_tail < m_head)
n = m_length - m_head + m_tail;
else
n = m_tail - m_head;
if (n > m_length)
n = 0U;
return n;
}
uint16_t CFMRB::getData() const
{
if (m_tail == m_head)
return m_full ? m_length : 0U;
else if (m_tail < m_head)
return m_head - m_tail;
else
return m_length - m_tail + m_head;
}
bool CFMRB::put(q15_t sample)
{
if (m_full) {
m_overflow = true;
return false;
}
m_samples[m_head] = sample;
m_head++;
if (m_head >= m_length)
m_head = 0U;
if (m_head == m_tail)
m_full = true;
return true;
}
bool CFMRB::get(q15_t& sample)
{
if (m_head == m_tail && !m_full)
return false;
sample = m_samples[m_tail];
m_full = false;
m_tail++;
if (m_tail >= m_length)
m_tail = 0U;
return true;
}
bool CFMRB::hasOverflowed()
{
bool overflow = m_overflow;
m_overflow = false;
return overflow;
}
void CFMRB::reset()
{
m_head = 0U;
m_tail = 0U;
m_full = false;
m_overflow = false;
}
-72
View File
@@ -1,72 +0,0 @@
/*
Serial fifo control - Copyright (C) KI6ZUM 2015
Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#if !defined(FMRB_H)
#define FMRB_H
#if defined(STM32F4XX)
#include "stm32f4xx.h"
#elif defined(STM32F7XX)
#include "stm32f7xx.h"
#elif defined(STM32F105xC)
#include "stm32f1xx.h"
#include <cstddef>
#else
#include <Arduino.h>
#endif
#if defined(__SAM3X8E__) || defined(STM32F105xC)
#define ARM_MATH_CM3
#elif defined(STM32F7XX)
#define ARM_MATH_CM7
#elif defined(STM32F4XX) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define ARM_MATH_CM4
#else
#error "Unknown processor type"
#endif
#include <arm_math.h>
class CFMRB {
public:
CFMRB(uint16_t length);
uint16_t getSpace() const;
uint16_t getData() const;
bool put(q15_t sample);
bool get(q15_t& sample);
bool hasOverflowed();
void reset();
private:
uint16_t m_length;
volatile q15_t* m_samples;
volatile uint16_t m_head;
volatile uint16_t m_tail;
volatile bool m_full;
bool m_overflow;
};
#endif
+10 -13
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2020 by Jonathan Naylor G4KLX * Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
* *
* 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
@@ -16,24 +17,20 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(AX25Twist_H)
#define AX25Twist_H
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
class CAX25Twist { #if !defined(TSAMPLEPACK_H)
public: #define TSAMPLEPACK_H
CAX25Twist(int8_t n);
void process(q15_t* in, q15_t* out, uint8_t length); struct TSamplePairPack {
uint8_t byte0;
void setTwist(int8_t n); uint8_t byte1;
uint8_t byte2;
private:
arm_fir_instance_q15 m_filter;
q15_t m_state[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare
}; };
#endif #endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMTimeout.h" #include "FMTimeout.h"
@@ -72,3 +75,6 @@ void CFMTimeout::stop()
{ {
m_running = false; m_running = false;
} }
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMTimeout_H) #if !defined(FMTimeout_H)
#define FMTimeout_H #define FMTimeout_H
#include "Config.h"
class CFMTimeout { class CFMTimeout {
public: public:
CFMTimeout(); CFMTimeout();
@@ -40,3 +42,6 @@ private:
}; };
#endif #endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_FM)
#include "Globals.h" #include "Globals.h"
#include "FMTimer.h" #include "FMTimer.h"
@@ -68,3 +71,6 @@ bool CFMTimer::hasExpired() const
return false; return false;
} }
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMTimer_H) #if !defined(FMTimer_H)
#define FMTimer_H #define FMTimer_H
#include "Config.h"
class CFMTimer { class CFMTimer {
public: public:
CFMTimer(); CFMTimer();
@@ -45,3 +47,6 @@ private:
}; };
#endif #endif
#endif
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#include "FMUpSampler.h"
const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU;
CFMUpSampler::CFMUpSampler() :
m_upSampleIndex(0),
m_pack(0U),
m_packPointer(NULL),
m_samples(3600U), //300ms of 12 bit 8kHz audio
m_running(false)
{
m_packPointer = (uint8_t*)&m_pack;
}
void CFMUpSampler::reset()
{
m_upSampleIndex = 0U;
m_pack = 0U;
m_samples.reset();
m_running = false;
}
void CFMUpSampler::addData(const uint8_t* data, uint16_t length)
{
TSamplePairPack* packPointer = (TSamplePairPack*)data;
TSamplePairPack* packPointerEnd = packPointer + (length / 3U);
while(packPointer != packPointerEnd) {
m_samples.put(*packPointer);
packPointer++;
}
if(!m_running)
m_running = m_samples.getData() > 300U;//75ms of audio
}
bool CFMUpSampler::getSample(q15_t& sample)
{
if(!m_running)
return false;
switch (m_upSampleIndex)
{
case 0: {
TSamplePairPack pairPack;
if(!m_samples.get(pairPack)) {
m_running = false;
return false;
}
m_pack = 0U;
m_packPointer = (uint8_t*)&m_pack;
m_packPointer[0U] = pairPack.byte0;
m_packPointer[1U] = pairPack.byte1;
m_packPointer[2U] = pairPack.byte2;
sample = q15_t(m_pack >> 12) - 2048;
break;
}
case 3:
sample = q15_t(m_pack & FM_UPSAMPLE_MASK) - 2048;
break;
default:
sample = 0;
break;
}
m_upSampleIndex++;
if(m_upSampleIndex >= 6U)
m_upSampleIndex = 0U;
return true;
}
uint16_t CFMUpSampler::getSpace() const
{
//return available space in bytes
return m_samples.getSpace() * sizeof(TSamplePairPack);
}
#endif
+21 -21
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2020 by Jonathan Naylor G4KLX * Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
* *
* 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
@@ -16,39 +17,38 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(AX25TX_H)
#define AX25TX_H
#include "Config.h" #include "Config.h"
#include "AX25Twist.h" #if defined(MODE_FM)
class CAX25TX { #if !defined(FMUPSAMPLER_H)
#define FMUPSAMPLER_H
#include "RingBuffer.h"
#include "FMSamplePairPack.h"
class CFMUpSampler {
public: public:
CAX25TX(); CFMUpSampler();
uint8_t writeData(const uint8_t* data, uint16_t length); void reset();
void process(); void addData(const uint8_t* data, uint16_t length);
void setParams(int8_t twist); bool getSample(q15_t& sample);
void setTXDelay(uint8_t delay); uint16_t getSpace() const;
uint8_t getSpace() const;
private: private:
CAX25Twist m_twist; uint8_t m_upSampleIndex;
uint8_t m_poBuffer[600U]; uint32_t m_pack;
uint16_t m_poLen; uint8_t * m_packPointer;
uint16_t m_poPtr; CRingBuffer<TSamplePairPack> m_samples;
uint16_t m_txDelay; bool m_running;
uint16_t m_tablePtr;
bool m_nrzi;
void writeBit(bool b);
bool NRZI(bool b);
}; };
#endif #endif
#endif
+32 -22
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2025 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,14 +23,12 @@
#include "stm32f4xx.h" #include "stm32f4xx.h"
#elif defined(STM32F7XX) #elif defined(STM32F7XX)
#include "stm32f7xx.h" #include "stm32f7xx.h"
#elif defined(STM32F105xC)
#include "stm32f1xx.h"
#include "STM32Utils.h"
#else #else
#include <Arduino.h> #include <Arduino.h>
#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h.
#endif #endif
#if defined(__SAM3X8E__) || defined(STM32F105xC) #if defined(__SAM3X8E__)
#define ARM_MATH_CM3 #define ARM_MATH_CM3
#elif defined(STM32F7XX) #elif defined(STM32F7XX)
#define ARM_MATH_CM7 #define ARM_MATH_CM7
@@ -51,7 +49,6 @@ enum MMDVM_STATE {
STATE_NXDN = 5, STATE_NXDN = 5,
STATE_POCSAG = 6, STATE_POCSAG = 6,
STATE_FM = 10, STATE_FM = 10,
STATE_AX25 = 11,
// Dummy states start at 90 // Dummy states start at 90
STATE_NXDNCAL1K = 91, STATE_NXDNCAL1K = 91,
@@ -97,8 +94,6 @@ enum MMDVM_STATE {
#include "CalPOCSAG.h" #include "CalPOCSAG.h"
#include "CalRSSI.h" #include "CalRSSI.h"
#include "CWIdTX.h" #include "CWIdTX.h"
#include "AX25RX.h"
#include "AX25TX.h"
#include "Debug.h" #include "Debug.h"
#include "IO.h" #include "IO.h"
#include "FM.h" #include "FM.h"
@@ -112,7 +107,7 @@ const uint16_t RX_BLOCK_SIZE = 2U;
const uint16_t TX_RINGBUFFER_SIZE = 500U; const uint16_t TX_RINGBUFFER_SIZE = 500U;
const uint16_t RX_RINGBUFFER_SIZE = 600U; const uint16_t RX_RINGBUFFER_SIZE = 600U;
#if defined(STM32F105xC) || defined(__MK20DX256__) #if defined(__MK20DX256__)
const uint16_t TX_BUFFER_LEN = 2000U; const uint16_t TX_BUFFER_LEN = 2000U;
#else #else
const uint16_t TX_BUFFER_LEN = 4000U; const uint16_t TX_BUFFER_LEN = 4000U;
@@ -127,7 +122,6 @@ extern bool m_p25Enable;
extern bool m_nxdnEnable; extern bool m_nxdnEnable;
extern bool m_pocsagEnable; extern bool m_pocsagEnable;
extern bool m_fmEnable; extern bool m_fmEnable;
extern bool m_ax25Enable;
extern bool m_duplex; extern bool m_duplex;
@@ -137,9 +131,15 @@ extern bool m_dcd;
extern CSerialPort serial; extern CSerialPort serial;
extern CIO io; extern CIO io;
#if defined(MODE_DSTAR)
extern CDStarRX dstarRX; extern CDStarRX dstarRX;
extern CDStarTX dstarTX; extern CDStarTX dstarTX;
extern CCalDStarRX calDStarRX;
extern CCalDStarTX calDStarTX;
#endif
#if defined(MODE_DMR)
extern CDMRIdleRX dmrIdleRX; extern CDMRIdleRX dmrIdleRX;
extern CDMRRX dmrRX; extern CDMRRX dmrRX;
extern CDMRTX dmrTX; extern CDMRTX dmrTX;
@@ -147,29 +147,39 @@ extern CDMRTX dmrTX;
extern CDMRDMORX dmrDMORX; extern CDMRDMORX dmrDMORX;
extern CDMRDMOTX dmrDMOTX; extern CDMRDMOTX dmrDMOTX;
extern CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
extern CYSFRX ysfRX; extern CYSFRX ysfRX;
extern CYSFTX ysfTX; extern CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
extern CP25RX p25RX; extern CP25RX p25RX;
extern CP25TX p25TX; extern CP25TX p25TX;
extern CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
extern CNXDNRX nxdnRX; extern CNXDNRX nxdnRX;
extern CNXDNTX nxdnTX; extern CNXDNTX nxdnTX;
extern CPOCSAGTX pocsagTX; extern CCalNXDN calNXDN;
#endif
extern CFM fm; #if defined(MODE_POCSAG)
extern CAX25RX ax25RX; extern CPOCSAGTX pocsagTX;
extern CAX25TX ax25TX; extern CCalPOCSAG calPOCSAG;
#endif
extern CCalDStarRX calDStarRX; #if defined(MODE_FM)
extern CCalDStarTX calDStarTX; extern CFM fm;
extern CCalDMR calDMR; extern CCalFM calFM;
extern CCalFM calFM; #endif
extern CCalP25 calP25;
extern CCalNXDN calNXDN; extern CCalRSSI calRSSI;
extern CCalPOCSAG calPOCSAG;
extern CCalRSSI calRSSI;
extern CCWIdTX cwIdTX; extern CCWIdTX cwIdTX;
+233 -94
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2023,2025,2026 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM * Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@@ -22,16 +22,26 @@
#include "Globals.h" #include "Globals.h"
#include "IO.h" #include "IO.h"
#if defined(USE_DCBLOCKER)
// Generated using [b, a] = butter(1, 0.001) in MATLAB // Generated using [b, a] = butter(1, 0.001) in MATLAB
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2} static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
#endif
#if defined(MODE_DMR) || defined(MODE_YSF)
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB // Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995, static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112, 11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
-553, -847, -731, -340, 104, 401, 0}; -553, -847, -731, -340, 104, 401, 0};
const uint16_t RRC_0_2_FILTER_LEN = 42U; const uint16_t RRC_0_2_FILTER_LEN = 42U;
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
// One symbol boxcar filter
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
const uint16_t BOXCAR10_FILTER_LEN = 10U;
#else
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB // Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819, static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184, 483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
@@ -43,14 +53,20 @@ const uint16_t NXDN_0_2_FILTER_LEN = 82U;
static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394, static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394,
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790}; 12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
const uint16_t NXDN_ISINC_FILTER_LEN = 32U; const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
#endif
#endif
#if defined(MODE_DSTAR)
// Generated using gaussfir(0.5, 4, 5) in MATLAB // Generated using gaussfir(0.5, 4, 5) in MATLAB
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0}; static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U; const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
#endif
#if defined(MODE_P25)
// One symbol boxcar filter // One symbol boxcar filter
static q15_t BOXCAR_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0}; static q15_t BOXCAR5_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
const uint16_t BOXCAR_FILTER_LEN = 6U; const uint16_t BOXCAR5_FILTER_LEN = 6U;
#endif
const uint16_t DC_OFFSET = 2048U; const uint16_t DC_OFFSET = 2048U;
@@ -59,18 +75,37 @@ m_started(false),
m_rxBuffer(RX_RINGBUFFER_SIZE), m_rxBuffer(RX_RINGBUFFER_SIZE),
m_txBuffer(TX_RINGBUFFER_SIZE), m_txBuffer(TX_RINGBUFFER_SIZE),
m_rssiBuffer(RX_RINGBUFFER_SIZE), m_rssiBuffer(RX_RINGBUFFER_SIZE),
#if defined(USE_DCBLOCKER)
m_dcFilter(), m_dcFilter(),
m_dcState(), m_dcState(),
m_rrcFilter(), #endif
#if defined(MODE_DSTAR)
m_gaussianFilter(), m_gaussianFilter(),
m_boxcarFilter(), m_gaussianState(),
#endif
#if defined(MODE_DMR)
m_rrc02Filter1(),
m_rrc02State1(),
#endif
#if defined(MODE_YSF)
m_rrc02Filter2(),
m_rrc02State2(),
#endif
#if defined(MODE_P25)
m_boxcar5Filter(),
m_boxcar5State(),
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
m_boxcar10Filter(),
m_boxcar10State(),
#else
m_nxdnFilter(), m_nxdnFilter(),
m_nxdnISincFilter(), m_nxdnISincFilter(),
m_rrcState(),
m_gaussianState(),
m_boxcarState(),
m_nxdnState(), m_nxdnState(),
m_nxdnISincState(), m_nxdnISincState(),
#endif
#endif
m_pttInvert(false), m_pttInvert(false),
m_rxLevel(128 * 128), m_rxLevel(128 * 128),
m_cwIdTXLevel(128 * 128), m_cwIdTXLevel(128 * 128),
@@ -81,7 +116,6 @@ m_p25TXLevel(128 * 128),
m_nxdnTXLevel(128 * 128), m_nxdnTXLevel(128 * 128),
m_pocsagTXLevel(128 * 128), m_pocsagTXLevel(128 * 128),
m_fmTXLevel(128 * 128), m_fmTXLevel(128 * 128),
m_ax25TXLevel(128 * 128),
m_rxDCOffset(DC_OFFSET), m_rxDCOffset(DC_OFFSET),
m_txDCOffset(DC_OFFSET), m_txDCOffset(DC_OFFSET),
m_useCOSAsLockout(false), m_useCOSAsLockout(false),
@@ -93,30 +127,52 @@ m_dacOverflow(0U),
m_watchdog(0U), m_watchdog(0U),
m_lockout(false) m_lockout(false)
{ {
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t)); #if defined(USE_DCBLOCKER)
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t)); ::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
m_dcFilter.numStages = DC_FILTER_STAGES; m_dcFilter.numStages = DC_FILTER_STAGES;
m_dcFilter.pState = m_dcState; m_dcFilter.pState = m_dcState;
m_dcFilter.pCoeffs = DC_FILTER; m_dcFilter.pCoeffs = DC_FILTER;
m_dcFilter.postShift = 0; m_dcFilter.postShift = 0;
#endif
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN; #if defined(MODE_DSTAR)
m_rrcFilter.pState = m_rrcState; ::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN; m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
m_gaussianFilter.pState = m_gaussianState; m_gaussianFilter.pState = m_gaussianState;
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER; m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
#endif
#if defined(MODE_DMR)
::memset(m_rrc02State1, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter1.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter1.pState = m_rrc02State1;
m_rrc02Filter1.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_YSF)
::memset(m_rrc02State2, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter2.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter2.pState = m_rrc02State2;
m_rrc02Filter2.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_P25)
::memset(m_boxcar5State, 0x00U, 30U * sizeof(q15_t));
m_boxcar5Filter.numTaps = BOXCAR5_FILTER_LEN;
m_boxcar5Filter.pState = m_boxcar5State;
m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER;
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t));
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
m_boxcar10Filter.pState = m_boxcar10State;
m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER;
#else
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
m_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
m_boxcarFilter.pState = m_boxcarState;
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN; m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN;
m_nxdnFilter.pState = m_nxdnState; m_nxdnFilter.pState = m_nxdnState;
m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER; m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER;
@@ -124,6 +180,8 @@ m_lockout(false)
m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN; m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN;
m_nxdnISincFilter.pState = m_nxdnISincState; m_nxdnISincFilter.pState = m_nxdnISincState;
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER; m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
#endif
#endif
initInt(); initInt();
@@ -134,7 +192,7 @@ void CIO::selfTest()
{ {
bool ledValue = false; bool ledValue = false;
for (uint8_t i = 0; i < 6; i++) { for (uint8_t i = 0U; i < 6U; i++) {
ledValue = !ledValue; ledValue = !ledValue;
// We exclude PTT to avoid trigger the transmitter // We exclude PTT to avoid trigger the transmitter
@@ -145,21 +203,34 @@ void CIO::selfTest()
setDMRInt(ledValue); setDMRInt(ledValue);
setYSFInt(ledValue); setYSFInt(ledValue);
setP25Int(ledValue); setP25Int(ledValue);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDNInt(ledValue); setNXDNInt(ledValue);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAGInt(ledValue); setPOCSAGInt(ledValue);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
setFMInt(ledValue); setFMInt(ledValue);
#endif
#endif #endif
delayInt(250); delayInt(250);
} }
#if defined(MODE_LEDS) #if defined(MODE_LEDS)
setDStarInt(true); setDStarInt(false);
setDMRInt(false); setDMRInt(false);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDNInt(false); setNXDNInt(false);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAGInt(false); setPOCSAGInt(false);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
setFMInt(false); setFMInt(false);
#endif
setDStarInt(true);
delayInt(250); delayInt(250);
setDMRInt(true); setDMRInt(true);
@@ -221,7 +292,7 @@ void CIO::start()
m_started = true; m_started = true;
setMode(); setMode(STATE_IDLE);
} }
void CIO::process() void CIO::process()
@@ -231,10 +302,11 @@ void CIO::process()
// Two seconds timeout // Two seconds timeout
if (m_watchdog >= 48000U) { if (m_watchdog >= 48000U) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) { if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) {
#if defined(MODE_DMR)
if (m_modemState == STATE_DMR && m_tx) if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false); dmrTX.setStart(false);
m_modemState = STATE_IDLE; #endif
setMode(); setMode(STATE_IDLE);
} }
m_watchdog = 0U; m_watchdog = 0U;
@@ -265,6 +337,7 @@ void CIO::process()
if (m_txBuffer.getData() == 0U && m_tx) { if (m_txBuffer.getData() == 0U && m_tx) {
m_tx = false; m_tx = false;
setPTTInt(m_pttInvert ? true : false); setPTTInt(m_pttInvert ? true : false);
DEBUG1("TX OFF");
} }
if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) { if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) {
@@ -273,15 +346,16 @@ void CIO::process()
uint16_t rssi[RX_BLOCK_SIZE]; uint16_t rssi[RX_BLOCK_SIZE];
for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) { for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) {
uint16_t sample; TSample sample;
m_rxBuffer.get(sample, control[i]); m_rxBuffer.get(sample);
control[i] = sample.control;
m_rssiBuffer.get(rssi[i]); m_rssiBuffer.get(rssi[i]);
// Detect ADC overflow // Detect ADC overflow
if (m_detect && (sample == 0U || sample == 4095U)) if (m_detect && (sample.sample == 0U || sample.sample == 4095U))
m_adcOverflow++; m_adcOverflow++;
q15_t res1 = q15_t(sample) - m_rxDCOffset; q15_t res1 = q15_t(sample.sample) - m_rxDCOffset;
q31_t res2 = res1 * m_rxLevel; q31_t res2 = res1 * m_rxLevel;
samples[i] = q15_t(__SSAT((res2 >> 15), 16)); samples[i] = q15_t(__SSAT((res2 >> 15), 16));
} }
@@ -309,6 +383,7 @@ void CIO::process()
#endif #endif
if (m_modemState == STATE_IDLE) { if (m_modemState == STATE_IDLE) {
#if defined(MODE_DSTAR)
if (m_dstarEnable) { if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE]; q15_t GMSKVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
@@ -318,62 +393,80 @@ void CIO::process()
#endif #endif
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE); dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
} }
#endif
#if defined(MODE_P25)
if (m_p25Enable) { if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE]; q15_t P25Vals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
#else #else
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
#endif #endif
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
} }
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable) { if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
#if defined(USE_NXDN_BOXCAR)
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
#endif
#else
q15_t NXDNValsTmp[RX_BLOCK_SIZE]; q15_t NXDNValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
#else #else
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
#endif #endif
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
#endif
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE); nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
} }
#endif
if (m_dmrEnable || m_ysfEnable) { #if defined(MODE_DMR)
q15_t RRCVals[RX_BLOCK_SIZE]; if (m_dmrEnable) {
::arm_fir_fast_q15(&m_rrcFilter, samples, RRCVals, RX_BLOCK_SIZE); q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_ysfEnable) if (m_duplex)
ysfRX.samples(RRCVals, rssi, RX_BLOCK_SIZE); dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
else
if (m_dmrEnable) { dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
if (m_duplex)
dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
}
} }
#endif
#if defined(MODE_YSF)
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_FM)
if (m_fmEnable) { if (m_fmEnable) {
bool cos = getCOSInt(); bool cos = getCOSInt();
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE); fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
#else #else
fm.samples(cos, samples, RX_BLOCK_SIZE); fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
#endif #endif
} }
#endif
}
if (m_ax25Enable) { #if defined(MODE_DSTAR)
#if defined(USE_DCBLOCKER) else if (m_modemState == STATE_DSTAR) {
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
#else
ax25RX.samples(samples, RX_BLOCK_SIZE);
#endif
}
} else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) { if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE]; q15_t GMSKVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
@@ -383,10 +476,14 @@ void CIO::process()
#endif #endif
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE); dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_DMR) { }
#endif
#if defined(MODE_DMR)
else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) { if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE]; q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, DMRVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex) { if (m_duplex) {
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs // If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
@@ -398,56 +495,82 @@ void CIO::process()
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE); dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
} }
} }
} else if (m_modemState == STATE_YSF) { }
#endif
#if defined(MODE_YSF)
else if (m_modemState == STATE_YSF) {
if (m_ysfEnable) { if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE]; q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, YSFVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else #else
::arm_fir_fast_q15(&m_rrcFilter, samples, YSFVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif #endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE); ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_P25) { }
#endif
#if defined(MODE_P25)
else if (m_modemState == STATE_P25) {
if (m_p25Enable) { if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE]; q15_t P25Vals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
#else #else
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
#endif #endif
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_NXDN) { }
#endif
#if defined(MODE_NXDN)
else if (m_modemState == STATE_NXDN) {
if (m_nxdnEnable) { if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
#if defined(USE_NXDN_BOXCAR)
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
#endif
#else
q15_t NXDNValsTmp[RX_BLOCK_SIZE]; q15_t NXDNValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
#else #else
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
#endif #endif
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
#endif
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE); nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_FM) { }
#endif
#if defined(MODE_FM)
else if (m_modemState == STATE_FM) {
bool cos = getCOSInt(); bool cos = getCOSInt();
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE); fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
if (m_ax25Enable)
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
#else #else
fm.samples(cos, samples, RX_BLOCK_SIZE); fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
if (m_ax25Enable)
ax25RX.samples(samples, RX_BLOCK_SIZE);
#endif #endif
} else if (m_modemState == STATE_DSTARCAL) { }
#endif
#if defined(MODE_DSTAR)
else if (m_modemState == STATE_DSTARCAL) {
q15_t GMSKVals[RX_BLOCK_SIZE]; q15_t GMSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE); calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_RSSICAL) { }
#endif
else if (m_modemState == STATE_RSSICAL) {
calRSSI.samples(rssi, RX_BLOCK_SIZE); calRSSI.samples(rssi, RX_BLOCK_SIZE);
} }
} }
@@ -465,6 +588,7 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
if (!m_tx) { if (!m_tx) {
m_tx = true; m_tx = true;
setPTTInt(m_pttInvert ? false : true); setPTTInt(m_pttInvert ? false : true);
DEBUG1("TX ON");
} }
q15_t txLevel = 0; q15_t txLevel = 0;
@@ -490,9 +614,6 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
case STATE_FM: case STATE_FM:
txLevel = m_fmTXLevel; txLevel = m_fmTXLevel;
break; break;
case STATE_AX25:
txLevel = m_ax25TXLevel;
break;
default: default:
txLevel = m_cwIdTXLevel; txLevel = m_cwIdTXLevel;
break; break;
@@ -508,9 +629,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
m_dacOverflow++; m_dacOverflow++;
if (control == NULL) if (control == NULL)
m_txBuffer.put(res3, MARK_NONE); m_txBuffer.put({res3, MARK_NONE});
else else
m_txBuffer.put(res3, control[i]); m_txBuffer.put({res3, control[i]});
} }
} }
@@ -532,20 +653,39 @@ void CIO::setADCDetection(bool detect)
m_detect = detect; m_detect = detect;
} }
void CIO::setMode() void CIO::setMode(MMDVM_STATE state)
{ {
if (state == m_modemState)
return;
#if defined(MODE_LEDS) #if defined(MODE_LEDS)
setDStarInt(m_modemState == STATE_DSTAR); switch (m_modemState) {
setDMRInt(m_modemState == STATE_DMR); case STATE_DSTAR: setDStarInt(false); break;
setYSFInt(m_modemState == STATE_YSF); case STATE_DMR: setDMRInt(false); break;
setP25Int(m_modemState == STATE_P25); case STATE_YSF: setYSFInt(false); break;
setNXDNInt(m_modemState == STATE_NXDN); case STATE_P25: setP25Int(false); break;
setPOCSAGInt(m_modemState == STATE_POCSAG); case STATE_NXDN: setNXDNInt(false); break;
setFMInt(m_modemState == STATE_FM); case STATE_POCSAG: setPOCSAGInt(false); break;
case STATE_FM: setFMInt(false); break;
default: break;
}
switch (state) {
case STATE_DSTAR: setDStarInt(true); break;
case STATE_DMR: setDMRInt(true); break;
case STATE_YSF: setYSFInt(true); break;
case STATE_P25: setP25Int(true); break;
case STATE_NXDN: setNXDNInt(true); break;
case STATE_POCSAG: setPOCSAGInt(true); break;
case STATE_FM: setFMInt(true); break;
default: break;
}
#endif #endif
m_modemState = state;
} }
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout) void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
{ {
m_pttInvert = pttInvert; m_pttInvert = pttInvert;
@@ -558,7 +698,6 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128); m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128); m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
m_fmTXLevel = q15_t(fmTXLevel * 128); m_fmTXLevel = q15_t(fmTXLevel * 128);
m_ax25TXLevel = q15_t(ax25TXLevel * 128);
m_rxDCOffset = DC_OFFSET + rxDCOffset; m_rxDCOffset = DC_OFFSET + rxDCOffset;
m_txDCOffset = DC_OFFSET + txDCOffset; m_txDCOffset = DC_OFFSET + txDCOffset;
+46 -15
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2025 by Jonathan Naylor G4KLX
* *
* 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
@@ -21,8 +21,12 @@
#include "Globals.h" #include "Globals.h"
#include "SampleRB.h" #include "RingBuffer.h"
#include "RSSIRB.h"
struct TSample {
volatile uint16_t sample;
volatile uint8_t control;
};
class CIO { class CIO {
public: public:
@@ -38,11 +42,11 @@ public:
void setDecode(bool dcd); void setDecode(bool dcd);
void setADCDetection(bool detect); void setADCDetection(bool detect);
void setMode(); void setMode(MMDVM_STATE state);
void interrupt(); void interrupt();
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout); void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
void getOverflow(bool& adcOverflow, bool& dacOverflow); void getOverflow(bool& adcOverflow, bool& dacOverflow);
@@ -54,28 +58,55 @@ public:
void resetWatchdog(); void resetWatchdog();
uint32_t getWatchdog(); uint32_t getWatchdog();
uint8_t getCPU() const;
void getUDID(uint8_t* buffer);
void selfTest(); void selfTest();
private: private:
bool m_started; bool m_started;
CSampleRB m_rxBuffer; CRingBuffer<TSample> m_rxBuffer;
CSampleRB m_txBuffer; CRingBuffer<TSample> m_txBuffer;
CRSSIRB m_rssiBuffer; CRingBuffer<uint16_t> m_rssiBuffer;
#if defined(USE_DCBLOCKER)
arm_biquad_casd_df1_inst_q31 m_dcFilter; arm_biquad_casd_df1_inst_q31 m_dcFilter;
q31_t m_dcState[4]; q31_t m_dcState[4];
#endif
arm_fir_instance_q15 m_rrcFilter; #if defined(MODE_DSTAR)
arm_fir_instance_q15 m_gaussianFilter; arm_fir_instance_q15 m_gaussianFilter;
arm_fir_instance_q15 m_boxcarFilter; q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
#endif
#if defined(MODE_DMR)
arm_fir_instance_q15 m_rrc02Filter1;
q15_t m_rrc02State1[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_YSF)
arm_fir_instance_q15 m_rrc02Filter2;
q15_t m_rrc02State2[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_P25)
arm_fir_instance_q15 m_boxcar5Filter;
q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
arm_fir_instance_q15 m_boxcar10Filter;
q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare
#else
arm_fir_instance_q15 m_nxdnFilter; arm_fir_instance_q15 m_nxdnFilter;
arm_fir_instance_q15 m_nxdnISincFilter; arm_fir_instance_q15 m_nxdnISincFilter;
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
#endif
#endif
bool m_pttInvert; bool m_pttInvert;
q15_t m_rxLevel; q15_t m_rxLevel;
@@ -87,7 +118,6 @@ private:
q15_t m_nxdnTXLevel; q15_t m_nxdnTXLevel;
q15_t m_pocsagTXLevel; q15_t m_pocsagTXLevel;
q15_t m_fmTXLevel; q15_t m_fmTXLevel;
q15_t m_ax25TXLevel;
uint16_t m_rxDCOffset; uint16_t m_rxDCOffset;
uint16_t m_txDCOffset; uint16_t m_txDCOffset;
@@ -128,3 +158,4 @@ private:
}; };
#endif #endif
+36 -8
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM * Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@@ -110,7 +110,7 @@ void CIO::initInt()
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_POCSAG, OUTPUT); pinMode(PIN_POCSAG, OUTPUT);
#endif #endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_FM_LEDS)
pinMode(PIN_FM, OUTPUT); pinMode(PIN_FM, OUTPUT);
#endif #endif
#endif #endif
@@ -185,14 +185,13 @@ void CIO::startInt()
void CIO::interrupt() void CIO::interrupt()
{ {
if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg
uint8_t control = MARK_NONE; TSample sample = {DC_OFFSET, MARK_NONE};
uint16_t sample = DC_OFFSET;
m_txBuffer.get(sample, control); m_txBuffer.get(sample);
DACC->DACC_CDR = sample; DACC->DACC_CDR = sample.sample;
sample = ADC->ADC_CDR[ADC_CDR_Chan]; sample.sample = ADC->ADC_CDR[ADC_CDR_Chan];
m_rxBuffer.put(sample, control); m_rxBuffer.put(sample);
#if defined(SEND_RSSI_DATA) #if defined(SEND_RSSI_DATA)
m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]); m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]);
@@ -279,4 +278,33 @@ void CIO::delayInt(unsigned int dly)
delay(dly); delay(dly);
} }
uint8_t CIO::getCPU() const
{
return 0U;
}
// Code taken from https://github.com/emagii/at91sam3s/blob/master/examples/eefc_uniqueid/main.c
void CIO::getUDID(uint8_t* buffer)
{
uint32_t status;
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY );
for (uint8_t i = 0; i < 16; i+=4) {
buffer[i + 0] = *(uint32_t *)(IFLASH1_ADDR + i) >> 24;
buffer[i + 1] = *(uint32_t *)(IFLASH1_ADDR + i) >> 16;
buffer[i + 2] = *(uint32_t *)(IFLASH1_ADDR + i) >> 8;
buffer[i + 3] = *(uint32_t *)(IFLASH1_ADDR + i) >> 0;
}
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY );
}
#endif #endif
+6
View File
@@ -59,9 +59,15 @@
#elif defined(STM32F4_DVM) #elif defined(STM32F4_DVM)
#include "pins/pins_f4_stm32dvm_v3.h" #include "pins/pins_f4_stm32dvm_v3.h"
#elif defined(STM32F7_DVM)
#include "pins/pins_f7_stm32dvm_v5.h"
#elif defined(DRCC_DVM_NQF) #elif defined(DRCC_DVM_NQF)
#include "pins/pins_f4_drcc_nqf.h" #include "pins/pins_f4_drcc_nqf.h"
#elif defined(DRCC_DVM_HHP446)
#include "pins/pins_f4_drcc_hhp446.h"
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446) #elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
#include "pins/pins_f4_stm32eda.h" #include "pins/pins_f4_stm32eda.h"
+32 -10
View File
@@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM * Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2017,2018,2020,2023,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2019,2020 by BG5HHP * Copyright (C) 2019,2020 by BG5HHP
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -326,35 +326,40 @@ void CIO::startInt()
void CIO::interrupt() void CIO::interrupt()
{ {
uint8_t control = MARK_NONE; TSample sample = {DC_OFFSET, MARK_NONE};
uint16_t sample = DC_OFFSET;
uint16_t rawRSSI = 0U; uint16_t rawRSSI = 0U;
m_txBuffer.get(sample, control); m_txBuffer.get(sample);
// Send the value to the DAC // Send the value to the DAC
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
DAC_SetChannel2Data(DAC_Align_12b_R, sample); DAC_SetChannel2Data(DAC_Align_12b_R, sample.sample);
#else #else
DAC_SetChannel1Data(DAC_Align_12b_R, sample); DAC_SetChannel1Data(DAC_Align_12b_R, sample.sample);
#endif #endif
// Read value from ADC1 and ADC2 // Read value from ADC1 and ADC2
if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)) { if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)) {
// shouldn't be still in reset at this point so null the sample value? // shouldn't be still in reset at this point so null the sample value?
sample = 0U; sample.sample = 0U;
} else { } else {
sample = ADC_GetConversionValue(ADC1); sample.sample = ADC_GetConversionValue(ADC1);
#if defined(SEND_RSSI_DATA) #if defined(SEND_RSSI_DATA)
rawRSSI = ADC_GetConversionValue(ADC2); rawRSSI = ADC_GetConversionValue(ADC2);
#endif #endif
} }
// trigger next ADC1 // Trigger next ADC1
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC1); ADC_SoftwareStartConv(ADC1);
m_rxBuffer.put(sample, control); #if defined(SEND_RSSI_DATA)
// Trigger next ADC2
ADC_ClearFlag(ADC2, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC2);
#endif
m_rxBuffer.put(sample);
m_rssiBuffer.put(rawRSSI); m_rssiBuffer.put(rawRSSI);
m_watchdog++; m_watchdog++;
@@ -509,4 +514,21 @@ void CIO::delayInt(unsigned int dly)
} }
} }
uint8_t CIO::getCPU() const
{
return 2U;
}
void CIO::getUDID(uint8_t* buffer)
{
#if defined(STM32F4XX)
::memcpy(buffer, (void *)0x1FFF7A10, 12U);
#elif defined(STM32F722xx)
::memcpy(buffer, (void *)0x1FF07A10, 12U);
#elif defined(STM32F767xx)
::memcpy(buffer, (void *)0x1FF0F420, 12U);
#endif #endif
}
#endif
-476
View File
@@ -1,476 +0,0 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "IO.h"
#if defined(STM32F1)
#if defined(STM32F1_POG)
/*
Pin definitions for STM32F1 POG Board:
PTT PB12 output
COSLED PB5 output
LED PB4 output
COS PB13 input/PD
DSTAR PB7 output
DMR PB6 output
YSF PB8 output
P25 PB9 output
NXDN PB10 output
POCSAG PB11 output
RX PB0 analog input (ADC1_8)
RSSI PB1 analog input (ADC2_9)
TX PA4 analog output (DAC_OUT1)
EXT_CLK PA15 input (AF: TIM2_CH1_ETR)
USART1_TXD PA9 output (AF)
USART1_RXD PA10 input (AF)
*/
#define PIN_PTT 12
#define PORT_PTT GPIOB
#define BB_PTT *((bitband_t)BITBAND_PERIPH(&PORT_PTT->ODR, PIN_PTT))
#define PIN_COSLED 5
#define PORT_COSLED GPIOB
#define BB_COSLED *((bitband_t)BITBAND_PERIPH(&PORT_COSLED->ODR, PIN_COSLED))
#define PIN_LED 4
#define PORT_LED GPIOB
#define BB_LED *((bitband_t)BITBAND_PERIPH(&PORT_LED->ODR, PIN_LED))
#define PIN_COS 13
#define PORT_COS GPIOB
#define BB_COS *((bitband_t)BITBAND_PERIPH(&PORT_COS->IDR, PIN_COS))
#define PIN_DSTAR 7
#define PORT_DSTAR GPIOB
#define BB_DSTAR *((bitband_t)BITBAND_PERIPH(&PORT_DSTAR->ODR, PIN_DSTAR))
#define PIN_DMR 6
#define PORT_DMR GPIOB
#define BB_DMR *((bitband_t)BITBAND_PERIPH(&PORT_DMR->ODR, PIN_DMR))
#define PIN_YSF 8
#define PORT_YSF GPIOB
#define BB_YSF *((bitband_t)BITBAND_PERIPH(&PORT_YSF->ODR, PIN_YSF))
#define PIN_P25 9
#define PORT_P25 GPIOB
#define BB_P25 *((bitband_t)BITBAND_PERIPH(&PORT_P25->ODR, PIN_P25))
#define PIN_NXDN 10
#define PORT_NXDN GPIOB
#define BB_NXDN *((bitband_t)BITBAND_PERIPH(&PORT_NXDN->ODR, PIN_NXDN))
#define PIN_POCSAG 11
#define PORT_POCSAG GPIOB
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
#define PIN_RX 0
#define PIN_RX_ADC_CH 8
#define PORT_RX GPIOB
#define PIN_RSSI 1
#define PIN_RSSI_ADC_CH 9
#define PORT_RSSI GPIOB
#define PIN_TX 4
#define PIN_TX_DAC_CH 1
#define PORT_TX GPIOA
#define PIN_EXT_CLK 15
#define SRC_EXT_CLK 15
#define PORT_EXT_CLK GPIOA
#define PIN_USART1_TXD 9
#define PORT_USART1_TXD GPIOA
#define PIN_USART1_RXD 10
#define PORT_USART1_RXD GPIOA
#else // defined(STM32F1_POG)
#error "Either STM32F1_POG, or sth need to be defined"
#endif // defined(STM32F1_POG)
const uint16_t DC_OFFSET = 2048U;
// Sampling frequency
#define SAMP_FREQ 24000
extern "C" {
void TIM2_IRQHandler() {
if ((TIM2->SR & TIM_SR_UIF) == TIM_SR_UIF) {
TIM2->SR = ~TIM_SR_UIF; // clear UI flag
io.interrupt();
}
}
}
void delay(uint32_t cnt)
{
while(cnt--)
asm("nop");
}
// source: http://www.freddiechopin.info/
void GPIOConfigPin(GPIO_TypeDef *port_ptr, uint32_t pin, uint32_t mode_cnf_value)
{
volatile uint32_t *cr_ptr;
uint32_t cr_value;
cr_ptr = &port_ptr->CRL; // configuration of pins [0,7] is in CRL
if (pin >= 8) // is pin in [8; 15]?
{ // configuration of pins [8,15] is in CRH
cr_ptr++; // advance to next struct element CRL -> CRH
pin -= 8; // crop the pin number
}
cr_value = *cr_ptr; // localize the CRL / CRH value
cr_value &= ~(0xF << (pin * 4)); // clear the MODE and CNF fields (now that pin is an analog input)
cr_value |= (mode_cnf_value << (pin * 4)); // save new MODE and CNF value for desired pin
*cr_ptr = cr_value; // save localized value to CRL / CRL
}
#if defined(STM32F1_POG)
void FancyLEDEffect()
{
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
for(int i=0; i<7; i++){
*foo[i] = 0x01;
}
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*100);
for(int i=0; i<7; i++){
*foo[i] = 0x00;
}
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
delay(SystemCoreClock/1000*20);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*10);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
*foo[0] = 0x01;
for(int i=1; i<7; i++){
delay(SystemCoreClock/1000*10);
*foo[i-1] = 0x00;
*foo[i] = 0x01;
}
for(int i=5; i>=0; i--){
delay(SystemCoreClock/1000*10);
*foo[i+1] = 0x00;
*foo[i] = 0x01;
}
delay(SystemCoreClock/1000*10);
*foo[5+1-6] = 0x00;
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*10);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
delay(SystemCoreClock/1000*50);
}
#endif
static inline void GPIOInit()
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN
| RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN
| RCC_APB2ENR_AFIOEN; // enable all GPIOs
// set all ports to input with pull-down
GPIOA->CRL = 0x88888888;
GPIOA->CRH = 0x88888888;
GPIOA->ODR = 0;
GPIOB->CRL = 0x88888888;
GPIOB->CRH = 0x88888888;
GPIOB->ODR = 0;
GPIOC->CRL = 0x88888888;
GPIOC->CRH = 0x88888888;
GPIOC->ODR = 0;
GPIOD->CRL = 0x88888888;
GPIOD->CRH = 0x88888888;
GPIOD->ODR = 0;
// configure ports
GPIOConfigPin(PORT_PTT, PIN_PTT, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_COSLED, PIN_COSLED, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_LED, PIN_LED, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_COS, PIN_COS, GPIO_CRL_CNF0_1);
GPIOConfigPin(PORT_DSTAR, PIN_DSTAR, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_YSF, PIN_YSF, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_P25, PIN_P25, GPIO_CRL_MODE0_1);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
#endif
GPIOConfigPin(PORT_RX, PIN_RX, 0);
#if defined(SEND_RSSI_DATA)
GPIOConfigPin(PORT_RSSI, PIN_RSSI, 0);
#endif
GPIOConfigPin(PORT_TX, PIN_TX, 0);
#if defined(EXTERNAL_OSC)
#if defined(STM32F1_POG)
GPIOConfigPin(PORT_EXT_CLK, PIN_EXT_CLK, GPIO_CRL_CNF0_0);
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_TIM2_REMAP) | AFIO_MAPR_TIM2_REMAP_0;
#endif
#endif
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
GPIOConfigPin(PORT_USART1_RXD, PIN_USART1_RXD, GPIO_CRL_CNF0_0);
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_SWJ_CFG) | AFIO_MAPR_SWJ_CFG_1;
}
static inline void ADCInit()
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE_Msk)
| RCC_CFGR_ADCPRE_DIV6; // ADC clock divided by 6 (72MHz/6 = 12MHz)
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
#if defined(SEND_RSSI_DATA)
RCC->APB2ENR |= RCC_APB2ENR_ADC2EN;
#endif
// Init ADCs in dual mode (RSSI)
#if defined(SEND_RSSI_DATA)
ADC1->CR1 = ADC_CR1_DUALMOD_1|ADC_CR1_DUALMOD_2; // Regular simultaneous mode
#endif
// Set sampling time to 7.5 cycles
if (PIN_RX_ADC_CH < 10) {
ADC1->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RX_ADC_CH);
} else {
ADC1->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RX_ADC_CH);
}
#if defined(SEND_RSSI_DATA)
if (PIN_RSSI_ADC_CH < 10) {
ADC2->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RSSI_ADC_CH);
} else {
ADC2->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RSSI_ADC_CH);
}
#endif
// Set conversion channel (single conversion)
ADC1->SQR3 = PIN_RX_ADC_CH;
#if defined(SEND_RSSI_DATA)
ADC2->SQR3 = PIN_RSSI_ADC_CH;
#endif
// Enable ADC
ADC1->CR2 |= ADC_CR2_ADON;
#if defined(SEND_RSSI_DATA)
// Enable ADC2
ADC2->CR2 |= ADC_CR2_ADON;
#endif
// Start calibration
delay(6*2);
ADC1->CR2 |= ADC_CR2_CAL;
while((ADC1->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
;
#if defined(SEND_RSSI_DATA)
ADC2->CR2 |= ADC_CR2_CAL;
while((ADC2->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
;
#endif
// Trigger first conversion
ADC1->CR2 |= ADC_CR2_ADON;
#if defined(SEND_RSSI_DATA)
ADC2->CR2 |= ADC_CR2_ADON;
#endif
}
static inline void DACInit()
{
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
DAC->CR = DAC_CR_EN1;
}
static inline void TimerInit()
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
#if defined(EXTERNAL_OSC)
// Enable external clock, prescaler /4
TIM2->SMCR = TIM_SMCR_ECE | TIM_SMCR_ETPS_1;
#endif
// TIM2 output frequency
TIM2->PSC = 0;
#if defined(EXTERNAL_OSC)
// TimerCount = ExternalOsc
// /4 (external clock prescaler)
// /SAMP_FREQ
TIM2->ARR = (uint16_t) ((EXTERNAL_OSC/(4*SAMP_FREQ)) - 1);
#else
TIM2->ARR = (uint16_t) ((SystemCoreClock/(SAMP_FREQ)) - 1);
#endif
// Enable TIse 1%-tolerance comM2 interrupt
TIM2->DIER = TIM_DIER_UIE;
NVIC_EnableIRQ(TIM2_IRQn);
// Enable TIM2
TIM2->CR1 |= TIM_CR1_CEN;
}
void CIO::initInt()
{
GPIOInit();
ADCInit();
DACInit();
#if defined(STM32F1_POG)
FancyLEDEffect();
#endif
}
void CIO::startInt()
{
TimerInit();
BB_COSLED = 0;
BB_LED = 1;
}
void CIO::interrupt()
{
uint8_t control = MARK_NONE;
uint16_t sample = DC_OFFSET;
#if defined(SEND_RSSI_DATA)
uint16_t rawRSSI = 0U;
#endif
bitband_t eoc = (bitband_t)BITBAND_PERIPH(&ADC1->SR, ADC_SR_EOS_Pos);
bitband_t adon = (bitband_t)BITBAND_PERIPH(&ADC1->CR2, ADC_CR2_ADON_Pos);
#if defined(SEND_RSSI_DATA)
bitband_t rssi_adon = (bitband_t)BITBAND_PERIPH(&ADC2->CR2, ADC_CR2_ADON_Pos);
#endif
if (*eoc) {
// trigger next conversion
*adon = 1;
#if defined(SEND_RSSI_DATA)
*rssi_adon = 1;
#endif
m_txBuffer.get(sample, control);
DAC->DHR12R1 = sample; // Send the value to the DAC
// Read value from ADC1 and ADC2
sample = ADC1->DR; // read conversion result; EOC is cleared by this read
m_rxBuffer.put(sample, control);
#if defined(SEND_RSSI_DATA)
rawRSSI = ADC2->DR;
m_rssiBuffer.put(rawRSSI);
#endif
m_watchdog++;
}
}
bool CIO::getCOSInt()
{
return BB_COS;
}
void CIO::setLEDInt(bool on)
{
BB_LED = !!on;
}
void CIO::setPTTInt(bool on)
{
BB_PTT = !!on;
}
void CIO::setCOSInt(bool on)
{
BB_COSLED = !!on;
}
void CIO::setDStarInt(bool on)
{
BB_DSTAR = !!on;
}
void CIO::setDMRInt(bool on)
{
BB_DMR = !!on;
}
void CIO::setYSFInt(bool on)
{
BB_YSF = !!on;
}
void CIO::setP25Int(bool on)
{
BB_P25 = !!on;
}
void CIO::setNXDNInt(bool on)
{
#if defined(USE_ALTERNATE_NXDN_LEDS)
BB_YSF = !!on;
BB_P25 = !!on;
#else
BB_NXDN = !!on;
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
BB_DSTAR = !!on;
BB_DMR = !!on;
#else
BB_POCSAG = !!on;
#endif
}
void CIO::setFMInt(bool on)
{
#if defined(USE_ALTERNATE_FM_LEDS)
BB_DSTAR = !!on;
BB_YSF = !!on;
#endif
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
}
#endif
+17 -7
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018,2020,2025 by Jonathan Naylor G4KLX
* *
* 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
@@ -161,15 +161,14 @@ void CIO::startInt()
void CIO::interrupt() void CIO::interrupt()
{ {
uint8_t control = MARK_NONE; TSample sample = {DC_OFFSET, MARK_NONE};
uint16_t sample = DC_OFFSET;
m_txBuffer.get(sample, control); m_txBuffer.get(sample);
*(int16_t *)&(DAC0_DAT0L) = sample; *(int16_t *)&(DAC0_DAT0L) = sample.sample;
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) { if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
sample = ADC0_RA; sample.sample = ADC0_RA;
m_rxBuffer.put(sample, control); m_rxBuffer.put(sample);
} }
#if defined(SEND_RSSI_DATA) #if defined(SEND_RSSI_DATA)
@@ -263,4 +262,15 @@ void CIO::delayInt(unsigned int dly)
delay(dly); delay(dly);
} }
uint8_t CIO::getCPU() const
{
return 1U;
}
void CIO::getUDID(uint8_t* buffer)
{
::memcpy(buffer, (void *)0x4058, 16U);
}
#endif #endif
+78 -39
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT * Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@@ -18,7 +18,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if defined(STM32F4XX) || defined(STM32F7XX) || defined(STM32F105xC) #if defined(STM32F4XX) || defined(STM32F7XX)
#include "Config.h" #include "Config.h"
#include "Globals.h" #include "Globals.h"
@@ -33,46 +33,61 @@ bool m_p25Enable = true;
bool m_nxdnEnable = true; bool m_nxdnEnable = true;
bool m_pocsagEnable = true; bool m_pocsagEnable = true;
bool m_fmEnable = true; bool m_fmEnable = true;
bool m_ax25Enable = true;
bool m_duplex = true; bool m_duplex = true;
bool m_tx = false; bool m_tx = false;
bool m_dcd = false; bool m_dcd = false;
CDStarRX dstarRX; #if defined(MODE_DSTAR)
CDStarTX dstarTX; CDStarRX dstarRX;
CDStarTX dstarTX;
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CYSFRX ysfRX;
CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CPOCSAGTX pocsagTX;
CFM fm;
CAX25RX ax25RX;
CAX25TX ax25TX;
CCalDStarRX calDStarRX; CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX; CCalDStarTX calDStarTX;
CCalDMR calDMR; #endif
CCalP25 calP25;
CCalNXDN calNXDN; #if defined(MODE_DMR)
CCalFM calFM; CDMRIdleRX dmrIdleRX;
CCalPOCSAG calPOCSAG; CDMRRX dmrRX;
CCalRSSI calRSSI; CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
CYSFRX ysfRX;
CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
CP25RX p25RX;
CP25TX p25TX;
CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalNXDN calNXDN;
#endif
#if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_FM)
CFM fm;
CCalFM calFM;
#endif
CCalRSSI calRSSI;
CCWIdTX cwIdTX; CCWIdTX cwIdTX;
@@ -91,51 +106,74 @@ void loop()
io.process(); io.process();
// The following is for transmitting // The following is for transmitting
#if defined(MODE_DSTAR)
if (m_dstarEnable && m_modemState == STATE_DSTAR) if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process(); dstarTX.process();
#endif
#if defined(MODE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) { if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_duplex) if (m_duplex)
dmrTX.process(); dmrTX.process();
else else
dmrDMOTX.process(); dmrDMOTX.process();
} }
#endif
#if defined(MODE_YSF)
if (m_ysfEnable && m_modemState == STATE_YSF) if (m_ysfEnable && m_modemState == STATE_YSF)
ysfTX.process(); ysfTX.process();
#endif
#if defined(MODE_P25)
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN) if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process(); nxdnTX.process();
#endif
#if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process(); pocsagTX.process();
#endif
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) #if defined(MODE_FM)
ax25TX.process();
if (m_fmEnable && m_modemState == STATE_FM) if (m_fmEnable && m_modemState == STATE_FM)
fm.process(); fm.process();
#endif
#if defined(MODE_DSTAR)
if (m_modemState == STATE_DSTARCAL) if (m_modemState == STATE_DSTARCAL)
calDStarTX.process(); calDStarTX.process();
#endif
#if defined(MODE_DMR)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K) if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
calDMR.process(); calDMR.process();
#endif
#if defined(MODE_FM)
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
calFM.process();
#endif
#if defined(MODE_P25)
if (m_modemState == STATE_P25CAL1K) if (m_modemState == STATE_P25CAL1K)
calP25.process(); calP25.process();
#endif
#if defined(MODE_NXDN)
if (m_modemState == STATE_NXDNCAL1K) if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process(); calNXDN.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL) if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process(); calPOCSAG.process();
#endif
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K ||m_modemState == STATE_FMCAL30K)
calFM.process();
if (m_modemState == STATE_IDLE) if (m_modemState == STATE_IDLE)
cwIdTX.process(); cwIdTX.process();
@@ -150,3 +188,4 @@ int main()
} }
#endif #endif
+74 -35
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2025 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -30,46 +30,61 @@ bool m_p25Enable = true;
bool m_nxdnEnable = true; bool m_nxdnEnable = true;
bool m_pocsagEnable = true; bool m_pocsagEnable = true;
bool m_fmEnable = true; bool m_fmEnable = true;
bool m_ax25Enable = true;
bool m_duplex = true; bool m_duplex = true;
bool m_tx = false; bool m_tx = false;
bool m_dcd = false; bool m_dcd = false;
CDStarRX dstarRX; #if defined(MODE_DSTAR)
CDStarTX dstarTX; CDStarRX dstarRX;
CDStarTX dstarTX;
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CYSFRX ysfRX;
CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CPOCSAGTX pocsagTX;
CFM fm;
CAX25RX ax25RX;
CAX25 ax25TX;
CCalDStarRX calDStarRX; CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX; CCalDStarTX calDStarTX;
CCalDMR calDMR; #endif
CCalFM calFM;
CCalP25 calP25; #if defined(MODE_DMR)
CCalNXDN calNXDN; CDMRIdleRX dmrIdleRX;
CCalPOCSAG calPOCSAG; CDMRRX dmrRX;
CCalRSSI calRSSI; CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
CYSFRX ysfRX;
CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
CP25RX p25RX;
CP25TX p25TX;
CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalNXDN calNXDN;
#endif
#if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_FM)
CFM fm;
CCalFM calFM;
#endif
CCalRSSI calRSSI;
CCWIdTX cwIdTX; CCWIdTX cwIdTX;
@@ -88,52 +103,76 @@ void loop()
io.process(); io.process();
// The following is for transmitting // The following is for transmitting
#if defined(MODE_DSTAR)
if (m_dstarEnable && m_modemState == STATE_DSTAR) if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process(); dstarTX.process();
#endif
#if defined(MODE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) { if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_duplex) if (m_duplex)
dmrTX.process(); dmrTX.process();
else else
dmrDMOTX.process(); dmrDMOTX.process();
} }
#endif
#if defined(MODE_YSF)
if (m_ysfEnable && m_modemState == STATE_YSF) if (m_ysfEnable && m_modemState == STATE_YSF)
ysfTX.process(); ysfTX.process();
#endif
#if defined(MODE_P25)
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN) if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process(); nxdnTX.process();
#endif
#if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process(); pocsagTX.process();
#endif
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) #if defined(MODE_FM)
ax25TX.process();
if (m_fmEnable && m_modemState == STATE_FM) if (m_fmEnable && m_modemState == STATE_FM)
fm.process(); fm.process();
#endif
#if defined(MODE_DSTAR)
if (m_modemState == STATE_DSTARCAL) if (m_modemState == STATE_DSTARCAL)
calDStarTX.process(); calDStarTX.process();
#endif
#if defined(MODE_DMR)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K) if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
calDMR.process(); calDMR.process();
#endif
#if defined(MODE_FM)
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K) if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
calFM.process(); calFM.process();
#endif
#if defined(MODE_P25)
if (m_modemState == STATE_P25CAL1K) if (m_modemState == STATE_P25CAL1K)
calP25.process(); calP25.process();
#endif
#if defined(MODE_NXDN)
if (m_modemState == STATE_NXDNCAL1K) if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process(); calNXDN.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL) if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process(); calPOCSAG.process();
#endif
if (m_modemState == STATE_IDLE) if (m_modemState == STATE_IDLE)
cwIdTX.process(); cwIdTX.process();
} }
Binary file not shown.
+23 -11
View File
@@ -133,8 +133,10 @@ DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VAL
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board: # MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# STM32F4 DVM board: # RB STM32F4_DVM board:
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# RB STM32F7 DVM board:
DEFS_DVM722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F7_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat BG4TGO, BG5HHP board: # MMDVM_RPT_Hat BG4TGO, BG5HHP board:
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# DRCC_DVM BG7NQF board: # DRCC_DVM BG7NQF board:
@@ -147,9 +149,9 @@ DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446
# Build compiler flags # Build compiler flags
CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) -std=c++11
CFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7) CFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7)
CXXFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7) CXXFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7) -std=c++11
# Linker flags # Linker flags
LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4)
@@ -222,17 +224,29 @@ f767: LDFLAGS+=$(LDFLAGS_F767)
f767: release_f7 f767: release_f7
dvm: GitVersion.h dvm: GitVersion.h
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM) dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM) dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: LDFLAGS+=$(LDFLAGS_F4) dvm: LDFLAGS+=$(LDFLAGS_F4)
dvm: release_f4 dvm: release_f4
dvm722: GitVersion.h
dvm722: CFLAGS+=$(CFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: LDFLAGS+=$(LDFLAGS_F722)
dvm722: release_f7
drcc_nqf: GitVersion.h drcc_nqf: GitVersion.h
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4) drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
drcc_nqf: release_f4 drcc_nqf: release_f4
hhp446: GitVersion.h
hhp446: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: LDFLAGS+=$(LDFLAGS_F4)
hhp446: release_f4
eda405: GitVersion.h eda405: GitVersion.h
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405) eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405) eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
@@ -354,14 +368,12 @@ endif
deploy-pi: deploy-pi:
ifneq ($(wildcard /usr/local/bin/stm32flash),) ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0 -/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
-/usr/local/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4) /usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
endif endif
ifneq ($(wildcard /usr/bin/stm32flash),) ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0 -/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
-/usr/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4) /usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
endif endif
deploy-f4m: deploy-pi deploy-f4m: deploy-pi
@@ -372,11 +384,11 @@ deploy-eda446: deploy-pi
deploy-pi-f7: deploy-pi-f7:
ifneq ($(wildcard /usr/local/bin/stm32flash),) ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0 -/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0 /usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
else ifneq ($(wildcard /usr/bin/stm32flash),) else ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0 -/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0 /usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
endif endif
deploy-f7m: deploy-pi-f7 deploy-f7m: deploy-pi-f7
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/make #!/usr/bin/make
# makefile for the arduino due (works with arduino IDE 1.6.11) # makefile for the arduino due (works with arduino IDE 1.6.12)
# #
# The original file can be found at https://github.com/pauldreik/arduino-due-makefile # The original file can be found at https://github.com/pauldreik/arduino-due-makefile
# #
@@ -34,7 +34,7 @@ OBJCOPY:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-n
C:=$(CC) C:=$(CC)
#SAM:=arduino/sam/ #SAM:=arduino/sam/
SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.11 SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.12
#CMSIS:=arduino/sam/system/CMSIS/ #CMSIS:=arduino/sam/system/CMSIS/
#LIBSAM:=arduino/sam/system/libsam #LIBSAM:=arduino/sam/system/libsam
TMPDIR:=$(PWD)/build TMPDIR:=$(PWD)/build
-165
View File
@@ -1,165 +0,0 @@
# The name for the project
TARGET:=mmdvm
# The CPU architecture (will be used for -mcpu)
MCPU:=cortex-m3
MCU:=STM32F105xC
# The source files of the project
CSRC:=
CXXSRC:=$(wildcard *.cpp)
# Include directory for the system include files and system source file
SYSDIR:=system_stm32f1xx
SYSSRC:=$(SYSDIR)/system_stm32f1xx.c
# Other include directories
INCDIR:=
# Definitions
CDEFS:=
CXXDEFS:=
# The name of the startup file which matches to the architecture (MCPU)
STARTUP:=$(SYSDIR)/startup_stm32f105xc.S
STARTUP_DEFS=
# Include directory for CMSIS
CMSISDIR:=STM32F10X_Lib/CMSIS
# Libraries
LIBDIR:=
LIBS:=-larm_cortexM3l_math
# Name of the linker script
LDSCRIPT:=$(SYSDIR)/gcc.ld
# Target objects and binaries directory
OBJDIR:=obj
BINDIR:=bin
# Port definition for programming via bootloader (using stm32flash)
BL_PORT:=ttyUSB0
# Internal Variables
ELF:=$(BINDIR)/$(TARGET).elf
HEX:=$(BINDIR)/$(TARGET).hex
DIS:=$(BINDIR)/$(TARGET).dis
MAP:=$(BINDIR)/$(TARGET).map
OBJ:=$(CSRC:%.c=$(OBJDIR)/%.o) $(CXXSRC:%.cpp=$(OBJDIR)/%.o)
OBJ+=$(SYSSRC:$(SYSDIR)/%.c=$(OBJDIR)/%.o) $(STARTUP:$(SYSDIR)/%.S=$(OBJDIR)/%.o)
# Replace standard build tools by arm tools
CC:=arm-none-eabi-gcc
CXX:=arm-none-eabi-g++
AS:=arm-none-eabi-gcc
LD:=arm-none-eabi-g++
OBJCOPY:=arm-none-eabi-objcopy
OBJDUMP:=arm-none-eabi-objdump
SIZE:=arm-none-eabi-size
# Common flags
COMMON_FLAGS =-mthumb -mlittle-endian -mcpu=$(MCPU)
COMMON_FLAGS+= -Wall
COMMON_FLAGS+= -I. -I$(CMSISDIR)/Include -I$(CMSISDIR)/Device/ST/STM32F1xx/Include -I$(SYSDIR)
COMMON_FLAGS+= $(addprefix -I,$(INCDIR))
COMMON_FLAGS+= -D$(MCU) -DMADEBYMAKEFILE -DSTM32F1
COMMON_FLAGS+= -Os -flto -ffunction-sections -fdata-sections
COMMON_FLAGS+= -g
# Assembler flags
ASFLAGS:=$(COMMON_FLAGS)
# C flags
CFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CDEFS))
CFLAGS+= -std=gnu11 -nostdlib
# CXX flags
CXXFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CXXDEFS))
CXXFLAGS+= -nostdlib -fno-exceptions -fno-rtti
# LD flags
LDFLAGS:=$(COMMON_FLAGS) -Wl,--gc-sections -Wl,-Map=$(MAP) -Wl,--no-wchar-size-warning
LDFLAGS+= --specs=nosys.specs --specs=nano.specs
LDFLAGS+= -L$(CMSISDIR)/Lib/GCC/ $(addprefix -L,$(LIBDIR))
LDLIBS:=-T$(LDSCRIPT) $(LIBS)
# Dependecies
DEPENDS:=$(CSRC:%.c=$(OBJDIR)/%.d) $(CXXSRC:%.cpp=$(OBJDIR)/%.d)
# Additional Suffixes
.SUFFIXES: .elf .hex
# Targets
.PHONY: all
all: GitVersion.h $(DIS) $(HEX)
$(SIZE) $(ELF)
.PHONY: program
program: $(HEX) $(ELF)
openocd -f openocd.cfg \
-c "program $(HEX) verify reset exit"
$(SIZE) $(ELF)
.PHONY: program_bl
program_bl: $(HEX) $(ELF)
stm32flash -w $(HEX) -v /dev/$(BL_PORT)
$(SIZE) $(ELF)
.PHONY: run
run: $(HEX) $(ELF)
openocd -f openocd.cfg \
-c "init" -c "reset" -c "exit"
.PHONY: debug
debug: $(ELF)
./debug.sh $(ELF)
.PHONY: clean
clean:
$(RM) $(OBJ) $(HEX) $(ELF) $(DIS) $(MAP) $(DEPENDS) GitVersion.h
# implicit rules
.elf.hex:
$(OBJCOPY) -O ihex $< $@
$(OBJDIR)/%.o: %.c
$(CC) -MMD $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: %.cpp
$(CXX) -MMD $(CXXFLAGS) -c $< -o $@
$(OBJDIR)/%.o: $(SYSDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: $(SYSDIR)/%.S
$(AS) $(ASFLAGS) -c $< -o $@
# explicit rules
$(OBJDIR):
mkdir -p $(OBJDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(ELF): $(OBJDIR) $(BINDIR) $(OBJ)
$(LD) $(OBJ) $(LDFLAGS) $(LDLIBS) -o $@
$(DIS): $(ELF)
$(OBJDUMP) -S $< > $@
# include dependecies
-include $(DEPENDS)
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifdef SYSTEMROOT
echo #define GITVERSION "0000000" > $@
else ifdef SystemRoot
echo #define GITVERSION "0000000" > $@
else
ifneq ("$(wildcard .git/index)","")
echo "#define GITVERSION \"$(shell git rev-parse --short HEAD)\"" > $@
else
echo "#define GITVERSION \"0000000\"" > $@
endif
endif
+6 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX * Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h" #include "Globals.h"
#include "NXDNRX.h" #include "NXDNRX.h"
#include "Utils.h" #include "Utils.h"
@@ -403,3 +406,5 @@ void CNXDNRX::writeRSSIData(uint8_t* data)
m_rssiCount = 0U; m_rssiCount = 0U;
} }
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* *
* 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
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(NXDNRX_H) #if !defined(NXDNRX_H)
#define NXDNRX_H #define NXDNRX_H
#include "Config.h"
#include "NXDNDefines.h" #include "NXDNDefines.h"
enum NXDNRX_STATE { enum NXDNRX_STATE {
@@ -67,3 +70,5 @@ private:
#endif #endif
#endif
+9 -2
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h" #include "Globals.h"
#include "NXDNTX.h" #include "NXDNTX.h"
@@ -81,7 +84,8 @@ void CNXDNTX::process()
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U]; m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
} else { } else {
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) { for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
uint8_t c = m_buffer.get(); uint8_t c = 0U;
m_buffer.get(c);
m_poBuffer[m_poLen++] = c; m_poBuffer[m_poLen++] = c;
} }
} }
@@ -171,7 +175,7 @@ void CNXDNTX::writeByte(uint8_t c)
void CNXDNTX::writeSilence() void CNXDNTX::writeSilence()
{ {
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U}; q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U]; q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U]; q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
@@ -199,3 +203,6 @@ void CNXDNTX::setParams(uint8_t txHang)
{ {
m_txHang = txHang * 600U; m_txHang = txHang * 600U;
} }
#endif
+9 -4
View File
@@ -16,12 +16,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(NXDNTX_H) #if !defined(NXDNTX_H)
#define NXDNTX_H #define NXDNTX_H
#include "Config.h" #include "RingBuffer.h"
#include "SerialRB.h"
class CNXDNTX { class CNXDNTX {
public: public:
@@ -38,7 +40,7 @@ public:
void setParams(uint8_t txHang); void setParams(uint8_t txHang);
private: private:
CSerialRB m_buffer; CRingBuffer<uint8_t> m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_interpolate_instance_q15 m_modFilter;
arm_fir_instance_q15 m_sincFilter; arm_fir_instance_q15 m_sincFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
@@ -55,3 +57,6 @@ private:
}; };
#endif #endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com> * Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_P25)
#include "Globals.h" #include "Globals.h"
#include "P25RX.h" #include "P25RX.h"
#include "Utils.h" #include "Utils.h"
@@ -535,3 +538,6 @@ void CP25RX::writeRSSILdu(uint8_t* ldu)
m_rssiAccum = 0U; m_rssiAccum = 0U;
m_rssiCount = 0U; m_rssiCount = 0U;
} }
#endif
+8 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com> * Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_P25)
#if !defined(P25RX_H) #if !defined(P25RX_H)
#define P25RX_H #define P25RX_H
#include "Config.h"
#include "P25Defines.h" #include "P25Defines.h"
enum P25RX_STATE { enum P25RX_STATE {
@@ -72,3 +75,6 @@ private:
}; };
#endif #endif
#endif
+11 -3
View File
@@ -18,6 +18,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_P25)
#include "Globals.h" #include "Globals.h"
#include "P25TX.h" #include "P25TX.h"
@@ -75,9 +78,11 @@ void CP25TX::process()
for (uint16_t i = 0U; i < m_txDelay; i++) for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = P25_START_SYNC; m_poBuffer[m_poLen++] = P25_START_SYNC;
} else { } else {
uint8_t length = m_buffer.get(); uint8_t length;
m_buffer.get(length);
for (uint8_t i = 0U; i < length; i++) { for (uint8_t i = 0U; i < length; i++) {
uint8_t c = m_buffer.get(); uint8_t c = 0U;
m_buffer.get(c);
m_poBuffer[m_poLen++] = c; m_poBuffer[m_poLen++] = c;
} }
} }
@@ -168,7 +173,7 @@ void CP25TX::writeByte(uint8_t c)
void CP25TX::writeSilence() void CP25TX::writeSilence()
{ {
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U}; q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U]; q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
@@ -196,3 +201,6 @@ void CP25TX::setParams(uint8_t txHang)
{ {
m_txHang = txHang * 1200U; m_txHang = txHang * 1200U;
} }
#endif
+9 -4
View File
@@ -16,12 +16,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_P25)
#if !defined(P25TX_H) #if !defined(P25TX_H)
#define P25TX_H #define P25TX_H
#include "Config.h" #include "RingBuffer.h"
#include "SerialRB.h"
class CP25TX { class CP25TX {
public: public:
@@ -38,7 +40,7 @@ public:
void setParams(uint8_t txHang); void setParams(uint8_t txHang);
private: private:
CSerialRB m_buffer; CRingBuffer<uint8_t> m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_interpolate_instance_q15 m_modFilter;
arm_fir_instance_q15 m_lpFilter; arm_fir_instance_q15 m_lpFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
@@ -55,3 +57,6 @@ private:
}; };
#endif #endif
#endif
+7 -1
View File
@@ -17,6 +17,9 @@
*/ */
#include "Config.h" #include "Config.h"
#if defined(MODE_POCSAG)
#include "Globals.h" #include "Globals.h"
#include "POCSAGTX.h" #include "POCSAGTX.h"
@@ -61,7 +64,8 @@ void CPOCSAGTX::process()
m_poBuffer[m_poLen++] = POCSAG_SYNC; m_poBuffer[m_poLen++] = POCSAG_SYNC;
} else { } else {
for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) { for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) {
uint8_t c = m_buffer.get(); uint8_t c = 0U;
m_buffer.get(c);
m_poBuffer[m_poLen++] = c; m_poBuffer[m_poLen++] = c;
} }
} }
@@ -147,3 +151,5 @@ uint8_t CPOCSAGTX::getSpace() const
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES; return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
} }
#endif
+8 -4
View File
@@ -16,12 +16,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "Config.h"
#if defined(MODE_POCSAG)
#if !defined(POCSAGTX_H) #if !defined(POCSAGTX_H)
#define POCSAGTX_H #define POCSAGTX_H
#include "Config.h" #include "RingBuffer.h"
#include "SerialRB.h"
class CPOCSAGTX { class CPOCSAGTX {
public: public:
@@ -40,7 +42,7 @@ public:
bool busy(); bool busy();
private: private:
CSerialRB m_buffer; CRingBuffer<uint8_t> m_buffer;
arm_fir_instance_q15 m_modFilter; arm_fir_instance_q15 m_modFilter;
q15_t m_modState[170U]; // NoTaps + BlockSize - 1, 6 + 160 - 1 plus some spare q15_t m_modState[170U]; // NoTaps + BlockSize - 1, 6 + 160 - 1 plus some spare
uint8_t m_poBuffer[200U]; uint8_t m_poBuffer[200U];
@@ -51,3 +53,5 @@ private:
#endif #endif
#endif
+32 -14
View File
@@ -1,17 +1,35 @@
This is the source code of the MMDVM firmware that supports D-Star, DMR, This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, POCSAG, and FM modes.
System Fusion, P25, NXDN, POCSAG, and FM modes.
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx It runs on the Arduino Due, the ST-Micro STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3, M4, or M7 processors with a minimum clock speed greater of 80 MHz, and access to at least one analogue to digital converter, one digital to analogue converter, as well as a number of GPIO pins.
processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in
common is the use of an ARM Cortex-M3, M4, or M7 processors with a clock speed
greater than 70 MHz, and access to at least one analogue to digital converter
and one digital to analogue converter.
In order to build this software for the Arduino Due, you will need to edit a In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is supplied via the ARM GCC compiler. The Teensy support uses Teensyduino.
file within the Arduino GUI and that is detailed in the BUILD.txt file. The
STM32 support is being supplied via the ARM GCC compiler. The Teensy support
uses Teensyduino.
This software is licenced under the GPL v2 and is intended for amateur and This software is licenced under the GPL v2 and is primarily intended for amateur and educational use.
educational use only. Use of this software for commercial purposes is strictly
forbidden. Portions of the ARM support code include the following copyright:
Copyright (c) 2011 - 2013 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-102
View File
@@ -1,102 +0,0 @@
/*
TX fifo control - Copyright (C) KI6ZUM 2015
Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "RSSIRB.h"
CRSSIRB::CRSSIRB(uint16_t length) :
m_length(length),
m_head(0U),
m_tail(0U),
m_full(false),
m_overflow(false)
{
m_rssi = new uint16_t[length];
}
uint16_t CRSSIRB::getSpace() const
{
uint16_t n = 0U;
if (m_tail == m_head)
n = m_full ? 0U : m_length;
else if (m_tail < m_head)
n = m_length - m_head + m_tail;
else
n = m_tail - m_head;
if (n > m_length)
n = 0U;
return n;
}
uint16_t CRSSIRB::getData() const
{
if (m_tail == m_head)
return m_full ? m_length : 0U;
else if (m_tail < m_head)
return m_head - m_tail;
else
return m_length - m_tail + m_head;
}
bool CRSSIRB::put(uint16_t rssi)
{
if (m_full) {
m_overflow = true;
return false;
}
m_rssi[m_head] = rssi;
m_head++;
if (m_head >= m_length)
m_head = 0U;
if (m_head == m_tail)
m_full = true;
return true;
}
bool CRSSIRB::get(uint16_t& rssi)
{
if (m_head == m_tail && !m_full)
return false;
rssi = m_rssi[m_tail];
m_full = false;
m_tail++;
if (m_tail >= m_length)
m_tail = 0U;
return true;
}
bool CRSSIRB::hasOverflowed()
{
bool overflow = m_overflow;
m_overflow = false;
return overflow;
}
-59
View File
@@ -1,59 +0,0 @@
/*
Serial fifo control - Copyright (C) KI6ZUM 2015
Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#if !defined(RSSIRB_H)
#define RSSIRB_H
#if defined(STM32F4XX)
#include "stm32f4xx.h"
#elif defined(STM32F7XX)
#include "stm32f7xx.h"
#elif defined(STM32F105xC)
#include "stm32f1xx.h"
#include <cstddef>
#else
#include <Arduino.h>
#endif
class CRSSIRB {
public:
CRSSIRB(uint16_t length);
uint16_t getSpace() const;
uint16_t getData() const;
bool put(uint16_t rssi);
bool get(uint16_t& rssi);
bool hasOverflowed();
private:
uint16_t m_length;
volatile uint16_t* m_rssi;
volatile uint16_t m_head;
volatile uint16_t m_tail;
volatile bool m_full;
bool m_overflow;
};
#endif
-47
View File
@@ -1,47 +0,0 @@
/*
* Copyright (C) 2017 Wojciech Krutnik N0CALL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* FIFO ring buffer
* source:
* http://stackoverflow.com/questions/6822548/correct-way-of-implementing-a-uart-receive-buffer-in-a-small-arm-microcontroller
* (modified)
*
*/
#if !defined(RINGBUFF_H)
#define RINGBUFF_H
#define RINGBUFF_SIZE(ringBuff) (ringBuff.size) /* serial buffer in bytes (power 2) */
#define RINGBUFF_MASK(ringBuff) (ringBuff.size-1U) /* buffer size mask */
/* Buffer read / write macros */
#define RINGBUFF_RESET(ringBuff) (ringBuff).rdIdx = ringBuff.wrIdx = 0
#define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn)
#define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)])
#define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx)
#define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringFifo.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringFifo.wrIdx))
#define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx))
/* Buffer type */
#define DECLARE_RINGBUFFER_TYPE(name, _size) \
typedef struct{ \
uint32_t size; \
uint32_t wrIdx; \
uint32_t rdIdx; \
uint8_t data[_size]; \
}name##_t
#endif
+23 -17
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2020 by Jonathan Naylor G4KLX * Copyright (C) 2020,2026 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
* *
* 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
@@ -16,21 +17,19 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if !defined(FMDOWNSAMPLERB_H) #if !defined(RINGBUFFER_H)
#define FMDOWNSAMPLERB_H #define RINGBUFFER_H
#if defined(STM32F4XX) #if defined(STM32F4XX)
#include "stm32f4xx.h" #include "stm32f4xx.h"
#elif defined(STM32F7XX) #elif defined(STM32F7XX)
#include "stm32f7xx.h" #include "stm32f7xx.h"
#elif defined(STM32F105xC)
#include "stm32f1xx.h"
#include <cstddef>
#else #else
#include <Arduino.h> #include <Arduino.h>
#undef PI
#endif #endif
#if defined(__SAM3X8E__) || defined(STM32F105xC) #if defined(__SAM3X8E__)
#define ARM_MATH_CM3 #define ARM_MATH_CM3
#elif defined(STM32F7XX) #elif defined(STM32F7XX)
#define ARM_MATH_CM7 #define ARM_MATH_CM7
@@ -42,27 +41,34 @@
#include <arm_math.h> #include <arm_math.h>
class CFMDownsampleRB { template <typename TDATATYPE>
class CRingBuffer {
public: public:
CFMDownsampleRB(uint16_t length); CRingBuffer(uint16_t length = 370U);
uint16_t getSpace() const; uint16_t getSpace() const;
uint16_t getData() const; uint16_t getData() const;
bool put(uint8_t sample); bool put(const TDATATYPE& item) volatile;
bool get(uint8_t& sample); bool get(TDATATYPE& item) volatile;
TDATATYPE peek() const;
bool hasOverflowed(); bool hasOverflowed();
void reset();
private: private:
uint16_t m_length; uint16_t m_length;
volatile uint8_t* m_samples; TDATATYPE* m_buffer;
volatile uint16_t m_head; volatile uint16_t m_head;
volatile uint16_t m_tail; volatile uint16_t m_tail;
volatile bool m_full; volatile bool m_full;
bool m_overflow; bool m_overflow;
}; };
#include "RingBuffer.impl.h"
#endif #endif
+25 -12
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2020 by Jonathan Naylor G4KLX * Copyright (C) 2020,2026 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
* *
* 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
@@ -16,20 +17,19 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "RingBuffer.h"
#include "FMDownsampleRB.h" template <typename TDATATYPE> CRingBuffer<TDATATYPE>::CRingBuffer(uint16_t length) :
CFMDownsampleRB::CFMDownsampleRB(uint16_t length) :
m_length(length), m_length(length),
m_head(0U), m_head(0U),
m_tail(0U), m_tail(0U),
m_full(false), m_full(false),
m_overflow(false) m_overflow(false)
{ {
m_samples = new uint8_t[length]; m_buffer = new TDATATYPE[length];
} }
uint16_t CFMDownsampleRB::getSpace() const template <typename TDATATYPE> uint16_t CRingBuffer<TDATATYPE>::getSpace() const
{ {
uint16_t n = 0U; uint16_t n = 0U;
@@ -46,7 +46,7 @@ uint16_t CFMDownsampleRB::getSpace() const
return n; return n;
} }
uint16_t CFMDownsampleRB::getData() const template <typename TDATATYPE> uint16_t CRingBuffer<TDATATYPE>::getData() const
{ {
if (m_tail == m_head) if (m_tail == m_head)
return m_full ? m_length : 0U; return m_full ? m_length : 0U;
@@ -56,14 +56,14 @@ uint16_t CFMDownsampleRB::getData() const
return m_length - m_tail + m_head; return m_length - m_tail + m_head;
} }
bool CFMDownsampleRB::put(uint8_t sample) template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::put(const TDATATYPE& item) volatile
{ {
if (m_full) { if (m_full) {
m_overflow = true; m_overflow = true;
return false; return false;
} }
m_samples[m_head] = sample; m_buffer[m_head] = item;
m_head++; m_head++;
if (m_head >= m_length) if (m_head >= m_length)
@@ -75,12 +75,17 @@ bool CFMDownsampleRB::put(uint8_t sample)
return true; return true;
} }
bool CFMDownsampleRB::get(uint8_t& sample) template <typename TDATATYPE> TDATATYPE CRingBuffer<TDATATYPE>::peek() const
{
return m_buffer[m_tail];
}
template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::get(TDATATYPE& item) volatile
{ {
if (m_head == m_tail && !m_full) if (m_head == m_tail && !m_full)
return false; return false;
sample = m_samples[m_tail]; item = m_buffer[m_tail];
m_full = false; m_full = false;
@@ -91,7 +96,7 @@ bool CFMDownsampleRB::get(uint8_t& sample)
return true; return true;
} }
bool CFMDownsampleRB::hasOverflowed() template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::hasOverflowed()
{ {
bool overflow = m_overflow; bool overflow = m_overflow;
@@ -99,3 +104,11 @@ bool CFMDownsampleRB::hasOverflowed()
return overflow; return overflow;
} }
template <typename TDATATYPE> void CRingBuffer<TDATATYPE>::reset()
{
m_head = 0U;
m_tail = 0U;
m_full = false;
m_overflow = false;
}
Submodule STM32F10X_Lib deleted from 417e0c2f4a

Some files were not shown because too many files have changed in this diff Show More