├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── COPYING ├── CWIdTX.cpp ├── CWIdTX.h ├── CalRSSI.cpp ├── CalRSSI.h ├── Debug.h ├── Defines.h ├── FirmwareMain.cpp ├── Globals.h ├── IO.cpp ├── IO.h ├── IODue.cpp ├── IOSTM.cpp ├── LICENSE ├── LICENSE.md ├── Makefile ├── Makefile.NATIVE_SDR ├── Makefile.SAM3X8_DUE ├── Makefile.STM32F4 ├── Makefile.STM32F4_DVMV1 ├── Makefile.STM32F4_EDA ├── Makefile.STM32F4_POG ├── Makefile.STM32F7 ├── README.md ├── RSSIBuffer.cpp ├── RSSIBuffer.h ├── RingBuffer.h ├── STM_UART.cpp ├── STM_UART.h ├── SampleBuffer.cpp ├── SampleBuffer.h ├── SerialBuffer.cpp ├── SerialBuffer.h ├── SerialDue.cpp ├── SerialPort.cpp ├── SerialPort.h ├── SerialSTM.cpp ├── Utils.cpp ├── Utils.h ├── dmr ├── CalDMR.cpp ├── CalDMR.h ├── DMRDMORX.cpp ├── DMRDMORX.h ├── DMRDMOTX.cpp ├── DMRDMOTX.h ├── DMRDefines.h ├── DMRIdleRX.cpp ├── DMRIdleRX.h ├── DMRRX.cpp ├── DMRRX.h ├── DMRSlotRX.cpp ├── DMRSlotRX.h ├── DMRSlotType.cpp ├── DMRSlotType.h ├── DMRTX.cpp └── DMRTX.h ├── nxdn ├── CalNXDN.cpp ├── CalNXDN.h ├── NXDNDefines.h ├── NXDNRX.cpp ├── NXDNRX.h ├── NXDNTX.cpp └── NXDNTX.h ├── p25 ├── CalP25.cpp ├── CalP25.h ├── P25Defines.h ├── P25RX.cpp ├── P25RX.h ├── P25TX.cpp └── P25TX.h ├── sdr ├── IOSDR.cpp ├── Log.cpp ├── Log.h ├── SerialPortSDR.cpp ├── SerialPortSDR.h ├── SerialSDR.cpp ├── Utils.cpp ├── Utils.h ├── arm_math.cpp ├── arm_math.h └── port │ ├── ISerialPort.cpp │ ├── ISerialPort.h │ ├── PseudoPTYPort.cpp │ ├── PseudoPTYPort.h │ ├── UARTPort.cpp │ └── UARTPort.h ├── stm32f4xx_link.ld ├── stm32f4xx_link_debug.ld ├── stm32f722_link.ld ├── stm32f722_link_debug.ld ├── stm32f767_link.ld └── stm32f767_link_debug.ld /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: dvmfirmware-build 2 | 3 | # Controls when the workflow will run 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: [ master ] 8 | pull_request: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | # This workflow contains a single job called "build" 17 | build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Get branch name 21 | id: branch-name 22 | uses: tj-actions/branch-names@v7.0.7 23 | - name: Get current date 24 | id: date 25 | run: echo "::set-output name=date::$(date +'%Y-%m-%d')" 26 | 27 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | 31 | - name: Install Dependencies 32 | run: sudo apt-get install -y gcc-arm-none-eabi 33 | 34 | - name: Sync Git Submodules 35 | run: git submodule init && git submodule update 36 | 37 | - name: Build STM32F4 Firmware 38 | run: make -f Makefile.STM32F4 39 | - name: Build STM32F4_POG Firmware 40 | run: make -f Makefile.STM32F4_POG 41 | - name: Build STM32F4_EDA Firmware 42 | run: make -f Makefile.STM32F4_EDA 43 | - name: Build STM32F4_DVMV1 Firmware 44 | run: make -f Makefile.STM32F4_DVMV1 45 | 46 | - name: Firmware Hash 47 | run: | 48 | echo "BRANCH: ${{steps.branch-name.outputs.current_branch}}" >> release.txt 49 | echo "COMMIT: ${{github.sha}}" >> release.txt 50 | echo >> release.txt 51 | echo '```' >> release.txt 52 | cat << EOF >> release.txt 53 | dvm-firmware_f4.bin 54 | size : $(wc -c dvm-firmware_f4.bin) 55 | md5 : $(md5sum dvm-firmware_f4.bin) 56 | sha1 : $(sha1sum dvm-firmware_f4.bin) 57 | sha256: $(sha256sum dvm-firmware_f4.bin) 58 | 59 | dvm-firmware_f4-pog.bin 60 | size : $(wc -c dvm-firmware_f4-pog.bin) 61 | md5 : $(md5sum dvm-firmware_f4-pog.bin) 62 | sha1 : $(sha1sum dvm-firmware_f4-pog.bin) 63 | sha256: $(sha256sum dvm-firmware_f4-pog.bin) 64 | 65 | dvm-firmware_eda.bin 66 | size : $(wc -c dvm-firmware_eda.bin) 67 | md5 : $(md5sum dvm-firmware_eda.bin) 68 | sha1 : $(sha1sum dvm-firmware_eda.bin) 69 | sha256: $(sha256sum dvm-firmware_eda.bin) 70 | 71 | dvm-firmware_f4-dvmv1.bin 72 | size : $(wc -c dvm-firmware_f4-dvmv1.bin) 73 | md5 : $(md5sum dvm-firmware_f4-dvmv1.bin) 74 | sha1 : $(sha1sum dvm-firmware_f4-dvmv1.bin) 75 | sha256: $(sha256sum dvm-firmware_f4-dvmv1.bin) 76 | EOF 77 | echo '```' >> release.txt 78 | 79 | - name: Release Artifacts 80 | uses: softprops/action-gh-release@v1 81 | with: 82 | tag_name: ${{steps.date.outputs.date}} 83 | body_path: release.txt 84 | files: | 85 | dvm-firmware_f4.bin 86 | dvm-firmware_f4-pog.bin 87 | dvm-firmware_eda.bin 88 | dvm-firmware_f4-dvmv1.bin 89 | 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore thumbnails created by windows 2 | Thumbs.db 3 | 4 | # Ignore files build by Visual Studio 5 | *.obj 6 | *.pdb 7 | *.mdb # Mono debug file 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | [Oo]bj*/ 27 | #[Rr]elease*/ 28 | [R]elease*/ 29 | _ReSharper*/ 30 | [Tt]est[Rr]esult* 31 | *.sdf 32 | *.opensdf 33 | *.userprefs 34 | build.mk 35 | *.prv.xml 36 | *.pub.xml 37 | build/ 38 | .vscode/ 39 | package/ 40 | 41 | # Compiled binary files 42 | *.exe 43 | *.dll 44 | *.bin 45 | *.elf 46 | 47 | # Compiled Object files 48 | *.slo 49 | *.lo 50 | *.o 51 | *.obj 52 | 53 | # Compiled Dynamic libraries 54 | *.so 55 | *.dylib 56 | *.dll 57 | 58 | # Compiled Static libraries 59 | *.lai 60 | *.la 61 | *.a 62 | *.lib 63 | 64 | # Visual Studio 65 | .vs 66 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "STM32F4XX_Platform"] 2 | path = STM32F4XX_Platform 3 | url = https://github.com/DVMProject/STM32F4XX_Platform.git 4 | [submodule "STM32F7XX_Platform"] 5 | path = STM32F7XX_Platform 6 | url = https://github.com/DVMProject/STM32F7XX_Platform.git 7 | -------------------------------------------------------------------------------- /CWIdTX.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2009-2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2016 Colin Durbridge, G4EML 9 | * 10 | */ 11 | #include "Globals.h" 12 | #include "CWIdTX.h" 13 | 14 | // --------------------------------------------------------------------------- 15 | // Constants 16 | // --------------------------------------------------------------------------- 17 | 18 | q15_t TONE[] = { 19 | 0, 518, 1000, 1414, 1732, 1932, 2000, 1932, 1732, 1414, 1000, 518, 0, -518, -1000, 20 | -1414, -1732, -1932, -2000, -1932, -1732, -1414, -1000, -518 }; 21 | 22 | q15_t SILENCE[] = { 23 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 24 | 25 | const uint8_t CYCLE_LENGTH = 24U; 26 | 27 | const uint8_t DOT_LENGTH = 50U; 28 | 29 | const struct { 30 | uint8_t c; 31 | uint32_t pattern; 32 | uint8_t length; 33 | } SYMBOL_LIST[] = { 34 | { 'A', 0xB8000000U, 8U }, 35 | { 'B', 0xEA800000U, 12U }, 36 | { 'C', 0xEBA00000U, 14U }, 37 | { 'D', 0xEA000000U, 10U }, 38 | { 'E', 0x80000000U, 4U }, 39 | { 'F', 0xAE800000U, 12U }, 40 | { 'G', 0xEE800000U, 12U }, 41 | { 'H', 0xAA000000U, 10U }, 42 | { 'I', 0xA0000000U, 6U }, 43 | { 'J', 0xBBB80000U, 16U }, 44 | { 'K', 0xEB800000U, 12U }, 45 | { 'L', 0xBA800000U, 12U }, 46 | { 'M', 0xEE000000U, 10U }, 47 | { 'N', 0xE8000000U, 8U }, 48 | { 'O', 0xEEE00000U, 14U }, 49 | { 'P', 0xBBA00000U, 14U }, 50 | { 'Q', 0xEEB80000U, 16U }, 51 | { 'R', 0xBA000000U, 10U }, 52 | { 'S', 0xA8000000U, 8U }, 53 | { 'T', 0xE0000000U, 6U }, 54 | { 'U', 0xAE000000U, 10U }, 55 | { 'V', 0xAB800000U, 12U }, 56 | { 'W', 0xBB800000U, 12U }, 57 | { 'X', 0xEAE00000U, 14U }, 58 | { 'Y', 0xEBB80000U, 16U }, 59 | { 'Z', 0xEEA00000U, 14U }, 60 | { '1', 0xBBBB8000U, 20U }, 61 | { '2', 0xAEEE0000U, 18U }, 62 | { '3', 0xABB80000U, 16U }, 63 | { '4', 0xAAE00000U, 14U }, 64 | { '5', 0xAA800000U, 12U }, 65 | { '6', 0xEAA00000U, 14U }, 66 | { '7', 0xEEA80000U, 16U }, 67 | { '8', 0xEEEA0000U, 18U }, 68 | { '9', 0xEEEE8000U, 20U }, 69 | { '0', 0xEEEEE000U, 22U }, 70 | { '/', 0xEAE80000U, 16U }, 71 | { '?', 0xAEEA0000U, 18U }, 72 | { ',', 0xEEAEE000U, 22U }, 73 | { '-', 0xEAAE0000U, 18U }, 74 | { '=', 0xEAB80000U, 16U }, 75 | { ' ', 0x00000000U, 4U }, 76 | { 0U, 0x00000000U, 0U } 77 | }; 78 | 79 | // --------------------------------------------------------------------------- 80 | // Public Class Members 81 | // --------------------------------------------------------------------------- 82 | 83 | /* Initializes a new instance of the CWIdTX class. */ 84 | 85 | CWIdTX::CWIdTX() : 86 | m_poBuffer(), 87 | m_poLen(0U), 88 | m_poPtr(0U), 89 | m_n(0U) 90 | { 91 | /* stub */ 92 | } 93 | 94 | /* Process local buffer and transmit on the air interface. */ 95 | 96 | void CWIdTX::process() 97 | { 98 | if (m_poLen == 0U) 99 | return; 100 | 101 | uint16_t space = io.getSpace(); 102 | 103 | while (space > CYCLE_LENGTH) { 104 | bool b = _READ_BIT(m_poBuffer, m_poPtr); 105 | if (b) 106 | io.write(STATE_CW, TONE, CYCLE_LENGTH); 107 | else 108 | io.write(STATE_CW, SILENCE, CYCLE_LENGTH); 109 | 110 | space -= CYCLE_LENGTH; 111 | 112 | m_n++; 113 | if (m_n >= DOT_LENGTH) { 114 | m_poPtr++; 115 | m_n = 0U; 116 | } 117 | 118 | if (m_poPtr >= m_poLen) { 119 | m_poPtr = 0U; 120 | m_poLen = 0U; 121 | return; 122 | } 123 | } 124 | } 125 | 126 | /* Write CW ID data to the local buffer. */ 127 | 128 | uint8_t CWIdTX::write(const uint8_t* data, uint8_t length) 129 | { 130 | ::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t)); 131 | 132 | m_poLen = 8U; 133 | m_poPtr = 0U; 134 | m_n = 0U; 135 | 136 | for (uint8_t i = 0U; i < length; i++) { 137 | for (uint8_t j = 0U; SYMBOL_LIST[j].c != 0U; j++) { 138 | if (SYMBOL_LIST[j].c == data[i]) { 139 | uint32_t MASK = 0x80000000U; 140 | for (uint8_t k = 0U; k < SYMBOL_LIST[j].length; k++, m_poLen++, MASK >>= 1) { 141 | bool b = (SYMBOL_LIST[j].pattern & MASK) == MASK; 142 | _WRITE_BIT(m_poBuffer, m_poLen, b); 143 | 144 | if (m_poLen >= 995U) { 145 | m_poLen = 0U; 146 | return 4U; 147 | } 148 | } 149 | 150 | break; 151 | } 152 | } 153 | } 154 | 155 | // An empty message 156 | if (m_poLen == 8U) { 157 | m_poLen = 0U; 158 | return RSN_ILLEGAL_LENGTH; 159 | } 160 | 161 | m_poLen += 5U; 162 | 163 | DEBUG2("CWIdTx::write() message length", m_poLen); 164 | 165 | return RSN_OK; 166 | } 167 | 168 | /* Helper to reset data values to defaults. */ 169 | 170 | void CWIdTX::reset() 171 | { 172 | m_poLen = 0U; 173 | m_poPtr = 0U; 174 | m_n = 0U; 175 | } 176 | -------------------------------------------------------------------------------- /CWIdTX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * @package DVM / Modem Firmware 8 | * @derivedfrom MMDVM (https://github.com/g4klx/MMDVM) 9 | * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) 10 | * 11 | * Copyright (C) 2009-2015 Jonathan Naylor, G4KLX 12 | * Copyright (C) 2016 Colin Durbridge, G4EML 13 | * 14 | */ 15 | /** 16 | * @file CWIdTX.h 17 | * @ingroup modem_fw 18 | * @file CWIdTX.cpp 19 | * @ingroup modem_fw 20 | */ 21 | #if !defined(__CWID_TX_H__) 22 | #define __CWID_TX_H__ 23 | 24 | #include "Defines.h" 25 | 26 | // --------------------------------------------------------------------------- 27 | // Class Declaration 28 | // --------------------------------------------------------------------------- 29 | 30 | /** 31 | * @brief Implements logic to transmit a CW ID. 32 | * @ingroup modem_fw 33 | */ 34 | class DSP_FW_API CWIdTX { 35 | public: 36 | /** 37 | * @brief Initializes a new instance of the CWIdTX class. 38 | */ 39 | CWIdTX(); 40 | 41 | /** 42 | * @brief Process local buffer and transmit on the air interface. 43 | */ 44 | void process(); 45 | 46 | /** 47 | * @brief Write CW ID data to the local buffer. 48 | * @param[in] data Buffer. 49 | * @param length Length of buffer. 50 | * @returns uint8_t Reason code. 51 | */ 52 | uint8_t write(const uint8_t* data, uint8_t length); 53 | 54 | /** 55 | * @brief Helper to reset data values to defaults. 56 | */ 57 | void reset(); 58 | 59 | private: 60 | uint8_t m_poBuffer[1000U]; 61 | uint16_t m_poLen; 62 | uint16_t m_poPtr; 63 | 64 | uint8_t m_n; 65 | }; 66 | 67 | #endif // __CWID_TX_H__ 68 | -------------------------------------------------------------------------------- /CalRSSI.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | #include "Globals.h" 11 | #include "CalRSSI.h" 12 | #include "Utils.h" 13 | 14 | // --------------------------------------------------------------------------- 15 | // Public Class Members 16 | // --------------------------------------------------------------------------- 17 | 18 | /* Initializes a new instance of the CalRSSI class. */ 19 | 20 | CalRSSI::CalRSSI() : 21 | m_count(0U), 22 | m_accum(0U), 23 | m_min(0xFFFFU), 24 | m_max(0x0000U) 25 | { 26 | /* stub */ 27 | } 28 | 29 | /* Sample RSSI values from the air interface. */ 30 | 31 | void CalRSSI::samples(const uint16_t* rssi, uint8_t length) 32 | { 33 | for (uint16_t i = 0U; i < length; i++) { 34 | uint16_t ss = rssi[i]; 35 | 36 | m_accum += ss; 37 | 38 | if (ss > m_max) 39 | m_max = ss; 40 | if (ss < m_min) 41 | m_min = ss; 42 | 43 | m_count++; 44 | if (m_count >= 24000U) { 45 | uint16_t ave = m_accum / m_count; 46 | 47 | uint8_t buffer[6U]; 48 | buffer[0U] = (m_max >> 8) & 0xFFU; 49 | buffer[1U] = (m_max >> 0) & 0xFFU; 50 | buffer[2U] = (m_min >> 8) & 0xFFU; 51 | buffer[3U] = (m_min >> 0) & 0xFFU; 52 | buffer[4U] = (ave >> 8) & 0xFFU; 53 | buffer[5U] = (ave >> 0) & 0xFFU; 54 | 55 | serial.writeRSSIData(buffer, 6U); 56 | 57 | m_count = 0U; 58 | m_accum = 0U; 59 | m_min = 0xFFFFU; 60 | m_max = 0x0000U; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /CalRSSI.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file CalRSSI.h 12 | * @ingroup modem_fw 13 | * @file CalRSSI.cpp 14 | * @ingroup modem_fw 15 | */ 16 | #if !defined(__CAL_RSSI_H__) 17 | #define __CAL_RSSI_H__ 18 | 19 | #include "Defines.h" 20 | 21 | // --------------------------------------------------------------------------- 22 | // Class Declaration 23 | // --------------------------------------------------------------------------- 24 | 25 | /** 26 | * @brief Implements logic for RSSI calibration mode. 27 | * @ingroup modem_fw 28 | */ 29 | class DSP_FW_API CalRSSI { 30 | public: 31 | /** 32 | * @brief Initializes a new instance of the CalRSSI class. 33 | */ 34 | CalRSSI(); 35 | 36 | /** 37 | * @brief Sample RSSI values from the air interface. 38 | * @param rssi 39 | * @param length 40 | */ 41 | void samples(const uint16_t* rssi, uint8_t length); 42 | 43 | private: 44 | uint32_t m_count; 45 | uint32_t m_accum; 46 | uint16_t m_min; 47 | uint16_t m_max; 48 | }; 49 | 50 | #endif // __CAL_RSSI_H__ 51 | -------------------------------------------------------------------------------- /Debug.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file Debug.h 12 | * @ingroup modem_fw 13 | */ 14 | #if !defined(__DEBUG_H__) 15 | #define __DEBUG_H__ 16 | 17 | #include "Globals.h" 18 | 19 | // --------------------------------------------------------------------------- 20 | // Macros 21 | // --------------------------------------------------------------------------- 22 | 23 | #define DEBUG1(a) serial.writeDebug((a)) 24 | #define DEBUG2(a,b) serial.writeDebug((a),(b)) 25 | #define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c)) 26 | #define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d)) 27 | #define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e)) 28 | 29 | #endif // __DEBUG_H__ 30 | -------------------------------------------------------------------------------- /Defines.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2018,2025 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @file Defines.h 13 | * @ingroup modem_fw 14 | */ 15 | #if !defined(__DEFINES_H__) 16 | #define __DEFINES_H__ 17 | 18 | #include 19 | 20 | 21 | 22 | #if !defined(NATIVE_SDR) 23 | #if defined(__SAM3X8E__) && !defined(STM32F4XX) 24 | #define ARM_MATH_CM3 25 | #elif defined(STM32F4XX) 26 | #define ARM_MATH_CM4 27 | #elif defined(STM32F7XX) 28 | #define ARM_MATH_CM7 29 | #else 30 | #error "Unknown processor type" 31 | #endif 32 | #else 33 | #include 34 | #endif 35 | 36 | #if !defined(NATIVE_SDR) 37 | #include 38 | #else 39 | #include "sdr/arm_math.h" 40 | #endif 41 | 42 | // --------------------------------------------------------------------------- 43 | // Types 44 | // --------------------------------------------------------------------------- 45 | 46 | #ifndef _INT8_T_DECLARED 47 | #ifndef __INT8_TYPE__ 48 | typedef signed char int8_t; 49 | #endif // __INT8_TYPE__ 50 | #endif // _INT8_T_DECLARED 51 | #ifndef _INT16_T_DECLARED 52 | #ifndef __INT16_TYPE__ 53 | typedef short int16_t; 54 | #endif // __INT16_TYPE__ 55 | #endif // _INT16_T_DECLARED 56 | #ifndef _INT32_T_DECLARED 57 | #ifndef __INT32_TYPE__ 58 | typedef int int32_t; 59 | #endif // __INT32_TYPE__ 60 | #endif // _INT32_T_DECLARED 61 | #ifndef _INT64_T_DECLARED 62 | #ifndef __INT64_TYPE__ 63 | typedef long long int64_t; 64 | #endif // __INT64_TYPE__ 65 | #endif // _INT64_T_DECLARED 66 | #ifndef _UINT8_T_DECLARED 67 | #ifndef __UINT8_TYPE__ 68 | typedef unsigned char uint8_t; 69 | #endif // __UINT8_TYPE__ 70 | #endif // _UINT8_T_DECLARED 71 | #ifndef _UINT16_T_DECLARED 72 | #ifndef __UINT16_TYPE__ 73 | typedef unsigned short uint16_t; 74 | #endif // __UINT16_TYPE__ 75 | #endif // _UINT16_T_DECLARED 76 | #ifndef _UINT32_T_DECLARED 77 | #ifndef __UINT32_TYPE__ 78 | typedef unsigned int uint32_t; 79 | #endif // __UINT32_TYPE__ 80 | #endif // _UINT32_T_DECLARED 81 | #ifndef _UINT64_T_DECLARED 82 | #ifndef __UINT64_TYPE__ 83 | typedef unsigned long long uint64_t; 84 | #endif // __UINT64_TYPE__ 85 | #endif // _UINT64_T_DECLARED 86 | 87 | #ifndef __LONG64_TYPE__ 88 | typedef long long long64_t; 89 | #endif // __LONG64_TYPE__ 90 | #ifndef __ULONG64_TYPE__ 91 | typedef unsigned long long ulong64_t; 92 | #endif // __ULONG64_TYPE__ 93 | 94 | // --------------------------------------------------------------------------- 95 | // Constants 96 | // --------------------------------------------------------------------------- 97 | 98 | #define __PROG_NAME__ "Digital Voice Modem DSP" 99 | #define __NET_NAME__ "DVM_DMR_P25" 100 | #define __EXE_NAME__ "dvm-firmware" 101 | #define __BUILD__ __DATE__ " " __TIME__ 102 | 103 | #define DSP_FW_API 104 | 105 | // Normal Boxcar Filter for P25 106 | //#define P25_RX_NORMAL_BOXCAR 107 | 108 | // Narrow Boxcar Filter for P25 109 | #define P25_RX_NARROW_BOXCAR 110 | 111 | // Boxcar Filter for NXDN 112 | //#define NXDN_BOXCAR_FILTER 113 | 114 | // Alternate P25 Symbol Levels 115 | //#define P25_ALTERNATE_SYM_LEVELS 116 | 117 | // Allow for the use of high quality external clock oscillators 118 | // The number is the frequency of the oscillator in Hertz. 119 | // 120 | // The frequency of the TCXO must be an integer multiple of 48000. 121 | // Frequencies such as 12.0 Mhz (48000 * 250) and 14.4 Mhz (48000 * 300) are suitable. 122 | // Frequencies such as 10.0 Mhz (48000 * 208.333) or 20 Mhz (48000 * 416.666) are not suitable. 123 | // 124 | #ifndef EXTERNAL_OSC 125 | #define EXTERNAL_OSC 12000000 126 | #endif 127 | 128 | // Sanity check to make sure EXTERNAL_OSC is a valid integer multiple of 48kHz 129 | #if (EXTERNAL_OSC % 48000 != 0) 130 | #error "Invalid EXTERNAL_OSC specified! Must be an integer multiple of 48000" 131 | #endif 132 | 133 | // Pass RSSI information to the host 134 | // #define SEND_RSSI_DATA 135 | 136 | #define DESCR_DMR "DMR, " 137 | #define DESCR_P25 "P25, " 138 | #define DESCR_NXDN "NXDN, " 139 | 140 | #if defined(EXTERNAL_OSC) 141 | #define DESCR_OSC "TCXO, " 142 | #else 143 | #define DESCR_OSC "" 144 | #endif 145 | 146 | #if defined(SEND_RSSI_DATA) 147 | #define DESCR_RSSI "RSSI, " 148 | #else 149 | #define DESCR_RSSI "" 150 | #endif 151 | 152 | #define DESCRIPTION __PROG_NAME__ " (" DESCR_DMR DESCR_P25 DESCR_NXDN DESCR_OSC DESCR_RSSI "CW Id)" 153 | 154 | const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; 155 | 156 | #define CPU_TYPE_ARDUINO_DUE 0x00U 157 | #define CPU_TYPE_NXP 0x01U 158 | #define CPU_TYPE_STM32 0x02U 159 | #define CPU_TYPE_NATIVE_SDR 0xF0U 160 | 161 | // --------------------------------------------------------------------------- 162 | // Macros 163 | // --------------------------------------------------------------------------- 164 | 165 | #define _WRITE_BIT(p, i, b) p[(i) >> 3] = (b) ? (p[(i) >> 3] | BIT_MASK_TABLE[(i) & 7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i) & 7]) 166 | #define _READ_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7]) 167 | 168 | #endif // __DEFINES_H__ 169 | -------------------------------------------------------------------------------- /Globals.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2017-2021 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @defgroup modem_fw Modem Firmware 13 | * @brief Digital Voice Modem - Modem Firmware 14 | * @details Firmware that is used for repeater interface boards. 15 | * @ingroup modem_fw 16 | * 17 | * @file Globals.h 18 | * @ingroup modem_fw 19 | */ 20 | #if !defined(__GLOBALS_H__) 21 | #define __GLOBALS_H__ 22 | 23 | #if !defined(NATIVE_SDR) 24 | #if defined(STM32F4XX) || defined(STM32F7XX) 25 | #if defined(STM32F4XX) 26 | #include "stm32f4xx.h" 27 | #endif // defined(STM32F4XX) 28 | #if defined(STM32F7XX) 29 | #include "stm32f7xx.h" 30 | #endif // defined(STM32F7XX) 31 | #include 32 | #else // defined(STM32F4XX) || defined(STM32F7XX) 33 | #include 34 | #endif 35 | #endif // !defined(NATIVE_SDR) 36 | 37 | #include "Defines.h" 38 | #include "SerialPort.h" 39 | #include "dmr/DMRIdleRX.h" 40 | #include "dmr/DMRDMORX.h" 41 | #include "dmr/DMRDMOTX.h" 42 | #include "dmr/DMRRX.h" 43 | #include "dmr/DMRTX.h" 44 | #include "dmr/CalDMR.h" 45 | #include "p25/P25RX.h" 46 | #include "p25/P25TX.h" 47 | #include "p25/CalP25.h" 48 | #include "nxdn/NXDNRX.h" 49 | #include "nxdn/NXDNTX.h" 50 | #include "nxdn/CalNXDN.h" 51 | #if defined(NATIVE_SDR) 52 | #include "sdr/Log.h" 53 | #include "sdr/SerialPortSDR.h" 54 | #endif 55 | #include "CalRSSI.h" 56 | #include "CWIdTX.h" 57 | #include "IO.h" 58 | 59 | #if defined(NATIVE_SDR) 60 | #include 61 | #endif 62 | 63 | // --------------------------------------------------------------------------- 64 | // Constants 65 | // --------------------------------------------------------------------------- 66 | 67 | const uint8_t MARK_SLOT1 = 0x08U; 68 | const uint8_t MARK_SLOT2 = 0x04U; 69 | const uint8_t MARK_NONE = 0x00U; 70 | 71 | const uint16_t RX_BLOCK_SIZE = 2U; 72 | 73 | const uint16_t TX_RINGBUFFER_SIZE = 500U; 74 | const uint16_t RX_RINGBUFFER_SIZE = 600U; 75 | 76 | // --------------------------------------------------------------------------- 77 | // Macros 78 | // --------------------------------------------------------------------------- 79 | 80 | #define DEBUG1(a) serial.writeDebug((a)) 81 | #define DEBUG2(a,b) serial.writeDebug((a),(b)) 82 | #define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c)) 83 | #define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d)) 84 | #define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e)) 85 | #define DEBUG_DUMP(a,b) serial.writeDump((a),(b)) 86 | 87 | // --------------------------------------------------------------------------- 88 | // Global Externs 89 | // --------------------------------------------------------------------------- 90 | 91 | extern DVM_STATE m_modemState; 92 | 93 | extern bool m_dmrEnable; 94 | extern bool m_p25Enable; 95 | extern bool m_nxdnEnable; 96 | 97 | extern bool m_dcBlockerEnable; 98 | extern bool m_cosLockoutEnable; 99 | 100 | extern bool m_duplex; 101 | 102 | extern bool m_tx; 103 | extern bool m_dcd; 104 | 105 | #if defined(NATIVE_SDR) 106 | extern SerialPortSDR serial; 107 | #else 108 | extern SerialPort serial; 109 | #endif 110 | extern IO io; 111 | 112 | /* DMR BS */ 113 | extern dmr::DMRIdleRX dmrIdleRX; 114 | extern dmr::DMRRX dmrRX; 115 | extern dmr::DMRTX dmrTX; 116 | 117 | /* DMR MS-DMO */ 118 | extern dmr::DMRDMORX dmrDMORX; 119 | extern dmr::DMRDMOTX dmrDMOTX; 120 | 121 | /* P25 BS */ 122 | extern p25::P25RX p25RX; 123 | extern p25::P25TX p25TX; 124 | 125 | /* NXDN BS */ 126 | extern nxdn::NXDNRX nxdnRX; 127 | extern nxdn::NXDNTX nxdnTX; 128 | 129 | /* Calibration */ 130 | extern dmr::CalDMR calDMR; 131 | extern p25::CalP25 calP25; 132 | extern nxdn::CalNXDN calNXDN; 133 | extern CalRSSI calRSSI; 134 | 135 | /* CW */ 136 | extern CWIdTX cwIdTX; 137 | 138 | #if defined(NATIVE_SDR) 139 | /* Native SDR */ 140 | extern std::string m_zmqRx; 141 | extern std::string m_zmqTx; 142 | extern std::string m_ptyPort; 143 | extern bool g_debug; 144 | #endif 145 | 146 | #endif // __GLOBALS_H__ 147 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make 2 | 3 | default: 4 | @echo Use the appropriate platform specific Makefile: Makefile.SAM3X8_DUE, Makefile.STM32F4, Makefile.STM32F4_POG, Makefile.STM32F4_EDA, Makefile.STM32F4_DVMV1. 5 | 6 | clean: 7 | $(MAKE) -f Makefile.SAM3X8_DUE clean 8 | $(MAKE) -f Makefile.STM32F4 clean 9 | $(MAKE) -f Makefile.STM32F4_POG clean 10 | $(MAKE) -f Makefile.STM32F4_EDA clean 11 | $(MAKE) -f Makefile.STM32F4_DVMV1 clean 12 | $(MAKE) -f Makefile.STM32F7 clean 13 | $(MAKE) -f Makefile.NATIVE_SDR clean 14 | 15 | .FORCE: 16 | -------------------------------------------------------------------------------- /Makefile.NATIVE_SDR: -------------------------------------------------------------------------------- 1 | # MCU external clock frequency (Hz) 2 | OSC=12000000 3 | 4 | # Directory Structure 5 | BINDIR=. 6 | OBJDIR_SDR=obj_sdr 7 | 8 | # Output files 9 | BINELF_SDR=dvm-firmware_sdr 10 | 11 | # GNU Toolchain 12 | CC=gcc 13 | CXX=g++ 14 | LD=ld 15 | AR=ar 16 | AS=as 17 | CP=objcopy 18 | OD=objdump 19 | NM=nm 20 | SIZE=size 21 | A2L=addr2line 22 | 23 | # Build object lists 24 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) $(wildcard ./sdr/*.cpp) $(wildcard ./sdr/port/*.cpp) 25 | OBJ_SDR=$(CXXSRC:./%.cpp=$(OBJDIR_SDR)/%.o) 26 | 27 | # Compile flags 28 | DEFS_PI=-DNATIVE_SDR -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 29 | 30 | # Common flags 31 | CFLAGS=-g -O3 -Wall -std=c++0x -pthread -I. 32 | CXXFLAGS=-g -O3 -Wall -std=c++0x -pthread -I. 33 | LIBS=-lpthread -lzmq -lutil 34 | LDFLAGS=-g 35 | 36 | # Build Rules 37 | .PHONY: all sdr clean 38 | 39 | all: sdr 40 | 41 | sdr: CFLAGS+=$(DEFS_PI) 42 | sdr: CXXFLAGS+=$(DEFS_PI) 43 | sdr: $(BINDIR) 44 | sdr: $(OBJDIR_SDR) 45 | sdr: $(BINDIR)/$(BINELF_SDR) 46 | 47 | $(BINDIR): 48 | mkdir $@ 49 | $(OBJDIR_SDR): 50 | mkdir $@ 51 | mkdir $@/dmr 52 | mkdir $@/p25 53 | mkdir $@/nxdn 54 | mkdir $@/sdr 55 | mkdir $@/sdr/port 56 | 57 | $(BINDIR)/$(BINELF_SDR): $(OBJ_SDR) 58 | $(CXX) $(OBJ_SDR) $(LDFLAGS) $(LIBS) -o $@ 59 | $(SIZE) $(BINDIR)/$(BINELF_SDR) 60 | 61 | $(OBJDIR_SDR)/%.o: ./%.cpp 62 | $(CXX) $(CXXFLAGS) -c -o $@ $< 63 | 64 | clean-objs: 65 | test ! -d $(OBJDIR_SDR) || rm -rf $(OBJDIR_SDR) 66 | clean: 67 | test ! -d $(OBJDIR_SDR) || rm -rf $(OBJDIR_SDR) 68 | rm -f $(BINDIR)/$(BINELF_SDR) 69 | -------------------------------------------------------------------------------- /Makefile.STM32F4: -------------------------------------------------------------------------------- 1 | # STM32 library paths 2 | F4_LIB_PATH=./STM32F4XX_Platform 3 | 4 | # MCU external clock frequency (Hz) 5 | OSC=12000000 6 | 7 | # Directory Structure 8 | BINDIR=. 9 | OBJDIR_F4=obj_f4 10 | 11 | # Output files 12 | BINELF_F4=dvm-firmware_f4.elf 13 | BINBIN_F4=dvm-firmware_f4.bin 14 | 15 | # Header directories 16 | INC_F4=. $(F4_LIB_PATH)/CMSIS/Include/ $(F4_LIB_PATH)/Device/ $(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/include/ 17 | INCLUDES_F4=$(INC_F4:%=-I%) 18 | 19 | # CMSIS libraries 20 | INCLUDES_LIBS_F4=$(F4_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a 21 | 22 | # STM32F4 Standard Peripheral Libraries source path 23 | STD_LIB_F4=$(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/source 24 | 25 | # STM32F4 system source path 26 | SYS_DIR_F4=$(F4_LIB_PATH)/Device 27 | STARTUP_DIR_F4=$(F4_LIB_PATH)/Device/startup 28 | 29 | # GNU ARM Embedded Toolchain 30 | CC=arm-none-eabi-gcc 31 | CXX=arm-none-eabi-g++ 32 | LD=arm-none-eabi-ld 33 | AR=arm-none-eabi-ar 34 | AS=arm-none-eabi-as 35 | CP=arm-none-eabi-objcopy 36 | OD=arm-none-eabi-objdump 37 | NM=arm-none-eabi-nm 38 | SIZE=arm-none-eabi-size 39 | A2L=arm-none-eabi-addr2line 40 | 41 | # Build object lists 42 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) 43 | CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c) 44 | SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c) 45 | STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c) 46 | OBJ_F4=$(CXXSRC:./%.cpp=$(OBJDIR_F4)/%.o) $(CSRC_STD_F4:$(STD_LIB_F4)/%.c=$(OBJDIR_F4)/%.o) $(SYS_F4:$(SYS_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) $(STARTUP_F4:$(STARTUP_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) 47 | 48 | # MCU flags 49 | MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork 50 | 51 | # Compile flags 52 | DEFS_PI=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 53 | 54 | # Build compiler flags 55 | CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 56 | CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 57 | 58 | # Linker flags 59 | LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 60 | LDFLAGS_F4_D =-T stm32f4xx_link_debug.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 61 | 62 | # Common flags 63 | CFLAGS=-Os -g -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS 64 | CXXFLAGS=-Os -g -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -Wall -DCUSTOM_NEW -DNO_EXCEPTIONS 65 | LDFLAGS=-Os -g --specs=nano.specs 66 | 67 | # Build Rules 68 | .PHONY: all f4 f4-debug clean 69 | 70 | all: f4 71 | 72 | f4: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 73 | f4: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 74 | f4: LDFLAGS+=$(LDFLAGS_F4) 75 | f4: $(BINDIR) 76 | f4: $(OBJDIR_F4) 77 | f4: $(BINDIR)/$(BINBIN_F4) 78 | 79 | f4-debug: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 80 | f4-debug: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 81 | f4-debug: LDFLAGS+=$(LDFLAGS_F4) 82 | f4-debug: $(BINDIR) 83 | f4-debug: $(OBJDIR_F4) 84 | f4-debug: $(BINDIR)/$(BINBIN_F4) 85 | 86 | $(BINDIR): 87 | mkdir $@ 88 | $(OBJDIR_F4): 89 | mkdir $@ 90 | mkdir $@/dmr 91 | mkdir $@/p25 92 | mkdir $@/nxdn 93 | 94 | $(BINDIR)/$(BINBIN_F4): $(BINDIR)/$(BINELF_F4) 95 | $(CP) -O binary $< $@ 96 | $(BINDIR)/$(BINELF_F4): $(OBJ_F4) 97 | $(CXX) $(OBJ_F4) $(LDFLAGS) -o $@ 98 | $(SIZE) $(BINDIR)/$(BINELF_F4) 99 | 100 | $(OBJDIR_F4)/%.o: ./%.cpp 101 | $(CXX) $(CXXFLAGS) $< -o $@ 102 | $(OBJDIR_F4)/%.o: $(STD_LIB_F4)/%.c 103 | $(CC) $(CFLAGS) $< -o $@ 104 | $(OBJDIR_F4)/%.o: $(SYS_DIR_F4)/%.c 105 | $(CC) $(CFLAGS) $< -o $@ 106 | $(OBJDIR_F4)/%.o: $(STARTUP_DIR_F4)/%.c 107 | $(CC) $(CFLAGS) $< -o $@ 108 | 109 | clean-objs: 110 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 111 | clean: 112 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 113 | rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf 114 | -------------------------------------------------------------------------------- /Makefile.STM32F4_DVMV1: -------------------------------------------------------------------------------- 1 | # STM32 library paths 2 | F4_LIB_PATH=./STM32F4XX_Platform 3 | 4 | # MCU external clock frequency (Hz) 5 | OSC=8000000 6 | 7 | # Directory Structure 8 | BINDIR=. 9 | OBJDIR_F4=obj_f4-dvmv1 10 | 11 | # Output files 12 | BINELF_F4=dvm-firmware_f4-dvmv1.elf 13 | BINBIN_F4=dvm-firmware_f4-dvmv1.bin 14 | 15 | # Header directories 16 | INC_F4=. $(F4_LIB_PATH)/CMSIS/Include/ $(F4_LIB_PATH)/Device/ $(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/include/ 17 | INCLUDES_F4=$(INC_F4:%=-I%) 18 | 19 | # CMSIS libraries 20 | INCLUDES_LIBS_F4=$(F4_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a 21 | 22 | # STM32F4 Standard Peripheral Libraries source path 23 | STD_LIB_F4=$(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/source 24 | 25 | # STM32F4 system source path 26 | SYS_DIR_F4=$(F4_LIB_PATH)/Device 27 | STARTUP_DIR_F4=$(F4_LIB_PATH)/Device/startup 28 | 29 | # GNU ARM Embedded Toolchain 30 | CC=arm-none-eabi-gcc 31 | CXX=arm-none-eabi-g++ 32 | LD=arm-none-eabi-ld 33 | AR=arm-none-eabi-ar 34 | AS=arm-none-eabi-as 35 | CP=arm-none-eabi-objcopy 36 | OD=arm-none-eabi-objdump 37 | NM=arm-none-eabi-nm 38 | SIZE=arm-none-eabi-size 39 | A2L=arm-none-eabi-addr2line 40 | 41 | # Build object lists 42 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) 43 | CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c) 44 | SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c) 45 | STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c) 46 | OBJ_F4=$(CXXSRC:./%.cpp=$(OBJDIR_F4)/%.o) $(CSRC_STD_F4:$(STD_LIB_F4)/%.c=$(OBJDIR_F4)/%.o) $(SYS_F4:$(SYS_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) $(STARTUP_F4:$(STARTUP_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) 47 | 48 | # MCU flags 49 | MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork 50 | 51 | # Compile flags (note that the V1 uses a different ext osc frequency) 52 | DEFS_PI=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVMV1 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE -DDIGIPOT_ENABLED -DSPI_ENABLED 53 | 54 | # Build compiler flags 55 | CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 56 | CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 57 | 58 | # Linker flags 59 | LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 60 | LDFLAGS_F4_D =-T stm32f4xx_link_debug.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 61 | 62 | # Debug Symbols 63 | CFLAGS_F4 += -ggdb 64 | CXXFLAGS_F4 += -ggdb 65 | LDFLAGS_F4 += -ggdb 66 | 67 | # Common flags 68 | CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS 69 | CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -Wall -DCUSTOM_NEW -DNO_EXCEPTIONS 70 | LDFLAGS=-Os --specs=nano.specs 71 | 72 | # Build Rules 73 | .PHONY: all f4 f4-debug clean 74 | 75 | all: f4 76 | 77 | f4: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 78 | f4: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 79 | f4: LDFLAGS+=$(LDFLAGS_F4) 80 | f4: $(BINDIR) 81 | f4: $(OBJDIR_F4) 82 | f4: $(BINDIR)/$(BINBIN_F4) 83 | 84 | f4-debug: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 85 | f4-debug: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 86 | f4-debug: LDFLAGS+=$(LDFLAGS_F4) 87 | f4-debug: $(BINDIR) 88 | f4-debug: $(OBJDIR_F4) 89 | f4-debug: $(BINDIR)/$(BINBIN_F4) 90 | 91 | $(BINDIR): 92 | mkdir $@ 93 | $(OBJDIR_F4): 94 | mkdir $@ 95 | mkdir $@/dmr 96 | mkdir $@/p25 97 | mkdir $@/nxdn 98 | 99 | $(BINDIR)/$(BINBIN_F4): $(BINDIR)/$(BINELF_F4) 100 | $(CP) -O binary $< $@ 101 | $(BINDIR)/$(BINELF_F4): $(OBJ_F4) 102 | $(CXX) $(OBJ_F4) $(LDFLAGS) -o $@ 103 | $(SIZE) $(BINDIR)/$(BINELF_F4) 104 | 105 | $(OBJDIR_F4)/%.o: ./%.cpp 106 | $(CXX) $(CXXFLAGS) $< -o $@ 107 | $(OBJDIR_F4)/%.o: $(STD_LIB_F4)/%.c 108 | $(CC) $(CFLAGS) $< -o $@ 109 | $(OBJDIR_F4)/%.o: $(SYS_DIR_F4)/%.c 110 | $(CC) $(CFLAGS) $< -o $@ 111 | $(OBJDIR_F4)/%.o: $(STARTUP_DIR_F4)/%.c 112 | $(CC) $(CFLAGS) $< -o $@ 113 | 114 | clean-objs: 115 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 116 | clean: 117 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 118 | rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf 119 | -------------------------------------------------------------------------------- /Makefile.STM32F4_EDA: -------------------------------------------------------------------------------- 1 | # STM32 library paths 2 | F4_LIB_PATH=./STM32F4XX_Platform 3 | 4 | # MCU external clock frequency (Hz) 5 | OSC=8000000 6 | 7 | # Directory Structure 8 | BINDIR=. 9 | OBJDIR_EDA=obj_eda 10 | 11 | # Output files 12 | BINELF_EDA=dvm-firmware_eda.elf 13 | BINBIN_EDA=dvm-firmware_eda.bin 14 | 15 | # Header directories 16 | INC_F4=. $(F4_LIB_PATH)/CMSIS/Include/ $(F4_LIB_PATH)/Device/ $(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/include/ 17 | INCLUDES_F4=$(INC_F4:%=-I%) 18 | 19 | # CMSIS libraries 20 | INCLUDES_LIBS_F4=$(F4_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a 21 | 22 | # STM32F4 Standard Peripheral Libraries source path 23 | STD_LIB_F4=$(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/source 24 | 25 | # STM32F4 system source path 26 | SYS_DIR_F4=$(F4_LIB_PATH)/Device 27 | STARTUP_DIR_F4=$(F4_LIB_PATH)/Device/startup 28 | 29 | # GNU ARM Embedded Toolchain 30 | CC=arm-none-eabi-gcc 31 | CXX=arm-none-eabi-g++ 32 | LD=arm-none-eabi-ld 33 | AR=arm-none-eabi-ar 34 | AS=arm-none-eabi-as 35 | CP=arm-none-eabi-objcopy 36 | OD=arm-none-eabi-objdump 37 | NM=arm-none-eabi-nm 38 | SIZE=arm-none-eabi-size 39 | A2L=arm-none-eabi-addr2line 40 | 41 | # Build object lists 42 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) 43 | CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c) 44 | SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c) 45 | STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c) 46 | OBJ_F4=$(CXXSRC:./%.cpp=$(OBJDIR_EDA)/%.o) $(CSRC_STD_F4:$(STD_LIB_F4)/%.c=$(OBJDIR_EDA)/%.o) $(SYS_F4:$(SYS_DIR_F4)/%.c=$(OBJDIR_EDA)/%.o) $(STARTUP_F4:$(STARTUP_DIR_F4)/%.c=$(OBJDIR_EDA)/%.o) 47 | 48 | # MCU flags 49 | MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork 50 | 51 | # Compile flags 52 | # WA0EDA F405 MTR2K, MASTR3 board: 53 | DEFS_EDA_405=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_EDA_405 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 54 | # WA0EDA F446 MTR2K, MASTR3 board: 55 | DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 56 | 57 | # Build compiler flags 58 | CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 59 | CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 60 | 61 | # Linker flags 62 | LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 63 | LDFLAGS_F4_D =-T stm32f4xx_link_debug.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 64 | 65 | # Common flags 66 | CFLAGS=-Os -g -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS 67 | CXXFLAGS=-Os -g -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -Wall -DCUSTOM_NEW -DNO_EXCEPTIONS 68 | LDFLAGS=-Os -g --specs=nano.specs 69 | 70 | # Build Rules 71 | .PHONY: all eda405 eda405-debug eda446 eda446-debug clean 72 | 73 | all: eda405 74 | 75 | eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405) 76 | eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405) 77 | eda405: LDFLAGS+=$(LDFLAGS_F4) 78 | eda405: $(BINDIR) 79 | eda405: $(OBJDIR_EDA) 80 | eda405: $(BINDIR)/$(BINBIN_EDA) 81 | 82 | eda405-debug: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405) 83 | eda405-debug: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405) 84 | eda405-debug: LDFLAGS+=$(LDFLAGS_F4_D) 85 | eda405-debug: $(BINDIR) 86 | eda405-debug: $(OBJDIR_EDA) 87 | eda405-debug: $(BINDIR)/$(BINBIN_EDA) 88 | 89 | eda446: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446) 90 | eda446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446) 91 | eda446: LDFLAGS+=$(LDFLAGS_F4) 92 | eda446: $(BINDIR) 93 | eda446: $(OBJDIR_EDA) 94 | eda446: $(BINDIR)/$(BINBIN_EDA) 95 | 96 | eda446-debug: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446) 97 | eda446-debug: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446) 98 | eda446-debug: LDFLAGS+=$(LDFLAGS_F4_D) 99 | eda446-debug: $(BINDIR) 100 | eda446-debug: $(OBJDIR_EDA) 101 | eda446-debug: $(BINDIR)/$(BINBIN_EDA) 102 | 103 | $(BINDIR): 104 | mkdir $@ 105 | $(OBJDIR_EDA): 106 | mkdir $@ 107 | mkdir $@/dmr 108 | mkdir $@/p25 109 | mkdir $@/nxdn 110 | 111 | $(BINDIR)/$(BINBIN_EDA): $(BINDIR)/$(BINELF_EDA) 112 | $(CP) -O binary $< $@ 113 | $(BINDIR)/$(BINELF_EDA): $(OBJ_F4) 114 | $(CXX) $(OBJ_F4) $(LDFLAGS) -o $@ 115 | $(SIZE) $(BINDIR)/$(BINELF_EDA) 116 | 117 | $(OBJDIR_EDA)/%.o: ./%.cpp 118 | $(CXX) $(CXXFLAGS) $< -o $@ 119 | $(OBJDIR_EDA)/%.o: $(STD_LIB_F4)/%.c 120 | $(CC) $(CFLAGS) $< -o $@ 121 | $(OBJDIR_EDA)/%.o: $(SYS_DIR_F4)/%.c 122 | $(CC) $(CFLAGS) $< -o $@ 123 | $(OBJDIR_EDA)/%.o: $(STARTUP_DIR_F4)/%.c 124 | $(CC) $(CFLAGS) $< -o $@ 125 | 126 | clean-objs: 127 | test ! -d $(OBJDIR_EDA) || rm -rf $(OBJDIR_EDA) 128 | clean: 129 | test ! -d $(OBJDIR_EDA) || rm -rf $(OBJDIR_EDA) 130 | rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf 131 | -------------------------------------------------------------------------------- /Makefile.STM32F4_POG: -------------------------------------------------------------------------------- 1 | # STM32 library paths 2 | F4_LIB_PATH=./STM32F4XX_Platform 3 | 4 | # MCU external clock frequency (Hz) 5 | OSC=8000000 6 | 7 | # Directory Structure 8 | BINDIR=. 9 | OBJDIR_F4=obj_f4-pog 10 | 11 | # Output files 12 | BINELF_F4=dvm-firmware_f4-pog.elf 13 | BINBIN_F4=dvm-firmware_f4-pog.bin 14 | 15 | # Header directories 16 | INC_F4=. $(F4_LIB_PATH)/CMSIS/Include/ $(F4_LIB_PATH)/Device/ $(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/include/ 17 | INCLUDES_F4=$(INC_F4:%=-I%) 18 | 19 | # CMSIS libraries 20 | INCLUDES_LIBS_F4=$(F4_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a 21 | 22 | # STM32F4 Standard Peripheral Libraries source path 23 | STD_LIB_F4=$(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/source 24 | 25 | # STM32F4 system source path 26 | SYS_DIR_F4=$(F4_LIB_PATH)/Device 27 | STARTUP_DIR_F4=$(F4_LIB_PATH)/Device/startup 28 | 29 | # GNU ARM Embedded Toolchain 30 | CC=arm-none-eabi-gcc 31 | CXX=arm-none-eabi-g++ 32 | LD=arm-none-eabi-ld 33 | AR=arm-none-eabi-ar 34 | AS=arm-none-eabi-as 35 | CP=arm-none-eabi-objcopy 36 | OD=arm-none-eabi-objdump 37 | NM=arm-none-eabi-nm 38 | SIZE=arm-none-eabi-size 39 | A2L=arm-none-eabi-addr2line 40 | 41 | # Build object lists 42 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) 43 | CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c) 44 | SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c) 45 | STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c) 46 | OBJ_F4=$(CXXSRC:./%.cpp=$(OBJDIR_F4)/%.o) $(CSRC_STD_F4:$(STD_LIB_F4)/%.c=$(OBJDIR_F4)/%.o) $(SYS_F4:$(SYS_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) $(STARTUP_F4:$(STARTUP_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) 47 | 48 | # MCU flags 49 | MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork 50 | 51 | # Compile flags 52 | DEFS_PI=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_POG -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 53 | 54 | # Build compiler flags 55 | CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 56 | CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4) 57 | 58 | # Linker flags 59 | LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 60 | LDFLAGS_F4_D =-T stm32f4xx_link_debug.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4) 61 | 62 | # Common flags 63 | CFLAGS=-Os -g -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS 64 | CXXFLAGS=-Os -g -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -Wall -DCUSTOM_NEW -DNO_EXCEPTIONS 65 | LDFLAGS=-Os -g --specs=nano.specs 66 | 67 | # Build Rules 68 | .PHONY: all f4 f4-debug clean 69 | 70 | all: f4 71 | 72 | f4: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 73 | f4: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 74 | f4: LDFLAGS+=$(LDFLAGS_F4) 75 | f4: $(BINDIR) 76 | f4: $(OBJDIR_F4) 77 | f4: $(BINDIR)/$(BINBIN_F4) 78 | 79 | f4-debug: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI) 80 | f4-debug: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI) 81 | f4-debug: LDFLAGS+=$(LDFLAGS_F4_D) 82 | f4-debug: $(BINDIR) 83 | f4-debug: $(OBJDIR_F4) 84 | f4-debug: $(BINDIR)/$(BINBIN_F4) 85 | 86 | $(BINDIR): 87 | mkdir $@ 88 | $(OBJDIR_F4): 89 | mkdir $@ 90 | mkdir $@/dmr 91 | mkdir $@/p25 92 | mkdir $@/nxdn 93 | 94 | $(BINDIR)/$(BINBIN_F4): $(BINDIR)/$(BINELF_F4) 95 | $(CP) -O binary $< $@ 96 | $(BINDIR)/$(BINELF_F4): $(OBJ_F4) 97 | $(CXX) $(OBJ_F4) $(LDFLAGS) -o $@ 98 | $(SIZE) $(BINDIR)/$(BINELF_F4) 99 | 100 | $(OBJDIR_F4)/%.o: ./%.cpp 101 | $(CXX) $(CXXFLAGS) $< -o $@ 102 | $(OBJDIR_F4)/%.o: $(STD_LIB_F4)/%.c 103 | $(CC) $(CFLAGS) $< -o $@ 104 | $(OBJDIR_F4)/%.o: $(SYS_DIR_F4)/%.c 105 | $(CC) $(CFLAGS) $< -o $@ 106 | $(OBJDIR_F4)/%.o: $(STARTUP_DIR_F4)/%.c 107 | $(CC) $(CFLAGS) $< -o $@ 108 | 109 | clean-objs: 110 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 111 | clean: 112 | test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4) 113 | rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf 114 | -------------------------------------------------------------------------------- /Makefile.STM32F7: -------------------------------------------------------------------------------- 1 | # STM32 library paths 2 | F7_LIB_PATH=./STM32F7XX_Platform 3 | 4 | # MCU external clock frequency (Hz) 5 | OSC=12000000 6 | 7 | # Directory Structure 8 | BINDIR=. 9 | OBJDIR_F7=obj_f722 10 | OBJDIR_F767=obj_f767 11 | 12 | 13 | # Output files 14 | BINELF_F7=dvm-firmware_f722.elf 15 | BINBIN_F7=dvm-firmware_f722.bin 16 | BINELF_F767=dvm-firmware_f767.elf 17 | BINBIN_F767=dvm-firmware_f767.bin 18 | 19 | # Header directories 20 | INC_F7=. $(F7_LIB_PATH)/CMSIS/Include/ $(F7_LIB_PATH)/Device/ $(F7_LIB_PATH)/STM32F7xx_StdPeriph_Driver/inc/ 21 | INCLUDES_F7=$(INC_F7:%=-I%) 22 | 23 | # CMSIS libraries 24 | INCLUDES_LIBS_F7=$(F7_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM7lfsp_math.a 25 | 26 | # STM32F7 Standard Peripheral Libraries source path 27 | STD_LIB_F7=$(F7_LIB_PATH)/STM32F7xx_StdPeriph_Driver/src 28 | 29 | # STM32F7 system source path 30 | SYS_DIR_F7=$(F7_LIB_PATH)/Device 31 | STARTUP_DIR_F7=$(F7_LIB_PATH)/Device/startup 32 | 33 | # GNU ARM Embedded Toolchain 34 | CC=arm-none-eabi-gcc 35 | CXX=arm-none-eabi-g++ 36 | LD=arm-none-eabi-ld 37 | AR=arm-none-eabi-ar 38 | AS=arm-none-eabi-as 39 | CP=arm-none-eabi-objcopy 40 | OD=arm-none-eabi-objdump 41 | NM=arm-none-eabi-nm 42 | SIZE=arm-none-eabi-size 43 | A2L=arm-none-eabi-addr2line 44 | 45 | # Build object lists 46 | CXXSRC=$(wildcard ./*.cpp) $(wildcard ./dmr/*.cpp) $(wildcard ./p25/*.cpp) $(wildcard ./nxdn/*.cpp) 47 | CSRC_STD_F7=$(wildcard $(STD_LIB_F7)/*.c) 48 | SYS_F7=$(wildcard $(SYS_DIR_F7)/*.c) 49 | STARTUP_F7=$(wildcard $(STARTUP_DIR_F7)/*.c) 50 | OBJ_F7=$(CXXSRC:./%.cpp=$(OBJDIR_F7)/%.o) $(CSRC_STD_F7:$(STD_LIB_F7)/%.c=$(OBJDIR_F7)/%.o) $(SYS_F7:$(SYS_DIR_F7)/%.c=$(OBJDIR_F7)/%.o) $(STARTUP_F7:$(STARTUP_DIR_F7)/%.c=$(OBJDIR_F7)/%.o) 51 | OBJ_F767=$(CXXSRC:./%.cpp=$(OBJDIR_F767)/%.o) $(CSRC_STD_F7:$(STD_LIB_F7)/%.c=$(OBJDIR_F767)/%.o) $(SYS_F7:$(SYS_DIR_F7)/%.c=$(OBJDIR_F767)/%.o) $(STARTUP_F7:$(STARTUP_DIR_F7)/%.c=$(OBJDIR_F767)/%.o) 52 | 53 | # MCU flags 54 | MCFLAGS_F7=-mcpu=cortex-m7 -mthumb -mlittle-endian -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb-interwork 55 | 56 | # Compile flags 57 | DEFS_PI=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F7_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 58 | DEFS_PI_767=-DUSE_HAL_DRIVER -DSTM32F767xx -DSTM32F7XX -DSTM32F7_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE 59 | 60 | # Build compiler flags 61 | CFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7) 62 | CXXFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7) 63 | 64 | # Linker flags 65 | LDFLAGS_F7 =-T stm32f722_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7) 66 | LDFLAGS_F7_D =-T stm32f722_link_debug.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7) 67 | LDFLAGS_F7_767 =-T stm32f767_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7) 68 | LDFLAGS_F7_767_D =-T stm32f767_link_debug.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7) 69 | 70 | # Common flags 71 | CFLAGS=-Os -g -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS 72 | CXXFLAGS=-Os -g -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -Wall -DCUSTOM_NEW -DNO_EXCEPTIONS 73 | LDFLAGS=-Os -g --specs=nano.specs 74 | 75 | # Build Rules 76 | .PHONY: all f7 f7-debug clean 77 | 78 | all: f7 79 | 80 | f7: CFLAGS+=$(CFLAGS_F7) $(DEFS_PI) 81 | f7: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_PI) 82 | f7: LDFLAGS+=$(LDFLAGS_F7) 83 | f7: $(BINDIR) 84 | f7: $(OBJDIR_F7) 85 | f7: $(BINDIR)/$(BINBIN_F7) 86 | 87 | f7-debug: CFLAGS+=$(CFLAGS_F7) $(DEFS_PI) 88 | f7-debug: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_PI) 89 | f7-debug: LDFLAGS+=$(LDFLAGS_F7_D) 90 | f7-debug: $(BINDIR) 91 | f7-debug: $(OBJDIR_F7) 92 | f7-debug: $(BINDIR)/$(BINBIN_F7) 93 | 94 | f767: CFLAGS+=$(CFLAGS_F7) $(DEFS_PI_767) 95 | f767: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_PI_767) 96 | f767: LDFLAGS+=$(LDFLAGS_F7_767) 97 | f767: $(BINDIR) 98 | f767: $(OBJDIR_F767) 99 | f767: $(BINDIR)/$(BINBIN_F767) 100 | 101 | f767-debug: CFLAGS+=$(CFLAGS_F7) $(DEFS_PI_767) 102 | f767-debug: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_PI_767) 103 | f767-debug: LDFLAGS+=$(LDFLAGS_F7_767_D) 104 | f767-debug: $(BINDIR) 105 | f767-debug: $(OBJDIR_F767) 106 | f767-debug: $(BINDIR)/$(BINBIN_F767) 107 | 108 | $(BINDIR): 109 | mkdir $@ 110 | $(OBJDIR_F7): 111 | mkdir $@ 112 | mkdir $@/dmr 113 | mkdir $@/p25 114 | mkdir $@/nxdn 115 | $(OBJDIR_F767): 116 | mkdir $@ 117 | mkdir $@/dmr 118 | mkdir $@/p25 119 | mkdir $@/nxdn 120 | 121 | $(BINDIR)/$(BINBIN_F7): $(BINDIR)/$(BINELF_F7) 122 | $(CP) -O binary $< $@ 123 | $(BINDIR)/$(BINELF_F7): $(OBJ_F7) 124 | $(CXX) $(OBJ_F7) $(LDFLAGS) -o $@ 125 | $(SIZE) $(BINDIR)/$(BINELF_F7) 126 | $(BINDIR)/$(BINBIN_F767): $(BINDIR)/$(BINELF_F767) 127 | $(CP) -O binary $< $@ 128 | $(BINDIR)/$(BINELF_F767): $(OBJ_F767) 129 | $(CXX) $(OBJ_F767) $(LDFLAGS) -o $@ 130 | $(SIZE) $(BINDIR)/$(BINELF_F767) 131 | 132 | $(OBJDIR_F7)/%.o: ./%.cpp 133 | $(CXX) $(CXXFLAGS) $< -o $@ 134 | $(OBJDIR_F7)/%.o: $(STD_LIB_F7)/%.c 135 | $(CC) $(CFLAGS) $< -o $@ 136 | $(OBJDIR_F7)/%.o: $(SYS_DIR_F7)/%.c 137 | $(CC) $(CFLAGS) $< -o $@ 138 | $(OBJDIR_F7)/%.o: $(STARTUP_DIR_F7)/%.c 139 | $(CC) $(CFLAGS) $< -o $@ 140 | $(OBJDIR_F767)/%.o: ./%.cpp 141 | $(CXX) $(CXXFLAGS) $< -o $@ 142 | $(OBJDIR_F767)/%.o: $(STD_LIB_F7)/%.c 143 | $(CC) $(CFLAGS) $< -o $@ 144 | $(OBJDIR_F767)/%.o: $(SYS_DIR_F7)/%.c 145 | $(CC) $(CFLAGS) $< -o $@ 146 | $(OBJDIR_F767)/%.o: $(STARTUP_DIR_F7)/%.c 147 | $(CC) $(CFLAGS) $< -o $@ 148 | 149 | clean-objs: 150 | test ! -d $(OBJDIR_F7) || rm -rf $(OBJDIR_F7) 151 | test ! -d $(OBJDIR_F767) || rm -rf $(OBJDIR_F767) 152 | clean: 153 | test ! -d $(OBJDIR_F7) || rm -rf $(OBJDIR_F7) 154 | test ! -d $(OBJDIR_F767) || rm -rf $(OBJDIR_F767) 155 | rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Digital Voice Modem Firmware 2 | 3 | The DVM firmware provides the embedded microcontroller implementation of a mixed-mode DMR, P25 and/or NXDN or dedicated-mode DMR, P25 or NXDN repeater system. The firmware; is the portion of a complete Over-The-Air modem implementation that connects directly to an appropriate air interface (usually a analog radio) and performs the actual reception and creation of the digitial waveforms. 4 | 5 | This project is a direct fork of the MMDVM (https://github.com/g4klx/MMDVM) project. 6 | 7 | Please feel free to reach out to us for help, comments or otherwise, on our Discord: https://discord.gg/3pBe8xgrEz 8 | 9 | ## Building 10 | 11 | Please see the various Makefile's included in the project for more information. This project includes a few Makefiles to target different hardware. (All following information assumes familiarity with the standard Linux make system.) 12 | 13 | * Makefile.SAM3X8_DUE - This makefile is used for building binaries to flash onto a Arduino Due device. 14 | * Makefile.STM32F4 - This makefile is used for targeting a generic STM32F4 device. 15 | * Makefile.STM32F4_POG - This makefile is used for targeting the STM32F4 device built by RepeaterBuilder (http://www.repeater-builder.com/products/stm32-dvm.html). 16 | * Makefile.STM32F4_EDA - This makefile is used for targeting the "v3" STM32F4 405 or 446 device built by WA0EDA for the MTR2000 and MASTR 3. 17 | * Makefile.STM32F4_DVMV1 - This makefile is used for targeting the official DVMProject DVM-V1 modem boards ([https://store.w3axl.com](https://store.w3axl.com/products/dvm-v1-duplex-modem)) 18 | 19 | All of these firmwares should be compiled on Linux, any other systems YMMV. 20 | 21 | * For the standard Arduino Due device, you should have the Arduino development SDK installed to your home directory under ".arduino15". There are some minor tweaks that must be performed to compile for this platform: 22 | 1. Locate platform.txt. On an Ubuntu OS it should be in: 23 | /home/$user/.arduino15/packages/arduino/hardware/sam/1.6.8/ 24 | 2. Open the file in a text editor and change the line: 25 | ``` 26 | # Combine gc-sections, archives, and objects 27 | recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group {compiler.combine.flags} {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc 28 | ``` 29 | 30 | To: 31 | ``` 32 | recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group {compiler.combine.flags} {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.system.path}/CMSIS/CMSIS/Lib/GCC/libarm_cortexM3l_math.a" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc 33 | ``` 34 | * For STM32F4 using Ubuntu OS install the standard ARM embedded toolchain (typically arm-gcc-none-eabi). 35 | - Make sure to clone this repository with the ```--recurse-submodules``` option, otherwise the STM32 platform files will be missing! ```git clone --recurse-submodules https://github.com/DVMProject/dvmfirmware.git``` 36 | 37 | Use the ```make``` command to build the firmware, choosing the appropriate makefile with the -f switch. 38 | 39 | ## Firmware installation 40 | 41 | Some devices can be used on top on a RPi attached via the GPIO port or standalone and others are connected via USB. Both variants require different handling of compiling and uploading the firmware, examples on flashing devices are mostly not included here because the methods to flash vary from device to device. 42 | 43 | ## Notes 44 | 45 | **NXDN Support Note**: NXDN support is currently experimental. 46 | 47 | ## License 48 | 49 | This project is licensed under the GPLv2 License - see the [LICENSE.md](LICENSE.md) file for details. Use of this project is intended, for amateur and/or educational use ONLY. Any other use is at the risk of user and all commercial purposes is strictly discouraged. 50 | 51 | -------------------------------------------------------------------------------- /RSSIBuffer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 9 | * 10 | */ 11 | #include "RSSIBuffer.h" 12 | 13 | // --------------------------------------------------------------------------- 14 | // Public Class Members 15 | // --------------------------------------------------------------------------- 16 | 17 | /* Initializes a new instance of the RSSIBuffer class. */ 18 | 19 | RSSIBuffer::RSSIBuffer(uint16_t length) : 20 | m_length(length), 21 | m_rssi(NULL), 22 | m_head(0U), 23 | m_tail(0U), 24 | m_full(false), 25 | m_overflow(false) 26 | { 27 | m_rssi = new uint16_t[length]; 28 | } 29 | 30 | /* Helper to get how much space the ring buffer has for samples. */ 31 | 32 | uint16_t RSSIBuffer::getSpace() const 33 | { 34 | uint16_t n = 0U; 35 | 36 | if (m_tail == m_head) 37 | n = m_full ? 0U : m_length; 38 | else if (m_tail < m_head) 39 | n = m_length - m_head + m_tail; 40 | else 41 | n = m_tail - m_head; 42 | 43 | if (n > m_length) 44 | n = 0U; 45 | 46 | return n; 47 | } 48 | 49 | /* */ 50 | 51 | uint16_t RSSIBuffer::getData() const 52 | { 53 | if (m_tail == m_head) 54 | return m_full ? m_length : 0U; 55 | else if (m_tail < m_head) 56 | return m_head - m_tail; 57 | else 58 | return m_length - m_tail + m_head; 59 | } 60 | 61 | /* */ 62 | 63 | bool RSSIBuffer::put(uint16_t rssi) 64 | { 65 | if (m_full) { 66 | m_overflow = true; 67 | return false; 68 | } 69 | 70 | m_rssi[m_head] = rssi; 71 | 72 | m_head++; 73 | if (m_head >= m_length) 74 | m_head = 0U; 75 | 76 | if (m_head == m_tail) 77 | m_full = true; 78 | 79 | return true; 80 | } 81 | 82 | /* */ 83 | 84 | bool RSSIBuffer::get(uint16_t& rssi) 85 | { 86 | if (m_head == m_tail && !m_full) 87 | return false; 88 | 89 | rssi = m_rssi[m_tail]; 90 | 91 | m_full = false; 92 | 93 | m_tail++; 94 | if (m_tail >= m_length) 95 | m_tail = 0U; 96 | 97 | return true; 98 | } 99 | 100 | /* Flag indicating whether or not the ring buffer has overflowed. */ 101 | 102 | bool RSSIBuffer::hasOverflowed() 103 | { 104 | bool overflow = m_overflow; 105 | 106 | m_overflow = false; 107 | 108 | return overflow; 109 | } 110 | -------------------------------------------------------------------------------- /RSSIBuffer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 9 | * 10 | */ 11 | /** 12 | * @file RSSIBuffer.h 13 | * @ingroup modem_fw 14 | * @file RSSIBuffer.cpp 15 | * @ingroup modem_fw 16 | */ 17 | #if !defined(__RSSI_RB_H__) 18 | #define __RSSI_RB_H__ 19 | 20 | #include "Defines.h" 21 | 22 | // --------------------------------------------------------------------------- 23 | // Class Declaration 24 | // --------------------------------------------------------------------------- 25 | 26 | /** 27 | * @brief Implements a circular buffer for RSSI data. 28 | * @ingroup modem_fw 29 | */ 30 | class DSP_FW_API RSSIBuffer { 31 | public: 32 | /** 33 | * @brief Initializes a new instance of the RSSIBuffer class. 34 | * @param length Length of buffer. 35 | */ 36 | RSSIBuffer(uint16_t length); 37 | 38 | /** 39 | * @brief Helper to get how much space the ring buffer has for data. 40 | * @returns uint16_t Amount of space remaining for data. 41 | */ 42 | uint16_t getSpace() const; 43 | 44 | /** 45 | * @brief 46 | * @returns uint16_t 47 | */ 48 | uint16_t getData() const; 49 | 50 | /** 51 | * @brief 52 | * @param rssi 53 | * @returns bool 54 | */ 55 | bool put(uint16_t rssi); 56 | 57 | /** 58 | * @brief 59 | * @param[out] rssi 60 | * @returns bool 61 | */ 62 | bool get(uint16_t& rssi); 63 | 64 | /** 65 | * @brief Flag indicating whether or not the ring buffer has overflowed. 66 | * @returns bool Flag indicating whether or not the ring buffer has overflowed. 67 | */ 68 | bool hasOverflowed(); 69 | 70 | private: 71 | uint16_t m_length; 72 | volatile uint16_t* m_rssi; 73 | 74 | volatile uint16_t m_head; 75 | volatile uint16_t m_tail; 76 | 77 | volatile bool m_full; 78 | 79 | bool m_overflow; 80 | }; 81 | 82 | #endif // __RSSI_RB_H__ 83 | -------------------------------------------------------------------------------- /RingBuffer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2017 Wojciech Krutnik, N0CALL 8 | * 9 | */ 10 | /** 11 | * @file RingBuffer.h 12 | * @ingroup modem_fw 13 | */ 14 | #if !defined(__RING_BUFFER_H__) 15 | #define __RING_BUFFER_H__ 16 | 17 | /* 18 | * FIFO ring buffer source: 19 | * http://stackoverflow.com/questions/6822548/correct-way-of-implementing-a-uart-receive-buffer-in-a-small-arm-microcontroller (modified) 20 | * 21 | */ 22 | 23 | #include "Defines.h" 24 | 25 | // --------------------------------------------------------------------------- 26 | // Macros 27 | // --------------------------------------------------------------------------- 28 | 29 | #define RINGBUFF_SIZE(ringBuff) (ringBuff.size) // serial buffer in bytes (power 2) 30 | #define RINGBUFF_MASK(ringBuff) (ringBuff.size-1U) // buffer size mask 31 | 32 | // Buffer read / write macros 33 | #define RINGBUFF_RESET(ringBuff) (ringBuff).rdIdx = ringBuff.wrIdx = 0 34 | #define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn) 35 | #define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)]) 36 | #define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx) 37 | #define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringFifo.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringFifo.wrIdx)) 38 | #define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx)) 39 | 40 | // Buffer type 41 | #define DECLARE_RINGBUFFER_TYPE(name, _size) \ 42 | typedef struct { \ 43 | uint32_t size; \ 44 | uint32_t wrIdx; \ 45 | uint32_t rdIdx; \ 46 | uint8_t data[_size]; \ 47 | } name##_t 48 | 49 | #endif // __RING_BUFFER_H__ 50 | -------------------------------------------------------------------------------- /STM_UART.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (c) 2020 Jonathan Naylor, G4KLX 8 | * Copyright (c) 2020 Geoffrey Merck, F4FXL - KC3FRA 9 | * 10 | */ 11 | #if defined(STM32F4XX) || defined(STM32F7XX) 12 | 13 | #include "STM_UART.h" 14 | 15 | // --------------------------------------------------------------------------- 16 | // Public Class Members 17 | // --------------------------------------------------------------------------- 18 | 19 | /* Initializes a new instance of the STM_UART class. */ 20 | 21 | STM_UART::STM_UART() : 22 | m_usart(NULL) 23 | { 24 | /* stub */ 25 | } 26 | 27 | /* Initializes the UART. */ 28 | 29 | void STM_UART::init(USART_TypeDef* usart) 30 | { 31 | m_usart = usart; 32 | } 33 | 34 | /* */ 35 | 36 | uint8_t STM_UART::read() 37 | { 38 | return m_rxFifo.get(); 39 | } 40 | 41 | /* */ 42 | 43 | void STM_UART::write(const uint8_t* data, uint16_t length) 44 | { 45 | if (length == 0U || m_usart == NULL) 46 | return; 47 | 48 | 49 | m_txFifo.put(data[0]); 50 | USART_ITConfig(m_usart, USART_IT_TXE, ENABLE); // switch TX IRQ is on 51 | 52 | for (uint16_t i = 1U; i < length; i++) { 53 | m_txFifo.put(data[i]); 54 | } 55 | 56 | USART_ITConfig(m_usart, USART_IT_TXE, ENABLE); // make sure TX IRQ is on 57 | } 58 | 59 | /* */ 60 | 61 | void STM_UART::handleIRQ() 62 | { 63 | if (m_usart == NULL) 64 | return; 65 | 66 | if (USART_GetITStatus(m_usart, USART_IT_RXNE)) { 67 | if (!m_rxFifo.isFull()) 68 | m_rxFifo.put((uint8_t)USART_ReceiveData(m_usart)); 69 | USART_ClearITPendingBit(USART1, USART_IT_RXNE); 70 | } 71 | 72 | if (USART_GetITStatus(m_usart, USART_IT_TXE)) { 73 | if (!m_txFifo.isEmpty()) 74 | USART_SendData(m_usart, m_txFifo.get()); 75 | 76 | USART_ClearITPendingBit(m_usart, USART_IT_TXE); 77 | 78 | if (m_txFifo.isEmpty()) // if there's no more data to transmit then turn off TX interrupts 79 | USART_ITConfig(m_usart, USART_IT_TXE, DISABLE); 80 | } 81 | } 82 | 83 | /* Flushes the transmit shift register. */ 84 | 85 | void STM_UART::flush() 86 | { 87 | if (m_usart == NULL) 88 | return; 89 | 90 | // wait until the TXE shows the shift register is empty 91 | while (USART_GetITStatus(m_usart, USART_FLAG_TXE)) 92 | ; 93 | } 94 | 95 | /* */ 96 | 97 | uint16_t STM_UART::available() 98 | { 99 | return m_rxFifo.isEmpty() ? 0U : 1U; 100 | } 101 | 102 | /* */ 103 | 104 | uint16_t STM_UART::availableForWrite() 105 | { 106 | return m_txFifo.isFull() ? 0U : 1U; 107 | } 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /STM_UART.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (c) 2020 Jonathan Naylor, G4KLX 8 | * Copyright (c) 2020 Geoffrey Merck, F4FXL - KC3FRA 9 | * 10 | */ 11 | /** 12 | * @file STM_UART.h 13 | * @ingroup modem_fw 14 | * @file STM_UART.cpp 15 | * @ingroup modem_fw 16 | */ 17 | #if defined(STM32F4XX) || defined(STM32F7XX) 18 | #if !defined(__STM_UART_H__) 19 | #define __STM_UART_H__ 20 | 21 | #include "Defines.h" 22 | 23 | #if defined(STM32F4XX) 24 | #include "stm32f4xx.h" 25 | #endif 26 | #if defined(STM32F7XX) 27 | #include "stm32f7xx.h" 28 | #endif 29 | 30 | const uint16_t BUFFER_SIZE = 2048U; //needs to be a power of 2 ! 31 | const uint16_t BUFFER_MASK = BUFFER_SIZE - 1; 32 | 33 | // --------------------------------------------------------------------------- 34 | // Class Declaration 35 | // --------------------------------------------------------------------------- 36 | 37 | /** 38 | * @brief This class represents a FIFO buffer on a STM32 UART. 39 | * @ingroup modem_fw 40 | */ 41 | class DSP_FW_API STM_UARTFIFO { 42 | public: 43 | /** 44 | * @brief Initializes a new instance of the STM_UARTFIFO class. 45 | */ 46 | STM_UARTFIFO() : 47 | m_head(0U), 48 | m_tail(0U) 49 | { 50 | /* stub */ 51 | } 52 | 53 | /** 54 | * @brief 55 | * @returns uint8_t 56 | */ 57 | uint8_t get() 58 | { 59 | return m_buffer[BUFFER_MASK & (m_tail++)]; 60 | } 61 | 62 | /** 63 | * @brief 64 | * @param data 65 | */ 66 | void put(uint8_t data) 67 | { 68 | m_buffer[BUFFER_MASK & (m_head++)] = data; 69 | } 70 | 71 | /** 72 | * @brief Helper to reset data values to defaults. 73 | */ 74 | void reset() 75 | { 76 | m_tail = 0U; 77 | m_head = 0U; 78 | } 79 | 80 | /** 81 | * @brief 82 | * @returns bool 83 | */ 84 | bool isEmpty() 85 | { 86 | return m_tail == m_head; 87 | } 88 | 89 | /** 90 | * @brief 91 | * @returns bool 92 | */ 93 | bool isFull() 94 | { 95 | return ((m_head + 1U) & BUFFER_MASK) == (m_tail & BUFFER_MASK); 96 | } 97 | 98 | private: 99 | volatile uint8_t m_buffer[BUFFER_SIZE]; 100 | volatile uint16_t m_head; 101 | volatile uint16_t m_tail; 102 | }; 103 | 104 | // --------------------------------------------------------------------------- 105 | // Class Declaration 106 | // --------------------------------------------------------------------------- 107 | 108 | /** 109 | * @brief This class represents an STM32 UART. 110 | * @ingroup modem_fw 111 | */ 112 | class STM_UART { 113 | public: 114 | /** 115 | * @brief Initializes a new instance of the STM_UART class. 116 | */ 117 | STM_UART(); 118 | 119 | /** 120 | * @brief Initializes the UART. 121 | * @param usart 122 | */ 123 | void init(USART_TypeDef* usart); 124 | 125 | /** 126 | * @brief 127 | * @returns uint8_t 128 | */ 129 | uint8_t read(); 130 | /** 131 | * @brief 132 | * @param[in] data 133 | * @param length 134 | */ 135 | void write(const uint8_t* data, uint16_t length); 136 | 137 | /** 138 | * @brief 139 | */ 140 | void handleIRQ(); 141 | 142 | /** 143 | * @brief Flushes the transmit shift register. 144 | * 145 | * This call is blocking! 146 | */ 147 | void flush(); 148 | 149 | /** 150 | * @brief 151 | * @returns uint16_t 152 | */ 153 | uint16_t available(); 154 | 155 | /** 156 | * @brief 157 | * @returns uint16_t 158 | */ 159 | uint16_t availableForWrite(); 160 | 161 | private: 162 | USART_TypeDef* m_usart; 163 | 164 | STM_UARTFIFO m_rxFifo; 165 | STM_UARTFIFO m_txFifo; 166 | }; 167 | 168 | #endif // __SERIAL_PORT_H__ 169 | #endif 170 | -------------------------------------------------------------------------------- /SampleBuffer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 9 | * 10 | */ 11 | #include "SampleBuffer.h" 12 | 13 | // --------------------------------------------------------------------------- 14 | // Public Class Members 15 | // --------------------------------------------------------------------------- 16 | 17 | /* Initializes a new instance of the SampleBuffer class. */ 18 | 19 | SampleBuffer::SampleBuffer(uint16_t length) : 20 | m_length(length), 21 | m_samples(NULL), 22 | m_control(NULL), 23 | m_head(0U), 24 | m_tail(0U), 25 | m_full(false), 26 | m_overflow(false) 27 | { 28 | m_samples = new uint16_t[length]; 29 | m_control = new uint8_t[length]; 30 | } 31 | 32 | /* Helper to get how much space the ring buffer has for samples. */ 33 | 34 | uint16_t SampleBuffer::getSpace() const 35 | { 36 | uint16_t n = 0U; 37 | 38 | if (m_tail == m_head) 39 | n = m_full ? 0U : m_length; 40 | else if (m_tail < m_head) 41 | n = m_length - m_head + m_tail; 42 | else 43 | n = m_tail - m_head; 44 | 45 | if (n > m_length) 46 | n = 0U; 47 | 48 | return n; 49 | } 50 | 51 | /* */ 52 | 53 | uint16_t SampleBuffer::getData() const 54 | { 55 | if (m_tail == m_head) 56 | return m_full ? m_length : 0U; 57 | else if (m_tail < m_head) 58 | return m_head - m_tail; 59 | else 60 | return m_length - m_tail + m_head; 61 | } 62 | 63 | /* */ 64 | 65 | bool SampleBuffer::put(uint16_t sample, uint8_t control) 66 | { 67 | if (m_full) { 68 | m_overflow = true; 69 | return false; 70 | } 71 | 72 | m_samples[m_head] = sample; 73 | m_control[m_head] = control; 74 | 75 | m_head++; 76 | if (m_head >= m_length) 77 | m_head = 0U; 78 | 79 | if (m_head == m_tail) 80 | m_full = true; 81 | 82 | return true; 83 | } 84 | 85 | /* */ 86 | 87 | bool SampleBuffer::get(uint16_t& sample, uint8_t& control) 88 | { 89 | if (m_head == m_tail && !m_full) 90 | return false; 91 | 92 | sample = m_samples[m_tail]; 93 | control = m_control[m_tail]; 94 | 95 | m_full = false; 96 | 97 | m_tail++; 98 | if (m_tail >= m_length) 99 | m_tail = 0U; 100 | 101 | return true; 102 | } 103 | 104 | /* Flag indicating whether or not the ring buffer has overflowed. */ 105 | 106 | bool SampleBuffer::hasOverflowed() 107 | { 108 | bool overflow = m_overflow; 109 | 110 | m_overflow = false; 111 | 112 | return overflow; 113 | } 114 | -------------------------------------------------------------------------------- /SampleBuffer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 9 | * 10 | */ 11 | /** 12 | * @file SampleBuffer.h 13 | * @ingroup modem_fw 14 | * @file SampleBuffer.cpp 15 | * @ingroup modem_fw 16 | */ 17 | #if !defined(__SAMPLE_RB_H__) 18 | #define __SAMPLE_RB_H__ 19 | 20 | #include "Defines.h" 21 | 22 | // --------------------------------------------------------------------------- 23 | // Class Declaration 24 | // --------------------------------------------------------------------------- 25 | 26 | /** 27 | * @brief Implements a circular ring buffer for sample data. 28 | * @ingroup modem_fw 29 | */ 30 | class DSP_FW_API SampleBuffer { 31 | public: 32 | /** 33 | * @brief Initializes a new instance of the SampleBuffer class. 34 | * @param length Length of buffer. 35 | */ 36 | SampleBuffer(uint16_t length); 37 | 38 | /** 39 | * @brief Helper to get how much space the ring buffer has for samples. 40 | * @returns uint16_t Amount of space remaining for samples. 41 | */ 42 | uint16_t getSpace() const; 43 | 44 | /** 45 | * @brief 46 | * @returns uint16_t 47 | */ 48 | uint16_t getData() const; 49 | 50 | /** 51 | * @brief 52 | * @param sample 53 | * @param control 54 | * @returns bool 55 | */ 56 | bool put(uint16_t sample, uint8_t control); 57 | 58 | /** 59 | * @brief 60 | * @param[out] sample 61 | * @param[out] control 62 | * @returns bool 63 | */ 64 | bool get(uint16_t& sample, uint8_t& control); 65 | 66 | /** 67 | * @brief Flag indicating whether or not the ring buffer has overflowed. 68 | * @returns bool Flag indicating whether or not the ring buffer has overflowed. 69 | */ 70 | bool hasOverflowed(); 71 | 72 | private: 73 | uint16_t m_length; 74 | volatile uint16_t* m_samples; 75 | volatile uint8_t* m_control; 76 | 77 | volatile uint16_t m_head; 78 | volatile uint16_t m_tail; 79 | 80 | volatile bool m_full; 81 | 82 | bool m_overflow; 83 | }; 84 | 85 | #endif // __SAMPLE_RB_H__ 86 | -------------------------------------------------------------------------------- /SerialBuffer.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 9 | * 10 | */ 11 | #include "SerialBuffer.h" 12 | 13 | // --------------------------------------------------------------------------- 14 | // Public Class Members 15 | // --------------------------------------------------------------------------- 16 | 17 | /* Initializes a new instance of the SerialBuffer class. */ 18 | 19 | SerialBuffer::SerialBuffer(uint16_t length) : 20 | m_length(length), 21 | m_buffer(NULL), 22 | m_head(0U), 23 | m_tail(0U), 24 | m_full(false) 25 | { 26 | m_buffer = new uint8_t[length]; 27 | } 28 | 29 | /* Finalizes a instance of the SerialBuffer class. */ 30 | 31 | SerialBuffer::~SerialBuffer() 32 | { 33 | delete[] m_buffer; 34 | } 35 | 36 | /* Helper to get how much space the ring buffer has for data. */ 37 | 38 | uint16_t SerialBuffer::getSpace() const 39 | { 40 | uint16_t n = 0U; 41 | 42 | if (m_tail == m_head) 43 | n = m_full ? 0U : m_length; 44 | else if (m_tail < m_head) 45 | n = m_length - m_head + m_tail; 46 | else 47 | n = m_tail - m_head; 48 | 49 | if (n > m_length) 50 | n = 0U; 51 | 52 | return n; 53 | } 54 | 55 | /* */ 56 | 57 | uint16_t SerialBuffer::getData() const 58 | { 59 | if (m_tail == m_head) 60 | return m_full ? m_length : 0U; 61 | else if (m_tail < m_head) 62 | return m_head - m_tail; 63 | else 64 | return m_length - m_tail + m_head; 65 | } 66 | 67 | /* Helper to reset data values to defaults. */ 68 | 69 | void SerialBuffer::reset() 70 | { 71 | m_head = 0U; 72 | m_tail = 0U; 73 | m_full = false; 74 | } 75 | 76 | /* Helper to reset and reinitialize data values to defaults. */ 77 | 78 | void SerialBuffer::reinitialize(uint16_t length) 79 | { 80 | reset(); 81 | 82 | m_length = length; 83 | 84 | delete[] m_buffer; 85 | m_buffer = new uint8_t[length]; 86 | } 87 | 88 | /* */ 89 | 90 | bool SerialBuffer::put(uint8_t c) 91 | { 92 | if (m_full) 93 | return false; 94 | 95 | m_buffer[m_head] = c; 96 | 97 | m_head++; 98 | if (m_head >= m_length) 99 | m_head = 0U; 100 | 101 | if (m_head == m_tail) 102 | m_full = true; 103 | 104 | return true; 105 | } 106 | 107 | /* */ 108 | 109 | uint8_t SerialBuffer::peek() const 110 | { 111 | return m_buffer[m_tail]; 112 | } 113 | 114 | /* */ 115 | 116 | uint8_t SerialBuffer::get() 117 | { 118 | uint8_t value = m_buffer[m_tail]; 119 | 120 | m_full = false; 121 | 122 | m_tail++; 123 | if (m_tail >= m_length) 124 | m_tail = 0U; 125 | 126 | return value; 127 | } 128 | -------------------------------------------------------------------------------- /SerialBuffer.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * @package DVM / Modem Firmware 8 | * @derivedfrom MMDVM (https://github.com/g4klx/MMDVM) 9 | * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) 10 | * 11 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 12 | * Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM 13 | * 14 | */ 15 | /** 16 | * @file SerialBuffer.h 17 | * @ingroup modem_fw 18 | * @file SerialBuffer.cpp 19 | * @ingroup modem_fw 20 | */ 21 | #if !defined(__SERIAL_RB_H__) 22 | #define __SERIAL_RB_H__ 23 | 24 | #include "Defines.h" 25 | 26 | // --------------------------------------------------------------------------- 27 | // Constants 28 | // --------------------------------------------------------------------------- 29 | 30 | const uint16_t SERIAL_RINGBUFFER_SIZE = 396U; 31 | 32 | // --------------------------------------------------------------------------- 33 | // Class Declaration 34 | // --------------------------------------------------------------------------- 35 | 36 | /** 37 | * @brief Implements a circular ring buffer for serial data. 38 | * @ingroup modem_fw 39 | */ 40 | class DSP_FW_API SerialBuffer { 41 | public: 42 | /** 43 | * @brief Initializes a new instance of the SerialBuffer class. 44 | * @param length Length of buffer. 45 | */ 46 | SerialBuffer(uint16_t length = SERIAL_RINGBUFFER_SIZE); 47 | /** 48 | * @brief Finalizes a instance of the SerialBuffer class. 49 | */ 50 | ~SerialBuffer(); 51 | 52 | /** 53 | * @brief Helper to get how much space the ring buffer has for data. 54 | * @returns uint16_t Amount of space remaining for data. 55 | */ 56 | uint16_t getSpace() const; 57 | 58 | /** 59 | * @brief 60 | * @returns uint16_t 61 | */ 62 | uint16_t getData() const; 63 | 64 | /** 65 | * @brief Helper to reset data values to defaults. 66 | */ 67 | void reset(); 68 | /** 69 | * @brief Helper to reset and reinitialize data values to defaults. 70 | * @param length Length of buffer. 71 | */ 72 | void reinitialize(uint16_t length); 73 | 74 | /** 75 | * @brief 76 | * @param c 77 | * @returns bool 78 | */ 79 | bool put(uint8_t c); 80 | 81 | /** 82 | * @brief 83 | * @returns uint8_t 84 | */ 85 | uint8_t peek() const; 86 | 87 | /** 88 | * @brief 89 | * @returns uint8_t 90 | */ 91 | uint8_t get(); 92 | 93 | private: 94 | uint16_t m_length; 95 | volatile uint8_t* m_buffer; 96 | 97 | volatile uint16_t m_head; 98 | volatile uint16_t m_tail; 99 | 100 | volatile bool m_full; 101 | }; 102 | 103 | #endif // __SERIAL_RB_H__ 104 | -------------------------------------------------------------------------------- /SerialDue.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2018,2022 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | #include "Globals.h" 12 | #include "SerialPort.h" 13 | 14 | // --------------------------------------------------------------------------- 15 | // Private Class Members 16 | // --------------------------------------------------------------------------- 17 | 18 | #if (defined(__SAM3X8E__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)) && defined(ARDUINO_SAM_DUE) 19 | /* Reads data from the modem flash parititon. */ 20 | 21 | void SerialPort::flashRead() 22 | { 23 | DEBUG1("SerialPort: flashRead(): unsupported on Arduino Due"); 24 | sendNAK(RSN_NO_INTERNAL_FLASH); 25 | // unused on Arduino Due based dedicated modems 26 | } 27 | 28 | /* Writes data to the modem flash partition. */ 29 | 30 | uint8_t SerialPort::flashWrite(const uint8_t* data, uint8_t length) 31 | { 32 | DEBUG1("SerialPort: flashWrite(): unsupported on Arduino Due"); 33 | // unused on Arduino Due based dedicated modems 34 | return RSN_NO_INTERNAL_FLASH; 35 | } 36 | 37 | /* */ 38 | 39 | void SerialPort::beginInt(uint8_t n, int speed) 40 | { 41 | switch (n) { 42 | case 1U: 43 | Serial.begin(speed); 44 | break; 45 | case 2U: 46 | Serial2.begin(speed); 47 | break; 48 | case 3U: 49 | Serial3.begin(speed); 50 | break; 51 | default: 52 | break; 53 | } 54 | } 55 | 56 | /* */ 57 | 58 | int SerialPort::availableInt(uint8_t n) 59 | { 60 | switch (n) { 61 | case 1U: 62 | return Serial.available(); 63 | case 2U: 64 | return Serial2.available(); 65 | case 3U: 66 | return Serial3.available(); 67 | default: 68 | return false; 69 | } 70 | } 71 | 72 | /* */ 73 | 74 | int SerialPort::availableForWriteInt(uint8_t n) 75 | { 76 | switch (n) { 77 | case 1U: 78 | return Serial.availableForWrite(); 79 | case 2U: 80 | return Serial2.availableForWrite(); 81 | case 3U: 82 | return Serial3.availableForWrite(); 83 | default: 84 | return false; 85 | } 86 | } 87 | 88 | /* */ 89 | 90 | uint8_t SerialPort::readInt(uint8_t n) 91 | { 92 | switch (n) { 93 | case 1U: 94 | return Serial.read(); 95 | case 2U: 96 | return Serial2.read(); 97 | case 3U: 98 | return Serial3.read(); 99 | default: 100 | return 0U; 101 | } 102 | } 103 | 104 | /* */ 105 | 106 | void SerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush) 107 | { 108 | switch (n) { 109 | case 1U: 110 | Serial.write(data, length); 111 | if (flush) 112 | Serial.flush(); 113 | break; 114 | case 2U: 115 | Serial2.write(data, length); 116 | if (flush) 117 | Serial2.flush(); 118 | break; 119 | case 3U: 120 | Serial3.write(data, length); 121 | if (flush) 122 | Serial3.flush(); 123 | break; 124 | default: 125 | break; 126 | } 127 | } 128 | 129 | #endif // (defined(__SAM3X8E__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)) && defined(ARDUINO_SAM_DUE) 130 | -------------------------------------------------------------------------------- /Utils.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | #include "Utils.h" 11 | 12 | // --------------------------------------------------------------------------- 13 | // Constants/Macros 14 | // --------------------------------------------------------------------------- 15 | 16 | const uint8_t BITS_TABLE[] = { 17 | # define B2(n) n, n+1, n+1, n+2 18 | # define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2) 19 | # define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2) 20 | B6(0), B6(1), B6(1), B6(2) 21 | }; 22 | 23 | // --------------------------------------------------------------------------- 24 | // Global Functions 25 | // --------------------------------------------------------------------------- 26 | 27 | /* Returns the count of bits in the passed 8 byte value. */ 28 | 29 | uint8_t countBits8(uint8_t bits) 30 | { 31 | return BITS_TABLE[bits]; 32 | } 33 | 34 | /* Returns the count of bits in the passed 32 byte value. */ 35 | 36 | uint8_t countBits32(uint32_t bits) 37 | { 38 | uint8_t* p = (uint8_t*)&bits; 39 | uint8_t n = 0U; 40 | n += BITS_TABLE[p[0U]]; 41 | n += BITS_TABLE[p[1U]]; 42 | n += BITS_TABLE[p[2U]]; 43 | n += BITS_TABLE[p[3U]]; 44 | return n; 45 | } 46 | 47 | /* Returns the count of bits in the passed 64 byte value. */ 48 | 49 | uint8_t countBits64(ulong64_t bits) 50 | { 51 | uint8_t* p = (uint8_t*)&bits; 52 | uint8_t n = 0U; 53 | n += BITS_TABLE[p[0U]]; 54 | n += BITS_TABLE[p[1U]]; 55 | n += BITS_TABLE[p[2U]]; 56 | n += BITS_TABLE[p[3U]]; 57 | n += BITS_TABLE[p[4U]]; 58 | n += BITS_TABLE[p[5U]]; 59 | n += BITS_TABLE[p[6U]]; 60 | n += BITS_TABLE[p[7U]]; 61 | return n; 62 | } 63 | -------------------------------------------------------------------------------- /Utils.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file Utils.h 12 | * @ingroup modem_fw 13 | * @file Utils.cpp 14 | * @ingroup modem_fw 15 | */ 16 | #if !defined(__UTILS_H__) 17 | #define __UTILS_H__ 18 | 19 | #include "Defines.h" 20 | 21 | // --------------------------------------------------------------------------- 22 | // Global Functions 23 | // --------------------------------------------------------------------------- 24 | 25 | /** 26 | * @brief Returns the count of bits in the passed 8 byte value. 27 | * @param bits uint8_t to count bits for. 28 | * @returns uint8_t Count of bits in passed value. 29 | */ 30 | DSP_FW_API uint8_t countBits8(uint8_t bits); 31 | /** 32 | * @brief Returns the count of bits in the passed 32 byte value. 33 | * @param bits uint32_t to count bits for. 34 | * @returns uint8_t Count of bits in passed value. 35 | */ 36 | DSP_FW_API uint8_t countBits32(uint32_t bits); 37 | /** 38 | * @brief Returns the count of bits in the passed 64 byte value. 39 | * @param bits ulong64_t to count bits for. 40 | * @returns uint8_t Count of bits in passed value. 41 | */ 42 | DSP_FW_API uint8_t countBits64(ulong64_t bits); 43 | 44 | #endif // __UTILS_H__ 45 | -------------------------------------------------------------------------------- /dmr/CalDMR.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2009-2015 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2016 Colin Durbridge, G4EML 9 | * Copyright (C) 2018 Andy Uribe, CA6JAU 10 | * 11 | */ 12 | /** 13 | * @file CalDMR.h 14 | * @ingroup dmr_mfw 15 | * @file CalDMR.cpp 16 | * @ingroup dmr_mfw 17 | */ 18 | #if !defined(__CAL_DMR_H__) 19 | #define __CAL_DMR_H__ 20 | 21 | #include "Defines.h" 22 | #include "dmr/DMRDefines.h" 23 | 24 | namespace dmr 25 | { 26 | // --------------------------------------------------------------------------- 27 | // Constants 28 | // --------------------------------------------------------------------------- 29 | 30 | /** 31 | * @brief Calibration States 32 | * @ingroup dmr_mfw 33 | */ 34 | enum DMR1KCAL { 35 | DMRCAL1K_IDLE, //! Idle 36 | DMRCAL1K_VH, //! Voice Header 37 | DMRCAL1K_VOICE, //! Voice 38 | DMRCAL1K_VT, //! Voice Terminator 39 | DMRCAL1K_WAIT //! 40 | }; 41 | 42 | // --------------------------------------------------------------------------- 43 | // Class Declaration 44 | // --------------------------------------------------------------------------- 45 | 46 | /** 47 | * @brief Implements logic for DMR calibration mode. 48 | * @ingroup dmr_mfw 49 | */ 50 | class DSP_FW_API CalDMR { 51 | public: 52 | /** 53 | * @brief Initializes a new instance of the CalDMR class. 54 | */ 55 | CalDMR(); 56 | 57 | /** 58 | * @brief Process local state and transmit on the air interface. 59 | */ 60 | void process(); 61 | 62 | /** 63 | * @brief 64 | * @param n 65 | */ 66 | void createData1k(uint8_t n); 67 | /** 68 | * @brief 69 | * @param n 70 | */ 71 | void createDataDMO1k(uint8_t n); 72 | 73 | /** 74 | * @brief 75 | */ 76 | void dmr1kcal(); 77 | /** 78 | * @brief 79 | */ 80 | void dmrDMO1kcal(); 81 | 82 | /** 83 | * @brief Write DMR calibration state. 84 | * @param[in] data Buffer. 85 | * @param length Length of buffer. 86 | * @returns uint8_t Reason code. 87 | */ 88 | uint8_t write(const uint8_t* data, uint8_t length); 89 | 90 | private: 91 | bool m_transmit; 92 | DMR1KCAL m_state; 93 | uint32_t m_frameStart; 94 | 95 | uint8_t m_dmr1k[DMR_FRAME_LENGTH_BYTES + 1U]; 96 | 97 | uint8_t m_audioSeq; 98 | }; 99 | } // namespace dmr 100 | 101 | #endif // __CAL_DMR_H__ 102 | -------------------------------------------------------------------------------- /dmr/DMRDMORX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * @package DVM / Modem Firmware 8 | * @derivedfrom MMDVM (https://github.com/g4klx/MMDVM) 9 | * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) 10 | * 11 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 12 | * 13 | */ 14 | /** 15 | * @file DMRDMORX.h 16 | * @ingroup dmr_mfw 17 | * @file DMRDMORX.cpp 18 | * @ingroup dmr_mfw 19 | */ 20 | #if !defined(__DMR_DMO_RX_H__) 21 | #define __DMR_DMO_RX_H__ 22 | 23 | #include "Defines.h" 24 | #include "dmr/DMRDefines.h" 25 | 26 | namespace dmr 27 | { 28 | // --------------------------------------------------------------------------- 29 | // Constants 30 | // --------------------------------------------------------------------------- 31 | 32 | const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz 33 | 34 | /** 35 | * @brief DMR DMO Receiver State 36 | * @ingroup dmr_mfw 37 | */ 38 | enum DMORX_STATE { 39 | DMORXS_NONE, //! None 40 | DMORXS_VOICE, //! Voice Data 41 | DMORXS_DATA //! PDU Data 42 | }; 43 | 44 | // --------------------------------------------------------------------------- 45 | // Class Declaration 46 | // --------------------------------------------------------------------------- 47 | 48 | /** 49 | * @brief Implements receiver logic for DMR DMO mode operation. 50 | * @ingroup dmr_mfw 51 | */ 52 | class DSP_FW_API DMRDMORX { 53 | public: 54 | /** 55 | * @brief Initializes a new instance of the DMRDMORX class. 56 | */ 57 | DMRDMORX(); 58 | 59 | /** 60 | * @brief Helper to reset data values to defaults. 61 | */ 62 | void reset(); 63 | 64 | /** 65 | * @brief Sample DMR values from the air interface. 66 | * @param[in] samples 67 | * @param[in] rssi 68 | * @param length 69 | */ 70 | void samples(const q15_t* samples, const uint16_t* rssi, uint8_t length); 71 | 72 | /** 73 | * @brief Sets the DMR color code. 74 | * @param colorCode 75 | */ 76 | void setColorCode(uint8_t colorCode); 77 | 78 | private: 79 | uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; 80 | q15_t m_buffer[DMO_BUFFER_LENGTH_SAMPLES]; 81 | 82 | uint16_t m_bitPtr; 83 | uint16_t m_dataPtr; 84 | uint16_t m_syncPtr; 85 | uint16_t m_startPtr; 86 | uint16_t m_endPtr; 87 | 88 | q31_t m_maxCorr; 89 | q15_t m_centre[4U]; 90 | q15_t m_threshold[4U]; 91 | uint8_t m_averagePtr; 92 | 93 | uint8_t m_control; 94 | uint8_t m_syncCount; 95 | 96 | uint8_t m_colorCode; 97 | 98 | DMORX_STATE m_state; 99 | 100 | uint8_t m_n; 101 | 102 | uint8_t m_type; 103 | 104 | uint16_t m_rssi[DMO_BUFFER_LENGTH_SAMPLES]; 105 | 106 | /** 107 | * @brief Helper to perform sample processing. 108 | * @param sample 109 | * @param rssi 110 | */ 111 | bool processSample(q15_t sample, uint16_t rssi); 112 | 113 | /** 114 | * @brief Frame synchronization correlator. 115 | * @param first 116 | */ 117 | void correlateSync(bool first); 118 | 119 | /** 120 | * @brief 121 | * @param start 122 | * @param count 123 | * @param buffer 124 | * @param offset 125 | * @param centre 126 | * @param threshold 127 | */ 128 | void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); 129 | /** 130 | * @brief 131 | * @param frame 132 | */ 133 | void writeRSSIData(uint8_t* frame); 134 | }; 135 | } // namespace dmr 136 | 137 | #endif // __DMR_DMO_RX_H__ 138 | -------------------------------------------------------------------------------- /dmr/DMRDMOTX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2016 Colin Durbridge, G4EML 9 | * Copyright (C) 2020 Bryan Biedenkapp, N2PLL 10 | * 11 | */ 12 | /** 13 | * @file DMRDMOTX.h 14 | * @ingroup dmr_mfw 15 | * @file DMRDMOTX.cpp 16 | * @ingroup dmr_mfw 17 | */ 18 | #if !defined(__DMR_DMO_TX_H__) 19 | #define __DMR_DMO_TX_H__ 20 | 21 | #include "Defines.h" 22 | #include "dmr/DMRDefines.h" 23 | #include "SerialBuffer.h" 24 | 25 | namespace dmr 26 | { 27 | // --------------------------------------------------------------------------- 28 | // Constants 29 | // --------------------------------------------------------------------------- 30 | 31 | #define DMRDMO_FIXED_DELAY 300 // 300 = 62.49ms 32 | // Delay Value * 0.2083 = Preamble Length (ms) 33 | 34 | // --------------------------------------------------------------------------- 35 | // Class Declaration 36 | // --------------------------------------------------------------------------- 37 | 38 | /** 39 | * @brief Implements transmitter logic for DMR DMO mode operation. 40 | * @ingroup dmr_mfw 41 | */ 42 | class DSP_FW_API DMRDMOTX { 43 | public: 44 | /** 45 | * @brief Initializes a new instance of the DMRDMOTX class. 46 | */ 47 | DMRDMOTX(); 48 | 49 | /** 50 | * @brief Process local buffer and transmit on the air interface. 51 | */ 52 | void process(); 53 | 54 | /** 55 | * @brief Write data to the local buffer. 56 | * @param[in] data Buffer. 57 | * @param length Length of buffer. 58 | * @returns uint8_t Reason code. 59 | */ 60 | uint8_t writeData(const uint8_t* data, uint8_t length); 61 | 62 | /** 63 | * @brief Sets the FDMA preamble count. 64 | * @param preambleCnt FDMA preamble count. 65 | */ 66 | void setPreambleCount(uint8_t preambleCnt); 67 | /** 68 | * @brief Sets the fine adjust 4FSK symbol levels. 69 | * @param level3Adj +3/-3 Level Adjustment 70 | * @param level1Adj +1/-1 Level Adjustment 71 | */ 72 | void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj); 73 | 74 | /** 75 | * @brief Helper to resize the FIFO buffer. 76 | * @param size 77 | */ 78 | void resizeBuffer(uint16_t size); 79 | 80 | /** 81 | * @brief Helper to get how much space the ring buffer has for samples. 82 | * @returns uint8_t Amount of space in ring buffer for samples. 83 | */ 84 | uint8_t getSpace() const; 85 | 86 | private: 87 | SerialBuffer m_fifo; 88 | 89 | arm_fir_interpolate_instance_q15 m_modFilter; 90 | 91 | q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare 92 | 93 | uint8_t m_poBuffer[1200U]; 94 | uint16_t m_poLen; 95 | uint16_t m_poPtr; 96 | 97 | uint32_t m_preambleCnt; 98 | 99 | int8_t m_symLevel3Adj; 100 | int8_t m_symLevel1Adj; 101 | 102 | /** 103 | * @brief Helper to write a raw byte to the DAC. 104 | * @param c Byte. 105 | */ 106 | void writeByte(uint8_t c); 107 | /** 108 | * @brief 109 | */ 110 | void writeSilence(); 111 | }; 112 | } // namespace dmr 113 | 114 | #endif // __DMR_DMO_TX_H__ 115 | -------------------------------------------------------------------------------- /dmr/DMRDefines.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2009-2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @defgroup dmr_mfw Digital Mobile Radio 12 | * @brief Implementation for the ETSI TS-102 Digital Mobile Radio (DMR) standard. 13 | * @ingroup modem_fw 14 | * 15 | * @file DMRDefines.h 16 | * @ingroup dmr_mfw 17 | */ 18 | #if !defined(__DMR_DEFINES_H__) 19 | #define __DMR_DEFINES_H__ 20 | 21 | #include "Defines.h" 22 | 23 | namespace dmr 24 | { 25 | // --------------------------------------------------------------------------- 26 | // Constants 27 | // --------------------------------------------------------------------------- 28 | 29 | /** 30 | * @addtogroup dmr_mfw 31 | * @{ 32 | */ 33 | 34 | const uint32_t DMR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate 35 | 36 | const uint32_t DMR_FRAME_LENGTH_BYTES = 33U; 37 | const uint32_t DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U; 38 | const uint32_t DMR_FRAME_LENGTH_SYMBOLS = DMR_FRAME_LENGTH_BYTES * 4U; 39 | const uint32_t DMR_FRAME_LENGTH_SAMPLES = DMR_FRAME_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 40 | 41 | const uint32_t DMR_SYNC_LENGTH_BYTES = 6U; 42 | const uint32_t DMR_SYNC_LENGTH_BITS = DMR_SYNC_LENGTH_BYTES * 8U; 43 | const uint32_t DMR_SYNC_LENGTH_SYMBOLS = DMR_SYNC_LENGTH_BYTES * 4U; 44 | const uint32_t DMR_SYNC_LENGTH_SAMPLES = DMR_SYNC_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 45 | 46 | const uint32_t DMR_EMB_LENGTH_BITS = 16U; 47 | const uint32_t DMR_EMB_LENGTH_SYMBOLS = 8U; 48 | const uint32_t DMR_EMB_LENGTH_SAMPLES = DMR_EMB_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 49 | 50 | const uint32_t DMR_EMBSIG_LENGTH_BITS = 32U; 51 | const uint32_t DMR_EMBSIG_LENGTH_SYMBOLS = 16U; 52 | const uint32_t DMR_EMBSIG_LENGTH_SAMPLES = DMR_EMBSIG_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 53 | 54 | const uint32_t DMR_SLOT_TYPE_LENGTH_BITS = 20U; 55 | const uint32_t DMR_SLOT_TYPE_LENGTH_SYMBOLS = 10U; 56 | const uint32_t DMR_SLOT_TYPE_LENGTH_SAMPLES = DMR_SLOT_TYPE_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 57 | 58 | const uint32_t DMR_INFO_LENGTH_BITS = 196U; 59 | const uint32_t DMR_INFO_LENGTH_SYMBOLS = 98U; 60 | const uint32_t DMR_INFO_LENGTH_SAMPLES = DMR_INFO_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 61 | 62 | const uint32_t DMR_AUDIO_LENGTH_BITS = 216U; 63 | const uint32_t DMR_AUDIO_LENGTH_SYMBOLS = 108U; 64 | const uint32_t DMR_AUDIO_LENGTH_SAMPLES = DMR_AUDIO_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 65 | 66 | const uint32_t DMR_CACH_LENGTH_BYTES = 3U; 67 | const uint32_t DMR_CACH_LENGTH_BITS = DMR_CACH_LENGTH_BYTES * 8U; 68 | const uint32_t DMR_CACH_LENGTH_SYMBOLS = DMR_CACH_LENGTH_BYTES * 4U; 69 | const uint32_t DMR_CACH_LENGTH_SAMPLES = DMR_CACH_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH; 70 | 71 | const uint8_t DMR_SYNC_BYTES_LENGTH = 7U; 72 | const uint8_t DMR_MS_DATA_SYNC_BYTES[] = { 0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U }; 73 | const uint8_t DMR_MS_VOICE_SYNC_BYTES[] = { 0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U }; 74 | const uint8_t DMR_BS_DATA_SYNC_BYTES[] = { 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U }; 75 | const uint8_t DMR_BS_VOICE_SYNC_BYTES[] = { 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U }; 76 | const uint8_t DMR_SYNC_BYTES_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U }; 77 | 78 | const uint8_t DMR_START_SYNC = 0x5FU; 79 | 80 | const uint64_t DMR_MS_DATA_SYNC_BITS = 0x0000D5D7F77FD757U; 81 | const uint64_t DMR_MS_VOICE_SYNC_BITS = 0x00007F7D5DD57DFDU; 82 | const uint64_t DMR_BS_DATA_SYNC_BITS = 0x0000DFF57D75DF5DU; 83 | const uint64_t DMR_BS_VOICE_SYNC_BITS = 0x0000755FD7DF75F7U; 84 | const uint64_t DMR_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; 85 | 86 | const uint32_t DMR_MS_DATA_SYNC_SYMBOLS = 0x0076286EU; 87 | const uint32_t DMR_MS_VOICE_SYNC_SYMBOLS = 0x0089D791U; 88 | const uint32_t DMR_BS_DATA_SYNC_SYMBOLS = 0x00439B4DU; 89 | const uint32_t DMR_BS_VOICE_SYNC_SYMBOLS = 0x00BC64B2U; 90 | const uint32_t DMR_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; 91 | 92 | // D 5 D 7 F 7 7 F D 7 5 7 93 | // 11 01 01 01 11 01 01 11 11 11 01 11 01 11 11 11 11 01 01 11 01 01 01 11 94 | // -3 +3 +3 +3 -3 +3 +3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 +3 +3 -3 +3 +3 +3 -3 95 | 96 | const int8_t DMR_MS_DATA_SYNC_SYMBOLS_VALUES[] = { -3, +3, +3, +3, -3, +3, +3, -3, -3, -3, +3, -3, +3, -3, -3, -3, -3, +3, +3, -3, +3, +3, +3, -3 }; 97 | 98 | // 7 F 7 D 5 D D 5 7 D F D 99 | // 01 11 11 11 01 11 11 01 01 01 11 01 11 01 01 01 01 11 11 01 11 11 11 01 100 | // +3 -3 -3 -3 +3 -3 -3 +3 +3 +3 -3 +3 -3 +3 +3 +3 +3 -3 -3 +3 -3 -3 -3 +3 101 | 102 | const int8_t DMR_MS_VOICE_SYNC_SYMBOLS_VALUES[] = { +3, -3, -3, -3, +3, -3, -3, +3, +3, +3, -3, +3, -3, +3, +3, +3, +3, -3, -3, +3, -3, -3, -3, +3 }; 103 | 104 | // 505 = DMR_FRAME_LENGTH_BYTES * 15 + 10 (BUFFER_LEN = DMR_FRAME_LENGTH_BYTES * NO_OF_FRAMES + 10) 105 | const uint32_t DMR_TX_BUFFER_LEN = 505U; // 15 frames + pad 106 | 107 | // Data Type(s) 108 | const uint8_t DT_VOICE_PI_HEADER = 0U; 109 | const uint8_t DT_VOICE_LC_HEADER = 1U; 110 | const uint8_t DT_TERMINATOR_WITH_LC = 2U; 111 | const uint8_t DT_CSBK = 3U; 112 | const uint8_t DT_DATA_HEADER = 6U; 113 | const uint8_t DT_RATE_12_DATA = 7U; 114 | const uint8_t DT_RATE_34_DATA = 8U; 115 | const uint8_t DT_IDLE = 9U; 116 | const uint8_t DT_RATE_1_DATA = 10U; 117 | 118 | /** @} */ 119 | } // namespace dmr 120 | 121 | #endif // __DMR_DEFINES_H__ 122 | -------------------------------------------------------------------------------- /dmr/DMRIdleRX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * @package DVM / Modem Firmware 8 | * @derivedfrom MMDVM (https://github.com/g4klx/MMDVM) 9 | * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) 10 | * 11 | * Copyright (C) 2015 Jonathan Naylor, G4KLX 12 | * 13 | */ 14 | /** 15 | * @file DMRIdleRX.h 16 | * @ingroup dmr_mfw 17 | * @file DMRIdleRX.cpp 18 | * @ingroup dmr_mfw 19 | */ 20 | #if !defined(__DMR_IDLE_RX_H__) 21 | #define __DMR_IDLE_RX_H__ 22 | 23 | #include "Defines.h" 24 | #include "dmr/DMRDefines.h" 25 | 26 | namespace dmr 27 | { 28 | // --------------------------------------------------------------------------- 29 | // Class Declaration 30 | // --------------------------------------------------------------------------- 31 | 32 | /** 33 | * @brief Implements receiver logic for idle DMR mode operation. 34 | * @ingroup dmr_mfw 35 | */ 36 | class DSP_FW_API DMRIdleRX { 37 | public: 38 | /** 39 | * @brief Initializes a new instance of the DMRIdleRX class. 40 | */ 41 | DMRIdleRX(); 42 | 43 | /** 44 | * @brief Helper to reset data values to defaults. 45 | */ 46 | void reset(); 47 | 48 | /** 49 | * @brief Sample DMR values from the air interface. 50 | * @param[in] samples 51 | * @param length 52 | */ 53 | void samples(const q15_t* samples, uint8_t length); 54 | 55 | /** 56 | * @brief Sets the DMR color code. 57 | * @param colorCode 58 | */ 59 | void setColorCode(uint8_t colorCode); 60 | 61 | private: 62 | uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; 63 | q15_t m_buffer[DMR_FRAME_LENGTH_SAMPLES]; 64 | uint16_t m_bitPtr; 65 | uint16_t m_dataPtr; 66 | uint16_t m_endPtr; 67 | 68 | q31_t m_maxCorr; 69 | q15_t m_centre; 70 | q15_t m_threshold; 71 | 72 | uint8_t m_colorCode; 73 | 74 | /** 75 | * @brief Helper to perform sample processing. 76 | * @param sample 77 | */ 78 | void processSample(q15_t sample); 79 | 80 | /** 81 | * @brief 82 | * @param start 83 | * @param count 84 | * @param buffer 85 | * @param offset 86 | * @param centre 87 | * @param threshold 88 | */ 89 | void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); 90 | }; 91 | } // namespace dmr 92 | 93 | #endif // __DMR_IDLE_RX_H__ 94 | -------------------------------------------------------------------------------- /dmr/DMRRX.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | #include "Globals.h" 11 | #include "dmr/DMRRX.h" 12 | 13 | using namespace dmr; 14 | 15 | // --------------------------------------------------------------------------- 16 | // Public Class Members 17 | // --------------------------------------------------------------------------- 18 | 19 | /* Initializes a new instance of the DMRRX class. */ 20 | 21 | DMRRX::DMRRX() : 22 | m_slot1RX(false), 23 | m_slot2RX(true) 24 | { 25 | /* stub */ 26 | } 27 | 28 | /* Helper to reset data values to defaults. */ 29 | 30 | void DMRRX::reset() 31 | { 32 | m_slot1RX.reset(); 33 | m_slot2RX.reset(); 34 | } 35 | 36 | /* Sample DMR values from the air interface. */ 37 | 38 | void DMRRX::samples(const q15_t* samples, const uint16_t* rssi, const uint8_t* control, uint8_t length) 39 | { 40 | bool dcd1 = false; 41 | bool dcd2 = false; 42 | 43 | for (uint16_t i = 0U; i < length; i++) { 44 | switch (control[i]) { 45 | case MARK_SLOT1: 46 | m_slot1RX.start(); 47 | break; 48 | case MARK_SLOT2: 49 | m_slot2RX.start(); 50 | break; 51 | default: 52 | break; 53 | } 54 | 55 | dcd1 = m_slot1RX.processSample(samples[i], rssi[i]); 56 | dcd2 = m_slot2RX.processSample(samples[i], rssi[i]); 57 | } 58 | 59 | io.setDecode(dcd1 || dcd2); 60 | } 61 | 62 | /* Sets the DMR color code. */ 63 | 64 | void DMRRX::setColorCode(uint8_t colorCode) 65 | { 66 | m_slot1RX.setColorCode(colorCode); 67 | m_slot2RX.setColorCode(colorCode); 68 | } 69 | 70 | /* Sets the number of samples to delay before processing. */ 71 | 72 | void DMRRX::setRxDelay(uint8_t delay) 73 | { 74 | m_slot1RX.setRxDelay(delay); 75 | m_slot2RX.setRxDelay(delay); 76 | } 77 | -------------------------------------------------------------------------------- /dmr/DMRRX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file DMRRX.h 12 | * @ingroup dmr_mfw 13 | * @file DMRRX.cpp 14 | * @ingroup dmr_mfw 15 | */ 16 | #if !defined(__DMR_RX_H__) 17 | #define __DMR_RX_H__ 18 | 19 | #include "Defines.h" 20 | #include "dmr/DMRSlotRX.h" 21 | 22 | namespace dmr 23 | { 24 | // --------------------------------------------------------------------------- 25 | // Class Declaration 26 | // --------------------------------------------------------------------------- 27 | 28 | /** 29 | * @brief Implements receiver logic for duplex DMR mode operation. 30 | * @ingroup dmr_mfw 31 | */ 32 | class DSP_FW_API DMRRX { 33 | public: 34 | /** 35 | * @brief Initializes a new instance of the DMRRX class. 36 | */ 37 | DMRRX(); 38 | 39 | /** 40 | * @brief Helper to reset data values to defaults. 41 | */ 42 | void reset(); 43 | 44 | /** 45 | * @brief Sample DMR values from the air interface. 46 | * @param[in] samples 47 | * @param[in] rssi 48 | * @param[in] control 49 | * @param length 50 | */ 51 | void samples(const q15_t* samples, const uint16_t* rssi, const uint8_t* control, uint8_t length); 52 | 53 | /** 54 | * @brief Sets the DMR color code. 55 | * @param colorCode 56 | */ 57 | void setColorCode(uint8_t colorCode); 58 | /** 59 | * @brief Sets the number of samples to delay before processing. 60 | * @param delay 61 | */ 62 | void setRxDelay(uint8_t delay); 63 | 64 | private: 65 | DMRSlotRX m_slot1RX; 66 | DMRSlotRX m_slot2RX; 67 | }; 68 | } // namespace dmr 69 | 70 | #endif // __DMR_RX_H__ 71 | -------------------------------------------------------------------------------- /dmr/DMRSlotRX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file DMRSlotRX.h 12 | * @ingroup dmr_mfw 13 | * @file DMRSlotRX.cpp 14 | * @ingroup dmr_mfw 15 | */ 16 | #if !defined(__DMR_SLOT_RX_H__) 17 | #define __DMR_SLOT_RX_H__ 18 | 19 | #include "Defines.h" 20 | #include "dmr/DMRDefines.h" 21 | 22 | namespace dmr 23 | { 24 | // --------------------------------------------------------------------------- 25 | // Constants 26 | // --------------------------------------------------------------------------- 27 | 28 | /** 29 | * @brief DMR Slot Receiver State 30 | * @ingroup dmr_mfw 31 | */ 32 | enum DMRRX_STATE { 33 | DMRRXS_NONE, //! None 34 | DMRRXS_VOICE, //! Voice Data 35 | DMRRXS_DATA //! PDU Data 36 | }; 37 | 38 | // --------------------------------------------------------------------------- 39 | // Class Declaration 40 | // --------------------------------------------------------------------------- 41 | 42 | /** 43 | * @brief Implements receiver logic for DMR slots. 44 | * @ingroup dmr_mfw 45 | */ 46 | class DSP_FW_API DMRSlotRX { 47 | public: 48 | /** 49 | * @brief Initializes a new instance of the DMRSlotRX class. 50 | * @param slot 51 | */ 52 | DMRSlotRX(bool slot); 53 | 54 | /** 55 | * @brief Helper to set data values for start of Rx. 56 | */ 57 | void start(); 58 | /** 59 | * @brief Helper to reset data values to defaults. 60 | */ 61 | void reset(); 62 | 63 | /** 64 | * @brief Perform DMR slot sample processing. 65 | * @param sample 66 | * @param rssi 67 | */ 68 | bool processSample(q15_t sample, uint16_t rssi); 69 | 70 | /** 71 | * @brief Sets the DMR color code. 72 | * @param colorCode 73 | */ 74 | void setColorCode(uint8_t colorCode); 75 | /** 76 | * @brief Sets the number of samples to delay before processing. 77 | * @param delay 78 | */ 79 | void setRxDelay(uint8_t delay); 80 | 81 | private: 82 | bool m_slot; 83 | 84 | uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH]; 85 | q15_t m_buffer[900U]; 86 | 87 | uint16_t m_bitPtr; 88 | uint16_t m_dataPtr; 89 | uint16_t m_syncPtr; 90 | uint16_t m_startPtr; 91 | uint16_t m_endPtr; 92 | uint16_t m_delayPtr; 93 | 94 | q31_t m_maxCorr; 95 | q15_t m_centre[4U]; 96 | q15_t m_threshold[4U]; 97 | uint8_t m_averagePtr; 98 | 99 | uint8_t m_control; 100 | uint8_t m_syncCount; 101 | 102 | uint8_t m_colorCode; 103 | 104 | uint16_t m_delay; 105 | 106 | DMRRX_STATE m_state; 107 | 108 | uint8_t m_n; 109 | 110 | uint8_t m_type; 111 | 112 | uint16_t m_rssi[900U]; 113 | 114 | /** 115 | * @brief Frame synchronization correlator. 116 | * @param first 117 | */ 118 | void correlateSync(bool first); 119 | 120 | /** 121 | * @brief 122 | * @param start 123 | * @param count 124 | * @param buffer 125 | * @param offset 126 | * @param centre 127 | * @param threshold 128 | */ 129 | void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); 130 | /** 131 | * @brief 132 | * @param frame 133 | */ 134 | void writeRSSIData(uint8_t* frame); 135 | }; 136 | } // namespace dmr 137 | 138 | #endif // __DMR_SLOT_RX_H__ 139 | -------------------------------------------------------------------------------- /dmr/DMRSlotType.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file DMRSlotType.h 12 | * @ingroup dmr_mfw 13 | * @file DMRSlotType.cpp 14 | * @ingroup dmr_mfw 15 | */ 16 | #if !defined(__DMR_SLOT_TYPE_H__) 17 | #define __DMR_SLOT_TYPE_H__ 18 | 19 | #include "Defines.h" 20 | 21 | namespace dmr 22 | { 23 | // --------------------------------------------------------------------------- 24 | // Class Declaration 25 | // --------------------------------------------------------------------------- 26 | 27 | /** 28 | * @brief Represents DMR slot type. 29 | * @ingroup dmr_mfw 30 | */ 31 | class DSP_FW_API DMRSlotType { 32 | public: 33 | /** 34 | * @brief Initializes a new instance of the DMRSlotType class. 35 | */ 36 | DMRSlotType(); 37 | 38 | /** 39 | * @brief Decodes DMR slot type. 40 | * @param[in] frame 41 | * @param[out] colorCode 42 | * @param[out] dataType 43 | */ 44 | void decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const; 45 | /** 46 | * @brief Encodes DMR slot type. 47 | * @param colorCode 48 | * @param dataType 49 | * @param[out] frame 50 | */ 51 | void encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const; 52 | 53 | private: 54 | /** 55 | * @brief 56 | * @param[in] data 57 | * @returns uint8_t 58 | */ 59 | uint8_t decode2087(const uint8_t* data) const; 60 | /** 61 | * @brief 62 | * @param pattern 63 | * @returns uint32_t 64 | */ 65 | uint32_t getSyndrome1987(uint32_t pattern) const; 66 | }; 67 | } // namespace dmr 68 | 69 | #endif // __DMR_SLOT_TYPE_H__ 70 | -------------------------------------------------------------------------------- /nxdn/CalNXDN.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2018 Andy Uribe, CA6JAU 8 | * Copyright (C) 2020 Jonathan Naylor, G4KLX 9 | * 10 | */ 11 | #include "Globals.h" 12 | #include "nxdn/CalNXDN.h" 13 | 14 | using namespace nxdn; 15 | 16 | // --------------------------------------------------------------------------- 17 | // Constants 18 | // --------------------------------------------------------------------------- 19 | 20 | // NXDN 1031 Hz Test Pattern, RAN: 1, Unit ID: 1, Dst Group ID: 1, Outbound Direction 21 | const uint8_t NXDN_CAL1K[4][49] = { 22 | { 0x00U, 23 | 0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0xFAU, 0x0AU, 0x6EU, 0x8AU, 0x23U, 0x56U, 0xE8U, 24 | 0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U, 25 | 0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U, 26 | 0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U, 27 | 0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U }, 28 | 29 | { 0x00U, 30 | 0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0x6DU, 0xBBU, 0x0EU, 0xB3U, 0xA4U, 0x26U, 0xA8U, 31 | 0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U, 32 | 0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U, 33 | 0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U, 34 | 0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U }, 35 | 36 | { 0x00U, 37 | 0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x76U, 0x3AU, 0x1BU, 0x4AU, 0x81U, 0xA8U, 0xE2U, 0x80U, 38 | 0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U, 39 | 0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U, 40 | 0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U, 41 | 0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U }, 42 | 43 | { 0x00U, 44 | 0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x74U, 0x28U, 0x83U, 0x02U, 0xB0U, 0x2DU, 0x07U, 0xE2U, 45 | 0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U, 46 | 0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U, 47 | 0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U, 48 | 0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U } 49 | }; 50 | 51 | // --------------------------------------------------------------------------- 52 | // Public Class Members 53 | // --------------------------------------------------------------------------- 54 | 55 | /* Initializes a new instance of the CalNXDN class. */ 56 | 57 | CalNXDN::CalNXDN() : 58 | m_transmit(false), 59 | m_state(NXDNCAL1K_IDLE), 60 | m_audioSeq(0U) 61 | { 62 | /* stub */ 63 | } 64 | 65 | /* Process local state and transmit on the air interface. */ 66 | 67 | void CalNXDN::process() 68 | { 69 | if (m_transmit) { 70 | nxdnTX.setCal(true); 71 | nxdnTX.process(); 72 | } 73 | else { 74 | nxdnTX.setCal(false); 75 | } 76 | 77 | uint16_t space = nxdnTX.getSpace(); 78 | if (space < 1U) 79 | return; 80 | 81 | if (m_audioSeq > 3U) { 82 | m_audioSeq = 0U; 83 | } 84 | 85 | switch (m_state) { 86 | case NXDNCAL1K_TX: 87 | nxdnTX.writeData(NXDN_CAL1K[m_audioSeq], NXDN_FRAME_LENGTH_BYTES + 1U); 88 | m_audioSeq++; 89 | if (!m_transmit) { 90 | m_state = NXDNCAL1K_IDLE; 91 | m_audioSeq = 0U; 92 | } 93 | break; 94 | default: 95 | m_state = NXDNCAL1K_IDLE; 96 | m_audioSeq = 0U; 97 | break; 98 | } 99 | } 100 | 101 | /* Write NXDN calibration data to the local buffer. */ 102 | 103 | uint8_t CalNXDN::write(const uint8_t* data, uint16_t length) 104 | { 105 | if (length != 1U) 106 | return RSN_ILLEGAL_LENGTH; 107 | 108 | m_transmit = data[0U] == 1U; 109 | 110 | if(m_transmit && m_state == NXDNCAL1K_IDLE) 111 | m_state = NXDNCAL1K_TX; 112 | 113 | return RSN_OK; 114 | } 115 | -------------------------------------------------------------------------------- /nxdn/CalNXDN.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2018 Andy Uribe, CA6JAU 8 | * Copyright (C) 2020 Jonathan Naylor, G4KLX 9 | * 10 | */ 11 | /** 12 | * @file CalNXDN.h 13 | * @ingroup nxdn_mfw 14 | * @file CalNXDN.cpp 15 | * @ingroup nxdn_mfw 16 | */ 17 | #if !defined(__CAL_NXDN_H__) 18 | #define __CAL_NXDN_H__ 19 | 20 | #include "Defines.h" 21 | #include "nxdn/NXDNDefines.h" 22 | 23 | namespace nxdn 24 | { 25 | // --------------------------------------------------------------------------- 26 | // Constants 27 | // --------------------------------------------------------------------------- 28 | 29 | /** 30 | * @brief Calibration States 31 | * @ingroup nxdn_mfw 32 | */ 33 | enum NXDNCAL1K { 34 | NXDNCAL1K_IDLE, //! Idle 35 | NXDNCAL1K_TX //! Transmit 36 | }; 37 | 38 | // --------------------------------------------------------------------------- 39 | // Class Declaration 40 | // --------------------------------------------------------------------------- 41 | 42 | /** 43 | * @brief Implements logic for NXDN calibration mode. 44 | * @ingroup nxdn_mfw 45 | */ 46 | class DSP_FW_API CalNXDN { 47 | public: 48 | /** 49 | * @brief Initializes a new instance of the CalNXDN class. 50 | */ 51 | CalNXDN(); 52 | 53 | /** 54 | * @brief Process local state and transmit on the air interface. 55 | */ 56 | void process(); 57 | 58 | /** 59 | * @brief Write NXDN calibration state. 60 | * @param[in] data Buffer. 61 | * @param length Length of buffer. 62 | * @returns uint8_t Reason code. 63 | */ 64 | uint8_t write(const uint8_t* data, uint16_t length); 65 | 66 | private: 67 | bool m_transmit; 68 | NXDNCAL1K m_state; 69 | 70 | uint8_t m_audioSeq; 71 | }; 72 | } // namespace nxdn 73 | 74 | #endif // __CAL_NXDN_H__ 75 | -------------------------------------------------------------------------------- /nxdn/NXDNDefines.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /** 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * @package DVM / Modem Firmware 8 | * @derivedfrom MMDVM (https://github.com/g4klx/MMDVM) 9 | * @license GPLv2 License (https://opensource.org/licenses/GPL-2.0) 10 | * 11 | * Copyright (C) 2016,2017,2018 Jonathan Naylor, G4KLX 12 | * 13 | */ 14 | /** 15 | * @defgroup nxdn_mfw Next Generation Digital Narrowband 16 | * @brief Implementation for the NXDN standard. 17 | * @ingroup modem_fw 18 | * 19 | * @file NXDNDefines.h 20 | * @ingroup nxdn_mfw 21 | */ 22 | #if !defined(__NXDN_DEFINES_H__) 23 | #define __NXDN_DEFINES_H__ 24 | 25 | #include "Defines.h" 26 | 27 | namespace nxdn 28 | { 29 | // --------------------------------------------------------------------------- 30 | // Constants 31 | // --------------------------------------------------------------------------- 32 | 33 | /** 34 | * @addtogroup nxdn_mfw 35 | * @{ 36 | */ 37 | 38 | const uint32_t NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate 39 | 40 | const uint32_t NXDN_FRAME_LENGTH_BITS = 384U; 41 | const uint32_t NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U; 42 | const uint32_t NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U; 43 | const uint32_t NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH; 44 | 45 | const uint32_t NXDN_FSW_LENGTH_BITS = 20U; 46 | const uint32_t NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U; 47 | const uint32_t NXDN_FSW_LENGTH_SAMPLES = NXDN_FSW_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH; 48 | 49 | const uint8_t NXDN_FSW_BYTES[] = { 0xCDU, 0xF5U, 0x90U }; 50 | const uint8_t NXDN_FSW_BYTES_MASK[] = { 0xFFU, 0xFFU, 0xF0U }; 51 | const uint8_t NXDN_FSW_BYTES_LENGTH = 3U; 52 | 53 | const uint32_t NXDN_FSW_BITS = 0x000CDF59U; 54 | const uint32_t NXDN_FSW_BITS_MASK = 0x000FFFFFU; 55 | 56 | const uint8_t NXDN_PREAMBLE[] = { 0x57U, 0x75U, 0xFDU }; 57 | const uint8_t NXDN_SYNC = 0x5FU; 58 | 59 | // C D F 5 9 60 | // 11 00 11 01 11 11 01 01 10 01 61 | // -3 +1 -3 +3 -3 -3 +3 +3 -1 +3 62 | 63 | const int8_t NXDN_FSW_SYMBOLS_VALUES[] = {-3, +1, -3, +3, -3, -3, +3, +3, -1, +3}; 64 | 65 | const uint16_t NXDN_FSW_SYMBOLS = 0x014DU; 66 | const uint16_t NXDN_FSW_SYMBOLS_MASK = 0x03FFU; 67 | 68 | // 538 = NXDN_FRAME_LENGTH_BYTES * 11 + 10 (BUFFER_LEN = NXDN_FRAME_LENGTH_BYTES * NO_OF_FRAMES) 69 | const uint32_t NXDN_TX_BUFFER_LEN = 538U; // 11 frames + pad 70 | 71 | /** @} */ 72 | } // namespace nxdn 73 | 74 | #endif // __NXDN_DEFINES_H__ 75 | -------------------------------------------------------------------------------- /nxdn/NXDNRX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017,2018,2020 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file NXDNRX.h 12 | * @ingroup nxdn_mfw 13 | * @file NXDNRX.cpp 14 | * @ingroup nxdn_mfw 15 | */ 16 | #if !defined(__NXDN_RX_H__) 17 | #define __NXDN_RX_H__ 18 | 19 | #include "Defines.h" 20 | #include "nxdn/NXDNDefines.h" 21 | 22 | namespace nxdn 23 | { 24 | // --------------------------------------------------------------------------- 25 | // Constants 26 | // --------------------------------------------------------------------------- 27 | 28 | /** 29 | * @brief NXDN Receiver State 30 | * @ingroup nxdn_mfw 31 | */ 32 | enum NXDNRX_STATE { 33 | NXDNRXS_NONE, //! None 34 | NXDNRXS_DATA //! Data 35 | }; 36 | 37 | // --------------------------------------------------------------------------- 38 | // Class Declaration 39 | // --------------------------------------------------------------------------- 40 | 41 | /** 42 | * @brief Implements receiver logic for NXDN mode operation. 43 | * @ingroup nxdn_mfw 44 | */ 45 | class DSP_FW_API NXDNRX { 46 | public: 47 | /** 48 | * @brief Initializes a new instance of the NXDNRX class. 49 | */ 50 | NXDNRX(); 51 | 52 | /** 53 | * @brief Helper to reset data values to defaults. 54 | */ 55 | void reset(); 56 | 57 | /** 58 | * @brief Sample NXDN values from the air interface. 59 | * @param[in] samples 60 | * @param rssi 61 | * @param length 62 | */ 63 | void samples(const q15_t* samples, uint16_t* rssi, uint8_t length); 64 | 65 | /** 66 | * @brief Sets the NXDN sync correlation countdown. 67 | * @param count Sync Correlation Countdown. 68 | */ 69 | void setCorrCount(uint8_t count); 70 | 71 | private: 72 | uint16_t m_bitBuffer[NXDN_RADIO_SYMBOL_LENGTH]; 73 | q15_t m_buffer[NXDN_FRAME_LENGTH_SAMPLES]; 74 | 75 | uint16_t m_bitPtr; 76 | uint16_t m_dataPtr; 77 | 78 | uint16_t m_startPtr; 79 | uint16_t m_endPtr; 80 | 81 | uint16_t m_fswPtr; 82 | uint16_t m_minFSWPtr; 83 | uint16_t m_maxFSWPtr; 84 | 85 | q31_t m_maxCorr; 86 | q15_t m_centre[16U]; 87 | q15_t m_centreVal; 88 | q15_t m_threshold[16U]; 89 | q15_t m_thresholdVal; 90 | uint8_t m_averagePtr; 91 | 92 | uint16_t m_lostCount; 93 | uint8_t m_countdown; 94 | 95 | uint8_t m_corrCountdown; 96 | 97 | NXDNRX_STATE m_state; 98 | 99 | uint32_t m_rssiAccum; 100 | uint16_t m_rssiCount; 101 | 102 | /** 103 | * @brief Helper to process NXDN samples. 104 | * @param sample 105 | */ 106 | void processSample(q15_t sample); 107 | /** 108 | * @brief Helper to process NXDN data samples. 109 | * @param sample 110 | */ 111 | void processData(q15_t sample); 112 | 113 | /** 114 | * @brief Frame synchronization correlator. 115 | * @returns bool 116 | */ 117 | bool correlateSync(); 118 | 119 | /** 120 | * @brief 121 | * @param start 122 | * @param count 123 | */ 124 | void calculateLevels(uint16_t start, uint16_t count); 125 | /** 126 | * @brief 127 | * @param start 128 | * @param count 129 | * @param buffer 130 | * @param offset 131 | * @param centre 132 | * @param threshold 133 | */ 134 | void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); 135 | }; 136 | } // namespace nxdn 137 | 138 | #endif // __NXDN_RX_H__ 139 | -------------------------------------------------------------------------------- /nxdn/NXDNTX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017,2018,2020 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2022 by Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @file NXDNTX.h 13 | * @ingroup nxdn_mfw 14 | * @file NXDNTX.cpp 15 | * @ingroup nxdn_mfw 16 | */ 17 | #if !defined(__NXDN_TX_H__) 18 | #define __NXDN_TX_H__ 19 | 20 | #include "Defines.h" 21 | #include "SerialBuffer.h" 22 | 23 | namespace nxdn 24 | { 25 | // --------------------------------------------------------------------------- 26 | // Constants 27 | // --------------------------------------------------------------------------- 28 | 29 | #define NXDN_FIXED_TX_HANG 600 30 | 31 | /** 32 | * @brief NXDN Transmitter States 33 | * @ingroup nxdn_mfw 34 | */ 35 | enum NXDNTXSTATE { 36 | NXDNTXSTATE_NORMAL, //! Normal 37 | NXDNTXSTATE_CAL //! Calibration 38 | }; 39 | 40 | // --------------------------------------------------------------------------- 41 | // Class Declaration 42 | // --------------------------------------------------------------------------- 43 | 44 | /** 45 | * @brief Implements transmitter logic for NXDN mode operation. 46 | * @ingroup nxdn_mfw 47 | */ 48 | class DSP_FW_API NXDNTX { 49 | public: 50 | /** 51 | * @brief Initializes a new instance of the NXDNTX class. 52 | */ 53 | NXDNTX(); 54 | 55 | /** 56 | * @brief Process local buffer and transmit on the air interface. 57 | */ 58 | void process(); 59 | 60 | /** 61 | * @brief Write data to the local buffer. 62 | * @param[in] data Buffer. 63 | * @param length Length of buffer. 64 | * @returns uint8_t Reason code. 65 | */ 66 | uint8_t writeData(const uint8_t* data, uint8_t length); 67 | 68 | /** 69 | * @brief Clears the local buffer. 70 | */ 71 | void clear(); 72 | 73 | /** 74 | * @brief Sets the FDMA preamble count. 75 | * @param preambleCnt FDMA preamble count. 76 | */ 77 | void setPreambleCount(uint8_t preambleCnt); 78 | /** 79 | * @brief Sets the transmit hang time. 80 | * @param txHang Transmit hang time. 81 | */ 82 | void setTxHang(uint8_t txHang); 83 | /** 84 | * @brief Sets the fine adjust 4FSK symbol levels. 85 | * @param level3Adj +3/-3 Level Adjustment 86 | * @param level1Adj +1/-1 Level Adjustment 87 | */ 88 | void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj); 89 | /** 90 | * @brief Helper to set the calibration state for Tx. 91 | * @param start 92 | */ 93 | void setCal(bool start); 94 | 95 | /** 96 | * @brief Helper to resize the FIFO buffer. 97 | * @param size 98 | */ 99 | void resizeBuffer(uint16_t size); 100 | 101 | /** 102 | * @brief Helper to get how much space the ring buffer has for samples. 103 | * @returns uint8_t Amount of space in ring buffer for samples. 104 | */ 105 | uint8_t getSpace() const; 106 | 107 | private: 108 | SerialBuffer m_fifo; 109 | 110 | NXDNTXSTATE m_state; 111 | 112 | arm_fir_interpolate_instance_q15 m_modFilter; 113 | arm_fir_instance_q15 m_sincFilter; 114 | 115 | q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare 116 | q15_t m_sincState[70U]; // NoTaps + BlockSize - 1, 22 + 40 - 1 plus some spare 117 | 118 | uint8_t m_poBuffer[1200U]; 119 | uint16_t m_poLen; 120 | uint16_t m_poPtr; 121 | 122 | uint16_t m_preambleCnt; 123 | uint32_t m_txHang; 124 | uint32_t m_tailCnt; 125 | 126 | int8_t m_symLevel3Adj; 127 | int8_t m_symLevel1Adj; 128 | 129 | /** 130 | * @brief Helper to generate data. 131 | */ 132 | void createData(); 133 | 134 | /** 135 | * @brief Helper to write a raw byte to the DAC. 136 | * @param c Byte. 137 | */ 138 | void writeByte(uint8_t c); 139 | /** 140 | * @brief 141 | */ 142 | void writeSilence(); 143 | }; 144 | } // namespace nxdn 145 | 146 | #endif // __NXDN_TX_H__ 147 | -------------------------------------------------------------------------------- /p25/CalP25.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2018 Andy Uribe, CA6JAU 8 | * 9 | */ 10 | #include "Globals.h" 11 | #include "p25/CalP25.h" 12 | 13 | using namespace p25; 14 | 15 | // --------------------------------------------------------------------------- 16 | // Constants 17 | // --------------------------------------------------------------------------- 18 | 19 | // Recommended 1011 Hz test pattern for P25 Phase 1 (ANSI/TIA-102.CAAA) 20 | // NAC: 0x293, srcID: 1, dstID: TG1 21 | unsigned char LDU1_1K[] = { 0x00, 22 | 0x55, 0x75, 0xF5, 0xFF, 0x77, 0xFF, 0x29, 0x35, 0x54, 0x7B, 0xCB, 0x19, 0x4D, 0x0D, 0xCE, 0x24, 0xA1, 0x24, 23 | 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB9, 0x18, 0x44, 0xFC, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xE4, 0xE2, 0x4A, 0x10, 24 | 0x90, 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4C, 0xFC, 0x16, 0x29, 0x62, 0x76, 0x0E, 0xC0, 0x00, 0x00, 25 | 0x00, 0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x02, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x94, 26 | 0x89, 0xD8, 0x39, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x24, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 27 | 0x18, 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x70, 0xE2, 0x4A, 0x12, 0x40, 28 | 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x16, 0x29, 0x62, 0x76, 0x0E, 0x6D, 0xE5, 0xD5, 0x48, 29 | 0xAD, 0xE3, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x08, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x24, 30 | 0xD8, 0x3B, 0xA1, 0x41, 0xC2, 0xD2, 0xBA, 0x38, 0x90, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 0x60, 31 | 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0x94, 0xC8, 0xFB, 0x02, 0x35, 0xA4, 0xE2, 0x4A, 0x12, 0x43, 0x50, 32 | 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x58, 0x29, 0x62, 0x76, 0x0E, 0xC0, 0x00, 0x00, 0x00, 0x0C, 33 | 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB8, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xE4 }; 34 | 35 | unsigned char LDU2_1K[] = { 0x00, 36 | 0x55, 0x75, 0xF5, 0xFF, 0x77, 0xFF, 0x29, 0x3A, 0xB8, 0xA4, 0xEF, 0xB0, 0x9A, 0x8A, 0xCE, 0x24, 0xA1, 0x24, 37 | 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB9, 0x18, 0x44, 0xFC, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xEC, 0xE2, 0x4A, 0x10, 38 | 0x90, 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4C, 0xFC, 0x16, 0x29, 0x62, 0x76, 0x0E, 0x40, 0x00, 0x00, 39 | 0x00, 0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x02, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x94, 40 | 0x89, 0xD8, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 41 | 0x18, 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x4A, 0x12, 0x40, 42 | 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x16, 0x29, 0x62, 0x76, 0x0E, 0xE0, 0xE0, 0x00, 0x00, 43 | 0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x08, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x24, 44 | 0xD8, 0x39, 0xAE, 0x8B, 0x48, 0xB6, 0x49, 0x38, 0x90, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 0x60, 45 | 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0xB9, 0xA8, 0xF4, 0xF1, 0xFD, 0x60, 0xE2, 0x4A, 0x12, 0x43, 0x50, 46 | 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x58, 0x29, 0x62, 0x76, 0x0E, 0x40, 0x00, 0x00, 0x00, 0x0C, 47 | 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB8, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xEC }; 48 | 49 | // --------------------------------------------------------------------------- 50 | // Public Class Members 51 | // --------------------------------------------------------------------------- 52 | 53 | /* Initializes a new instance of the CalP25 class. */ 54 | 55 | CalP25::CalP25() : 56 | m_transmit(false), 57 | m_state(P25CAL1K_IDLE) 58 | { 59 | /* stub */ 60 | } 61 | 62 | /* Process local state and transmit on the air interface. */ 63 | 64 | void CalP25::process() 65 | { 66 | if (m_modemState == STATE_P25_CAL) { 67 | m_state = P25CAL1K_IDLE; 68 | 69 | if (m_transmit) { 70 | p25TX.setCal(true); 71 | p25TX.process(); 72 | } 73 | else { 74 | p25TX.setCal(false); 75 | } 76 | } 77 | else { 78 | p25TX.process(); 79 | 80 | uint16_t space = p25TX.getSpace(); 81 | if (space < 1U) 82 | return; 83 | 84 | switch (m_state) { 85 | case P25CAL1K_LDU1: 86 | p25TX.writeData(LDU1_1K, P25_LDU_FRAME_LENGTH_BYTES + 1U); 87 | m_state = P25CAL1K_LDU2; 88 | break; 89 | case P25CAL1K_LDU2: 90 | p25TX.writeData(LDU2_1K, P25_LDU_FRAME_LENGTH_BYTES + 1U); 91 | if (!m_transmit) { 92 | m_state = P25CAL1K_IDLE; 93 | } 94 | else 95 | m_state = P25CAL1K_LDU1; 96 | break; 97 | default: 98 | m_state = P25CAL1K_IDLE; 99 | break; 100 | } 101 | } 102 | } 103 | 104 | /* Write P25 calibration data to the local buffer. */ 105 | 106 | uint8_t CalP25::write(const uint8_t* data, uint8_t length) 107 | { 108 | if (length != 1U) 109 | return RSN_ILLEGAL_LENGTH; 110 | 111 | m_transmit = data[0U] == 1U; 112 | 113 | if (m_transmit && m_state == P25CAL1K_IDLE) 114 | m_state = P25CAL1K_LDU1; 115 | 116 | return RSN_OK; 117 | } 118 | -------------------------------------------------------------------------------- /p25/CalP25.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2018 Andy Uribe, CA6JAU 8 | * 9 | */ 10 | /** 11 | * @file CalP25.h 12 | * @ingroup p25_mfw 13 | * @file CalP25.cpp 14 | * @ingroup p25_mfw 15 | */ 16 | #if !defined(__CAL_P25_H__) 17 | #define __CAL_P25_H__ 18 | 19 | #include "Defines.h" 20 | #include "p25/P25Defines.h" 21 | 22 | namespace p25 23 | { 24 | // --------------------------------------------------------------------------- 25 | // Constants 26 | // --------------------------------------------------------------------------- 27 | 28 | /** 29 | * @brief Calibration States 30 | * @ingroup p25_mfw 31 | */ 32 | enum P25CAL1K { 33 | P25CAL1K_IDLE, //! Idle 34 | P25CAL1K_LDU1, //! LDU1 35 | P25CAL1K_LDU2 //! LDU2 36 | }; 37 | 38 | // --------------------------------------------------------------------------- 39 | // Class Declaration 40 | // --------------------------------------------------------------------------- 41 | 42 | /** 43 | * @brief Implements logic for P25 calibration mode. 44 | * @ingroup p25_mfw 45 | */ 46 | class DSP_FW_API CalP25 { 47 | public: 48 | /** 49 | * @brief Initializes a new instance of the CalP25 class. 50 | */ 51 | CalP25(); 52 | 53 | /** 54 | * @brief Process local state and transmit on the air interface. 55 | */ 56 | void process(); 57 | 58 | /** 59 | * @brief Write P25 calibration state. 60 | * @param[in] data Buffer. 61 | * @param length Length of buffer. 62 | * @returns uint8_t Reason code. 63 | */ 64 | uint8_t write(const uint8_t* data, uint8_t length); 65 | 66 | private: 67 | bool m_transmit; 68 | P25CAL1K m_state; 69 | }; 70 | } // namespace p25 71 | 72 | #endif // __CAL_P25_H__ 73 | -------------------------------------------------------------------------------- /p25/P25Defines.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @defgroup p25_mfw Project 25 13 | * @brief Implementation for the TIA-102 Project 25 standard. 14 | * @ingroup modem_fw 15 | * 16 | * @file P25Defines.h 17 | * @ingroup p25_mfw 18 | */ 19 | #if !defined(__P25_DEFINES_H__) 20 | #define __P25_DEFINES_H__ 21 | 22 | #include "Defines.h" 23 | 24 | namespace p25 25 | { 26 | // --------------------------------------------------------------------------- 27 | // Constants 28 | // --------------------------------------------------------------------------- 29 | 30 | /** 31 | * @addtogroup p25_mfw 32 | * @{ 33 | */ 34 | 35 | const uint32_t P25_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate 36 | 37 | const uint32_t P25_HDU_FRAME_LENGTH_BYTES = 99U; 38 | const uint32_t P25_HDU_FRAME_LENGTH_BITS = P25_HDU_FRAME_LENGTH_BYTES * 8U; 39 | const uint32_t P25_HDU_FRAME_LENGTH_SYMBOLS = P25_HDU_FRAME_LENGTH_BYTES * 4U; 40 | const uint32_t P25_HDU_FRAME_LENGTH_SAMPLES = P25_HDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 41 | 42 | const uint32_t P25_TDU_FRAME_LENGTH_BYTES = 18U; 43 | const uint32_t P25_TDU_FRAME_LENGTH_BITS = P25_TDU_FRAME_LENGTH_BYTES * 8U; 44 | const uint32_t P25_TDU_FRAME_LENGTH_SYMBOLS = P25_TDU_FRAME_LENGTH_BYTES * 4U; 45 | const uint32_t P25_TDU_FRAME_LENGTH_SAMPLES = P25_TDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 46 | 47 | const uint32_t P25_LDU_FRAME_LENGTH_BYTES = 216U; 48 | const uint32_t P25_LDU_FRAME_LENGTH_BITS = P25_LDU_FRAME_LENGTH_BYTES * 8U; 49 | const uint32_t P25_LDU_FRAME_LENGTH_SYMBOLS = P25_LDU_FRAME_LENGTH_BYTES * 4U; 50 | const uint32_t P25_LDU_FRAME_LENGTH_SAMPLES = P25_LDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 51 | 52 | const uint32_t P25_TSDU_FRAME_LENGTH_BYTES = 45U; 53 | const uint32_t P25_TSDU_FRAME_LENGTH_BITS = P25_TSDU_FRAME_LENGTH_BYTES * 8U; 54 | const uint32_t P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U; 55 | const uint32_t P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 56 | 57 | const uint32_t P25_PDU_FRAME_LENGTH_BYTES = 512U; 58 | const uint32_t P25_PDU_FRAME_LENGTH_BITS = P25_PDU_FRAME_LENGTH_BYTES * 8U; 59 | const uint32_t P25_PDU_FRAME_LENGTH_SYMBOLS = P25_PDU_FRAME_LENGTH_BYTES * 4U; 60 | const uint32_t P25_PDU_FRAME_LENGTH_SAMPLES = P25_PDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 61 | 62 | const uint32_t P25_TDULC_FRAME_LENGTH_BYTES = 54U; 63 | const uint32_t P25_TDULC_FRAME_LENGTH_BITS = P25_TDULC_FRAME_LENGTH_BYTES * 8U; 64 | const uint32_t P25_TDULC_FRAME_LENGTH_SYMBOLS = P25_TDULC_FRAME_LENGTH_BYTES * 4U; 65 | const uint32_t P25_TDULC_FRAME_LENGTH_SAMPLES = P25_TDULC_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 66 | 67 | const uint32_t P25_SYNC_LENGTH_BYTES = 6U; 68 | const uint32_t P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U; 69 | const uint32_t P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U; 70 | const uint32_t P25_SYNC_LENGTH_SAMPLES = P25_SYNC_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 71 | 72 | const uint32_t P25_NID_LENGTH_BYTES = 2U; 73 | const uint32_t P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U; 74 | const uint32_t P25_NID_LENGTH_SYMBOLS = P25_NID_LENGTH_BYTES * 4U; 75 | const uint32_t P25_NID_LENGTH_SAMPLES = P25_NID_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH; 76 | 77 | const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU }; 78 | const uint8_t P25_SYNC_BYTES_LENGTH = 6U; 79 | const uint8_t P25_START_SYNC = 0x5FU; 80 | const uint8_t P25_NULL = 0x00U; 81 | 82 | const uint8_t P25_TEST_PATTERN[] = { 0x55, 0xFF }; 83 | const uint8_t P25_TEST_PATTERN_LENGTH = 2U; 84 | 85 | const ulong64_t P25_SYNC_BITS = 0x00005575F5FF77FFU; 86 | const ulong64_t P25_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; 87 | 88 | // 5 5 7 5 F 5 F F 7 7 F F 89 | // 01 01 01 01 01 11 01 01 11 11 01 01 11 11 11 11 01 11 01 11 11 11 11 11 90 | // +3 +3 +3 +3 +3 -3 +3 +3 -3 -3 +3 +3 -3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 -3 91 | 92 | const int8_t P25_SYNC_SYMBOLS_VALUES[] = { +3, +3, +3, +3, +3, -3, +3, +3, -3, -3, +3, +3, -3, -3, -3, -3, +3, -3, +3, -3, -3, -3, -3, -3 }; 93 | 94 | const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U; 95 | const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; 96 | 97 | // 522 = P25_PDU_FRAME_LENGTH_BYTES + 10 (BUFFER_LEN = P25_PDU_FRAME_LENGTH_BYTES + 10) 98 | const uint32_t P25_TX_BUFFER_LEN = 522U; 99 | 100 | // Data Unit ID(s) 101 | const uint8_t P25_DUID_HDU = 0x00U; //! Header Data Unit 102 | const uint8_t P25_DUID_TDU = 0x03U; //! Simple Terminator Data Unit 103 | const uint8_t P25_DUID_LDU1 = 0x05U; //! Logical Link Data Unit 1 104 | const uint8_t P25_DUID_VSELP1 = 0x06U; //! Motorola VSELP 1 105 | const uint8_t P25_DUID_TSDU = 0x07U; //! Trunking System Data Unit 106 | const uint8_t P25_DUID_VSELP2 = 0x09U; //! Motorola VSELP 2 107 | const uint8_t P25_DUID_LDU2 = 0x0AU; //! Logical Link Data Unit 2 108 | const uint8_t P25_DUID_PDU = 0x0CU; //! Packet Data Unit 109 | const uint8_t P25_DUID_TDULC = 0x0FU; //! Terminator Data Unit with Link Control 110 | 111 | /** @} */ 112 | } // namespace p25 113 | 114 | #endif // __P25_DEFINES_H__ 115 | -------------------------------------------------------------------------------- /p25/P25RX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2017-2025 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @file P25RX.h 13 | * @ingroup p25_mfw 14 | * @file P25RX.cpp 15 | * @ingroup p25_mfw 16 | */ 17 | #if !defined(__P25_RX_H__) 18 | #define __P25_RX_H__ 19 | 20 | #include "Defines.h" 21 | #include "p25/P25Defines.h" 22 | 23 | namespace p25 24 | { 25 | // --------------------------------------------------------------------------- 26 | // Constants 27 | // --------------------------------------------------------------------------- 28 | 29 | /** 30 | * @brief P25 Receiver State 31 | * @ingroup p25_mfw 32 | */ 33 | enum P25RX_STATE { 34 | P25RXS_NONE, //! None 35 | P25RXS_SYNC, //! Found Sync 36 | P25RXS_VOICE, //! Voice Data 37 | P25RXS_DATA //! PDU Data 38 | }; 39 | 40 | // --------------------------------------------------------------------------- 41 | // Class Declaration 42 | // --------------------------------------------------------------------------- 43 | 44 | /** 45 | * @brief Implements receiver logic for P25 mode operation. 46 | * @ingroup p25_mfw 47 | */ 48 | class DSP_FW_API P25RX { 49 | public: 50 | /** 51 | * @brief Initializes a new instance of the P25RX class. 52 | */ 53 | P25RX(); 54 | 55 | /** 56 | * @brief Helper to reset data values to defaults. 57 | */ 58 | void reset(); 59 | 60 | /** 61 | * @brief Sample P25 values from the air interface. 62 | * @param[in] samples 63 | * @param rssi 64 | * @param length 65 | */ 66 | void samples(const q15_t* samples, uint16_t* rssi, uint8_t length); 67 | 68 | /** 69 | * @brief Sets the P25 NAC. 70 | * @param nac Network Access Code. 71 | */ 72 | void setNAC(uint16_t nac); 73 | /** 74 | * @brief Sets the P25 sync correlation countdown. 75 | * @param count Sync Correlation Countdown. 76 | */ 77 | void setCorrCount(uint8_t count); 78 | 79 | private: 80 | uint32_t m_bitBuffer[P25_RADIO_SYMBOL_LENGTH]; 81 | q15_t m_buffer[P25_PDU_FRAME_LENGTH_SAMPLES]; 82 | 83 | uint16_t m_bitPtr; 84 | uint16_t m_dataPtr; 85 | 86 | uint16_t m_minSyncPtr; 87 | uint16_t m_maxSyncPtr; 88 | 89 | uint16_t m_startPtr; 90 | uint16_t m_endPtr; 91 | uint16_t m_pduEndPtr; 92 | uint16_t m_syncPtr; 93 | 94 | q31_t m_maxCorr; 95 | q15_t m_centre[16U]; 96 | q15_t m_centreVal; 97 | q15_t m_threshold[16U]; 98 | q15_t m_thresholdVal; 99 | uint8_t m_averagePtr; 100 | 101 | uint16_t m_lostCount; 102 | uint8_t m_countdown; 103 | 104 | uint16_t m_nac; 105 | 106 | uint8_t m_corrCountdown; 107 | 108 | P25RX_STATE m_state; 109 | bool m_lduSyncPos; 110 | 111 | uint8_t m_duid; 112 | 113 | uint32_t m_rssiAccum; 114 | uint16_t m_rssiCount; 115 | 116 | /** 117 | * @brief Helper to process P25 samples. 118 | * @param sample 119 | */ 120 | void processSample(q15_t sample); 121 | /** 122 | * @brief Helper to process LDU P25 samples. 123 | * @param sample 124 | */ 125 | void processVoice(q15_t sample); 126 | /** 127 | * @brief Helper to write a LDU data frame. 128 | */ 129 | void writeLDUFrame(); 130 | 131 | /** 132 | * @brief Helper to process PDU P25 samples. 133 | * @param sample 134 | */ 135 | void processData(q15_t sample); 136 | 137 | /** 138 | * @brief Frame synchronization correlator. 139 | * @returns bool 140 | */ 141 | bool correlateSync(); 142 | 143 | /** 144 | * @brief Helper to decode the P25 NID. 145 | * @param start 146 | * @returns bool True, if P25 NID was decoded, otherwise false. 147 | */ 148 | bool decodeNid(uint16_t start); 149 | 150 | /** 151 | * @brief 152 | * @param start 153 | * @param count 154 | */ 155 | void calculateLevels(uint16_t start, uint16_t count); 156 | /** 157 | * @brief 158 | * @param start 159 | * @param count 160 | * @param buffer 161 | * @param offset 162 | * @param centre 163 | * @param threshold 164 | */ 165 | void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold); 166 | }; 167 | } // namespace p25 168 | 169 | #endif // __P25_RX_H__ 170 | -------------------------------------------------------------------------------- /p25/P25TX.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016,2017,2020 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2020-2022 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @file P25TX.h 13 | * @ingroup p25_mfw 14 | * @file P25TX.cpp 15 | * @ingroup p25_mfw 16 | */ 17 | #if !defined(__P25_TX_H__) 18 | #define __P25_TX_H__ 19 | 20 | #include "Defines.h" 21 | #include "SerialBuffer.h" 22 | 23 | namespace p25 24 | { 25 | // --------------------------------------------------------------------------- 26 | // Constants 27 | // --------------------------------------------------------------------------- 28 | 29 | #define P25_FIXED_DELAY 90 // 90 = 20ms 30 | #define P25_FIXED_TX_HANG 750 // 750 = 625ms 31 | 32 | /** 33 | * @brief P25 Transmitter State 34 | * @ingroup p25_mfw 35 | */ 36 | enum P25TXSTATE { 37 | P25TXSTATE_NORMAL, //! Normal 38 | P25TXSTATE_CAL //! Calibration 39 | }; 40 | 41 | // --------------------------------------------------------------------------- 42 | // Class Declaration 43 | // --------------------------------------------------------------------------- 44 | 45 | /** 46 | * @brief Implements transmitter logic for P25 mode operation. 47 | * @ingroup p25_mfw 48 | */ 49 | class DSP_FW_API P25TX { 50 | public: 51 | /** 52 | * @brief Initializes a new instance of the P25TX class. 53 | */ 54 | P25TX(); 55 | 56 | /** 57 | * @brief Process local buffer and transmit on the air interface. 58 | */ 59 | void process(); 60 | 61 | /** 62 | * @brief Write data to the local buffer. 63 | * @param[in] data Buffer. 64 | * @param length Length of buffer. 65 | * @returns uint8_t Reason code. 66 | */ 67 | uint8_t writeData(const uint8_t* data, uint16_t length); 68 | 69 | /** 70 | * @brief Clears the local buffer. 71 | */ 72 | void clear(); 73 | 74 | /** 75 | * @brief Sets the FDMA preamble count. 76 | * @param preambleCnt FDMA preamble count. 77 | */ 78 | void setPreambleCount(uint8_t preambleCnt); 79 | /** 80 | * @brief Sets the transmit hang time. 81 | * @param txHang Transmit hang time. 82 | */ 83 | void setTxHang(uint8_t txHang); 84 | /** 85 | * @brief Sets the fine adjust 4FSK symbol levels. 86 | * @param level3Adj +3/-3 Level Adjustment 87 | * @param level1Adj +1/-1 Level Adjustment 88 | */ 89 | void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj); 90 | /** 91 | * @brief Helper to set the calibration state for Tx. 92 | * @param start 93 | */ 94 | void setCal(bool start); 95 | 96 | /** 97 | * @brief Helper to resize the FIFO buffer. 98 | * @param size 99 | */ 100 | void resizeBuffer(uint16_t size); 101 | 102 | /** 103 | * @brief Helper to get how much space the ring buffer has for samples. 104 | * @returns uint8_t Amount of space in ring buffer for samples. 105 | */ 106 | uint8_t getSpace() const; 107 | 108 | private: 109 | SerialBuffer m_fifo; 110 | 111 | P25TXSTATE m_state; 112 | 113 | arm_fir_interpolate_instance_q15 m_modFilter; 114 | arm_fir_instance_q15 m_lpFilter; 115 | 116 | q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare 117 | q15_t m_lpState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare 118 | 119 | uint8_t m_poBuffer[1200U]; 120 | uint16_t m_poLen; 121 | uint16_t m_poPtr; 122 | 123 | uint16_t m_preambleCnt; 124 | uint16_t m_txHang; 125 | uint16_t m_tailCnt; 126 | 127 | int8_t m_symLevel3Adj; 128 | int8_t m_symLevel1Adj; 129 | 130 | /** 131 | * @brief Helper to generate data. 132 | */ 133 | void createData(); 134 | /** 135 | * @brief Helper to generate calibration data. 136 | */ 137 | void createCal(); 138 | 139 | /** 140 | * @brief Helper to write a raw byte to the DAC. 141 | * @param c Byte. 142 | */ 143 | void writeByte(uint8_t c); 144 | /** 145 | * @brief 146 | */ 147 | void writeSilence(); 148 | }; 149 | } // namespace p25 150 | 151 | #endif // __P25_TX_H__ 152 | -------------------------------------------------------------------------------- /sdr/Log.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2018-2025 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @defgroup logging Logging Routines 13 | * @brief Defines and implements logging routines. 14 | * @ingroup modem_fw 15 | * 16 | * @file Log.h 17 | * @ingroup logging 18 | * @file Log.cpp 19 | * @ingroup logging 20 | */ 21 | #if !defined(__LOG_H__) 22 | #define __LOG_H__ 23 | 24 | #include "Defines.h" 25 | 26 | #include 27 | 28 | // --------------------------------------------------------------------------- 29 | // Constants 30 | // --------------------------------------------------------------------------- 31 | 32 | #define LOG_DSP "DSP" 33 | 34 | // --------------------------------------------------------------------------- 35 | // Macros 36 | // --------------------------------------------------------------------------- 37 | 38 | /** 39 | * @brief Macro helper to create a debug log entry. 40 | * @param fmt String format. 41 | * 42 | * This is a variable argument function. 43 | */ 44 | #define LogDebug(fmt, ...) Log(1U, LOG_DSP, __FILE__, __LINE__, nullptr, fmt, ##__VA_ARGS__) 45 | /** 46 | * @brief Macro helper to create a debug log entry. 47 | * @param _func Name of function generating log entry. 48 | * @param fmt String format. 49 | * 50 | * This is a variable argument function. 51 | */ 52 | #define LogDebugEx(_func, fmt, ...) Log(1U, LOG_DSP, __FILE__, __LINE__, _func, fmt, ##__VA_ARGS__) 53 | /** 54 | * @brief Macro helper to create a message log entry. 55 | * @param fmt String format. 56 | * 57 | * This is a variable argument function. 58 | */ 59 | #define LogMessage(fmt, ...) Log(2U, LOG_DSP, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 60 | /** 61 | * @brief Macro helper to create a informational log entry. 62 | * @param fmt String format. 63 | * 64 | * This is a variable argument function. LogInfo() does not use a module 65 | * name when creating a log entry. 66 | */ 67 | #define LogInfo(fmt, ...) Log(3U, nullptr, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 68 | /** 69 | * @brief Macro helper to create a informational log entry with module name. 70 | * @param fmt String format. 71 | * 72 | * This is a variable argument function. 73 | */ 74 | #define LogInfoEx(fmt, ...) Log(3U, LOG_DSP, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 75 | /** 76 | * @brief Macro helper to create a warning log entry. 77 | * @param fmt String format. 78 | * 79 | * This is a variable argument function. 80 | */ 81 | #define LogWarning(fmt, ...) Log(4U, LOG_DSP, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 82 | /** 83 | * @brief Macro helper to create a error log entry. 84 | * @param fmt String format. 85 | * 86 | * This is a variable argument function. 87 | */ 88 | #define LogError(fmt, ...) Log(5U, LOG_DSP, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 89 | /** 90 | * @brief Macro helper to create a fatal log entry. 91 | * @param fmt String format. 92 | * 93 | * This is a variable argument function. 94 | */ 95 | #define LogFatal(fmt, ...) Log(6U, LOG_DSP, nullptr, 0, nullptr, fmt, ##__VA_ARGS__) 96 | 97 | // --------------------------------------------------------------------------- 98 | // Externs 99 | // --------------------------------------------------------------------------- 100 | 101 | /** 102 | * @brief (Global) Flag indicating whether or not logging goes to the syslog. 103 | */ 104 | extern bool g_useSyslog; 105 | 106 | // --------------------------------------------------------------------------- 107 | // Global Functions 108 | // --------------------------------------------------------------------------- 109 | 110 | /** 111 | * @brief Initializes the diagnostics log. 112 | * @param filePath File path for the log file. 113 | * @param fileRoot Root name for log file. 114 | * @param fileLevel File log level. 115 | * @param displaylevel Display log level. 116 | * @param displayTimeDisplay Flag to disable the date and time stamp for the log entries. 117 | * @param syslog Flag indicating whether or not logs will be sent to syslog. 118 | * @returns 119 | */ 120 | extern DSP_FW_API bool LogInitialise(const std::string& filePath, const std::string& fileRoot, uint32_t fileLevel, uint32_t displayLevel, bool disableTimeDisplay = false, bool useSyslog = false); 121 | /** 122 | * @brief Finalizes the diagnostics log. 123 | */ 124 | extern DSP_FW_API void LogFinalise(); 125 | /** 126 | * @brief Writes a new entry to the diagnostics log. 127 | * @param level Log level for entry. 128 | * @param module Name of module generating log entry. 129 | * @param file Name of source code file generating log entry. 130 | * @param line Line number in source code file generating log entry. 131 | * @param func Name of function generating log entry. 132 | * @param fmt String format. 133 | * 134 | * This is a variable argument function. This shouldn't be called directly, utilize the LogXXXX macros above, instead. 135 | */ 136 | extern DSP_FW_API void Log(uint32_t level, const char* module, const char* file, const int lineNo, const char* func, const char* fmt, ...); 137 | 138 | #endif // __LOG_H__ 139 | -------------------------------------------------------------------------------- /sdr/SerialPortSDR.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2025 Bryan Biedenkapp N2PLL 8 | * 9 | */ 10 | #include "Globals.h" 11 | #include "sdr/SerialPortSDR.h" 12 | #include "sdr/Log.h" 13 | #include "sdr/Utils.h" 14 | 15 | // --------------------------------------------------------------------------- 16 | // Public Class Members 17 | // --------------------------------------------------------------------------- 18 | 19 | /* Initializes a new instance of the SerialPortSDR class. */ 20 | 21 | SerialPortSDR::SerialPortSDR() : 22 | SerialPort() 23 | { 24 | // stub 25 | } 26 | 27 | /* */ 28 | 29 | void SerialPortSDR::writeDebug(const char* text) 30 | { 31 | SerialPort::writeDebug(text); 32 | if (g_debug) 33 | ::LogDebug("DSP_FW_API %s", text); 34 | } 35 | 36 | /* */ 37 | 38 | void SerialPortSDR::writeDebug(const char* text, int16_t n1) 39 | { 40 | SerialPort::writeDebug(text, n1); 41 | if (g_debug) 42 | ::LogDebug("DSP_FW_API %s %X", text, n1); 43 | } 44 | 45 | /* */ 46 | 47 | void SerialPortSDR::writeDebug(const char* text, int16_t n1, int16_t n2) 48 | { 49 | SerialPort::writeDebug(text, n1, n2); 50 | if (g_debug) 51 | ::LogDebug("DSP_FW_API %s %X %X", text, n1, n2); 52 | } 53 | 54 | /* */ 55 | 56 | void SerialPortSDR::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3) 57 | { 58 | SerialPort::writeDebug(text, n1, n2, n3); 59 | if (g_debug) 60 | ::LogDebug("DSP_FW_API %s %X %X %X", text, n1, n2, n3); 61 | } 62 | 63 | /* */ 64 | 65 | void SerialPortSDR::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4) 66 | { 67 | SerialPort::writeDebug(text, n1, n2, n3, n4); 68 | if (g_debug) 69 | ::LogDebug("DSP_FW_API %s %X %X %X %X", text, n1, n2, n3, n4); 70 | } 71 | 72 | /* */ 73 | 74 | void SerialPortSDR::writeDump(const uint8_t* data, uint16_t length) 75 | { 76 | SerialPort::writeDump(data, length); 77 | if (g_debug) 78 | Utils::dump(1U, "DSP_FW_API Dump", data, length); 79 | } 80 | -------------------------------------------------------------------------------- /sdr/SerialPortSDR.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2025 Bryan Biedenkapp, N2PLL 8 | * 9 | */ 10 | /** 11 | * @file SerialPortSDR.h 12 | * @ingroup modem_fw 13 | * @file SerialPortSDR.cpp 14 | * @ingroup modem_fw 15 | */ 16 | #if !defined(__SERIAL_PORT_SDR_H__) 17 | #define __SERIAL_PORT_SDR_H__ 18 | 19 | #include "Defines.h" 20 | #include "SerialPort.h" 21 | 22 | // --------------------------------------------------------------------------- 23 | // Class Declaration 24 | // --------------------------------------------------------------------------- 25 | 26 | /** 27 | * @brief Implements the RS232 serial bus to communicate with the HOST S/W. 28 | * @ingroup modem_fw 29 | */ 30 | class DSP_FW_API SerialPortSDR : public SerialPort { 31 | public: 32 | /** 33 | * @brief Initializes a new instance of the SerialPortSDR class. 34 | */ 35 | SerialPortSDR(); 36 | 37 | /** 38 | * @brief 39 | * @param[in] text 40 | */ 41 | void writeDebug(const char* text) override; 42 | /** 43 | * @brief 44 | * @param[in] text 45 | * @param n1 46 | */ 47 | void writeDebug(const char* text, int16_t n1) override; 48 | /** 49 | * @brief 50 | * @param[in] text 51 | * @param n1 52 | * @param n2 53 | */ 54 | void writeDebug(const char* text, int16_t n1, int16_t n2) override; 55 | /** 56 | * @brief 57 | * @param[in] text 58 | * @param n1 59 | * @param n2 60 | * @param n3 61 | */ 62 | void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3) override; 63 | /** 64 | * @brief 65 | * @param[in] text 66 | * @param n1 67 | * @param n2 68 | * @param n3 69 | * @param n4 70 | */ 71 | void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4) override; 72 | /** 73 | * @brief 74 | * @param[in] data 75 | * @param length 76 | */ 77 | void writeDump(const uint8_t* data, uint16_t length) override; 78 | }; 79 | 80 | #endif // __SERIAL_PORT_SDR_H__ 81 | -------------------------------------------------------------------------------- /sdr/SerialSDR.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2025 Bryan Biedenkapp N2PLL 8 | * 9 | */ 10 | /** 11 | * @file SerialSDR.cpp 12 | * @ingroup modem_fw 13 | */ 14 | #include "Globals.h" 15 | #include "SerialPort.h" 16 | 17 | #include "sdr/port/UARTPort.h" 18 | #include "sdr/port/PseudoPTYPort.h" 19 | 20 | using namespace sdr::port; 21 | 22 | // --------------------------------------------------------------------------- 23 | // Globals Variables 24 | // --------------------------------------------------------------------------- 25 | 26 | PseudoPTYPort* m_serialPort = nullptr; 27 | static uint8_t m_readBuffer = 0x00U; 28 | 29 | // --------------------------------------------------------------------------- 30 | // Private Class Members 31 | // --------------------------------------------------------------------------- 32 | 33 | /* Reads data from the modem flash parititon. */ 34 | 35 | void SerialPort::flashRead() 36 | { 37 | DEBUG1("SerialPort: flashRead(): unsupported on Native SDR"); 38 | sendNAK(RSN_NO_INTERNAL_FLASH); 39 | // unused on SDR based dedicated modems 40 | } 41 | 42 | /* Writes data to the modem flash partition. */ 43 | 44 | uint8_t SerialPort::flashWrite(const uint8_t* data, uint8_t length) 45 | { 46 | DEBUG1("SerialPort: flashWrite(): unsupported on Native SDR"); 47 | // unused on Arduino Due based dedicated modems 48 | return RSN_NO_INTERNAL_FLASH; 49 | } 50 | 51 | /* */ 52 | 53 | void SerialPort::beginInt(uint8_t n, int speed) 54 | { 55 | ::LogMessage("Starting PTY serial..."); 56 | 57 | switch (n) { 58 | case 1U: 59 | m_readBuffer = 0x00U; 60 | m_serialPort = new PseudoPTYPort(m_ptyPort, SERIAL_115200, false); 61 | m_serialPort->open(); 62 | break; 63 | default: 64 | break; 65 | } 66 | } 67 | 68 | /* */ 69 | 70 | int SerialPort::availableInt(uint8_t n) 71 | { 72 | switch (n) { 73 | case 1U: 74 | return m_serialPort->read(&m_readBuffer, (uint8_t)(1 * sizeof(uint8_t))); 75 | default: 76 | return 0; 77 | } 78 | } 79 | 80 | /* */ 81 | 82 | int SerialPort::availableForWriteInt(uint8_t n) 83 | { 84 | switch (n) { 85 | case 1U: 86 | return true; 87 | default: 88 | return false; 89 | } 90 | } 91 | 92 | /* */ 93 | 94 | uint8_t SerialPort::readInt(uint8_t n) 95 | { 96 | switch (n) { 97 | case 1U: 98 | return m_readBuffer; 99 | default: 100 | return 0U; 101 | } 102 | } 103 | 104 | /* */ 105 | 106 | void SerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush) 107 | { 108 | switch (n) { 109 | case 1U: 110 | m_serialPort->write(data, length); 111 | break; 112 | default: 113 | break; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /sdr/Utils.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Common Library 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2018-2025 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | #include "sdr/Utils.h" 12 | #include "sdr/Log.h" 13 | 14 | #include 15 | #include 16 | 17 | // --------------------------------------------------------------------------- 18 | // Static Class Members 19 | // --------------------------------------------------------------------------- 20 | 21 | /* Helper to dump the input buffer and display the hexadecimal output in the log. */ 22 | 23 | void Utils::dump(const std::string& title, const uint8_t* data, uint32_t length) 24 | { 25 | assert(data != nullptr); 26 | 27 | dump(2U, title, data, length); 28 | } 29 | 30 | /* Helper to dump the input buffer and display the hexadecimal output in the log. */ 31 | 32 | void Utils::dump(int level, const std::string& title, const uint8_t* data, uint32_t length) 33 | { 34 | assert(data != nullptr); 35 | 36 | ::Log(level, "DUMP", nullptr, 0, nullptr, "%s (len %u)", title.c_str(), length); 37 | 38 | uint32_t offset = 0U; 39 | 40 | while (length > 0U) { 41 | std::string output; 42 | 43 | uint32_t bytes = (length > 16U) ? 16U : length; 44 | 45 | for (uint32_t i = 0U; i < bytes; i++) { 46 | char temp[10U]; 47 | ::sprintf(temp, "%02X ", data[offset + i]); 48 | output += temp; 49 | } 50 | #if !defined(CATCH2_TEST_COMPILATION) 51 | for (uint32_t i = bytes; i < 16U; i++) 52 | output += " "; 53 | 54 | output += " *"; 55 | 56 | for (uint32_t i = 0U; i < bytes; i++) { 57 | uint8_t c = data[offset + i]; 58 | 59 | if (::isprint(c)) 60 | output += c; 61 | else 62 | output += '.'; 63 | } 64 | 65 | output += '*'; 66 | #endif 67 | ::Log(level, "DUMP", nullptr, 0, nullptr, "%04X: %s", offset, output.c_str()); 68 | 69 | offset += 16U; 70 | 71 | if (length >= 16U) 72 | length -= 16U; 73 | else 74 | length = 0U; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /sdr/Utils.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2009,2014,2015 Jonathan Naylor, G4KLX 8 | * Copyright (C) 2018-2025 Bryan Biedenkapp, N2PLL 9 | * 10 | */ 11 | /** 12 | * @defgroup utils Common Utility Routines 13 | * @brief Defines and implements utility routines. 14 | * @ingroup modem_fw 15 | * 16 | * @file Utils.h 17 | * @ingroup utils 18 | * @file Utils.cpp 19 | * @ingroup utils 20 | */ 21 | #if !defined(__SDR_UTILS_H__) 22 | #define __SDR_UTILS_H__ 23 | 24 | #include "Defines.h" 25 | 26 | #include 27 | #include 28 | 29 | // --------------------------------------------------------------------------- 30 | // Class Declaration 31 | // --------------------------------------------------------------------------- 32 | 33 | /** 34 | * @brief Various helper utilities. 35 | * @ingroup utils 36 | */ 37 | class DSP_FW_API Utils { 38 | public: 39 | /** 40 | * @brief Helper to dump the input buffer and display the hexadecimal output in the log. 41 | * @param title Name of buffer. 42 | * @param data Buffer to dump. 43 | * @param length Length of buffer. 44 | */ 45 | static void dump(const std::string& title, const uint8_t* data, uint32_t length); 46 | /** 47 | * @brief Helper to dump the input buffer and display the hexadecimal output in the log. 48 | * @param level Log level. 49 | * @param title Name of buffer. 50 | * @param data Buffer to dump. 51 | * @param length Length of buffer. 52 | */ 53 | static void dump(int level, const std::string& title, const uint8_t* data, uint32_t length); 54 | }; 55 | 56 | #endif // __SDR_UTILS_H__ 57 | -------------------------------------------------------------------------------- /sdr/arm_math.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2018 by Adrian Musceac YO8RZZ 8 | * 9 | */ 10 | /** 11 | * @defgroup math Math Routines 12 | * @brief Defines and implements math routines. 13 | * @ingroup modem_fw 14 | * 15 | * @file arm_math.h 16 | * @ingroup math 17 | * @file arm_math.cpp 18 | * @ingroup math 19 | */ 20 | #if !defined(__ARM_MATH_H__) 21 | #define __ARM_MATH_H__ 22 | 23 | #include 24 | 25 | // --------------------------------------------------------------------------- 26 | // Types 27 | // --------------------------------------------------------------------------- 28 | 29 | #ifndef _INT8_T_DECLARED 30 | #ifndef __INT8_TYPE__ 31 | typedef signed char int8_t; 32 | #endif // __INT8_TYPE__ 33 | #endif // _INT8_T_DECLARED 34 | #ifndef _INT16_T_DECLARED 35 | #ifndef __INT16_TYPE__ 36 | typedef short int16_t; 37 | #endif // __INT16_TYPE__ 38 | #endif // _INT16_T_DECLARED 39 | #ifndef _INT32_T_DECLARED 40 | #ifndef __INT32_TYPE__ 41 | typedef int int32_t; 42 | #endif // __INT32_TYPE__ 43 | #endif // _INT32_T_DECLARED 44 | #ifndef _INT64_T_DECLARED 45 | #ifndef __INT64_TYPE__ 46 | typedef long long int64_t; 47 | #endif // __INT64_TYPE__ 48 | #endif // _INT64_T_DECLARED 49 | #ifndef _UINT8_T_DECLARED 50 | #ifndef __UINT8_TYPE__ 51 | typedef unsigned char uint8_t; 52 | #endif // __UINT8_TYPE__ 53 | #endif // _UINT8_T_DECLARED 54 | #ifndef _UINT16_T_DECLARED 55 | #ifndef __UINT16_TYPE__ 56 | typedef unsigned short uint16_t; 57 | #endif // __UINT16_TYPE__ 58 | #endif // _UINT16_T_DECLARED 59 | #ifndef _UINT32_T_DECLARED 60 | #ifndef __UINT32_TYPE__ 61 | typedef unsigned int uint32_t; 62 | #endif // __UINT32_TYPE__ 63 | #endif // _UINT32_T_DECLARED 64 | #ifndef _UINT64_T_DECLARED 65 | #ifndef __UINT64_TYPE__ 66 | typedef unsigned long long uint64_t; 67 | #endif // __UINT64_TYPE__ 68 | #endif // _UINT64_T_DECLARED 69 | 70 | #ifndef __LONG64_TYPE__ 71 | typedef long long long64_t; 72 | #endif // __LONG64_TYPE__ 73 | #ifndef __ULONG64_TYPE__ 74 | typedef unsigned long long ulong64_t; 75 | #endif // __ULONG64_TYPE__ 76 | 77 | typedef int16_t q15_t; 78 | typedef int32_t q31_t; 79 | typedef int64_t q63_t; 80 | 81 | // --------------------------------------------------------------------------- 82 | // Structures 83 | // --------------------------------------------------------------------------- 84 | 85 | typedef struct { 86 | uint16_t numTaps; /**< number of filter coefficients in the filter. */ 87 | q15_t* pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ 88 | q15_t* pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ 89 | } arm_fir_instance_q15; 90 | 91 | typedef struct { 92 | uint8_t L; /**< upsample factor. */ 93 | uint16_t phaseLength; /**< length of each polyphase filter component. */ 94 | q15_t* pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ 95 | q15_t* pState; /**< points to the state variable array. The array is of length blockSize+phaseLength-1. */ 96 | } arm_fir_interpolate_instance_q15; 97 | 98 | typedef struct { 99 | uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ 100 | q31_t* pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ 101 | q31_t* pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ 102 | uint8_t postShift; /**< Additional shift, in bits, applied to each output sample. */ 103 | } arm_biquad_casd_df1_inst_q31; 104 | 105 | // --------------------------------------------------------------------------- 106 | // Macros 107 | // --------------------------------------------------------------------------- 108 | 109 | #define __SSAT(x, y) ((x>32767) ? 32767 : ((x < -32768) ? -32768 : x)) 110 | 111 | // --------------------------------------------------------------------------- 112 | // Global Functions 113 | // --------------------------------------------------------------------------- 114 | 115 | /** 116 | * @brief Processing function for the Q15 FIR interpolator. 117 | * @param S An instance of the Q15 FIR interpolator structure. 118 | * @param pSrc Block of input data. 119 | * @param pDst Block of output data. 120 | * @param blockSize Number of input samples to process per call. 121 | */ 122 | void arm_fir_interpolate_q15(const arm_fir_interpolate_instance_q15* S, q15_t* pSrc, q15_t* pDst, uint32_t blockSize); 123 | 124 | /** 125 | * @brief Processing function for the fast Q15 FIR filter for Cortex-M3 and Cortex-M4. 126 | * @param S An instance of the Q15 FIR interpolator structure. 127 | * @param pSrc Block of input data. 128 | * @param pDst Block of output data. 129 | * @param blockSize Number of input samples to process per call. 130 | */ 131 | void arm_fir_fast_q15(const arm_fir_instance_q15* S, q15_t* pSrc, q15_t* pDst, uint32_t blockSize); 132 | 133 | /** 134 | * @brief Processing function for the Q31 Biquad cascade filter 135 | * @param S An instance of the Q15 FIR interpolator structure. 136 | * @param pSrc Block of input data. 137 | * @param pDst Block of output data. 138 | * @param blockSize Number of input samples to process per call. 139 | */ 140 | void arm_biquad_cascade_df1_q31(const arm_biquad_casd_df1_inst_q31* S, q31_t* pSrc, q31_t* pDst, uint32_t blockSize); 141 | 142 | /** 143 | * @brief Converts the elements of the Q15 vector to Q31 vector. 144 | * 145 | * @param pSrc Input pointer. 146 | * @param pDst Output pointer. 147 | * @param blockSize Number of input samples to process. 148 | */ 149 | void arm_q15_to_q31(q15_t* pSrc, q31_t* pDst, uint32_t blockSize); 150 | 151 | #endif // __ARM_MATH_H__ 152 | -------------------------------------------------------------------------------- /sdr/port/ISerialPort.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016,2021 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | #include "sdr/port/ISerialPort.h" 11 | 12 | using namespace sdr::port; 13 | 14 | // --------------------------------------------------------------------------- 15 | // Public Class Members 16 | // --------------------------------------------------------------------------- 17 | 18 | /* Finalizes a instance of the ISerialPort class. */ 19 | 20 | ISerialPort::~ISerialPort() = default; 21 | -------------------------------------------------------------------------------- /sdr/port/ISerialPort.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2016,2021 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @defgroup port Modem Ports 12 | * @brief Implementation for various modem ports. 13 | * @ingroup modem_fw 14 | * 15 | * @file ISerialPort.h 16 | * @ingroup port 17 | * @file ISerialPort.cpp 18 | * @ingroup port 19 | */ 20 | #if !defined(__I_SERIAL_PORT_H__) 21 | #define __I_SERIAL_PORT_H__ 22 | 23 | #include "Defines.h" 24 | 25 | namespace sdr 26 | { 27 | namespace port 28 | { 29 | // --------------------------------------------------------------------------- 30 | // Class Declaration 31 | // --------------------------------------------------------------------------- 32 | 33 | /** 34 | * @brief Defines a serial port. 35 | * @ingroup port 36 | */ 37 | class DSP_FW_API ISerialPort { 38 | public: 39 | /** 40 | * @brief Finalizes a instance of the ISerialPort class. 41 | */ 42 | virtual ~ISerialPort() = 0; 43 | 44 | /** 45 | * @brief Opens a connection to the port. 46 | * @returns bool True, if connection is opened, otherwise false. 47 | */ 48 | virtual bool open() = 0; 49 | 50 | /** 51 | * @brief Reads data from the port. 52 | * @param[out] buffer Buffer to read data from the port to. 53 | * @param length Length of data to read from the port. 54 | * @returns int Actual length of data read from serial port. 55 | */ 56 | virtual int read(uint8_t* buffer, uint32_t length) = 0; 57 | /** 58 | * @brief Writes data to the port. 59 | * @param[in] buffer Buffer containing data to write to port. 60 | * @param length Length of data to write to port. 61 | * @returns int Actual length of data written to the port. 62 | */ 63 | virtual int write(const uint8_t* buffer, uint32_t length) = 0; 64 | 65 | /** 66 | * @brief Closes the connection to the port. 67 | */ 68 | virtual void close() = 0; 69 | }; 70 | } // namespace port 71 | } // namespace sdr 72 | 73 | #endif // __I_SERIAL_PORT_H__ 74 | -------------------------------------------------------------------------------- /sdr/port/PseudoPTYPort.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2020,2021 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | #if !defined(_WIN32) 11 | #include "sdr/Log.h" 12 | #include "sdr/port/PseudoPTYPort.h" 13 | 14 | #include 15 | #include 16 | 17 | using namespace sdr::port; 18 | 19 | #include 20 | #include 21 | #if defined(__linux__) 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | // --------------------------------------------------------------------------- 28 | // Public Class Members 29 | // --------------------------------------------------------------------------- 30 | 31 | /* Initializes a new instance of the PseudoPTYPort class. */ 32 | 33 | PseudoPTYPort::PseudoPTYPort(const std::string& symlink, UART_SERIAL_SPEED speed, bool assertRTS) : UARTPort(speed, assertRTS, false), 34 | m_symlink(symlink) 35 | { 36 | /* stub */ 37 | } 38 | 39 | /* Finalizes a instance of the PseudoPTYPort class. */ 40 | 41 | PseudoPTYPort::~PseudoPTYPort() = default; 42 | 43 | /* Opens a connection to the serial port. */ 44 | 45 | bool PseudoPTYPort::open() 46 | { 47 | assert(m_fd == -1); 48 | 49 | int slavefd; 50 | char slave[300]; 51 | int result = ::openpty(&m_fd, &slavefd, slave, NULL, NULL); 52 | if (result < 0) { 53 | ::LogError("Cannot open the pseudo tty - errno : %d", errno); 54 | return false; 55 | } 56 | 57 | // remove any previous stale symlink 58 | ::unlink(m_symlink.c_str()); 59 | 60 | int ret = ::symlink(slave, m_symlink.c_str()); 61 | if (ret != 0) { 62 | ::LogError("Cannot make symlink to %s with %s", slave, m_symlink.c_str()); 63 | close(); 64 | return false; 65 | } 66 | 67 | ::LogMessage("Made symbolic link from %s to %s", slave, m_symlink.c_str()); 68 | m_device = std::string(::ttyname(m_fd)); 69 | return setTermios(); 70 | } 71 | 72 | /* Closes the connection to the serial port. */ 73 | 74 | void PseudoPTYPort::close() 75 | { 76 | UARTPort::close(); 77 | ::unlink(m_symlink.c_str()); 78 | } 79 | #endif // !defined(_WIN32) 80 | -------------------------------------------------------------------------------- /sdr/port/PseudoPTYPort.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2020,2021 Jonathan Naylor, G4KLX 8 | * 9 | */ 10 | /** 11 | * @file PseudoPTYPort.h 12 | * @ingroup port 13 | * @file PseudoPTYPort.cpp 14 | * @ingroup port 15 | */ 16 | #if !defined(__PSEUDO_PTY_PORT_H__) 17 | #define __PSEUDO_PTY_PORT_H__ 18 | #if !defined(_WIN32) 19 | 20 | #include "Defines.h" 21 | #include "sdr/port/UARTPort.h" 22 | 23 | #include 24 | 25 | namespace sdr 26 | { 27 | namespace port 28 | { 29 | // --------------------------------------------------------------------------- 30 | // Class Declaration 31 | // --------------------------------------------------------------------------- 32 | 33 | /** 34 | * @brief This class implements low-level routines to communicate via a Linux 35 | * PTY serial port. 36 | * @ingroup port 37 | */ 38 | class DSP_FW_API PseudoPTYPort : public UARTPort 39 | { 40 | public: 41 | /** 42 | * @brief Initializes a new instance of the PseudoPTYPort class. 43 | * @param device Serial port device. 44 | * @param speed Serial port speed. 45 | * @param assertRTS 46 | */ 47 | PseudoPTYPort(const std::string& symlink, UART_SERIAL_SPEED speed, bool assertRTS = false); 48 | /** 49 | * @brief Finalizes a instance of the PseudoPTYPort class. 50 | */ 51 | ~PseudoPTYPort() override; 52 | 53 | /** 54 | * @brief Opens a connection to the serial port. 55 | * @returns bool True, if connection is opened, otherwise false. 56 | */ 57 | bool open() override; 58 | 59 | /** 60 | * @brief Closes the connection to the serial port. 61 | */ 62 | void close() override; 63 | 64 | protected: 65 | std::string m_symlink; 66 | }; // class HOST_SW_API PseudoPTYPort : public UARTPort 67 | } // namespace port 68 | } // namespace sdr 69 | 70 | #endif // !defined(_WIN32) 71 | #endif // __PSEUDO_PTY_PORT_H__ 72 | -------------------------------------------------------------------------------- /sdr/port/UARTPort.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Digital Voice Modem - Modem Firmware 4 | * GPLv2 Open Source. Use is subject to license terms. 5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 | * 7 | * Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017,2020,2021 Jonathan Naylor, G4KLX 8 | * Copyright (C) 1999-2001 Thomas Sailor, HB9JNX 9 | * Copyright (C) 2020-2024,2025 Bryan Biedenkapp, N2PLL 10 | * 11 | */ 12 | /** 13 | * @file UARTPort.h 14 | * @ingroup port 15 | * @file UARTPort.cpp 16 | * @ingroup port 17 | */ 18 | #if !defined(__UART_PORT_H__) 19 | #define __UART_PORT_H__ 20 | 21 | #include "Defines.h" 22 | #include "sdr/port/ISerialPort.h" 23 | 24 | #include 25 | 26 | #if defined(_WIN32) 27 | #include 28 | #endif // defined(_WIN32) 29 | 30 | namespace sdr 31 | { 32 | namespace port 33 | { 34 | // --------------------------------------------------------------------------- 35 | // Constants 36 | // --------------------------------------------------------------------------- 37 | 38 | /** 39 | * @addtogroup port 40 | * @{ 41 | */ 42 | 43 | /** 44 | * @brief Serial Port Speeds. 45 | */ 46 | enum UART_SERIAL_SPEED { 47 | SERIAL_1200 = 1200, 48 | SERIAL_2400 = 2400, 49 | SERIAL_4800 = 4800, 50 | SERIAL_9600 = 9600, 51 | SERIAL_19200 = 19200, 52 | SERIAL_38400 = 38400, 53 | SERIAL_76800 = 76800, 54 | SERIAL_115200 = 115200, 55 | SERIAL_230400 = 230400, 56 | SERIAL_460800 = 460800 57 | }; 58 | 59 | /** @} */ 60 | 61 | // --------------------------------------------------------------------------- 62 | // Class Declaration 63 | // --------------------------------------------------------------------------- 64 | 65 | /** 66 | * @brief This class implements low-level routines to communicate over a RS232 67 | * serial port. 68 | * @ingroup port 69 | */ 70 | class DSP_FW_API UARTPort : public ISerialPort { 71 | public: 72 | /** 73 | * @brief Initializes a new instance of the UARTPort class. 74 | * @param device Serial port device. 75 | * @param speed Serial port speed. 76 | * @param assertRTS 77 | */ 78 | UARTPort(const std::string& device, UART_SERIAL_SPEED speed, bool assertRTS = false, bool rtsBoot = false); 79 | /** 80 | * @brief Finalizes a instance of the UARTPort class. 81 | */ 82 | ~UARTPort() override; 83 | 84 | /** 85 | * @brief Opens a connection to the serial port. 86 | * @returns bool True, if connection is opened, otherwise false. 87 | */ 88 | bool open() override; 89 | 90 | /** 91 | * @brief Reads data from the serial port. 92 | * @param[out] buffer Buffer to read data from the port to. 93 | * @param length Length of data to read from the port. 94 | * @returns int Actual length of data read from serial port. 95 | */ 96 | int read(uint8_t* buffer, uint32_t length) override; 97 | /** 98 | * @brief Writes data to the serial port. 99 | * @param[in] buffer Buffer containing data to write to port. 100 | * @param length Length of data to write to port. 101 | * @returns int Actual length of data written to the port. 102 | */ 103 | int write(const uint8_t* buffer, uint32_t length) override; 104 | 105 | /** 106 | * @brief Closes the connection to the serial port. 107 | */ 108 | void close() override; 109 | 110 | #if defined(__APPLE__) 111 | /** 112 | * @brief Helper on Apple to set serial port to non-blocking. 113 | * @returns int 114 | */ 115 | int setNonblock(bool nonblock); 116 | #endif 117 | 118 | protected: 119 | /** 120 | * @brief Initializes a new instance of the UARTPort class. 121 | * @param speed Serial port speed. 122 | * @param assertRTS 123 | */ 124 | UARTPort(UART_SERIAL_SPEED speed, bool assertRTS = false, bool rtsBoot = false); 125 | 126 | bool m_isOpen; 127 | 128 | std::string m_device; 129 | UART_SERIAL_SPEED m_speed; 130 | bool m_assertRTS; 131 | bool m_rtsBoot; 132 | #if defined(_WIN32) 133 | HANDLE m_fd; 134 | #else 135 | int m_fd; 136 | #endif // defined(_WIN32) 137 | 138 | #if defined(_WIN32) 139 | /** 140 | * @brief Helper on Windows to read from serial port non-blocking. 141 | * @param[in] buffer Buffer containing data to write to port. 142 | * @param length Length of data to write to port. 143 | * @returns int Actual length of data written to the port. 144 | */ 145 | int readNonblock(uint8_t* buffer, uint32_t length); 146 | #endif // defined(_WIN32) 147 | /** 148 | * @brief Checks it the serial port can be written to. 149 | * @returns bool True, if port can be written to, otherwise false. 150 | */ 151 | bool canWrite(); 152 | 153 | /** 154 | * @brief Sets the termios setings on the serial port. 155 | * @returns bool True, if settings are set, otherwise false. 156 | */ 157 | bool setTermios(); 158 | }; 159 | } // namespace port 160 | } // namespace sdr 161 | 162 | #endif // __UART_PORT_H__ 163 | -------------------------------------------------------------------------------- /stm32f4xx_link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 by Andy Uribe CA6JAU 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Required amount of heap and stack */ 20 | _min_heap_size = 0x1000; 21 | _min_stack_size = 0x0800; 22 | 23 | /* The entry point in the interrupt vector table */ 24 | ENTRY(Reset_Handler) 25 | 26 | /* Memory areas */ 27 | MEMORY 28 | { 29 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* FLASH */ 30 | CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K /* Core Coupled Memory (CPU only access) */ 31 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Main RAM (bus matrix)*/ 32 | } 33 | 34 | /* Stack start address (end of 128K RAM) */ 35 | _estack = ORIGIN(RAM) + LENGTH(RAM); 36 | 37 | SECTIONS 38 | { 39 | .text : 40 | { 41 | /* The interrupt vector table */ 42 | . = ALIGN(4); 43 | KEEP(*(.isr_vector .isr_vector.*)) 44 | 45 | /* The program code */ 46 | . = ALIGN(4); 47 | *(.text .text*) 48 | *(.rodata .rodata*) 49 | 50 | /* ARM-Thumb code */ 51 | *(.glue_7) *(.glue_7t) 52 | 53 | . = ALIGN(4); 54 | KEEP(*(.init)) 55 | KEEP(*(.fini)) 56 | 57 | /* EABI C++ global constructors support */ 58 | . = ALIGN(4); 59 | __preinit_array_start = .; 60 | KEEP (*(.preinit_array)) 61 | __preinit_array_end = .; 62 | 63 | /* EABI C++ global constructors support */ 64 | . = ALIGN(4); 65 | __init_array_start = .; 66 | KEEP (*(SORT(.init_array.*))) 67 | KEEP (*(.init_array)) 68 | __init_array_end = .; 69 | 70 | /* EABI C++ global constructors support */ 71 | . = ALIGN(4); 72 | __fini_array_start = .; 73 | KEEP (*(.fini_array)) 74 | KEEP (*(SORT(.fini_array.*))) 75 | __fini_array_end = .; 76 | 77 | } > ROM 78 | 79 | /* ARM sections containing exception unwinding information */ 80 | .ARM.extab : { 81 | __extab_start = .; 82 | *(.ARM.extab* .gnu.linkonce.armextab.*) 83 | __extab_end = .; 84 | } > ROM 85 | 86 | /* ARM index entries for section unwinding */ 87 | .ARM.exidx : { 88 | __exidx_start = .; 89 | *(.ARM.exidx*) 90 | __exidx_end = .; 91 | } > ROM 92 | 93 | /* Start address for the initialization values of the .data section */ 94 | _sidata = .; 95 | 96 | /* The .data section (initialized data) */ 97 | .data : AT ( _sidata ) 98 | { 99 | . = ALIGN(4); 100 | _sdata = . ; /* Start address for the .data section */ 101 | *(.data .data*) 102 | 103 | . = ALIGN(4); 104 | _edata = . ; /* End address for the .data section */ 105 | } > RAM 106 | 107 | /* The .bss section (uninitialized data) */ 108 | .bss : 109 | { 110 | . = ALIGN(4); 111 | _sbss = .; /* Start address for the .bss section */ 112 | __bss_start__ = _sbss; 113 | *(.bss) 114 | *(.bss*) 115 | *(COMMON) 116 | 117 | . = ALIGN(4); 118 | _ebss = . ; /* End address for the .bss section */ 119 | __bss_end__ = _ebss; 120 | } > RAM 121 | 122 | /* Space for heap and stack */ 123 | .heap_stack : 124 | { 125 | end = . ; /* 'end' symbol defines heap location */ 126 | _end = end ; 127 | . = . + _min_heap_size; /* Additional space for heap and stack */ 128 | . = . + _min_stack_size; 129 | } > RAM 130 | 131 | /* Remove information from the standard libraries */ 132 | /DISCARD/ : 133 | { 134 | libc.a ( * ) 135 | libm.a ( * ) 136 | libgcc.a ( * ) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /stm32f4xx_link_debug.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 by Andy Uribe CA6JAU 3 | * Copyright (C) 2023 by Bryan Biedenkapp N2PLL 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | /* Required amount of heap and stack */ 21 | _min_heap_size = 0x1000; 22 | _min_stack_size = 0x0800; 23 | 24 | /* The entry point in the interrupt vector table */ 25 | ENTRY(Reset_Handler) 26 | 27 | /* Memory areas */ 28 | MEMORY 29 | { 30 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* FLASH */ 31 | CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K /* Core Coupled Memory (CPU only access) */ 32 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Main RAM (bus matrix)*/ 33 | } 34 | 35 | /* Stack start address (end of 128K RAM) */ 36 | _estack = ORIGIN(RAM) + LENGTH(RAM); 37 | 38 | SECTIONS 39 | { 40 | .text : 41 | { 42 | /* The interrupt vector table */ 43 | . = ALIGN(4); 44 | KEEP(*(.isr_vector .isr_vector.*)) 45 | 46 | /* The program code */ 47 | . = ALIGN(4); 48 | *(.text .text*) 49 | *(.rodata .rodata*) 50 | 51 | /* ARM-Thumb code */ 52 | *(.glue_7) *(.glue_7t) 53 | 54 | . = ALIGN(4); 55 | KEEP(*(.init)) 56 | KEEP(*(.fini)) 57 | 58 | /* EABI C++ global constructors support */ 59 | . = ALIGN(4); 60 | __preinit_array_start = .; 61 | KEEP (*(.preinit_array)) 62 | __preinit_array_end = .; 63 | 64 | /* EABI C++ global constructors support */ 65 | . = ALIGN(4); 66 | __init_array_start = .; 67 | KEEP (*(SORT(.init_array.*))) 68 | KEEP (*(.init_array)) 69 | __init_array_end = .; 70 | 71 | /* EABI C++ global constructors support */ 72 | . = ALIGN(4); 73 | __fini_array_start = .; 74 | KEEP (*(.fini_array)) 75 | KEEP (*(SORT(.fini_array.*))) 76 | __fini_array_end = .; 77 | 78 | } > ROM 79 | 80 | /* ARM sections containing exception unwinding information */ 81 | .ARM.extab : { 82 | __extab_start = .; 83 | *(.ARM.extab* .gnu.linkonce.armextab.*) 84 | __extab_end = .; 85 | } > ROM 86 | 87 | /* ARM index entries for section unwinding */ 88 | .ARM.exidx : { 89 | __exidx_start = .; 90 | *(.ARM.exidx*) 91 | __exidx_end = .; 92 | } > ROM 93 | 94 | /* Start address for the initialization values of the .data section */ 95 | _sidata = .; 96 | 97 | /* The .data section (initialized data) */ 98 | .data : AT ( _sidata ) 99 | { 100 | . = ALIGN(4); 101 | _sdata = . ; /* Start address for the .data section */ 102 | *(.data .data*) 103 | 104 | . = ALIGN(4); 105 | _edata = . ; /* End address for the .data section */ 106 | } > RAM 107 | 108 | /* The .bss section (uninitialized data) */ 109 | .bss : 110 | { 111 | . = ALIGN(4); 112 | _sbss = .; /* Start address for the .bss section */ 113 | __bss_start__ = _sbss; 114 | *(.bss) 115 | *(.bss*) 116 | *(COMMON) 117 | 118 | . = ALIGN(4); 119 | _ebss = . ; /* End address for the .bss section */ 120 | __bss_end__ = _ebss; 121 | } > RAM 122 | 123 | /* Space for heap and stack */ 124 | .heap_stack : 125 | { 126 | end = . ; /* 'end' symbol defines heap location */ 127 | _end = end ; 128 | . = . + _min_heap_size; /* Additional space for heap and stack */ 129 | . = . + _min_stack_size; 130 | } > RAM 131 | 132 | /* Stabs debugging sections. */ 133 | .stab 0 : { *(.stab) } > ROM 134 | .stabstr 0 : { *(.stabstr) } > ROM 135 | .stab.excl 0 : { *(.stab.excl) } > ROM 136 | .stab.exclstr 0 : { *(.stab.exclstr) } > ROM 137 | .stab.index 0 : { *(.stab.index) } > ROM 138 | .stab.indexstr 0 : { *(.stab.indexstr) } > ROM 139 | .comment 0 : { *(.comment) } > ROM 140 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } > ROM 141 | /* DWARF debug sections. 142 | Symbols in the DWARF debugging sections are relative to the beginning 143 | of the section so we begin them at 0. */ 144 | /* DWARF 1 */ 145 | .debug 0 : { *(.debug) } > ROM 146 | .line 0 : { *(.line) } > ROM 147 | /* GNU DWARF 1 extensions */ 148 | .debug_srcinfo 0 : { *(.debug_srcinfo) } > ROM 149 | .debug_sfnames 0 : { *(.debug_sfnames) } > ROM 150 | /* DWARF 1.1 and DWARF 2 */ 151 | .debug_aranges 0 : { *(.debug_aranges) } > ROM 152 | .debug_pubnames 0 : { *(.debug_pubnames) } > ROM 153 | /* DWARF 2 */ 154 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } > ROM 155 | .debug_abbrev 0 : { *(.debug_abbrev) } > ROM 156 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } > ROM 157 | .debug_frame 0 : { *(.debug_frame) } > ROM 158 | .debug_str 0 : { *(.debug_str) } > ROM 159 | .debug_loc 0 : { *(.debug_loc) } > ROM 160 | .debug_macinfo 0 : { *(.debug_macinfo) } > ROM 161 | 162 | /* Remove information from the standard libraries */ 163 | /DISCARD/ : 164 | { 165 | libc.a ( * ) 166 | libm.a ( * ) 167 | libgcc.a ( * ) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /stm32f722_link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 by Andy Uribe CA6JAU 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Required amount of heap and stack */ 20 | _min_heap_size = 0x1000; 21 | _min_stack_size = 0x0800; 22 | 23 | /* The entry point in the interrupt vector table */ 24 | ENTRY(Reset_Handler) 25 | 26 | /* Memory areas */ 27 | MEMORY 28 | { 29 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* FLASH */ 30 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* Main RAM */ 31 | } 32 | 33 | /* Stack start address (end of 256K RAM) */ 34 | _estack = ORIGIN(RAM) + LENGTH(RAM); 35 | 36 | SECTIONS 37 | { 38 | .text : 39 | { 40 | /* The interrupt vector table */ 41 | . = ALIGN(4); 42 | KEEP(*(.isr_vector .isr_vector.*)) 43 | 44 | /* The program code */ 45 | . = ALIGN(4); 46 | *(.text .text*) 47 | *(.rodata .rodata*) 48 | 49 | /* ARM-Thumb code */ 50 | *(.glue_7) *(.glue_7t) 51 | 52 | . = ALIGN(4); 53 | KEEP(*(.init)) 54 | KEEP(*(.fini)) 55 | 56 | /* EABI C++ global constructors support */ 57 | . = ALIGN(4); 58 | __preinit_array_start = .; 59 | KEEP (*(.preinit_array)) 60 | __preinit_array_end = .; 61 | 62 | /* EABI C++ global constructors support */ 63 | . = ALIGN(4); 64 | __init_array_start = .; 65 | KEEP (*(SORT(.init_array.*))) 66 | KEEP (*(.init_array)) 67 | __init_array_end = .; 68 | 69 | /* EABI C++ global constructors support */ 70 | . = ALIGN(4); 71 | __fini_array_start = .; 72 | KEEP (*(.fini_array)) 73 | KEEP (*(SORT(.fini_array.*))) 74 | __fini_array_end = .; 75 | 76 | } > ROM 77 | 78 | /* ARM sections containing exception unwinding information */ 79 | .ARM.extab : { 80 | __extab_start = .; 81 | *(.ARM.extab* .gnu.linkonce.armextab.*) 82 | __extab_end = .; 83 | } > ROM 84 | 85 | /* ARM index entries for section unwinding */ 86 | .ARM.exidx : { 87 | __exidx_start = .; 88 | *(.ARM.exidx*) 89 | __exidx_end = .; 90 | } > ROM 91 | 92 | /* Start address for the initialization values of the .data section */ 93 | _sidata = .; 94 | 95 | /* The .data section (initialized data) */ 96 | .data : AT ( _sidata ) 97 | { 98 | . = ALIGN(4); 99 | _sdata = . ; /* Start address for the .data section */ 100 | *(.data .data*) 101 | 102 | . = ALIGN(4); 103 | _edata = . ; /* End address for the .data section */ 104 | } > RAM 105 | 106 | /* The .bss section (uninitialized data) */ 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _sbss = .; /* Start address for the .bss section */ 111 | __bss_start__ = _sbss; 112 | *(.bss) 113 | *(.bss*) 114 | *(COMMON) 115 | 116 | . = ALIGN(4); 117 | _ebss = . ; /* End address for the .bss section */ 118 | __bss_end__ = _ebss; 119 | } > RAM 120 | 121 | /* Space for heap and stack */ 122 | .heap_stack : 123 | { 124 | end = . ; /* 'end' symbol defines heap location */ 125 | _end = end ; 126 | . = . + _min_heap_size; /* Additional space for heap and stack */ 127 | . = . + _min_stack_size; 128 | } > RAM 129 | 130 | /* Remove information from the standard libraries */ 131 | /DISCARD/ : 132 | { 133 | libc.a ( * ) 134 | libm.a ( * ) 135 | libgcc.a ( * ) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /stm32f722_link_debug.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 by Andy Uribe CA6JAU 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Required amount of heap and stack */ 20 | _min_heap_size = 0x1000; 21 | _min_stack_size = 0x0800; 22 | 23 | /* The entry point in the interrupt vector table */ 24 | ENTRY(Reset_Handler) 25 | 26 | /* Memory areas */ 27 | MEMORY 28 | { 29 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* FLASH */ 30 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* Main RAM */ 31 | } 32 | 33 | /* Stack start address (end of 256K RAM) */ 34 | _estack = ORIGIN(RAM) + LENGTH(RAM); 35 | 36 | SECTIONS 37 | { 38 | .text : 39 | { 40 | /* The interrupt vector table */ 41 | . = ALIGN(4); 42 | KEEP(*(.isr_vector .isr_vector.*)) 43 | 44 | /* The program code */ 45 | . = ALIGN(4); 46 | *(.text .text*) 47 | *(.rodata .rodata*) 48 | 49 | /* ARM-Thumb code */ 50 | *(.glue_7) *(.glue_7t) 51 | 52 | . = ALIGN(4); 53 | KEEP(*(.init)) 54 | KEEP(*(.fini)) 55 | 56 | /* EABI C++ global constructors support */ 57 | . = ALIGN(4); 58 | __preinit_array_start = .; 59 | KEEP (*(.preinit_array)) 60 | __preinit_array_end = .; 61 | 62 | /* EABI C++ global constructors support */ 63 | . = ALIGN(4); 64 | __init_array_start = .; 65 | KEEP (*(SORT(.init_array.*))) 66 | KEEP (*(.init_array)) 67 | __init_array_end = .; 68 | 69 | /* EABI C++ global constructors support */ 70 | . = ALIGN(4); 71 | __fini_array_start = .; 72 | KEEP (*(.fini_array)) 73 | KEEP (*(SORT(.fini_array.*))) 74 | __fini_array_end = .; 75 | 76 | } > ROM 77 | 78 | /* ARM sections containing exception unwinding information */ 79 | .ARM.extab : { 80 | __extab_start = .; 81 | *(.ARM.extab* .gnu.linkonce.armextab.*) 82 | __extab_end = .; 83 | } > ROM 84 | 85 | /* ARM index entries for section unwinding */ 86 | .ARM.exidx : { 87 | __exidx_start = .; 88 | *(.ARM.exidx*) 89 | __exidx_end = .; 90 | } > ROM 91 | 92 | /* Start address for the initialization values of the .data section */ 93 | _sidata = .; 94 | 95 | /* The .data section (initialized data) */ 96 | .data : AT ( _sidata ) 97 | { 98 | . = ALIGN(4); 99 | _sdata = . ; /* Start address for the .data section */ 100 | *(.data .data*) 101 | 102 | . = ALIGN(4); 103 | _edata = . ; /* End address for the .data section */ 104 | } > RAM 105 | 106 | /* The .bss section (uninitialized data) */ 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _sbss = .; /* Start address for the .bss section */ 111 | __bss_start__ = _sbss; 112 | *(.bss) 113 | *(.bss*) 114 | *(COMMON) 115 | 116 | . = ALIGN(4); 117 | _ebss = . ; /* End address for the .bss section */ 118 | __bss_end__ = _ebss; 119 | } > RAM 120 | 121 | /* Space for heap and stack */ 122 | .heap_stack : 123 | { 124 | end = . ; /* 'end' symbol defines heap location */ 125 | _end = end ; 126 | . = . + _min_heap_size; /* Additional space for heap and stack */ 127 | . = . + _min_stack_size; 128 | } > RAM 129 | 130 | /* Stabs debugging sections. */ 131 | .stab 0 : { *(.stab) } > ROM 132 | .stabstr 0 : { *(.stabstr) } > ROM 133 | .stab.excl 0 : { *(.stab.excl) } > ROM 134 | .stab.exclstr 0 : { *(.stab.exclstr) } > ROM 135 | .stab.index 0 : { *(.stab.index) } > ROM 136 | .stab.indexstr 0 : { *(.stab.indexstr) } > ROM 137 | .comment 0 : { *(.comment) } > ROM 138 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } > ROM 139 | /* DWARF debug sections. 140 | Symbols in the DWARF debugging sections are relative to the beginning 141 | of the section so we begin them at 0. */ 142 | /* DWARF 1 */ 143 | .debug 0 : { *(.debug) } > ROM 144 | .line 0 : { *(.line) } > ROM 145 | /* GNU DWARF 1 extensions */ 146 | .debug_srcinfo 0 : { *(.debug_srcinfo) } > ROM 147 | .debug_sfnames 0 : { *(.debug_sfnames) } > ROM 148 | /* DWARF 1.1 and DWARF 2 */ 149 | .debug_aranges 0 : { *(.debug_aranges) } > ROM 150 | .debug_pubnames 0 : { *(.debug_pubnames) } > ROM 151 | /* DWARF 2 */ 152 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } > ROM 153 | .debug_abbrev 0 : { *(.debug_abbrev) } > ROM 154 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } > ROM 155 | .debug_frame 0 : { *(.debug_frame) } > ROM 156 | .debug_str 0 : { *(.debug_str) } > ROM 157 | .debug_loc 0 : { *(.debug_loc) } > ROM 158 | .debug_macinfo 0 : { *(.debug_macinfo) } > ROM 159 | 160 | /* Remove information from the standard libraries */ 161 | /DISCARD/ : 162 | { 163 | libc.a ( * ) 164 | libm.a ( * ) 165 | libgcc.a ( * ) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /stm32f767_link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 by Andy Uribe CA6JAU 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Required amount of heap and stack */ 20 | _min_heap_size = 0x1000; 21 | _min_stack_size = 0x0800; 22 | 23 | /* The entry point in the interrupt vector table */ 24 | ENTRY(Reset_Handler) 25 | 26 | /* Memory areas */ 27 | MEMORY 28 | { 29 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* FLASH */ 30 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K /* Main RAM */ 31 | } 32 | 33 | /* Stack start address (end of 512K RAM) */ 34 | _estack = ORIGIN(RAM) + LENGTH(RAM); 35 | 36 | SECTIONS 37 | { 38 | .text : 39 | { 40 | /* The interrupt vector table */ 41 | . = ALIGN(4); 42 | KEEP(*(.isr_vector .isr_vector.*)) 43 | 44 | /* The program code */ 45 | . = ALIGN(4); 46 | *(.text .text*) 47 | *(.rodata .rodata*) 48 | 49 | /* ARM-Thumb code */ 50 | *(.glue_7) *(.glue_7t) 51 | 52 | . = ALIGN(4); 53 | KEEP(*(.init)) 54 | KEEP(*(.fini)) 55 | 56 | /* EABI C++ global constructors support */ 57 | . = ALIGN(4); 58 | __preinit_array_start = .; 59 | KEEP (*(.preinit_array)) 60 | __preinit_array_end = .; 61 | 62 | /* EABI C++ global constructors support */ 63 | . = ALIGN(4); 64 | __init_array_start = .; 65 | KEEP (*(SORT(.init_array.*))) 66 | KEEP (*(.init_array)) 67 | __init_array_end = .; 68 | 69 | /* EABI C++ global constructors support */ 70 | . = ALIGN(4); 71 | __fini_array_start = .; 72 | KEEP (*(.fini_array)) 73 | KEEP (*(SORT(.fini_array.*))) 74 | __fini_array_end = .; 75 | 76 | } > ROM 77 | 78 | /* ARM sections containing exception unwinding information */ 79 | .ARM.extab : { 80 | __extab_start = .; 81 | *(.ARM.extab* .gnu.linkonce.armextab.*) 82 | __extab_end = .; 83 | } > ROM 84 | 85 | /* ARM index entries for section unwinding */ 86 | .ARM.exidx : { 87 | __exidx_start = .; 88 | *(.ARM.exidx*) 89 | __exidx_end = .; 90 | } > ROM 91 | 92 | /* Start address for the initialization values of the .data section */ 93 | _sidata = .; 94 | 95 | /* The .data section (initialized data) */ 96 | .data : AT ( _sidata ) 97 | { 98 | . = ALIGN(4); 99 | _sdata = . ; /* Start address for the .data section */ 100 | *(.data .data*) 101 | 102 | . = ALIGN(4); 103 | _edata = . ; /* End address for the .data section */ 104 | } > RAM 105 | 106 | /* The .bss section (uninitialized data) */ 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _sbss = .; /* Start address for the .bss section */ 111 | __bss_start__ = _sbss; 112 | *(.bss) 113 | *(.bss*) 114 | *(COMMON) 115 | 116 | . = ALIGN(4); 117 | _ebss = . ; /* End address for the .bss section */ 118 | __bss_end__ = _ebss; 119 | } > RAM 120 | 121 | /* Space for heap and stack */ 122 | .heap_stack : 123 | { 124 | end = . ; /* 'end' symbol defines heap location */ 125 | _end = end ; 126 | . = . + _min_heap_size; /* Additional space for heap and stack */ 127 | . = . + _min_stack_size; 128 | } > RAM 129 | 130 | /* Remove information from the standard libraries */ 131 | /DISCARD/ : 132 | { 133 | libc.a ( * ) 134 | libm.a ( * ) 135 | libgcc.a ( * ) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /stm32f767_link_debug.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 by Andy Uribe CA6JAU 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Required amount of heap and stack */ 20 | _min_heap_size = 0x1000; 21 | _min_stack_size = 0x0800; 22 | 23 | /* The entry point in the interrupt vector table */ 24 | ENTRY(Reset_Handler) 25 | 26 | /* Memory areas */ 27 | MEMORY 28 | { 29 | ROM (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* FLASH */ 30 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K /* Main RAM */ 31 | } 32 | 33 | /* Stack start address (end of 512K RAM) */ 34 | _estack = ORIGIN(RAM) + LENGTH(RAM); 35 | 36 | SECTIONS 37 | { 38 | .text : 39 | { 40 | /* The interrupt vector table */ 41 | . = ALIGN(4); 42 | KEEP(*(.isr_vector .isr_vector.*)) 43 | 44 | /* The program code */ 45 | . = ALIGN(4); 46 | *(.text .text*) 47 | *(.rodata .rodata*) 48 | 49 | /* ARM-Thumb code */ 50 | *(.glue_7) *(.glue_7t) 51 | 52 | . = ALIGN(4); 53 | KEEP(*(.init)) 54 | KEEP(*(.fini)) 55 | 56 | /* EABI C++ global constructors support */ 57 | . = ALIGN(4); 58 | __preinit_array_start = .; 59 | KEEP (*(.preinit_array)) 60 | __preinit_array_end = .; 61 | 62 | /* EABI C++ global constructors support */ 63 | . = ALIGN(4); 64 | __init_array_start = .; 65 | KEEP (*(SORT(.init_array.*))) 66 | KEEP (*(.init_array)) 67 | __init_array_end = .; 68 | 69 | /* EABI C++ global constructors support */ 70 | . = ALIGN(4); 71 | __fini_array_start = .; 72 | KEEP (*(.fini_array)) 73 | KEEP (*(SORT(.fini_array.*))) 74 | __fini_array_end = .; 75 | 76 | } > ROM 77 | 78 | /* ARM sections containing exception unwinding information */ 79 | .ARM.extab : { 80 | __extab_start = .; 81 | *(.ARM.extab* .gnu.linkonce.armextab.*) 82 | __extab_end = .; 83 | } > ROM 84 | 85 | /* ARM index entries for section unwinding */ 86 | .ARM.exidx : { 87 | __exidx_start = .; 88 | *(.ARM.exidx*) 89 | __exidx_end = .; 90 | } > ROM 91 | 92 | /* Start address for the initialization values of the .data section */ 93 | _sidata = .; 94 | 95 | /* The .data section (initialized data) */ 96 | .data : AT ( _sidata ) 97 | { 98 | . = ALIGN(4); 99 | _sdata = . ; /* Start address for the .data section */ 100 | *(.data .data*) 101 | 102 | . = ALIGN(4); 103 | _edata = . ; /* End address for the .data section */ 104 | } > RAM 105 | 106 | /* The .bss section (uninitialized data) */ 107 | .bss : 108 | { 109 | . = ALIGN(4); 110 | _sbss = .; /* Start address for the .bss section */ 111 | __bss_start__ = _sbss; 112 | *(.bss) 113 | *(.bss*) 114 | *(COMMON) 115 | 116 | . = ALIGN(4); 117 | _ebss = . ; /* End address for the .bss section */ 118 | __bss_end__ = _ebss; 119 | } > RAM 120 | 121 | /* Space for heap and stack */ 122 | .heap_stack : 123 | { 124 | end = . ; /* 'end' symbol defines heap location */ 125 | _end = end ; 126 | . = . + _min_heap_size; /* Additional space for heap and stack */ 127 | . = . + _min_stack_size; 128 | } > RAM 129 | 130 | /* Stabs debugging sections. */ 131 | .stab 0 : { *(.stab) } > ROM 132 | .stabstr 0 : { *(.stabstr) } > ROM 133 | .stab.excl 0 : { *(.stab.excl) } > ROM 134 | .stab.exclstr 0 : { *(.stab.exclstr) } > ROM 135 | .stab.index 0 : { *(.stab.index) } > ROM 136 | .stab.indexstr 0 : { *(.stab.indexstr) } > ROM 137 | .comment 0 : { *(.comment) } > ROM 138 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } > ROM 139 | /* DWARF debug sections. 140 | Symbols in the DWARF debugging sections are relative to the beginning 141 | of the section so we begin them at 0. */ 142 | /* DWARF 1 */ 143 | .debug 0 : { *(.debug) } > ROM 144 | .line 0 : { *(.line) } > ROM 145 | /* GNU DWARF 1 extensions */ 146 | .debug_srcinfo 0 : { *(.debug_srcinfo) } > ROM 147 | .debug_sfnames 0 : { *(.debug_sfnames) } > ROM 148 | /* DWARF 1.1 and DWARF 2 */ 149 | .debug_aranges 0 : { *(.debug_aranges) } > ROM 150 | .debug_pubnames 0 : { *(.debug_pubnames) } > ROM 151 | /* DWARF 2 */ 152 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } > ROM 153 | .debug_abbrev 0 : { *(.debug_abbrev) } > ROM 154 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } > ROM 155 | .debug_frame 0 : { *(.debug_frame) } > ROM 156 | .debug_str 0 : { *(.debug_str) } > ROM 157 | .debug_loc 0 : { *(.debug_loc) } > ROM 158 | .debug_macinfo 0 : { *(.debug_macinfo) } > ROM 159 | 160 | /* Remove information from the standard libraries */ 161 | /DISCARD/ : 162 | { 163 | libc.a ( * ) 164 | libm.a ( * ) 165 | libgcc.a ( * ) 166 | } 167 | } 168 | --------------------------------------------------------------------------------