Compare commits

..

7 Commits

@ -41,6 +41,13 @@ jobs:
rm -f dvm-firmware-hs_f1.bin
make -f Makefile.STM32FX mmdvm-hs-hat-dual
mv -f dvm-firmware-hs_f1.bin dvm-firmware-hs-hat-dual.bin
- name: Build STM32FX mmdvm-hs-hat-usb-dual Firmware
run: |
rm -rf obj_f1
rm -rf obj_f4
rm -f dvm-firmware-hs_f1bl.bin
make -f Makefile.STM32FX mmdvm-hs-hat-usb-dual
mv -f dvm-firmware-hs_f1bl.bin dvm-firmware-hs-hat-dual_usb.bin
- name: Build STM32FX mmdvm-hs-hat Firmware
run: |
rm -rf obj_f1
@ -48,6 +55,13 @@ jobs:
rm -f dvm-firmware-hs_f1.bin
make -f Makefile.STM32FX mmdvm-hs-hat
mv -f dvm-firmware-hs_f1.bin dvm-firmware-hs-hat.bin
- name: Build STM32FX mmdvm-hs-hat-usb Firmware
run: |
rm -rf obj_f1
rm -rf obj_f4
rm -f dvm-firmware-hs_f1bl.bin
make -f Makefile.STM32FX mmdvm-hs-hat-usb
mv -f dvm-firmware-hs_f1bl.bin dvm-firmware-hs-hat_usb.bin
- name: Firmware Hash
run: |
@ -62,11 +76,23 @@ jobs:
sha1 : $(sha1sum dvm-firmware-hs-hat-dual.bin)
sha256: $(sha256sum dvm-firmware-hs-hat-dual.bin)
dvm-firmware-hs-hat-dual_usb.bin
size : $(wc -c dvm-firmware-hs-hat-dual_usb.bin)
md5 : $(md5sum dvm-firmware-hs-hat-dual_usb.bin)
sha1 : $(sha1sum dvm-firmware-hs-hat-dual_usb.bin)
sha256: $(sha256sum dvm-firmware-hs-hat-dual_usb.bin)
dvm-firmware-hs-hat.bin
size : $(wc -c dvm-firmware-hs-hat.bin)
md5 : $(md5sum dvm-firmware-hs-hat.bin)
sha1 : $(sha1sum dvm-firmware-hs-hat.bin)
sha256: $(sha256sum dvm-firmware-hs-hat.bin)
dvm-firmware-hs-hat_usb.bin
size : $(wc -c dvm-firmware-hs-hat_usb.bin)
md5 : $(md5sum dvm-firmware-hs-hat_usb.bin)
sha1 : $(sha1sum dvm-firmware-hs-hat_usb.bin)
sha256: $(sha256sum dvm-firmware-hs-hat_usb.bin)
EOF
echo '```' >> release.txt
@ -77,4 +103,6 @@ jobs:
body_path: release.txt
files: |
dvm-firmware-hs-hat-dual.bin
dvm-firmware-hs-hat-dual_usb.bin
dvm-firmware-hs-hat.bin
dvm-firmware-hs-hat_usb.bin

@ -1,26 +1,44 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2020,2021 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Jim McLaughlin, KI6ZUM
* Copyright (C) 2016,2017,2018,2019,2020 Andy Uribe, CA6JAU
* Copyright (C) 2017 Danilo, DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Danilo DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* Some of the code is based on work of Guus Van Dooren PE1PLM:
* https://github.com/ki6zum/gmsk-dstar/blob/master/firmware/dvmega/dvmega.ino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <math.h>
#include "Globals.h"
#include "ADF7021.h"
/*
* Some of the code is based on work of Guus Van Dooren PE1PLM:
* https://github.com/ki6zum/gmsk-dstar/blob/master/firmware/dvmega/dvmega.ino
*/
#if defined(ENABLE_ADF7021)
// ---------------------------------------------------------------------------
@ -70,8 +88,9 @@ uint8_t m_afcRange;
// Global Functions
// ---------------------------------------------------------------------------
/* */
/// <summary>
///
/// </summary>
static void AD7021_IOCTL_Shift()
{
for (int i = 31; i >= 0; i--) {
@ -90,8 +109,9 @@ static void AD7021_IOCTL_Shift()
io.SDATA(LOW);
}
/* */
/// <summary>
///
/// </summary>
static void AD7021_IOCTL_SLEPulse()
{
io.SLE1(HIGH);
@ -99,8 +119,10 @@ static void AD7021_IOCTL_SLEPulse()
io.SLE1(LOW);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="doSle"></param>
static void AD7021_1_IOCTL(bool doSle = true)
{
AD7021_IOCTL_Shift();
@ -110,8 +132,9 @@ static void AD7021_1_IOCTL(bool doSle = true)
}
#if defined(DUPLEX)
/* */
/// <summary>
///
/// </summary>
static void AD7021_2_IOCTL_SLEPulse()
{
io.SLE2(HIGH);
@ -119,8 +142,10 @@ static void AD7021_2_IOCTL_SLEPulse()
io.SLE2(LOW);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="doSle"></param>
static void AD7021_2_IOCTL(bool doSle = true)
{
AD7021_IOCTL_Shift();
@ -134,8 +159,9 @@ static void AD7021_2_IOCTL(bool doSle = true)
// Public Class Members
// ---------------------------------------------------------------------------
/* Hardware interrupt handler. */
/// <summary>
/// Hardware interrupt handler.
/// </summary>
void IO::interrupt1()
{
uint8_t bit = 0U;
@ -244,8 +270,9 @@ void IO::interrupt1()
}
#if defined(DUPLEX)
/* Hardware interrupt handler. */
/// <summary>
/// Hardware interrupt handler.
/// </summary>
void IO::interrupt2()
{
uint8_t bit = 0U;
@ -263,13 +290,16 @@ void IO::interrupt2()
}
#endif
/* Sets the ADF7021 RF configuration. */
/// <summary>
/// Sets the ADF7021 RF configuration.
/// </summary>
/// <param name="modemState"></param>
/// <param name="reset"></param>
void IO::rf1Conf(DVM_STATE modemState, bool reset)
{
uint32_t txFrequencyTmp, rxFrequencyTmp;
DEBUG4("IO::rf1Conf() ADF1 (Tx/Rx); modemState/reset/rxGain", modemState, reset, m_gainMode);
DEBUG4("IO::rf1Conf(): configuring ADF for Tx/Rx; modemState/reset/rxGain", modemState, reset, m_gainMode);
#if defined (ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
io.checkBand(m_rxFrequency, m_txFrequency);
@ -348,16 +378,12 @@ void IO::rf1Conf(DVM_STATE modemState, bool reset)
AD7021_CONTROL = ADF7021_REG3;
AD7021_1_IOCTL();
DEBUG3("IO::rf1Conf() ADF1 REG3 =", (ADF7021_REG3 >> 16 & 0xFFFFU), (ADF7021_REG3 & 0xFFFFU));
/*
** Demodulator Setup (Register 4)
*/
AD7021_CONTROL = ADF7021_REG4;
AD7021_1_IOCTL();
DEBUG3("IO::rf1Conf() ADF1 REG4 =", (ADF7021_REG4 >> 16 & 0xFFFFU), (ADF7021_REG4 & 0xFFFFU));
/*
** IF Fine Cal Setup (Register 6)
*/
@ -384,8 +410,6 @@ void IO::rf1Conf(DVM_STATE modemState, bool reset)
AD7021_CONTROL = ADF7021_REG2;
AD7021_1_IOCTL();
DEBUG3("IO::rf1Conf() ADF1 REG2 =", (ADF7021_REG2 >> 16 & 0xFFFFU), (ADF7021_REG3 & 0xFFFFU));
/*
** Test DAC (Register 14)
*/
@ -422,8 +446,6 @@ void IO::rf1Conf(DVM_STATE modemState, bool reset)
AD7021_CONTROL = ADF7021_REG10;
AD7021_1_IOCTL();
DEBUG3("IO::rf1Conf() ADF1 REG10 =", (ADF7021_REG10 >> 16 & 0xFFFFU), (ADF7021_REG10 & 0xFFFFU));
/*
** Sync Word Detect (Register 11)
*/
@ -442,8 +464,6 @@ void IO::rf1Conf(DVM_STATE modemState, bool reset)
AD7021_CONTROL = ADF7021_REG13;
AD7021_1_IOCTL();
DEBUG3("IO::rf1Conf() ADF1 REG13 =", (ADF7021_REG13 >> 16 & 0xFFFFU), (ADF7021_REG13 & 0xFFFFU));
/*
** Test Mode (Register 15)
*/
@ -466,11 +486,14 @@ void IO::rf1Conf(DVM_STATE modemState, bool reset)
}
#if defined(DUPLEX)
/* Sets the ADF7021 RF configuration. */
/// <summary>
/// Sets the ADF7021 RF configuration.
/// </summary>
/// <param name="modemState"></param>
/// <param name="reset"></param>
void IO::rf2Conf(DVM_STATE modemState)
{
DEBUG3("IO::rf2Conf() ADF2 (Rx); modemState/rxGain", modemState, m_gainMode);
DEBUG3("IO::rf2Conf(): configuring 2nd ADF for Rx; modemState/rxGain", modemState, m_gainMode);
// configure ADF Tx/RX
configureTxRx(modemState);
@ -488,16 +511,12 @@ void IO::rf2Conf(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG3;
AD7021_2_IOCTL();
DEBUG3("IO::rf2Conf() ADF2 REG3 =", (ADF7021_REG3 >> 16 & 0xFFFFU), (ADF7021_REG3 & 0xFFFFU));
/*
** Demodulator Setup (Register 4)
*/
AD7021_CONTROL = ADF7021_REG4;
AD7021_2_IOCTL();
DEBUG3("IO::rf2Conf() ADF2 REG4 =", (ADF7021_REG4 >> 16 & 0xFFFFU), (ADF7021_REG4 & 0xFFFFU));
/*
** IF Fine Cal Setup (Register 6)
*/
@ -526,8 +545,6 @@ void IO::rf2Conf(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG2;
AD7021_2_IOCTL();
DEBUG3("IO::rf2Conf() ADF2 REG2 =", (ADF7021_REG2 >> 16 & 0xFFFFU), (ADF7021_REG3 & 0xFFFFU));
/*
** Test DAC (Register 14)
*/
@ -560,8 +577,6 @@ void IO::rf2Conf(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG10;
AD7021_2_IOCTL();
DEBUG3("IO::rf2Conf() ADF2 REG10 =", (ADF7021_REG10 >> 16 & 0xFFFFU), (ADF7021_REG10 & 0xFFFFU));
/*
** Sync Word Detect (Register 11)
*/
@ -580,8 +595,6 @@ void IO::rf2Conf(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG13;
AD7021_2_IOCTL();
DEBUG3("IO::rf2Conf() ADF2 REG13 =", (ADF7021_REG13 >> 16 & 0xFFFFU), (ADF7021_REG13 & 0xFFFFU));
/*
** Test Mode (Register 15)
*/
@ -590,8 +603,12 @@ void IO::rf2Conf(DVM_STATE modemState)
}
#endif // DUPLEX
/* Sets the deviation levels. */
/// <summary>
///
/// </summary>
/// <param name="dmrTXLevel"></param>
/// <param name="p25TXLevel"></param>
/// <param name="nxdnTXLevel"></param>
void IO::setDeviations(uint8_t dmrTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel)
{
dmrDev = uint16_t((ADF7021_DEV_DMR * uint16_t(dmrTXLevel)) / 128U);
@ -599,8 +616,17 @@ void IO::setDeviations(uint8_t dmrTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLev
nxdnDev = uint16_t((ADF7021_DEV_NXDN * uint16_t(nxdnTXLevel)) / 128U);
}
/* Sets the RF adjustment parameters. */
/// <summary>
/// Sets the RF adjustment parameters.
/// </summary>
/// <param name="dmrDevAdj"></param>
/// <param name="p25DevAdj"></param>
/// <param name="dmrDiscBWAdj"></param>
/// <param name="p25DiscBWAdj"></param>
/// <param name="nxdnDiscBWAdj"></param>
/// <param name="dmrPostBWAdj"></param>
/// <param name="p25PostBWAdj"></param>
/// <param name="nxdnPostBWAdj"></param>
void IO::setRFAdjust(int8_t dmrDiscBWAdj, int8_t p25DiscBWAdj, int8_t nxdnDiscBWAdj, int8_t dmrPostBWAdj, int8_t p25PostBWAdj, int8_t nxdnPostBWADJ)
{
m_dmrDiscBWAdj = dmrDiscBWAdj;
@ -610,12 +636,17 @@ void IO::setRFAdjust(int8_t dmrDiscBWAdj, int8_t p25DiscBWAdj, int8_t nxdnDiscBW
m_p25PostBWAdj = p25PostBWAdj;
m_nxdnPostBWAdj = nxdnPostBWADJ;
DEBUG4("IO::setRFAdjust() RF adjustment, discBW", dmrDiscBWAdj, p25DiscBWAdj, nxdnDiscBWAdj);
DEBUG4("IO::setRFAdjust() RF adjustment, postBW", dmrPostBWAdj, p25PostBWAdj, nxdnPostBWADJ);
DEBUG4("IO::setRFAdjust(): setting RF adjustment, discBW", dmrDiscBWAdj, p25DiscBWAdj, nxdnDiscBWAdj);
DEBUG4("IO::setRFAdjust(): setting RF adjustment, postBW", dmrPostBWAdj, p25PostBWAdj, nxdnPostBWADJ);
}
/* Sets the RF AFC parameters. */
/// <summary>
/// Sets the RF AFC parameters.
/// </summary>
/// <param name="afcEnable"></param>
/// <param name="afcKI"></param>
/// <param name="afcKP"></param>
/// <param name="afcRange"></param>
void IO::setAFCParams(bool afcEnable, uint8_t afcKI, uint8_t afcKP, uint8_t afcRange)
{
m_afcEnable = afcEnable;
@ -623,11 +654,12 @@ void IO::setAFCParams(bool afcEnable, uint8_t afcKI, uint8_t afcKP, uint8_t afcR
m_afcKP = afcKP;
m_afcRange = afcRange;
DEBUG5("IO::setAFCParams() AFC params", afcEnable, afcKI, afcKP, afcRange);
DEBUG5("IO::setAFCParams(): setting AFC params", afcEnable, afcKI, afcKP, afcRange);
}
/* */
/// <summary>
///
/// </summary>
void IO::updateCal(DVM_STATE modemState)
{
uint32_t ADF7021_REG2;
@ -641,7 +673,7 @@ void IO::updateCal(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG1;
AD7021_1_IOCTL();
// configure ADF Tx/Rx
// configure ADF Tx/RX
configureTxRx(modemState);
/*
@ -680,7 +712,7 @@ void IO::updateCal(DVM_STATE modemState)
AD7021_CONTROL = ADF7021_REG2;
AD7021_1_IOCTL();
DEBUG2("IO::updateCal() ADF calibration; modemState", modemState);
DEBUG2("IO::updateCal(): updating ADF calibration; modemState", modemState);
if (m_tx)
setTX();
@ -688,8 +720,10 @@ void IO::updateCal(DVM_STATE modemState)
setRX();
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint16_t IO::readRSSI()
{
uint32_t AD7021_RB;
@ -778,8 +812,9 @@ uint16_t IO::readRSSI()
// Private Class Members
// ---------------------------------------------------------------------------
/* */
/// <summary>
///
/// </summary>
void IO::configureBand()
{
/*
@ -846,11 +881,13 @@ void IO::configureBand()
else
f_div = 1U;
DEBUG3("IO::configureBand() ADF freq band; reg1/f_div", ADF7021_REG1, f_div);
DEBUG3("IO::configureBand(): configuring ADF freq band; reg1/f_div", ADF7021_REG1, f_div);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="modemState"></param>
void IO::configureTxRx(DVM_STATE modemState)
{
uint16_t dmrDiscBW = ADF7021_DISC_BW_DMR, dmrPostBW = ADF7021_POST_BW_DMR;
@ -858,61 +895,49 @@ void IO::configureTxRx(DVM_STATE modemState)
uint16_t nxdnDiscBW = ADF7021_DISC_BW_NXDN, nxdnPostBW = ADF7021_POST_BW_NXDN;
// configure DMR discriminator and post demodulator BW
if (m_dmrDiscBWAdj != 0) {
if (dmrDiscBW + m_dmrDiscBWAdj < 0)
dmrDiscBW = 0U;
else
dmrDiscBW = ADF7021_DISC_BW_DMR + m_dmrDiscBWAdj;
if (dmrDiscBW > ADF7021_DISC_BW_MAX)
dmrDiscBW = ADF7021_DISC_BW_MAX;
}
if (dmrDiscBW + m_dmrDiscBWAdj < 0U)
dmrDiscBW = 0U;
else
dmrDiscBW = ADF7021_DISC_BW_DMR + m_dmrDiscBWAdj;
if (dmrDiscBW > ADF7021_DISC_BW_MAX)
dmrDiscBW = ADF7021_DISC_BW_MAX;
if (m_dmrPostBWAdj != 0) {
if (dmrPostBW + m_dmrPostBWAdj < 0)
dmrPostBW = 0U;
else
dmrPostBW = ADF7021_POST_BW_DMR + m_dmrPostBWAdj;
if (dmrPostBW > ADF7021_POST_BW_MAX)
dmrPostBW = ADF7021_POST_BW_MAX;
}
if (dmrPostBW + m_dmrPostBWAdj < 0)
dmrPostBW = 0U;
else
dmrPostBW = ADF7021_POST_BW_DMR + m_dmrPostBWAdj;
if (dmrPostBW > ADF7021_POST_BW_MAX)
dmrPostBW = ADF7021_POST_BW_MAX;
// configure P25 discriminator and post demodulator BW
if (m_p25DiscBWAdj != 0) {
if (p25DiscBW + m_p25DiscBWAdj < 0)
p25DiscBW = 0U;
else
p25DiscBW = ADF7021_DISC_BW_P25 + m_p25DiscBWAdj;
if (p25DiscBW > ADF7021_DISC_BW_MAX)
p25DiscBW = ADF7021_DISC_BW_MAX;
}
if (p25DiscBW + m_p25DiscBWAdj < 0U)
p25DiscBW = 0U;
else
p25DiscBW = ADF7021_DISC_BW_P25 + m_p25DiscBWAdj;
if (p25DiscBW > ADF7021_DISC_BW_MAX)
p25DiscBW = ADF7021_DISC_BW_MAX;
if (m_p25PostBWAdj != 0) {
if (p25PostBW + m_p25PostBWAdj < 0)
p25PostBW = 0U;
else
p25PostBW = ADF7021_POST_BW_P25 + m_p25PostBWAdj;
if (p25PostBW > ADF7021_POST_BW_MAX)
p25PostBW = ADF7021_POST_BW_MAX;
}
if (p25PostBW + m_p25PostBWAdj < 0)
p25PostBW = 0U;
else
p25PostBW = ADF7021_POST_BW_P25 + m_p25PostBWAdj;
if (p25PostBW > ADF7021_POST_BW_MAX)
p25PostBW = ADF7021_POST_BW_MAX;
// configure NXDN discriminator and post demodulator BW
if (m_nxdnDiscBWAdj != 0) {
if (nxdnDiscBW + m_nxdnDiscBWAdj < 0)
nxdnDiscBW = 0U;
else
nxdnDiscBW = ADF7021_DISC_BW_NXDN + m_nxdnDiscBWAdj;
if (nxdnDiscBW > ADF7021_DISC_BW_MAX)
nxdnDiscBW = ADF7021_DISC_BW_MAX;
}
if (nxdnDiscBW + m_nxdnDiscBWAdj < 0U)
nxdnDiscBW = 0U;
else
nxdnDiscBW = ADF7021_DISC_BW_NXDN + m_nxdnDiscBWAdj;
if (nxdnDiscBW > ADF7021_DISC_BW_MAX)
nxdnDiscBW = ADF7021_DISC_BW_MAX;
if (m_nxdnPostBWAdj != 0) {
if (nxdnPostBW + m_nxdnPostBWAdj < 0)
nxdnPostBW = 0U;
else
nxdnPostBW = ADF7021_POST_BW_NXDN + m_nxdnPostBWAdj;
if (nxdnPostBW > ADF7021_POST_BW_MAX)
nxdnPostBW = ADF7021_POST_BW_MAX;
}
if (nxdnPostBW + m_nxdnPostBWAdj < 0)
nxdnPostBW = 0U;
else
nxdnPostBW = ADF7021_POST_BW_NXDN + m_nxdnPostBWAdj;
if (nxdnPostBW > ADF7021_POST_BW_MAX)
nxdnPostBW = ADF7021_POST_BW_MAX;
/*
** Configure the remaining registers based on modem state.
@ -982,7 +1007,7 @@ void IO::configureTxRx(DVM_STATE modemState)
/*
** 3FSK/4FSK Demod (Register 13)
*/
ADF7021_REG13 = (uint32_t)ADF7021_REG13_ADDR; // Register Address 13
ADF7021_REG13 = (uint32_t)0b1101 << 0; // Register Address 13
ADF7021_REG13 |= (uint32_t)ADF7021_SLICER_TH_DMR << 4; // Slicer Threshold
/*
@ -1056,12 +1081,12 @@ void IO::configureTxRx(DVM_STATE modemState)
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_INV_CLKDAT << 8; // Clock/Data Inversion
ADF7021_REG4 |= (uint32_t)(dmrDiscBW & 0x3FFU) << 10; // Discriminator BW
ADF7021_REG4 |= (uint32_t)(dmrPostBW & 0xFFFU) << 20; // Post Demod BW
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_IF_25K << 30; // IF Filter
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_IF_125K << 30; // IF Filter
/*
** 3FSK/4FSK Demod (Register 13)
*/
ADF7021_REG13 = (uint32_t)ADF7021_REG13_ADDR; // Register Address 13
ADF7021_REG13 = (uint32_t)0b1101 << 0; // Register Address 13
ADF7021_REG13 |= (uint32_t)ADF7021_SLICER_TH_DMR << 4; // Slicer Threshold
/*
@ -1072,7 +1097,7 @@ void IO::configureTxRx(DVM_STATE modemState)
ADF7021_REG2 |= (uint32_t)ADF7021_REG2_PA_DEF << 7; // PA Enable & PA Bias
ADF7021_REG2 |= (uint32_t)(m_rfPower & 0x3FU) << 13; // PA Level (0 - Off, 63 - 13 dBm)
ADF7021_REG2 |= (uint32_t)(dmrDev / div2) << 19; // Freq. Deviation
ADF7021_REG2 |= (uint32_t)ADF7021_REG2_INV_DATA << 28; // Data Inversion
ADF7021_REG2 |= (uint32_t)ADF7021_REG2_INV_CLKDAT << 28; // Clock/Data Inversion
ADF7021_REG2 |= (uint32_t)ADF7021_REG2_RC_5 << 30; // R-Cosine Alpha
}
break;
@ -1135,12 +1160,12 @@ void IO::configureTxRx(DVM_STATE modemState)
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_INV_CLKDAT << 8; // Clock/Data Inversion
ADF7021_REG4 |= (uint32_t)(p25DiscBW & 0x3FFU) << 10; // Discriminator BW
ADF7021_REG4 |= (uint32_t)(p25PostBW & 0xFFFU) << 20; // Post Demod BW
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_IF_25K << 30; // IF Filter
ADF7021_REG4 |= (uint32_t)ADF7021_REG4_IF_125K << 30; // IF Filter
/*
** 3FSK/4FSK Demod (Register 13)
*/
ADF7021_REG13 = (uint32_t)ADF7021_REG13_ADDR; // Register Address 13
ADF7021_REG13 = (uint32_t)ADF70210_REG13_ADDR; // Register Address 13
ADF7021_REG13 |= (uint32_t)ADF7021_SLICER_TH_P25 << 4; // Slicer Threshold
/*
@ -1231,7 +1256,7 @@ void IO::configureTxRx(DVM_STATE modemState)
/*
** 3FSK/4FSK Demod (Register 13)
*/
ADF7021_REG13 = (uint32_t)ADF7021_REG13_ADDR; // Register Address 13
ADF7021_REG13 = (uint32_t)ADF70210_REG13_ADDR; // Register Address 13
ADF7021_REG13 |= (uint32_t)ADF7021_SLICER_TH_NXDN << 4; // Slicer Threshold
/*
@ -1309,7 +1334,7 @@ void IO::configureTxRx(DVM_STATE modemState)
/*
** 3FSK/4FSK Demod (Register 13)
*/
ADF7021_REG13 = (uint32_t)ADF7021_REG13_ADDR; // Register Address 13
ADF7021_REG13 = (uint32_t)ADF70210_REG13_ADDR; // Register Address 13
ADF7021_REG13 |= (uint32_t)ADF7021_SLICER_TH_DEFAULT << 4; // Slicer Threshold
/*
@ -1326,14 +1351,15 @@ void IO::configureTxRx(DVM_STATE modemState)
break;
}
DEBUG5("IO::configureTxRx() ADF Tx/Rx values; dmrDiscBW/dmrPostBW/p25DiscBW/p25PostBW", dmrDiscBW, dmrPostBW, p25DiscBW, p25PostBW);
DEBUG3("IO::configureTxRx() ADF Tx/Rx values; nxdnDiscBW/nxdnPostBW", nxdnDiscBW, nxdnPostBW);
DEBUG5("IO::configureTxRx() ADF Tx/Rx values; dmrSymDev/p25SymDev/nxdnSymDev/rfPower", (uint16_t)((ADF7021_PFD * dmrDev) / (f_div * 65536)),
DEBUG5("IO::configureTxRx(): configuring ADF Tx/Rx values; dmrDiscBW/dmrPostBW/p25DiscBW/p25PostBW", dmrDiscBW, dmrPostBW, p25DiscBW, p25PostBW);
DEBUG3("IO::configureTxRx(): configuring ADF Tx/Rx values; nxdnDiscBW/nxdnPostBW", nxdnDiscBW, nxdnPostBW);
DEBUG5("IO::configureTxRx(): configuring ADF Tx/Rx values; dmrSymDev/p25SymDev/nxdnSymDev/rfPower", (uint16_t)((ADF7021_PFD * dmrDev) / (f_div * 65536)),
(uint16_t)((ADF7021_PFD * p25Dev) / (f_div * 65536)), (uint16_t)((ADF7021_PFD * nxdnDev) / (f_div * 65536)), m_rfPower);
}
/* */
/// <summary>
///
/// </summary>
void IO::setTX()
{
// PTT pin on (doing it earlier helps to measure timing impact)
@ -1352,8 +1378,10 @@ void IO::setTX()
while(CLK());
}
/* */
/// <summary>
///
/// </summary>
/// <param name="doSle"></param>
void IO::setRX(bool doSle)
{
// PTT pin off (doing it earlier helps to measure timing impact)

@ -1,20 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Jim McLaughlin, KI6ZUM
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2017 Danilo, DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file ADF7021.h
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Danilo DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* Some of the code is based on work of Guus Van Dooren PE1PLM:
* https://github.com/ki6zum/gmsk-dstar/blob/master/firmware/dvmega/dvmega.ino
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__ADF7021_H__)
#define __ADF7021_H__
@ -24,11 +43,6 @@
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup hotspot_fw
* @{
*/
#define LOW 0
#define HIGH 1
@ -296,7 +310,7 @@
/*
** 3FSK/4FSK Demod (Register 13)
*/
#define ADF7021_REG13_ADDR 0b1101
#define ADF70210_REG13_ADDR 0b1101
// Slicer threshold for 4FSK demodulator
#define ADF7021_SLICER_TH_DEFAULT 0U
@ -317,5 +331,4 @@
#endif // ADF7021_N_VER
#endif // ENABLE_ADF7021
/** @} */
#endif // __ADF7021_H__

@ -0,0 +1,11 @@
# Digital Voice Modem Firmware (Hotspot)
## Project Technical Leads
- Bryan Biedenkapp (https://github.com/gatekeep)
## Developers
- Natalie Moore (https://github.com/jelimoore)
## Special thanks to
- Jonathan Naylor G4KLX (https://github.com/g4klx) and the MMDVM authors.
- Andy Uribe CA6JAU (https://github.com/juribeparada)

@ -1,21 +1,44 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM
*
*/
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "BitBuffer.h"
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the BitBuffer class. */
/// <summary>
/// Initializes a new instance of the BitBuffer class.
/// </summary>
BitBuffer::BitBuffer(uint16_t length) :
m_length(length),
m_bits(NULL),
@ -29,8 +52,10 @@ BitBuffer::BitBuffer(uint16_t length) :
m_control = new uint8_t[length / 8U];
}
/* Helper to get how much space the ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint16_t BitBuffer::getSpace() const
{
uint16_t n = 0U;
@ -48,8 +73,10 @@ uint16_t BitBuffer::getSpace() const
return n;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint16_t BitBuffer::getData() const
{
if (m_tail == m_head)
@ -60,8 +87,11 @@ uint16_t BitBuffer::getData() const
return m_length - m_tail + m_head;
}
/* */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
bool BitBuffer::put(uint8_t bit, uint8_t control)
{
if (m_full) {
@ -82,8 +112,10 @@ bool BitBuffer::put(uint8_t bit, uint8_t control)
return true;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool BitBuffer::get(uint8_t& bit, uint8_t& control)
{
if (m_head == m_tail && !m_full)
@ -101,8 +133,10 @@ bool BitBuffer::get(uint8_t& bit, uint8_t& control)
return true;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool BitBuffer::hasOverflowed()
{
bool overflow = m_overflow;

@ -1,19 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM
*
*/
/**
* @file BitBuffer.h
* @ingroup hotspot_fw
* @file BitBuffer.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#if !defined(__BIT_RB_H__)
#define __BIT_RB_H__
@ -28,52 +44,27 @@
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a circular buffer for bit data.
// ---------------------------------------------------------------------------
/**
* @brief Implements a circular ring buffer for bit data.
* @ingroup hotspot_fw
*/
class DSP_FW_API BitBuffer {
public:
/**
* @brief Initializes a new instance of the BitBuffer class.
* @param length Length of buffer.
*/
/// <summary>Initializes a new instance of the BitBuffer class.</summary>
BitBuffer(uint16_t length);
/**
* @brief Helper to get how much space the ring buffer has for samples.
* @returns uint16_t Amount of space remaining for data.
*/
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
uint16_t getSpace() const;
/**
* @brief
* @returns uint16_t
*/
/// <summary></summary>
uint16_t getData() const;
/**
* @brief
* @param bit
* @param control
* @returns bool
*/
/// <summary></summary>
bool put(uint8_t bit, uint8_t control);
/**
* @brief
* @param[out] bit
* @param[out] control
* @returns bool
*/
/// <summary></summary>
bool get(uint8_t& bit, uint8_t& control);
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool hasOverflowed();
private:

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

@ -1,14 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2017 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "CWIdTX.h"
@ -81,8 +101,9 @@ const struct {
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the CWIdTX class. */
/// <summary>
/// Initializes a new instance of the CWIdTX class.
/// </summary>
CWIdTX::CWIdTX() :
m_poBuffer(),
m_poLen(0U),
@ -92,8 +113,9 @@ CWIdTX::CWIdTX() :
/* stub */
}
/* Process local buffer and transmit on the air interface. */
/// <summary>
/// Process local buffer and transmit on the air interface.
/// </summary>
void CWIdTX::process()
{
if (m_poLen == 0U)
@ -124,8 +146,12 @@ void CWIdTX::process()
}
}
/* Write CW ID data to the local buffer. */
/// <summary>
/// Write CW ID data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t CWIdTX::write(const uint8_t* data, uint8_t length)
{
::memset(m_poBuffer, 0x00U, 300U * sizeof(uint8_t));
@ -161,13 +187,14 @@ uint8_t CWIdTX::write(const uint8_t* data, uint8_t length)
m_poLen += 5U;
DEBUG2("CWIdTx::write() message length", m_poLen);
DEBUG2("CWIdTx: write(): message created with length", m_poLen);
return RSN_OK;
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void CWIdTX::reset()
{
m_poLen = 0U;

@ -1,20 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2015 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2017 Andy Uribe, CA6JAU
*
*/
/**
* @file CWIdTX.h
* @ingroup hotspot_fw
* @file CWIdTX.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__CWID_TX_H__)
#define __CWID_TX_H__
@ -22,35 +36,21 @@
// ---------------------------------------------------------------------------
// Class Declaration
// Implements logic to transmit a CW ID.
// ---------------------------------------------------------------------------
/**
* @brief Implements logic to transmit a CW ID.
* @ingroup hotspot_fw
*/
class DSP_FW_API CWIdTX {
public:
/**
* @brief Initializes a new instance of the CWIdTX class.
*/
/// <summary>Initializes a new instance of the CWIdTX class.</summary>
CWIdTX();
/**
* @brief Process local buffer and transmit on the air interface.
*/
/// <summary>Process local buffer and transmit on the air interface.</summary>
void process();
/**
* @brief Write CW ID data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write CW ID data to the local buffer.</summary>
uint8_t write(const uint8_t* data, uint8_t length);
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
private:

@ -1,13 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "CalRSSI.h"
#include "Utils.h"
@ -16,8 +36,9 @@
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the CalRSSI class. */
/// <summary>
/// Initializes a new instance of the CalRSSI class.
/// </summary>
CalRSSI::CalRSSI() :
m_count(0U),
m_navg(0U),
@ -28,8 +49,9 @@ CalRSSI::CalRSSI() :
/* stub */
}
/* Sample RSSI values from the air interface. */
/// <summary>
/// Sample RSSI values from the air interface.
/// </summary>
void CalRSSI::process()
{
m_count++;

@ -1,19 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
*
*/
/**
* @file CalRSSI.h
* @ingroup hotspot_fw
* @file CalRSSI.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__CAL_RSSI_H__)
#define __CAL_RSSI_H__
@ -26,14 +40,10 @@
class DSP_FW_API CalRSSI {
public:
/**
* @brief Initializes a new instance of the CalRSSI class.
*/
/// <summary>Initializes a new instance of the CalRSSI class.</summary>
CalRSSI();
/**
* @brief Sample RSSI values from the air interface.
*/
/// <summary>Sample RSSI values from the air interface.</summary>
void process();
private:

@ -1,18 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2018,2019,2020 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file Defines.h
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018,2019,2020 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DEFINES_H__)
#define __DEFINES_H__
@ -76,6 +92,15 @@ typedef unsigned long long ulong64_t;
#define DSP_FW_API
// Allow the DMR protocol
#define ENABLE_DMR
// Allow the P25 protocol
#define ENABLE_P25
// Allow the NXDN protocol
#define ENABLE_NXDN
// Enable ADF7021 support
#define ENABLE_ADF7021
@ -98,14 +123,29 @@ typedef unsigned long long ulong64_t;
#define FORCE_UHF_INTERAL_L
// Alternate P25 Deviation Levels
// #define P25_ALTERNATE_DEV_LEVEL
//#define P25_ALTERNATE_DEV_LEVEL
// Pass RSSI information to the host
// #define SEND_RSSI_DATA
// Enable for RPi 3B+, USB mode
#define LONG_USB_RESET
#if defined(ENABLE_DMR)
#define DESCR_DMR "DMR, "
#else
#define DESCR_DMR ""
#endif
#if defined(ENABLE_P25)
#define DESCR_P25 "P25, "
#else
#define DESCR_P25 ""
#endif
#if defined(ENABLE_NXDN)
#define DESCR_NXDN "NXDN, "
#else
#define DESCR_NXDN ""
#endif
#if defined(SEND_RSSI_DATA)
#define DESCR_RSSI "RSSI, "
@ -157,4 +197,8 @@ const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x0
#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])
#define _READ_BIT(p, i) ((p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7]) >> (7 - ((i) & 7)))
#if !defined(ENABLE_DMR) && !defined(ENABLE_P25) && !defined(ENABLE_NXDN)
#error "No protocol support compiled in? Must enable at least one: ENABLE_DMR, ENABLE_P25 and/or ENABLE_NXDN."
#endif
#endif // __DEFINES_H__

@ -1,17 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Mathis Schmieder, DB9MAT
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
* Copyright (C) 2019 Florian Wolters, DF2ET
* Copyright (C) 2021,2024 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
* Copyright (C) 2019 by Florian Wolters DF2ET
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
// ---------------------------------------------------------------------------
@ -23,47 +42,70 @@ DVM_STATE m_modemState = STATE_IDLE;
bool m_cwIdState = false;
uint8_t m_cwIdTXLevel = 30;
#ifdef ENABLE_DMR
bool m_dmrEnable = true;
#else
bool m_dmrEnable = false;
#endif
#ifdef ENABLE_P25
bool m_p25Enable = true;
#else
bool m_p25Enable = false;
#endif
#ifdef ENABLE_NXDN
bool m_nxdnEnable = true;
#else
bool m_nxdnEnable = false;
#endif
bool m_duplex = false;
bool m_forceDMO = false;
bool m_tx = false;
bool m_dcd = false;
uint8_t m_control;
/* DMR BS */
/** DMR BS */
#if defined(ENABLE_DMR)
#if defined(DUPLEX)
dmr::DMRIdleRX dmrIdleRX;
dmr::DMRRX dmrRX;
#endif
dmr::DMRTX dmrTX;
/* DMR MS-DMO */
/** DMR MS-DMO */
dmr::DMRDMORX dmrDMORX;
dmr::DMRDMOTX dmrDMOTX;
#endif
/* P25 */
/** P25 */
#if defined(ENABLE_P25)
p25::P25RX p25RX;
p25::P25TX p25TX;
#endif
/* NXDN */
/** NXDN */
#if defined(ENABLE_NXDN)
nxdn::NXDNRX nxdnRX;
nxdn::NXDNTX nxdnTX;
#endif
/* Calibration */
/** Calibration */
#if defined(ENABLE_DMR)
dmr::CalDMR calDMR;
#endif
#if defined(ENABLE_P25)
p25::CalP25 calP25;
#endif
#if defined(ENABLE_NXDN)
nxdn::CalNXDN calNXDN;
#endif
CalRSSI calRSSI;
/* CW */
/** CW */
CWIdTX cwIdTX;
/* RS232 and Air Interface I/O */
/** RS232 and Air Interface I/O */
SerialPort serial;
IO io;
@ -73,8 +115,6 @@ IO io;
void setup()
{
io.init();
serial.start();
}
@ -85,6 +125,7 @@ void loop()
io.process();
// The following is for transmitting
#if defined(ENABLE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) {
#if defined(DUPLEX)
if (m_duplex)
@ -93,25 +134,36 @@ void loop()
dmrDMOTX.process();
#else
dmrDMOTX.process();
#endif
#endif // defined(DUPLEX)
}
#endif // defined(ENABLE_DMR)
#if defined(ENABLE_P25)
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
#endif // defined(ENABLE_P25)
#if defined(ENABLE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
#endif // defined(ENABLE_NXDN)
#if defined(ENABLE_DMR)
if (m_modemState == STATE_DMR_DMO_CAL_1K || m_modemState == STATE_DMR_CAL_1K ||
m_modemState == STATE_DMR_LF_CAL || m_modemState == STATE_DMR_CAL ||
m_modemState == STATE_INT_CAL)
calDMR.process();
#endif // defined(ENABLE_DMR)
#if defined(ENABLE_P25)
if (m_modemState == STATE_P25_CAL_1K || m_modemState == STATE_P25_CAL)
calP25.process();
#endif // defined(ENABLE_P25)
#if defined(ENABLE_NXDN)
if (m_modemState == STATE_NXDN_CAL)
calNXDN.process();
#endif // defined(ENABLE_NXDN)
if (m_modemState == STATE_RSSI_CAL)
calRSSI.process();
@ -123,68 +175,9 @@ void loop()
// ---------------------------------------------------------------------------
// Firmware Entry Point
// ---------------------------------------------------------------------------
#include <stm32f10x_flash.h>
#define STM32_CNF_PAGE_ADDR (uint32_t)0x0800FC00
#define STM32_CNF_PAGE ((uint32_t *)0x0800FC00)
#define STM32_CNF_PAGE_24 24U
void jumpToBootLoader()
{
// Disable RCC, set it to default (after reset) settings Internal clock, no PLL, etc.
RCC_DeInit();
USART_DeInit(USART1);
USART_DeInit(UART5);
// Disable Systick timer
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
// Clear Interrupt Enable Register & Interrupt Pending Register
for (uint8_t i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
#if defined(STM32F10X_MD)
volatile uint32_t addr = 0x1FFFF000;
#endif
// Update the NVIC's vector
SCB->VTOR = addr;
void (*SysMemBootJump)(void);
SysMemBootJump = (void (*)(void))(*((uint32_t *)(addr + 4)));
__ASM volatile ("MSR msp, %0" : : "r" (*(uint32_t *)addr) : "sp"); // __set_MSP
SysMemBootJump();
}
int main()
{
// does the configuration page contain the request bootloader flag?
if ((STM32_CNF_PAGE[STM32_CNF_PAGE_24] != 0xFFFFFFFFU) && (STM32_CNF_PAGE[STM32_CNF_PAGE_24] != 0x00U)) {
uint8_t bootloadMode = (STM32_CNF_PAGE[STM32_CNF_PAGE_24] >> 8) & 0xFFU;
if ((bootloadMode & 0x20U) == 0x20U) {
// we unfortunately need to discard the configuration area entirely for bootloader mode...
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
#if defined(STM32F4XX) || defined(STM32F7XX)
if (FLASH_EraseSector(STM32_CNF_SECTOR, VoltageRange_3) != FLASH_COMPLETE) {
FLASH_Lock();
return RSN_FAILED_ERASE_FLASH;
}
#elif defined(STM32F10X_MD)
if (FLASH_ErasePage(STM32_CNF_PAGE_ADDR) != FLASH_COMPLETE) {
FLASH_Lock();
return RSN_FAILED_ERASE_FLASH;
}
#endif
jumpToBootLoader();
}
}
setup();
for (;;)

@ -1,24 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
* Copyright (C) 2019 Florian Wolters, DF2ET
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @defgroup hotspot_fw Hotspot Firmware
* @brief Digital Voice Modem - Hotspot Firmware
* @details Firmware that is used for all-in-one hotspots.
* @ingroup hotspot_fw
*
* @file Globals.h
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
* Copyright (C) 2019 by Florian Wolters DF2ET
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__GLOBALS_H__)
#define __GLOBALS_H__
@ -61,8 +72,8 @@ const uint8_t MARK_SLOT1 = 0x08U;
const uint8_t MARK_SLOT2 = 0x04U;
const uint8_t MARK_NONE = 0x00U;
const uint8_t CONTROL_SLOT1 = 0x01U;
const uint8_t CONTROL_SLOT2 = 0x00U;
const uint8_t CONTROL_SLOT1 = 0x00U;
const uint8_t CONTROL_SLOT2 = 0x01U;
// ---------------------------------------------------------------------------
// Macros
@ -89,7 +100,6 @@ extern bool m_p25Enable;
extern bool m_nxdnEnable;
extern bool m_duplex;
extern bool m_forceDMO;
extern bool m_tx;
extern bool m_dcd;
@ -99,32 +109,44 @@ extern uint8_t m_control;
extern SerialPort serial;
extern IO io;
/* DMR BS */
/** DMR BS */
#if defined(ENABLE_DMR)
#if defined(DUPLEX)
extern dmr::DMRIdleRX dmrIdleRX;
extern dmr::DMRRX dmrRX;
#endif
#endif // defined(DUPLEX)
extern dmr::DMRTX dmrTX;
/* DMR MS-DMO */
/** DMR MS-DMO */
extern dmr::DMRDMORX dmrDMORX;
extern dmr::DMRDMOTX dmrDMOTX;
#endif // defined(ENABLE_DMR)
/* P25 BS */
/** P25 BS */
#if defined(ENABLE_P25)
extern p25::P25RX p25RX;
extern p25::P25TX p25TX;
#endif // defined(ENABLE_P25)
/* NXDN BS */
/** NXDN BS */
#if defined(ENABLE_NXDN)
extern nxdn::NXDNRX nxdnRX;
extern nxdn::NXDNTX nxdnTX;
#endif // defined(ENABLE_NXDN)
/* Calibration */
/** Calibration */
#if defined(ENABLE_DMR)
extern dmr::CalDMR calDMR;
#endif // defined(ENABLE_DMR)
#if defined(ENABLE_P25)
extern p25::CalP25 calP25;
#endif // defined(ENABLE_P25)
#if defined(ENABLE_NXDN)
extern nxdn::CalNXDN calNXDN;
#endif // defined(ENABLE_NXDN)
extern CalRSSI calRSSI;
/* CW */
/** CW */
extern CWIdTX cwIdTX;
#endif // __GLOBALS_H__

203
IO.cpp

@ -1,15 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018,2019,2020 Andy Uribe, CA6JAU
* Copyright (C) 2017 Danilo, DB4PLE
* Copyright (C) 2021,2024 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Danilo DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "ADF7021.h"
#include "IO.h"
@ -18,8 +38,9 @@
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the IO class. */
/// <summary>
/// Initializes a new instance of the IO class.
/// </summary>
IO::IO():
m_started(false),
m_rxBuffer(1024U),
@ -33,13 +54,6 @@ IO::IO():
m_txFrequency(DEFAULT_FREQUENCY),
m_rfPower(0U),
m_gainMode(ADF_GAIN_AUTO)
{
/* stub */
}
/* Initializes the air interface sampler. */
void IO::init()
{
initInt();
@ -66,8 +80,9 @@ void IO::init()
selfTest();
}
/* Starts air interface sampler. */
/// <summary>
/// Starts air interface sampler.
/// </summary>
void IO::start()
{
if (m_started)
@ -78,8 +93,9 @@ void IO::start()
m_started = true;
}
/* Process samples from air interface. */
/// <summary>
/// Process samples from air interface.
/// </summary>
void IO::process()
{
uint8_t bit;
@ -89,13 +105,12 @@ void IO::process()
if (m_started) {
// Two seconds timeout
if (m_watchdog >= 19200U) {
if (m_modemState == STATE_DMR || m_modemState == STATE_P25 || m_modemState == STATE_NXDN) {
#if defined(DUPLEX)
if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false);
#endif
/*
if (m_modemState == STATE_DMR || m_modemState == STATE_P25) {
m_modemState = STATE_IDLE;
setMode(m_modemState);
}
*/
m_watchdog = 0U;
}
@ -119,7 +134,7 @@ void IO::process()
if (m_cwIdState) {
// check for CW ID end of transmission
m_cwIdState = false;
DEBUG2("IO::process() setting modem state", m_modemState);
DEBUG2("IO::process(): setting modem state", m_modemState);
io.rf1Conf(m_modemState, true);
}
@ -130,9 +145,10 @@ void IO::process()
m_rxBuffer.get(bit, control);
if (m_modemState == STATE_DMR) {
#if defined(ENABLE_DMR)
/** Digital Mobile Radio */
#if defined(DUPLEX)
if (m_duplex && !m_forceDMO) {
if (m_duplex) {
if (m_tx)
dmrRX.databit(bit, control);
else
@ -142,21 +158,31 @@ void IO::process()
dmrDMORX.databit(bit);
#else
dmrDMORX.databit(bit);
#endif
#endif // defined(DUPLEX)
#endif // defined(ENABLE_DMR)
}
else if (m_modemState == STATE_P25) {
#if defined(ENABLE_P25)
/** Project 25 */
p25RX.databit(bit);
#endif // defined(ENABLE_P25)
}
else if (m_modemState == STATE_NXDN) {
#if defined(ENABLE_NXDN)
/** Next Generation Digital Narrowband */
nxdnRX.databit(bit);
#endif // defined(ENABLE_NXDN)
}
}
}
/* Write bits to air interface. */
/// <summary>
/// Write bits to air interface.
/// </summary>
/// <param name="mode"></param>
/// <param name="samples"></param>
/// <param name="length"></param>
/// <param name="control"></param>
void IO::write(uint8_t* data, uint16_t length, const uint8_t* control)
{
if (!m_started)
@ -176,15 +202,19 @@ void IO::write(uint8_t* data, uint16_t length, const uint8_t* control)
}
}
/* Helper to get how much space the transmit ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the transmit ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint16_t IO::getSpace() const
{
return m_txBuffer.getSpace();
}
/* */
/// <summary>
///
/// </summary>
/// <param name="dcd"></param>
void IO::setDecode(bool dcd)
{
if (dcd != m_dcd)
@ -193,8 +223,10 @@ void IO::setDecode(bool dcd)
m_dcd = dcd;
}
/* Helper to set the modem air interface state. */
/// <summary>
/// Helper to set the modem air interface state.
/// </summary>
/// <param name="modemState"></param>
void IO::setMode(DVM_STATE modemState)
{
DVM_STATE relativeState = modemState;
@ -203,17 +235,22 @@ void IO::setMode(DVM_STATE modemState)
relativeState = serial.calRelativeState(modemState);
}
DEBUG3("IO::setMode() setting modem state", modemState, relativeState);
DEBUG3("IO::setMode(): setting modem state", modemState, relativeState);
rf1Conf(relativeState, true);
DEBUG4("IO::setMode() setting lights", relativeState == STATE_DMR, relativeState == STATE_P25, relativeState == STATE_NXDN);
DEBUG4("IO::setMode(): setting lights", relativeState == STATE_DMR, relativeState == STATE_P25, relativeState == STATE_NXDN);
setDMRInt(relativeState == STATE_DMR);
setP25Int(relativeState == STATE_P25);
setNXDNInt(relativeState == STATE_NXDN);
}
/* Sets the RF parameters. */
/// <summary>
/// Sets the RF parameters.
/// </summary>
/// <param name="rxFreq"></param>
/// <param name="txFreq"></param>
/// <param name="rfPower"></param>
/// <param name="gainMode"></param>
uint8_t IO::setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower, ADF_GAIN_MODE gainMode)
{
m_rfPower = rfPower >> 2;
@ -221,22 +258,22 @@ uint8_t IO::setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower, ADF_G
// check frequency ranges
if (!(
/* 136 - 174 mhz */
((rxFreq >= VHF_MIN) && (rxFreq < VHF_MAX)) || ((txFreq >= VHF_MIN) && (txFreq < VHF_MAX)) ||
/* 216 - 225 mhz */
((rxFreq >= VHF_220_MIN) && (rxFreq < VHF_220_MAX)) || ((txFreq >= VHF_220_MIN) && (txFreq < VHF_220_MAX)) ||
/* 380 - 431 mhz */
((rxFreq >= UHF_380_MIN) && (rxFreq < UHF_380_MAX)) || ((txFreq >= UHF_380_MIN) && (txFreq < UHF_380_MAX)) ||
/* 431 - 450 mhz */
((rxFreq >= UHF_1_MIN) && (rxFreq < UHF_1_MAX)) || ((txFreq >= UHF_1_MIN) && (txFreq < UHF_1_MAX)) ||
/* 450 - 470 mhz */
((rxFreq >= UHF_2_MIN) && (rxFreq < UHF_2_MAX)) || ((txFreq >= UHF_2_MIN) && (txFreq < UHF_2_MAX)) ||
/* 470 - 520 mhz */
((rxFreq >= UHF_T_MIN) && (rxFreq < UHF_T_MAX)) || ((txFreq >= UHF_T_MIN) && (txFreq < UHF_T_MAX)) ||
/* 842 - 900 mhz */
((rxFreq >= UHF_800_MIN) && (rxFreq < UHF_800_MAX)) || ((txFreq >= UHF_800_MIN) && (txFreq < UHF_800_MAX)) ||
/* 900 - 950 mhz */
((rxFreq >= UHF_900_MIN) && (rxFreq < UHF_900_MAX)) || ((txFreq >= UHF_900_MIN) && (txFreq < UHF_900_MAX))
/** 136 - 174 mhz */
((rxFreq >= VHF_MIN) && (rxFreq < VHF_MAX)) || ((txFreq >= VHF_MIN) && (txFreq < VHF_MAX)) ||
/** 216 - 225 mhz */
((rxFreq >= VHF_220_MIN) && (rxFreq < VHF_220_MAX)) || ((txFreq >= VHF_220_MIN) && (txFreq < VHF_220_MAX)) ||
/** 380 - 431 mhz */
((rxFreq >= UHF_380_MIN) && (rxFreq < UHF_380_MAX)) || ((txFreq >= UHF_380_MIN) && (txFreq < UHF_380_MAX)) ||
/** 431 - 450 mhz */
((rxFreq >= UHF_1_MIN) && (rxFreq < UHF_1_MAX)) || ((txFreq >= UHF_1_MIN) && (txFreq < UHF_1_MAX)) ||
/** 450 - 470 mhz */
((rxFreq >= UHF_2_MIN) && (rxFreq < UHF_2_MAX)) || ((txFreq >= UHF_2_MIN) && (txFreq < UHF_2_MAX)) ||
/** 470 - 520 mhz */
((rxFreq >= UHF_T_MIN) && (rxFreq < UHF_T_MAX)) || ((txFreq >= UHF_T_MIN) && (txFreq < UHF_T_MAX)) ||
/** 842 - 900 mhz */
((rxFreq >= UHF_800_MIN) && (rxFreq < UHF_800_MAX)) || ((txFreq >= UHF_800_MIN) && (txFreq < UHF_800_MAX)) ||
/** 900 - 950 mhz */
((rxFreq >= UHF_900_MIN) && (rxFreq < UHF_900_MAX)) || ((txFreq >= UHF_900_MIN) && (txFreq < UHF_900_MAX))
))
return RSN_INVALID_REQUEST;
@ -268,41 +305,49 @@ uint8_t IO::setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower, ADF_G
m_rxFrequency = rxFreq;
m_txFrequency = txFreq;
DEBUG5("IO::setRFParams() setting RF params", m_rxFrequency, m_txFrequency, m_rfPower, m_gainMode);
DEBUG5("IO::setRFParams(): setting RF params", m_rxFrequency, m_txFrequency, m_rfPower, m_gainMode);
return RSN_OK;
}
/* Flag indicating the TX ring buffer has overflowed. */
/// <summary>
/// Flag indicating the TX ring buffer has overflowed.
/// </summary>
/// <returns></returns>
bool IO::hasTXOverflow()
{
return m_txBuffer.hasOverflowed();
}
/* Flag indicating the RX ring buffer has overflowed. */
/// <summary>
/// Flag indicating the RX ring buffer has overflowed.
/// </summary>
/// <returns></returns>
bool IO::hasRXOverflow()
{
return m_rxBuffer.hasOverflowed();
}
/* */
/// <summary>
///
/// </summary>
void IO::resetWatchdog()
{
m_watchdog = 0U;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint32_t IO::getWatchdog()
{
return m_watchdog;
}
/* */
/// <summary>
///
/// </summary>
void IO::selfTest()
{
bool ledValue = false;
@ -396,8 +441,11 @@ void IO::selfTest()
delayUS(125000U);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="int1"></param>
/// <param name="int2"></param>
void IO::getIntCounter(uint16_t& int1, uint16_t& int2)
{
int1 = m_int1Counter;
@ -411,8 +459,11 @@ void IO::getIntCounter(uint16_t& int1, uint16_t& int2)
// ---------------------------------------------------------------------------
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
/* */
/// <summary>
///
/// </summary>
/// <param name="rxFreq"></param>
/// <param name="txFreq"></param>
void IO::checkBand(uint32_t rxFreq, uint32_t txFreq)
{
// check hotspot configuration for single or dual ADF7021

375
IO.h

@ -1,25 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018,2019,2020 Andy Uribe, CA6JAU
* Copyright (C) 2017 Danilo, DB4PLE
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file IO.h
* @ingroup hotspot_fw
* @file IO.cpp
* @ingroup hotspot_fw
* @file IOSTM.cpp
* @ingroup hotspot_fw
* @file ADF7021.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Danilo DB4PLE
* Copyright (C) 2017-2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__IO_H__)
#define __IO_H__
@ -32,257 +42,128 @@
// ---------------------------------------------------------------------------
#if defined(DUPLEX)
#define CAL_DLY_LOOP 96100U
#define CAL_DLY_LOOP 98950U
#else
#define CAL_DLY_LOOP 104600U
#define CAL_DLY_LOOP 110850U
#endif
/**
* @brief ADF7021 Gain Modes
*/
enum ADF_GAIN_MODE {
ADF_GAIN_AUTO = 0U, //! AGC automatic, default settings
ADF_GAIN_AUTO_LIN = 1U, //! AGC automatic with high LNA linearity
ADF_GAIN_LOW = 2U, //! AGC OFF, lowest gain
ADF_GAIN_HIGH = 3U //! AGC OFF, highest gain
// AGC automatic, default settings
ADF_GAIN_AUTO = 0U,
// AGC automatic with high LNA linearity
ADF_GAIN_AUTO_LIN = 1U,
// AGC OFF, lowest gain
ADF_GAIN_LOW = 2U,
// AGC OFF, highest gain
ADF_GAIN_HIGH = 3U
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements the input/output data path with the radio air interface.
// ---------------------------------------------------------------------------
/**
* @brief Implements the input/output data path with the radio air interface.
* @ingroup hotspot_fw
*/
class DSP_FW_API IO {
public:
/**
* @brief Initializes a new instance of the IO class.
*/
/// <summary>Initializes a new instance of the IO class.</summary>
IO();
/**
* @brief Initializes the air interface sampler.
*/
void init();
/**
* @brief Starts air interface sampler.
*/
/// <summary>Starts air interface sampler.</summary>
void start();
/**
* @brief Process bits from air interface.
*/
/// <summary>Process bits from air interface.</summary>
void process();
/**
* @brief Write bits to air interface.
* @param data Data to write.
* @param length Length of data buffer.
* @param control
*/
/// <summary>Write bits to air interface.</summary>
void write(uint8_t* data, uint16_t length, const uint8_t* control = NULL);
/**
* @brief Helper to get how much space the transmit ring buffer has for samples.
* @returns uint16_t Amount of space in the transmit ring buffer for samples.
*/
/// <summary>Helper to get how much space the transmit ring buffer has for samples.</summary>
uint16_t getSpace(void) const;
/**
* @brief
* @param dcd
*/
/// <summary></summary>
void setDecode(bool dcd);
/**
* @brief Set modem mode.
* @param modemState
*/
/// <summary>Set modem mode.</summary>
void setMode(DVM_STATE modemState);
/**
* @brief Hardware interrupt handler.
*/
/// <summary>Hardware interrupt handler.</summary>
void interrupt1();
#if defined(DUPLEX)
/**
* @brief Hardware interrupt handler.
*/
/// <summary>Hardware interrupt handler.</summary>
void interrupt2();
#endif
/**
* @brief Sets the ADF7021 RF configuration.
* @param modemState
* @param reset
*/
/// <summary>Sets the ADF7021 RF configuration.</summary>
void rf1Conf(DVM_STATE modemState, bool reset);
#if defined(DUPLEX)
/**
* @brief Sets the ADF7021 RF configuration.
* @param modemState
*/
/// <summary>Sets the ADF7021 RF configuration.</summary>
void rf2Conf(DVM_STATE modemState);
#endif
/**
* @brief Sets the deviation levels.
* @param dmrTXLevel DMR Transmit Level.
* @param p25TXLevel P25 Transmit Level.
* @param nxdnTXLevel NXDN Transmit Level.
*/
/// <summary></summary>
void setDeviations(uint8_t dmrTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel);
/**
* @brief Sets the RF parameters.
* @param rxFreq Receive Frequency (hz).
* @param txFreq Transmit Frequency (hz).
* @param rfPower RF Power Level.
* @param gainMode Gain Mode.
* @returns uint8_t Reason code.
*/
/// <summary>Sets the RF parameters.</summary>
uint8_t setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower, ADF_GAIN_MODE gainMode);
/**
* @brief Sets the RF adjustment parameters.
* @param dmrDiscBWAdj DMR Discriminator Bandwidth Adjust.
* @param p25DiscBWAdj P25 Discriminator Bandwidth Adjust.
* @param nxdnDiscBWAdj NXDN Discriminator Bandwidth Adjust.
* @param dmrPostBWAdj DMR Post Bandwidth Adjust.
* @param p25PostBWAdj P25 Post Bandwidth Adjust.
* @param nxdnPostBWAdj NXDN Post Bandwidth Adjust.
*/
/// <summary>Sets the RF adjustment parameters.</summary>
void setRFAdjust(int8_t dmrDiscBWAdj, int8_t p25DiscBWAdj, int8_t nxdnDiscBWAdj, int8_t dmrPostBWAdj, int8_t p25PostBWAdj, int8_t nxdnPostBWAdj);
/**
* @brief Sets the RF AFC adjustment parameters.
* @param afcEnable Flag indicating the Automatic Frequency Correction is enabled.
* @param afcKI
* @param afcKP
* @param afcRange
*/
/// <summary>Sets the RF AFC adjustment parameters.</summary>
void setAFCParams(bool afcEnable, uint8_t afcKI, uint8_t afcKP, uint8_t afcRange);
/**
* @brief Flag indicating the TX ring buffer has overflowed.
* @returns bool Flag indicating the TX ring buffer has overflowed.
*/
/// <summary>Flag indicating the TX ring buffer has overflowed.</summary>
bool hasTXOverflow(void);
/**
* @brief Flag indicating the RX ring buffer has overflowed.
* @returns bool Flag indicating the RX ring buffer has overflowed.
*/
/// <summary>Flag indicating the RX ring buffer has overflowed.</summary>
bool hasRXOverflow(void);
/**
* @brief
*/
/// <summary></summary>
void resetWatchdog(void);
/**
* @brief
* @returns uint32_t
*/
/// <summary></summary>
uint32_t getWatchdog(void);
/**
* @brief Gets the CPU type the firmware is running on.
* @returns uint8_t
*/
/// <summary>Gets the CPU type the firmware is running on.</summary>
uint8_t getCPU() const;
/**
* @brief Gets the unique identifier for the air interface.
* @param buffer
*/
/// <summary>Gets the unique identifier for the air interface.</summary>
void getUDID(uint8_t* buffer);
/**
* @brief
* @param modemState
*/
/// <summary></summary>
void updateCal(DVM_STATE modemState);
/**
* @brief
*/
/// <summary></summary>
void delayBit(void);
/**
* @brief
* @returns uint16_t
*/
/// <summary></summary>
uint16_t readRSSI(void);
/**
* @brief
*/
/// <summary></summary>
void selfTest();
/**
* @brief
*/
void resetMCU();
/**
* @brief
* @param[out] int1
* @param[out] int2
*/
/// <summary></summary>
void getIntCounter(uint16_t& int1, uint16_t& int2);
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool isDualBand();
#endif
/**
* @brief
* @param on
*/
/// <summary></summary>
void SCLK(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void SDATA(bool on);
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool SREAD();
/**
* @brief
* @param on
*/
/// <summary></summary>
void SLE1(bool on);
#if defined(DUPLEX)
/**
* @brief
* @param on
*/
/// <summary></summary>
void SLE2(bool on);
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool RXD2();
#endif
/**
* @brief
* @param on
*/
/// <summary></summary>
void CE(bool on);
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool RXD1();
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool CLK();
private:
@ -304,116 +185,58 @@ private:
uint8_t m_rfPower;
ADF_GAIN_MODE m_gainMode;
/**
* @brief Helper to check the frequencies are within band ranges of the ADF7021.
* @param rxFreq Receive Frequency (hz).
* @param txFreq Transmit Frequency (hz).
*/
/// <summary>Helper to check the frequencies are within band ranges of the ADF7021.</summary>
void checkBand(uint32_t rxFreq, uint32_t txFreq);
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
/**
* @brief
* @param enable
*/
/// <summary></summary>
void setBandVHF(bool enable);
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool hasSingleADF7021();
#endif
/**
* @brief
*/
/// <summary></summary>
void configureBand();
/**
* @brief
* @param modemState
*/
/// <summary></summary>
void configureTxRx(DVM_STATE modemState);
/**
* @brief
*/
/// <summary></summary>
void setTX();
/**
* @brief
* @param doSle
*/
/// <summary></summary>
void setRX(bool doSle = true);
/**
* @brief
*/
/// <summary></summary>
void delayIfCal();
/**
* @brief
*/
/// <summary></summary>
void delayReset();
/**
* @brief
* @param us
*/
/// <summary></summary>
void delayUS(uint32_t us);
// Hardware specific routines
/**
* @brief Initializes hardware interrupts.
*/
/// <summary>Initializes hardware interrupts.</summary>
void initInt();
/**
* @brief Starts hardware interrupts.
*/
/// <summary>Starts hardware interrupts.</summary>
void startInt();
/**
* @brief
* @param on
*/
/// <summary></summary>
void setTXDInt(bool on);
#if defined(BIDIR_DATA_PIN)
/**
* @brief
* @param dir
*/
/// <summary></summary>
void setDataDirOut(bool dir);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setRXDInt(bool on);
#endif
/**
* @brief
* @param on
*/
/// <summary></summary>
void setLEDInt(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setPTTInt(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setCOSInt(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setDMRInt(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setP25Int(bool on);
/**
* @brief
* @param on
*/
/// <summary></summary>
void setNXDNInt(bool on);
};

@ -1,16 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2020 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Jim McLaughlin, KI6ZUM
* Copyright (C) 2016,2017,2018,2019,2020 Andy Uribe, CA6JAU
* Copyright (C) 2017 Danilo, DB4PLE
* Copyright (C) 2021,2024 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Danilo DB4PLE
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "IO.h"
@ -80,7 +100,7 @@
#define PIN_COS_LED GPIO_Pin_13
#define PORT_COS_LED GPIOB
#elif defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
#elif defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS) || defined(LONESTAR_USB)
#define PIN_SCLK GPIO_Pin_5
#define PORT_SCLK GPIOB
@ -142,7 +162,7 @@
#define PIN_DEB GPIO_Pin_9
#define PORT_DEB GPIOB
#define PIN_NXDN_LED GPIO_Pin_7
#define PIN_NXDN_LED GPIO_Pin_1
#define PORT_NXDN_LED GPIOA
#define PIN_DMR_LED GPIO_Pin_13
@ -224,7 +244,7 @@
#define PORT_COS_LED GPIOB
#else
#error "Either PI_HAT_7021_REV_02, ZUMSPOT_ADF7021, MMDVM_HS_HAT_REV12, MMDVM_HS_DUAL_HAT_REV10, NANO_HOTSPOT, NANO_DV_REV11, or SKYBRIDGE_HS need to be defined"
#error "Either PI_HAT_7021_REV_02, ZUMSPOT_ADF7021, LONESTAR_USB, MMDVM_HS_HAT_REV12, MMDVM_HS_DUAL_HAT_REV10, NANO_HOTSPOT, NANO_DV_REV11, or SKYBRIDGE_HS need to be defined"
#endif
// ---------------------------------------------------------------------------
@ -252,7 +272,7 @@ extern "C" {
}
#endif // BIDIR_DATA_PIN
#elif defined(ZUMSPOT_ADF7021) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#if defined(BIDIR_DATA_PIN)
void EXTI3_IRQHandler(void) {
@ -289,8 +309,10 @@ extern "C" {
#endif
}
/* Function delay_us() from stm32duino project */
/// <summary>
/// Function delay_us() from stm32duino project
/// </summary>
/// <param name="us">Number of microseconds to delay.</param>
static inline void delay_us(uint32_t us)
{
us *= 12;
@ -306,8 +328,9 @@ static inline void delay_us(uint32_t us)
: "r0");
}
/* */
/// <summary>
///
/// </summary>
static inline void delay_ns()
{
@ -322,115 +345,121 @@ static inline void delay_ns()
// Public Class Members
// ---------------------------------------------------------------------------
/* Gets the CPU type the firmware is running on. */
/// <summary>
/// Gets the CPU type the firmware is running on.
/// </summary>
/// <returns></returns>
uint8_t IO::getCPU() const
{
return CPU_TYPE_STM32;
}
/* Gets the unique identifier for the air interface. */
/// <summary>
/// Gets the unique identifier for the air interface.
/// </summary>
/// <returns></returns>
void IO::getUDID(uint8_t* buffer)
{
::memcpy(buffer, (void*)STM32_UUID, 12U);
}
/* */
void IO::resetMCU()
{
DEBUG1("reset - bye-bye");
delayUS(250 * 1000);
setLEDInt(false);
setCOSInt(false);
setDMRInt(false);
setP25Int(false);
setNXDNInt(false);
delayUS(250 * 1000);
NVIC_SystemReset();
}
/* */
/// <summary>
///
/// </summary>
void IO::delayBit()
{
delay_ns();
}
#if defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
/* */
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::isDualBand()
{
return GPIO_ReadInputDataBit(PORT_DL_DPX, PIN_DL_DPX) == Bit_SET;
}
#endif
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::SCLK(bool on)
{
GPIO_WriteBit(PORT_SCLK, PIN_SCLK, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::SDATA(bool on)
{
GPIO_WriteBit(PORT_SDATA, PIN_SDATA, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::SREAD()
{
return GPIO_ReadInputDataBit(PORT_SREAD, PIN_SREAD) == Bit_SET;
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::SLE1(bool on)
{
GPIO_WriteBit(PORT_SLE, PIN_SLE, on ? Bit_SET : Bit_RESET);
}
#if defined(DUPLEX)
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::SLE2(bool on)
{
GPIO_WriteBit(PORT_SLE2, PIN_SLE2, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::RXD2()
{
return GPIO_ReadInputDataBit(PORT_RXD2, PIN_RXD2) == Bit_SET;
}
#endif
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::CE(bool on)
{
GPIO_WriteBit(PORT_CE, PIN_CE, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::RXD1()
{
return GPIO_ReadInputDataBit(PORT_RXD, PIN_RXD) == Bit_SET;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::CLK()
{
#if defined(BIDIR_DATA_PIN)
@ -444,45 +473,54 @@ bool IO::CLK()
// Private Class Members
// ---------------------------------------------------------------------------
#if defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
/* */
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
/// <summary>
///
/// </summary>
/// <param name="enable"></param>
void IO::setBandVHF(bool enable)
{
GPIO_WriteBit(PORT_SET_BAND, PIN_SET_BAND, enable ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
bool IO::hasSingleADF7021()
{
return GPIO_ReadInputDataBit(PORT_SGL_DBL, PIN_SGL_DBL) == Bit_SET;
}
#endif
/* */
/// <summary>
///
/// </summary>
void IO::delayIfCal()
{
delayUS(10000);
}
/* */
/// <summary>
///
/// </summary>
void IO::delayReset()
{
delayUS(300);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="us"></param>
void IO::delayUS(uint32_t us)
{
::delay_us(us);
}
/* Initializes hardware interrupts. */
/// <summary>
/// Initializes hardware interrupts.
/// </summary>
void IO::initInt()
{
GPIO_InitTypeDef GPIO_InitStruct;
@ -497,11 +535,11 @@ void IO::initInt()
#if defined(PI_HAT_7021_REV_02)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
#elif defined(ZUMSPOT_ADF7021) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
#endif
#if defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
// Pin defines if the board has a single ADF7021 or double
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = PIN_SGL_DBL;
@ -524,12 +562,21 @@ void IO::initInt()
#endif
volatile unsigned int delay;
for (delay = 0; delay < 512; delay++);
// Pin PA11,PA12 = LOW, USB Reset
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_WriteBit(GPIOA, GPIO_Pin_11, Bit_RESET);
GPIO_WriteBit(GPIOA, GPIO_Pin_12, Bit_RESET);
#if defined(LONG_USB_RESET)
// 10 ms delay
delayUS(10000U);
#else
volatile unsigned int delay;
for (delay = 0; delay < 512; delay++);
#endif
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
@ -664,7 +711,7 @@ void IO::initInt()
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
#endif
#elif defined(ZUMSPOT_ADF7021) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#if defined(BIDIR_DATA_PIN)
// Connect EXTI3 Line
@ -682,7 +729,7 @@ void IO::initInt()
// Connect EXTI5 Line
GPIO_EXTILineConfig(PORT_TXD2_INT, PIN_TXD2_INT);
// Configure EXT5 line
#if defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
EXTI_InitStructure2.EXTI_Line = EXTI_Line8;
#else
EXTI_InitStructure2.EXTI_Line = EXTI_Line5;
@ -704,8 +751,9 @@ void IO::initInt()
#endif
}
/* Starts hardware interrupts. */
/// <summary>
/// Starts hardware interrupts.
/// </summary>
void IO::startInt()
{
NVIC_InitTypeDef NVIC_InitStructure;
@ -718,7 +766,7 @@ void IO::startInt()
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
#elif defined(ZUMSPOT_ADF7021) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
#if defined(BIDIR_DATA_PIN)
// Enable and set EXTI3 Interrupt
@ -749,8 +797,11 @@ void IO::startInt()
#if defined(BIDIR_DATA_PIN)
/* */
/// <summary>
///
/// </summary>
/// <remarks>RXD pin is bidirectional in standard interfaces</remarks>
/// <param name="dir"></param>
void IO::setDataDirOut(bool dir)
{
GPIO_InitTypeDef GPIO_InitStruct;
@ -768,58 +819,74 @@ void IO::setDataDirOut(bool dir)
#endif
#if defined(BIDIR_DATA_PIN)
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setRXDInt(bool on)
{
GPIO_WriteBit(PORT_RXD, PIN_RXD, on ? Bit_SET : Bit_RESET);
}
#endif
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setTXDInt(bool on)
{
GPIO_WriteBit(PORT_TXD, PIN_TXD, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setLEDInt(bool on)
{
GPIO_WriteBit(PORT_LED, PIN_LED, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setPTTInt(bool on)
{
GPIO_WriteBit(PORT_PTT_LED, PIN_PTT_LED, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setCOSInt(bool on)
{
GPIO_WriteBit(PORT_COS_LED, PIN_COS_LED, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setDMRInt(bool on)
{
GPIO_WriteBit(PORT_DMR_LED, PIN_DMR_LED, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setP25Int(bool on)
{
GPIO_WriteBit(PORT_P25_LED, PIN_P25_LED, on ? Bit_SET : Bit_RESET);
}
/* */
/// <summary>
///
/// </summary>
/// <param name="on"></param>
void IO::setNXDNInt(bool on)
{
GPIO_WriteBit(PORT_NXDN_LED, PIN_NXDN_LED, on ? Bit_SET : Bit_RESET);

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

@ -15,7 +15,10 @@ OBJDIR_F4=obj_f4
BINELF_F1=dvm-firmware-hs_f1.elf
BINHEX_F1=dvm-firmware-hs_f1.hex
BINBIN_F1=dvm-firmware-hs_f1.bin
BINELF_F4=dvm-firmware-hs_f4.elf
BINELF_F1BL=dvm-firmware-hs_f1bl.elf
BINHEX_F1BL=dvm-firmware-hs_f1bl.hex
BINBIN_F1BL=dvm-firmware-hs_f1bl.bin
BINELF_F4=dvm-firwmare-hs_f4.elf
BINHEX_F4=dvm-firmware-hs_f4.hex
BINBIN_F4=dvm-firmware-hs_f4.bin
@ -78,6 +81,7 @@ CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c)
SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c)
STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c)
OBJ_F1=$(CXXSRC:./%.cpp=$(OBJDIR_F1)/%.o) $(CSRC_STD_F1:$(STD_LIB_F1)/%.c=$(OBJDIR_F1)/%.o) $(SYS_F1:$(SYS_DIR_F1)/%.c=$(OBJDIR_F1)/%.o) $(STARTUP_F1:$(STARTUP_DIR_F1)/%.c=$(OBJDIR_F1)/%.o)
OBJ_F1BL=$(CXXSRC:./%.cpp=$(OBJDIR_F1)/%.o) $(CSRC_STD_F1:$(STD_LIB_F1)/%.c=$(OBJDIR_F1)/%.o) $(SYS_F1:$(SYS_DIR_F1)/%.c=$(OBJDIR_F1)/%.o) $(STARTUP_F1:$(STARTUP_DIR_F1)/%.c=$(OBJDIR_F1)/%.o) $(CXX_USB_F1:$(USB_F1)/%.cpp=$(OBJDIR_F1)/%.o) $(C_USB_F1:$(USB_F1)/%.c=$(OBJDIR_F1)/%.o)
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)
# MCU flags
@ -86,6 +90,7 @@ MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi
# Compile flags
DEFS_F1_HS=-DUSE_STDPERIPH_DRIVER -DSTM32F10X_MD -DHSE_VALUE=$(OSC) -DVECT_TAB_OFFSET=0x0 -DMADEBYMAKEFILE
DEFS_F1_HS_BL=-DUSE_STDPERIPH_DRIVER -DSTM32F10X_MD -DHSE_VALUE=$(OSC) -DVECT_TAB_OFFSET=0x2000 -DMADEBYMAKEFILE
# STM32F446 Pi-Hat board:
DEFS_PI_F4=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# STM32F4 Nucleo-64 F446RE board:
@ -99,6 +104,7 @@ CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
# Linker flags
LDFLAGS_F1_N =-T stm32f10x_normal.ld $(MCFLAGS_F1) $(INCLUDES_LIBS_F1)
LDFLAGS_F1_D =-T stm32f10x_debug.ld $(MCFLAGS_F1) $(INCLUDES_LIBS_F1)
LDFLAGS_F1_BL =-T stm32f10x_bootloader.ld $(MCFLAGS_F1) $(INCLUDES_LIBS_F1)
LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) $(INCLUDES_LIBS_F4)
LDFLAGS_F4_D =-T stm32f4xx_link_debug.ld $(MCFLAGS_F4) $(INCLUDES_LIBS_F4)
@ -108,52 +114,38 @@ CXXFLAGS=-Os -g -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin
LDFLAGS=-Os -g --specs=nano.specs --specs=nosys.specs
# Build Rules
.PHONY: all release_f1 release_f4 hs pi-f4 f446 clean
.PHONY: all release_f1bl bl f446 clean
all: hs
#error "Either PI_HAT_7021_REV_02, ZUMSPOT_ADF7021, LONESTAR_USB, MMDVM_HS_HAT_REV12, MMDVM_HS_DUAL_HAT_REV10, NANO_HOTSPOT, NANO_DV_REV11, or SKYBRIDGE_HS
zumspot-adf7021: CFLAGS+=-DZUMSPOT_ADF7021 -DSTM32_USART1_HOST
zumspot-adf7021: CXXFLAGS+=-DZUMSPOT_ADF7021 -DSTM32_USART1_HOST
zumspot-adf7021: hs
zumspot-adf7021: CFLAGS+=-DZUMSPOT_ADF7021 -DSTM32_USB_HOST
zumspot-adf7021: CXXFLAGS+=-DZUMSPOT_ADF7021 -DSTM32_USB_HOST
zumspot-adf7021: bl
zumspot-adf7021-duplex: CFLAGS+=-DDUPLEX
zumspot-adf7021-duplex: CXXFLAGS+=-DDUPLEX
zumspot-adf7021-duplex: zumspot-adf7021
pihat-7021-r2: CFLAGS+=-DPI_HAT_7021_REV_02 -DSTM32_USART1_HOST
pihat-7021-r2: CXXFLAGS+=-DZUMSPOT_ADF7021 -DSTM32_USART1_HOST
pihat-7021-r2: hs
pihat-7021-r2-duplex: CFLAGS+=-DDUPLEX
pihat-7021-r2-duplex: CXXFLAGS+=-DDUPLEX
pihat-7021-r2-duplex: pihat-7021-r2
mmdvm-hs-hat: CFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USART1_HOST
mmdvm-hs-hat: CXXFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USART1_HOST
mmdvm-hs-hat: hs
mmdvm-hs-hat-debug: CFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USART1_HOST
mmdvm-hs-hat-debug: CXXFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USART1_HOST
mmdvm-hs-hat-debug: hs-debug
lonestar-usb: CFLAGS+=-DLONESTAR_USB -DSTM32_USB_HOST
lonestar-usb: CXXFLAGS+=-DLONESTAR_USB -DSTM32_USB_HOST
lonestar-usb: bl
mmdvm-hs-hat: CFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USB_HOST
mmdvm-hs-hat: CXXFLAGS+=-DMMDVM_HS_HAT_REV12 -DSTM32_USB_HOST
mmdvm-hs-hat: bl
mmdvm-hs-hat-dual: CFLAGS+=-DDUPLEX
mmdvm-hs-hat-dual: CXXFLAGS+=-DDUPLEX
mmdvm-hs-hat-dual: mmdvm-hs-hat
mmdvm-hs-hat-dual-debug: CFLAGS+=-DDUPLEX
mmdvm-hs-hat-dual-debug: CXXFLAGS+=-DDUPLEX
mmdvm-hs-hat-dual-debug: mmdvm-hs-hat-debug
hs: CFLAGS+=$(CFLAGS_F1) $(DEFS_F1_HS)
hs: CXXFLAGS+=$(CXXFLAGS_F1) $(DEFS_F1_HS)
hs: LDFLAGS+=$(LDFLAGS_F1_N)
hs: release_f1
hs-debug: CFLAGS+=$(CFLAGS_F1) $(DEFS_F1_HS)
hs-debug: CXXFLAGS+=$(CXXFLAGS_F1) $(DEFS_F1_HS)
hs-debug: LDFLAGS+=$(LDFLAGS_F1_D)
hs-debug: release_f1
bl: CFLAGS+=$(CFLAGS_F1) $(DEFS_F1_HS_BL)
bl: CXXFLAGS+=$(CXXFLAGS_F1) $(DEFS_F1_HS_BL)
bl: LDFLAGS+=$(LDFLAGS_F1_BL)
bl: release_f1bl
release_f1: $(BINDIR)
release_f1: $(OBJDIR_F1)
release_f1: $(BINDIR)/$(BINBIN_F1)
release_f1bl: $(BINDIR)
release_f1bl: $(OBJDIR_F1)
release_f1bl: $(BINDIR)/$(BINBIN_F1BL)
release_f4: $(BINDIR)
release_f4: $(OBJDIR_F4)
@ -172,11 +164,11 @@ $(OBJDIR_F4):
mkdir $@/p25
mkdir $@/nxdn
$(BINDIR)/$(BINBIN_F1): $(BINDIR)/$(BINELF_F1)
$(BINDIR)/$(BINBIN_F1BL): $(BINDIR)/$(BINELF_F1BL)
$(CP) -O binary $< $@
$(BINDIR)/$(BINELF_F1): $(OBJ_F1)
$(CXX) $(OBJ_F1) $(LDFLAGS) -o $@
$(SIZE) $(BINDIR)/$(BINELF_F1)
$(BINDIR)/$(BINELF_F1BL): $(OBJ_F1BL)
$(CXX) $(OBJ_F1BL) $(LDFLAGS) -o $@
$(SIZE) $(BINDIR)/$(BINELF_F1BL)
$(BINDIR)/$(BINBIN_F4): $(BINDIR)/$(BINELF_F4)
$(CP) -O binary $< $@
@ -212,3 +204,4 @@ clean:
test ! -d $(OBJDIR_F1) || rm -rf $(OBJDIR_F1)
test ! -d $(OBJDIR_F4) || rm -rf $(OBJDIR_F4)
rm -f $(BINDIR)/*.bin $(BINDIR)/*.elf

@ -21,36 +21,51 @@ An example of this would be ```make -f Makefile.STM32FX mmdvm-hs-hat-dual``` for
## Firmware installation
The device can be used on top on a RPi attached via the GPIO port or standalone and connected via USB (see usb-support branch). 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.
The device can be used connected via USB.
### Install the firmware via GPIO on Raspberry Pi
The USB connection requires firmware with bootloader. For USB connection a bootloader has to be installed initally. This requires STlink connection. After that is done the firmware upgrade can be done via the USB connection. The STlink connection can be used as fallback if wrongly configured firmware was installed for example.
> **_NOTE:_** Your mileage may vary with these instructions, the hotspot boards are loosely designed around a common factor but not all are created equally.
### Install the firmware with bootloader support for USB connection
First you will need to disable the serial console and disable bluetooth. Edit ```/boot/cmdline.txt``` and remove the line ```console=serial0, 115200```.
Next, you will need to disable bluetooth on the board. Edit ```/boot/config.txt``` and add a line containing ```dtoverlay=disable-bt```. Reboot.
If you want to use the device via USB port you have to install a bootloader and build the firmware with bootloader support. As the raw device cannot be used with USB you have to use a USB-serial adapter or STlink device.
> Most sets of instructions reccomend to download stm32flash from online, however we have found the prepackaged version to work fine.
* The bootloader (https://github.com/DVMProject/STM32F10X_Platform/blob/527fee72ae2291486304380cb812c48f36122c32/utils/bootloader/generic_boot20_pc13.bin) should be installed starting at offset 0x8000000.
* The firmware should be installed starting at offset 0x8002000.
Once the hotspot is back on, navigate to the build folder where you compiled the firmware. Put a jumper across the J1 points on the board, and the RED heartbeat LED should stop flashing. Run the below command to flash. Sudo is required on most systems to access GPIO pins.
```sudo stm32flash -v -w dvm-firmware-hs_f1.bin -i 20,-21,21,-20 -R /dev/ttyAMA0```
Note that on newer raspbian versions, the way GPIO chips are numbered has changed. If you're using raspbian bookworm (debian 12) or greater, use this command instead:
```sudo stm32flash -v -w dvm-firmware-hs_f1.bin -i 532,-533,533,-520 -R /dev/ttyAMA0```
You should see the below output if the board flashed successfully.
An example Using STlink this can be done as follows:
```
Wrote and verified address 0x0800be40 (100.00%) Done.
Resetting device...
Reset done.
user@host:~/dvmfirmware-hs$ -f Makefile.STM32FX mmdvm-hs-hat-usb-dual
...
user@host:~/dvmfirmware-hs$ ./STM32F10X_Platform/utils/linux64/st-flash write ./STM32F10X_Platform/utils/bootloader/generic_boot20_pc13.bin 0x8000000
2018-03-02T10:01:04 INFO src/usb.c: -- exit_dfu_mode
2018-03-02T10:01:04 INFO src/common.c: Loading device parameters....
2018-03-02T10:01:04 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2018-03-02T10:01:04 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2018-03-02T10:01:04 INFO src/common.c: Attempting to write 7160 (0x1bf8) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08001800 erased
2018-03-02T10:01:04 INFO src/common.c: Finished erasing 7 pages of 1024 (0x400) bytes
2018-03-02T10:01:04 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2018-03-02T10:01:04 INFO src/common.c: Successfully loaded flash loader in sram
6/6 pages written
2018-03-02T10:01:05 INFO src/common.c: Starting verification of write complete
2018-03-02T10:01:05 INFO src/common.c: Flash written and verified! jolly good!
user@host:~/dvmfirmware-hs$ ./STM32F10X_Platform/utils/linux64/st-flash write dvm-firmware-hs_f1bl.bin 0x8002000
2018-03-02T10:01:05 INFO src/common.c: Loading device parameters....
2018-03-02T10:01:05 INFO src/common.c: Device connected is: F1 Medium-density device, id 0x20036410
2018-03-02T10:01:05 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2018-03-02T10:01:05 INFO src/common.c: Attempting to write 55016 (0xd6e8) bytes to stm32 address: 134225920 (0x8002000)
Flash page at addr: 0x0800f400 erased
2018-03-02T10:01:07 INFO src/common.c: Finished erasing 54 pages of 1024 (0x400) bytes
2018-03-02T10:01:07 INFO src/common.c: Starting Flash write for VL/F0/F3 core id
2018-03-02T10:01:07 INFO src/common.c: Successfully loaded flash loader in sram
53/53 pages written
2018-03-02T10:01:12 INFO src/common.c: Starting verification of write complete
2018-03-02T10:01:13 INFO src/common.c: Flash written and verified! jolly good!
```
The device should now be usable as /dev/ttyACMx.
## Notes
**USB Support Note**: See the usb-support branch for the version of this firmware that supports USB.
**NXDN Support Note**: NXDN support is currently experimental.
## License

@ -1,13 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2020 Jonathan Naylor, G4KLX
* Copyright (c) 2020 Geoffrey Merck, F4FXL - KC3FRA
*
*/
* Copyright (c) 2020 by Jonathan Naylor G4KLX
* Copyright (c) 2020 by Geoffrey Merck F4FXL - KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(STM32F10X_MD) || defined(STM32F4XX)
#include "STM_UART.h"
@ -16,23 +37,25 @@
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the STM_UART class. */
/// <summary>
/// Initializes a new instance of the STM_UART class.
/// </summary>
STM_UART::STM_UART() :
m_usart(NULL)
{
/* stub */
}
/* */
/// <summary></summary>
/// <param name="usart"></param>
void STM_UART::init(USART_TypeDef* usart)
{
m_usart = usart;
}
/* */
/// <summary></summary>
/// <param name="data"></param>
/// <param name="length"></param>
void STM_UART::write(const uint8_t* data, uint16_t length)
{
if (length == 0U || m_usart == NULL)
@ -49,15 +72,14 @@ void STM_UART::write(const uint8_t* data, uint16_t length)
USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);//make sure TX IRQ is on
}
/* */
/// <summary></summary>
/// <returns></returns>
uint8_t STM_UART::read()
{
return m_rxFifo.get();
}
/* */
/// <summary></summary>
void STM_UART::handleIRQ()
{
if (m_usart == NULL)
@ -80,8 +102,12 @@ void STM_UART::handleIRQ()
}
}
/* Flushes the transmit shift register. */
/// <summary>
/// Flushes the transmit shift register.
/// </summary>
/// <remarks>
/// This call is blocking!
/// </remarks>
void STM_UART::flush()
{
if (m_usart == NULL)
@ -92,15 +118,15 @@ void STM_UART::flush()
;
}
/* */
/// <summary></summary>
/// <returns></returns>
uint16_t STM_UART::available()
{
return m_rxFifo.isEmpty() ? 0U : 1U;
}
/* */
/// <summary></summary>
/// <returns></returns>
uint16_t STM_UART::availableForWrite()
{
return m_txFifo.isFull() ? 0U : 1U;

@ -1,19 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (c) 2020 Jonathan Naylor, G4KLX
* Copyright (c) 2020 Geoffrey Merck, F4FXL - KC3FRA
*
*/
/**
* @file STM_UART.h
* @ingroup hotspot_fw
* @file STM_UART.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (c) 2020 by Jonathan Naylor G4KLX
* Copyright (c) 2020 by Geoffrey Merck F4FXL - KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(STM32F10X_MD) || defined(STM32F4XX)
#if !defined(__STM_UART_H__)
#define __STM_UART_H__
@ -31,17 +46,12 @@ const uint16_t BUFFER_MASK = BUFFER_SIZE - 1;
// ---------------------------------------------------------------------------
// Class Declaration
// This class represents a FIFO buffer on a STM32 UART.
// ---------------------------------------------------------------------------
/**
* @brief This class represents a FIFO buffer on a STM32 UART.
* @ingroup hotspot_fw
*/
class DSP_FW_API STM_UARTFIFO {
public:
/**
* @brief Initializes a new instance of the STM_UARTFIFO class.
*/
/// <summary>Initializes a new instance of the STM_UARTFIFO class.</summary>
STM_UARTFIFO() :
m_head(0U),
m_tail(0U)
@ -49,46 +59,32 @@ public:
/* stub */
}
/**
* @brief
* @returns uint8_t
*/
/// <summary></summary>
uint8_t get()
{
return m_buffer[BUFFER_MASK & (m_tail++)];
}
/**
* @brief
* @param data
*/
/// <summary></summary>
void put(uint8_t data)
{
m_buffer[BUFFER_MASK & (m_head++)] = data;
}
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset()
{
m_tail = 0U;
m_head = 0U;
}
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool isEmpty()
{
return m_tail == m_head;
}
/**
* @brief
* @returns bool
*/
/// <summary></summary>
bool isFull()
{
return ((m_head + 1U) & BUFFER_MASK) == (m_tail & BUFFER_MASK);
@ -102,59 +98,32 @@ private:
// ---------------------------------------------------------------------------
// Class Declaration
// This class represents an STM32 UART.
// ---------------------------------------------------------------------------
/**
* @brief This class represents an STM32 UART.
* @ingroup hotspot_fw
*/
class STM_UART {
public:
/**
* @brief Initializes a new instance of the STM_UART class.
*/
/// <summary>Initializes a new instance of the STM_UART class.</summary>
STM_UART();
/**
* @brief Initializes the UART.
* @param usart
*/
/// <summary></summary>
void init(USART_TypeDef* usart);
/**
* @brief
* @returns uint8_t
*/
/// <summary></summary>
uint8_t read();
/**
* @brief
* @param[in] data
* @param length
*/
/// <summary></summary>
void write(const uint8_t* data, uint16_t length);
/**
* @brief
*/
/// <summary></summary>
void handleIRQ();
/**
* @brief Flushes the transmit shift register.
*
* This call is blocking!
*/
/// <summary>Flushes the transmit shift register.</summary>
void flush();
/**
* @brief
* @returns uint16_t
*/
/// <summary></summary>
uint16_t available();
/**
* @brief
* @returns uint16_t
*/
/// <summary></summary>
uint16_t availableForWrite();
private:

@ -1,22 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "SerialBuffer.h"
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the SerialBuffer class. */
/// <summary>
/// Initializes a new instance of the SerialBuffer class.
/// </summary>
SerialBuffer::SerialBuffer(uint16_t length) :
m_length(length),
m_buffer(NULL),
@ -27,15 +50,18 @@ SerialBuffer::SerialBuffer(uint16_t length) :
m_buffer = new uint8_t[length];
}
/* Finalizes a instance of the SerialBuffer class. */
/// <summary>
/// Finalizes a instance of the SerialBuffer class.
/// </summary>
SerialBuffer::~SerialBuffer()
{
delete[] m_buffer;
}
/* Helper to get how much space the ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint16_t SerialBuffer::getSpace() const
{
uint16_t n = 0U;
@ -53,8 +79,10 @@ uint16_t SerialBuffer::getSpace() const
return n;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint16_t SerialBuffer::getData() const
{
if (m_tail == m_head)
@ -65,8 +93,9 @@ uint16_t SerialBuffer::getData() const
return m_length - m_tail + m_head;
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void SerialBuffer::reset()
{
m_head = 0U;
@ -74,8 +103,9 @@ void SerialBuffer::reset()
m_full = false;
}
/* Helper to reset and reinitialize data values to defaults. */
/// <summary>
/// Helper to reset and reinitialize data values to defaults.
/// </summary>
void SerialBuffer::reinitialize(uint16_t length)
{
reset();
@ -86,8 +116,11 @@ void SerialBuffer::reinitialize(uint16_t length)
m_buffer = new uint8_t[length];
}
/* */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
bool SerialBuffer::put(uint8_t c)
{
if (m_full)
@ -105,15 +138,19 @@ bool SerialBuffer::put(uint8_t c)
return true;
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint8_t SerialBuffer::peek() const
{
return m_buffer[m_tail];
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint8_t SerialBuffer::get()
{
uint8_t value = m_buffer[m_tail];

@ -1,20 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin, KI6ZUM
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file SerialBuffer.h
* @ingroup hotspot_fw
* @file SerialBuffer.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#if !defined(__SERIAL_RB_H__)
#define __SERIAL_RB_H__
@ -35,64 +51,34 @@ const uint16_t SERIAL_RINGBUFFER_SIZE = 396U;
// ---------------------------------------------------------------------------
// Class Declaration
//
// Implements a circular buffer for serial data.
// ---------------------------------------------------------------------------
/**
* @brief Implements a circular ring buffer for serial data.
* @ingroup hotspot_fw
*/
class DSP_FW_API SerialBuffer {
public:
/**
* @brief Initializes a new instance of the SerialBuffer class.
* @param length Length of buffer.
*/
/// <summary>Initializes a new instance of the SerialBuffer class.</summary>
SerialBuffer(uint16_t length = SERIAL_RINGBUFFER_SIZE);
/**
* @brief Finalizes a instance of the SerialBuffer class.
*/
/// <summary>Finalizes a instance of the SerialBuffer class.</summary>
~SerialBuffer();
/**
* @brief Helper to get how much space the ring buffer has for samples.
* @returns uint16_t Amount of space remaining for data.
*/
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
uint16_t getSpace() const;
/**
* @brief
* @returns uint16_t
*/
/// <summary></summary>
uint16_t getData() const;
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Helper to reset and reinitialize data values to defaults.
* @param length Length of buffer.
*/
/// <summary>Helper to reset and reinitialize data values to defaults.</summary>
void reinitialize(uint16_t length);
/**
* @brief
* @param c
* @returns bool
*/
/// <summary></summary>
bool put(uint8_t c);
/**
* @brief
* @returns uint8_t
*/
/// <summary></summary>
uint8_t peek() const;
/**
* @brief
* @returns uint8_t
*/
/// <summary></summary>
uint8_t get();
private:

File diff suppressed because it is too large Load Diff

@ -1,22 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2018,2020,2021 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2018,2021-2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file SerialPort.h
* @ingroup hotspot_fw
* @file SerialPort.cpp
* @ingroup hotspot_fw
* @file SerialSTM.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Andy Uribe CA6JAU
* Copyright (C) 2018,2021-2022 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__SERIAL_PORT_H__)
#define __SERIAL_PORT_H__
@ -28,371 +40,209 @@
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup modem
* @{
*/
/**
* @brief Modem operation states.
*/
enum DVM_STATE {
STATE_IDLE = 0U, //! Idle
STATE_IDLE = 0U,
// DMR
STATE_DMR = 1U, //! DMR
STATE_DMR = 1U,
// Project 25
STATE_P25 = 2U, //! Project 25
STATE_P25 = 2U,
// NXDN
STATE_NXDN = 3U, //! NXDN
STATE_NXDN = 3U,
// CW
STATE_CW = 10U, //! Continuous Wave
STATE_CW = 10U,
// Calibration States
STATE_INT_CAL = 90U, //!
STATE_INT_CAL = 90U,
STATE_P25_CAL_1K = 92U, //! Project 25 Calibration 1K
STATE_P25_CAL_1K = 92U,
STATE_DMR_DMO_CAL_1K = 93U, //! DMR DMO Calibration 1K
STATE_DMR_CAL_1K = 94U, //! DMR Calibration 1K
STATE_DMR_LF_CAL = 95U, //! DMR Low Frequency Calibration
STATE_DMR_DMO_CAL_1K = 93U,
STATE_DMR_CAL_1K = 94U,
STATE_DMR_LF_CAL = 95U,
STATE_RSSI_CAL = 96U, //! RSSI Calibration
STATE_RSSI_CAL = 96U,
STATE_P25_CAL = 97U, //! Project 25 Calibration
STATE_DMR_CAL = 98U, //! DMR Calibration
STATE_NXDN_CAL = 99U //! NXDN Calibration
STATE_P25_CAL = 97U,
STATE_DMR_CAL = 98U,
STATE_NXDN_CAL = 99U
};
/**
* @brief Modem commands.
*/
enum DVM_COMMANDS {
CMD_GET_VERSION = 0x00U, //! Get Modem Version
CMD_GET_STATUS = 0x01U, //! Get Modem Status
CMD_SET_CONFIG = 0x02U, //! Set Modem Configuration
CMD_SET_MODE = 0x03U, //! Set Modem Mode
CMD_SET_SYMLVLADJ = 0x04U, //! Set Symbol Level Adjustments
CMD_SET_RXLEVEL = 0x05U, //! Set Rx Level
CMD_SET_RFPARAMS = 0x06U, //! (Hotspot) Set RF Parameters
CMD_CAL_DATA = 0x08U, //! Calibration Data
CMD_RSSI_DATA = 0x09U, //! RSSI Data
CMD_SEND_CWID = 0x0AU, //! Send Continous Wave ID (Morse)
CMD_SET_BUFFERS = 0x0FU, //! Set FIFO Buffer Lengths
CMD_DMR_DATA1 = 0x18U, //! DMR Data Slot 1
CMD_DMR_LOST1 = 0x19U, //! DMR Data Lost Slot 1
CMD_DMR_DATA2 = 0x1AU, //! DMR Data Slot 2
CMD_DMR_LOST2 = 0x1BU, //! DMR Data Lost Slot 2
CMD_DMR_SHORTLC = 0x1CU, //! DMR Short Link Control
CMD_DMR_START = 0x1DU, //! DMR Start Transmit
CMD_DMR_ABORT = 0x1EU, //! DMR Abort
CMD_DMR_CACH_AT_CTRL = 0x1FU, //! DMR Set CACH AT Control
CMD_DMR_CLEAR1 = 0x20U, //! DMR Clear Slot 1 Buffer
CMD_DMR_CLEAR2 = 0x21U, //! DMR Clear Slot 2 Buffer
CMD_P25_DATA = 0x31U, //! Project 25 Data
CMD_P25_LOST = 0x32U, //! Project 25 Data Lost
CMD_P25_CLEAR = 0x33U, //! Project 25 Clear Buffer
CMD_NXDN_DATA = 0x41U, //! NXDN Data
CMD_NXDN_LOST = 0x42U, //! NXDN Data Lost
CMD_NXDN_CLEAR = 0x43U, //! NXDN Clear Buffer
CMD_ACK = 0x70U, //! Command ACK
CMD_NAK = 0x7FU, //! Command NACK
CMD_FLSH_READ = 0xE0U, //! Read Flash Partition
CMD_FLSH_WRITE = 0xE1U, //! Write Flash Partition
CMD_RESET_MCU = 0xEAU, //! Soft Reboot MCU
CMD_DEBUG1 = 0xF1U, //!
CMD_DEBUG2 = 0xF2U, //!
CMD_DEBUG3 = 0xF3U, //!
CMD_DEBUG4 = 0xF4U, //!
CMD_DEBUG5 = 0xF5U, //!
CMD_DEBUG_DUMP = 0xFAU, //!
CMD_GET_VERSION = 0x00U,
CMD_GET_STATUS = 0x01U,
CMD_SET_CONFIG = 0x02U,
CMD_SET_MODE = 0x03U,
CMD_SET_SYMLVLADJ = 0x04U,
CMD_SET_RXLEVEL = 0x05U,
CMD_SET_RFPARAMS = 0x06U,
CMD_CAL_DATA = 0x08U,
CMD_RSSI_DATA = 0x09U,
CMD_SEND_CWID = 0x0AU,
CMD_DMR_DATA1 = 0x18U,
CMD_DMR_LOST1 = 0x19U,
CMD_DMR_DATA2 = 0x1AU,
CMD_DMR_LOST2 = 0x1BU,
CMD_DMR_SHORTLC = 0x1CU,
CMD_DMR_START = 0x1DU,
CMD_DMR_ABORT = 0x1EU,
CMD_DMR_CACH_AT_CTRL = 0x1FU,
CMD_P25_DATA = 0x31U,
CMD_P25_LOST = 0x32U,
CMD_P25_CLEAR = 0x33U,
CMD_NXDN_DATA = 0x41U,
CMD_NXDN_LOST = 0x42U,
CMD_ACK = 0x70U,
CMD_NAK = 0x7FU,
CMD_FLSH_READ = 0xE0U,
CMD_FLSH_WRITE = 0xE1U,
CMD_DEBUG1 = 0xF1U,
CMD_DEBUG2 = 0xF2U,
CMD_DEBUG3 = 0xF3U,
CMD_DEBUG4 = 0xF4U,
CMD_DEBUG5 = 0xF5U,
CMD_DEBUG_DUMP = 0xFAU,
};
/**
* @brief Modem response reason codes.
*/
enum CMD_REASON_CODE {
RSN_OK = 0U, //! OK
RSN_NAK = 1U, //! Negative Acknowledge
RSN_OK = 0U,
RSN_NAK = 1U,
RSN_ILLEGAL_LENGTH = 2U, //! Illegal Length
RSN_INVALID_REQUEST = 4U, //! Invalid Request
RSN_RINGBUFF_FULL = 8U, //! Ring Buffer Full
RSN_ILLEGAL_LENGTH = 2U,
RSN_INVALID_REQUEST = 4U,
RSN_RINGBUFF_FULL = 8U,
RSN_INVALID_FDMA_PREAMBLE = 10U, //! Invalid FDMA Preamble Length
RSN_INVALID_MODE = 11U, //! Invalid Mode
RSN_INVALID_FDMA_PREAMBLE = 10U,
RSN_INVALID_MODE = 11U,
RSN_INVALID_DMR_CC = 12U, //! Invalid DMR CC
RSN_INVALID_DMR_SLOT = 13U, //! Invalid DMR Slot
RSN_INVALID_DMR_START = 14U, //! Invaild DMR Start Transmit
RSN_INVALID_DMR_RX_DELAY = 15U, //! Invalid DMR Rx Delay
RSN_INVALID_DMR_CC = 12U,
RSN_INVALID_DMR_SLOT = 13U,
RSN_INVALID_DMR_START = 14U,
RSN_INVALID_DMR_RX_DELAY = 15U,
RSN_INVALID_P25_CORR_COUNT = 16U, //! Invalid P25 Correlation Count
RSN_INVALID_P25_CORR_COUNT = 16U,
RSN_NO_INTERNAL_FLASH = 20U, //! No Internal Flash
RSN_FAILED_ERASE_FLASH = 21U, //! Failed to erase flash partition
RSN_FAILED_WRITE_FLASH = 22U, //! Failed to write flash partition
RSN_FLASH_WRITE_TOO_BIG = 23U, //! Data to large for flash partition
RSN_NO_INTERNAL_FLASH = 20U,
RSN_FAILED_ERASE_FLASH = 21U,
RSN_FAILED_WRITE_FLASH = 22U,
RSN_FLASH_WRITE_TOO_BIG = 23U,
RSN_HS_NO_DUAL_MODE = 32U, //! (Hotspot) No Dual Mode Operation
RSN_HS_NO_DUAL_MODE = 32U,
RSN_DMR_DISABLED = 63U, //! DMR Disabled
RSN_P25_DISABLED = 64U, //! Project 25 Disabled
RSN_NXDN_DISABLED = 65U //! NXDN Disabled
RSN_DMR_DISABLED = 63U,
RSN_P25_DISABLED = 64U,
RSN_NXDN_DISABLED = 65U
};
const uint8_t DVM_SHORT_FRAME_START = 0xFEU;
const uint8_t DVM_LONG_FRAME_START = 0xFDU;
const uint8_t DVM_FRAME_START = 0xFEU;
#define SERIAL_FB_LEN 518U
#define SERIAL_SPEED 115200
/** @} */
#define STATE_SCAN_MAX 3
// ---------------------------------------------------------------------------
// Class Declaration
// Implements the RS232 serial bus to communicate with the HOST S/W.
// ---------------------------------------------------------------------------
/**
* @brief Implements the RS232 serial bus to communicate with the HOST S/W.
* @ingroup hotspot_fw
*/
class DSP_FW_API SerialPort {
public:
/**
* @brief Initializes a new instance of the SerialPort class.
*/
/// <summary>Initializes a new instance of the SerialPort class.</summary>
SerialPort();
/**
* @brief Starts serial port communications.
*/
/// <summary>Starts serial port communications.</summary>
void start();
/**
* @brief Process data from serial port.
*/
/// <summary>Process data from serial port.</summary>
void process();
/**
* @brief Helper to check if the modem is in a calibration state.
* @param state
* @returns bool
*/
/// <summary>Helper to check if the modem is in a calibration state.</summary>
bool isCalState(DVM_STATE state);
/**
* @brief Helper to determine digital mode if the modem is in a calibration state.
* @param state
* @returns DVM_STATE
*/
/// <summary>Helper to determine digital mode if the modem is in a calibration state.</summary>
DVM_STATE calRelativeState(DVM_STATE state);
/**
* @brief Write DMR frame data to serial port.
* @param slot DMR slot number.
* @param[in] data Data to write.
* @param length Length of data to write.
*/
/// <summary>Write DMR frame data to serial port.</summary>
void writeDMRData(bool slot, const uint8_t* data, uint8_t length);
/**
* @brief Write lost DMR frame data to serial port.
* @param slot DMR slot number.
*/
/// <summary>Write lost DMR frame data to serial port.</summary>
void writeDMRLost(bool slot);
/**
* @brief Write P25 frame data to serial port.
* @param[in] data Data to write.
* @param length Length of data to write.
*/
void writeP25Data(const uint8_t* data, uint16_t length);
/**
* @brief Write lost P25 frame data to serial port.
*/
/// <summary>Write P25 frame data to serial port.</summary>
void writeP25Data(const uint8_t* data, uint8_t length);
/// <summary>Write lost P25 frame data to serial port.</summary>
void writeP25Lost();
/**
* @brief Write NXDN frame data to serial port.
* @param[in] data Data to write.
* @param length Length of data to write.
*/
/// <summary>Write NXDN frame data to serial port.</summary>
void writeNXDNData(const uint8_t* data, uint8_t length);
/**
* @brief Write lost NXDN frame data to serial port.
*/
/// <summary>Write lost NXDN frame data to serial port.</summary>
void writeNXDNLost();
/**
* @brief Write calibration frame data to serial port.
* @param[in] data Data to write.
* @param length Length of data to write.
*/
/// <summary>Write calibration frame data to serial port.</summary>
void writeCalData(const uint8_t* data, uint8_t length);
/**
* @brief Write RSSI frame data to serial port.
* @param[in] data Data to write.
* @param length Length of data to write.
*/
/// <summary>Write RSSI frame data to serial port.</summary>
void writeRSSIData(const uint8_t* data, uint8_t length);
/**
* @brief
* @param[in] text
*/
/// <summary></summary>
void writeDebug(const char* text);
/**
* @brief
* @param[in] text
* @param n1
*/
/// <summary></summary>
void writeDebug(const char* text, int16_t n1);
/**
* @brief
* @param[in] text
* @param n1
* @param n2
*/
/// <summary></summary>
void writeDebug(const char* text, int16_t n1, int16_t n2);
/**
* @brief
* @param[in] text
* @param n1
* @param n2
* @param n3
*/
/// <summary></summary>
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3);
/**
* @brief
* @param[in] text
* @param n1
* @param n2
* @param n3
* @param n4
*/
/// <summary></summary>
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4);
/**
* @brief
* @param[in] data
* @param length
*/
/// <summary></summary>
void writeDump(const uint8_t* data, uint16_t length);
private:
uint8_t m_buffer[SERIAL_FB_LEN];
uint16_t m_ptr;
uint16_t m_len;
bool m_dblFrame;
uint8_t m_buffer[256U];
uint8_t m_ptr;
uint8_t m_len;
bool m_debug;
/**
* @brief Write acknowlegement.
*/
/// <summary>Write acknowlegement.</summary>
void sendACK();
/**
* @brief Write negative acknowlegement.
* @param err
*/
/// <summary>Write negative acknowlegement.</summary>
void sendNAK(uint8_t err);
/**
* @brief Write modem DSP status.
*/
/// <summary>Write modem DSP status.</summary>
void getStatus();
/**
* @brief Write modem DSP version.
*/
/// <summary>Write modem DSP version.</summary>
void getVersion();
/**
* @brief Helper to validate the passed modem state is valid.
* @param state
* @returns uint8_t Reason code.
*/
/// <summary>Helper to validate the passed modem state is valid.</summary>
uint8_t modemStateCheck(DVM_STATE state);
/**
* @brief Set modem DSP configuration from serial port data.
* @param[in] data Buffer containing configuration frame.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Set modem DSP configuration from serial port data.</summary>
uint8_t setConfig(const uint8_t* data, uint8_t length);
/**
* @brief Set modem DSP mode from serial port data.
* @param[in] data Buffer containing mode frame.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Set modem DSP mode from serial port data.</summary>
uint8_t setMode(const uint8_t* data, uint8_t length);
/**
* @brief Sets the modem state.
* @param modemState
*/
/// <summary>Sets the modem state.</summary>
void setMode(DVM_STATE modemState);
/**
* @brief Sets the RF parameters.
* @param[in] data Buffer containing RF parameters frame.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Sets the RF parameters.</summary>
uint8_t setRFParams(const uint8_t* data, uint8_t length);
/**
* @brief Sets the protocol ring buffer sizes.
* @param[in] data Buffer containing set buffers frame.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
uint8_t setBuffers(const uint8_t* data, uint8_t length);
/**
* @brief Reads data from the modem flash parititon.
*/
/// <summary></summary>
void flashRead();
/**
* @brief Writes data to the modem flash partition.
* @param[in] data Buffer containing data to write to flash partition.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary></summary>
uint8_t flashWrite(const uint8_t* data, uint8_t length);
// Hardware specific routines
/**
* @brief
* @param n
* @param speed
*/
/// <summary></summary>
void beginInt(uint8_t n, int speed);
/**
* @brief
* @param n
*/
/// <summary></summary>
int availableInt(uint8_t n);
/**
* @brief
* @param n
*/
/// <summary></summary>
int availableForWriteInt(uint8_t n);
/**
* @brief
* @param n
*/
/// <summary></summary>
uint8_t readInt(uint8_t n);
/**
* @brief
* @param n
* @param[in] data
* @param length
* @param flush
*/
/// <summary></summary>
void writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush = false);
};

@ -1,20 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016 Jim McLaughlin, KI6ZUM
* Copyright (C) 2016,2017,2018,2019 Andy Uribe, CA6JAU
* Copyright (C) 2021,2022,2024 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
* Copyright (C) 2021-2022 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "SerialPort.h"
#include "STM_UART.h"
#if defined(STM32F10X_MD)
#include <stm32f10x_flash.h>
#include <usb_serial.h>
// ---------------------------------------------------------------------------
// Constants
@ -50,18 +71,18 @@ extern "C" {
static STM_UART m_USART1;
/**
* @brief Helper to handle the USART1 IRQ.
*/
/// <summary>
///
/// </summary>
void USART1_IRQHandler()
{
m_USART1.handleIRQ();
}
/**
* @brief Initializes the USART1.
* @param speed Port speed.
*/
/// <summary>
///
/// </summary>
/// <param name="speed"></param>
void InitUSART1(int speed)
{
// USART1 - TXD PA9 - RXD PA10
@ -115,18 +136,18 @@ void InitUSART1(int speed)
static STM_UART m_USART2;
/**
* @brief Helper to handle the USART5 IRQ.
*/
/// <summary>
///
/// </summary>
void USART2_IRQHandler()
{
m_USART2.handleIRQ();
}
/**
* @brief Initializes the USART5.
* @param speed Port speed.
*/
/// <summary>
///
/// </summary>
/// <param name="speed"></param>
void InitUSART2(int speed)
{
// USART2 - TXD PA2 - RXD PA3
@ -176,13 +197,14 @@ void InitUSART2(int speed)
// Private Class Members
// ---------------------------------------------------------------------------
/* Reads data from the modem flash parititon. */
/// <summary>
///
/// </summary>
void SerialPort::flashRead()
{
uint8_t reply[249U];
reply[0U] = DVM_SHORT_FRAME_START;
reply[0U] = DVM_FRAME_START;
reply[1U] = 249U;
reply[2U] = CMD_FLSH_READ;
@ -191,8 +213,11 @@ void SerialPort::flashRead()
writeInt(1U, reply, 249U);
}
/* Writes data to the modem flash partition. */
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
uint8_t SerialPort::flashWrite(const uint8_t* data, uint8_t length)
{
if (length > 249U) {
@ -238,13 +263,16 @@ uint8_t SerialPort::flashWrite(const uint8_t* data, uint8_t length)
return RSN_OK;
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <param name="speed"></param>
void SerialPort::beginInt(uint8_t n, int speed)
{
switch (n) {
case 1U:
InitUSART1(speed);
usbserial.begin();
break;
case 3U:
InitUSART2(speed);
@ -254,13 +282,16 @@ void SerialPort::beginInt(uint8_t n, int speed)
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
int SerialPort::availableInt(uint8_t n)
{
switch (n) {
case 1U:
return m_USART1.available();
return usbserial.available();
case 3U:
m_USART2.available();
default:
@ -268,13 +299,17 @@ int SerialPort::availableInt(uint8_t n)
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
int SerialPort::availableForWriteInt(uint8_t n)
{
switch (n) {
case 1U:
return m_USART1.availableForWrite();
//return usbserial.availableForWrite();
return 1U; // we don't have this -- so fake it
case 3U:
return m_USART2.availableForWrite();
default:
@ -282,13 +317,16 @@ int SerialPort::availableForWriteInt(uint8_t n)
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
uint8_t SerialPort::readInt(uint8_t n)
{
switch (n) {
case 1U:
return m_USART1.read();
return usbserial.read();
case 3U:
return m_USART2.read();
default:
@ -297,15 +335,20 @@ uint8_t SerialPort::readInt(uint8_t n)
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="flush"></param>
void SerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush)
{
switch (n) {
case 1U:
m_USART1.write(data, length);
usbserial.write(data, length);
if (flush)
m_USART1.flush();
usbserial.flush();
break;
case 3U:
m_USART2.write(data, length);

@ -1,13 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2017 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Utils.h"
// ---------------------------------------------------------------------------
@ -25,15 +45,11 @@ const uint8_t BITS_TABLE[] = {
// Global Functions
// ---------------------------------------------------------------------------
/* Returns the count of bits in the passed 8 byte value. */
uint8_t countBits8(uint8_t bits)
{
return BITS_TABLE[bits];
}
/* Returns the count of bits in the passed 16 byte value. */
uint8_t countBits16(uint16_t bits)
{
uint8_t* p = (uint8_t*)&bits;
@ -43,8 +59,6 @@ uint8_t countBits16(uint16_t bits)
return n;
}
/* Returns the count of bits in the passed 32 byte value. */
uint8_t countBits32(uint32_t bits)
{
uint8_t* p = (uint8_t*)&bits;
@ -56,8 +70,6 @@ uint8_t countBits32(uint32_t bits)
return n;
}
/* Returns the count of bits in the passed 64 byte value. */
uint8_t countBits64(uint64_t bits)
{
uint8_t* p = (uint8_t*)&bits;

@ -1,19 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2017 Andy Uribe, CA6JAU
*
*/
/**
* @file Utils.h
* @ingroup hotspot_fw
* @file Utils.cpp
* @ingroup hotspot_fw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__UTILS_H__)
#define __UTILS_H__
@ -31,29 +45,9 @@
// Global Functions
// ---------------------------------------------------------------------------
/**
* @brief Returns the count of bits in the passed 8 byte value.
* @param bits uint8_t to count bits for.
* @returns uint8_t Count of bits in passed value.
*/
DSP_FW_API uint8_t countBits8(uint8_t bits);
/**
* @brief Returns the count of bits in the passed 16 byte value.
* @param bits uint16_t to count bits for.
* @returns uint8_t Count of bits in passed value.
*/
DSP_FW_API uint8_t countBits16(uint16_t bits);
/**
* @brief Returns the count of bits in the passed 32 byte value.
* @param bits uint32_t to count bits for.
* @returns uint8_t Count of bits in passed value.
*/
DSP_FW_API uint8_t countBits32(uint32_t bits);
/**
* @brief Returns the count of bits in the passed 64 byte value.
* @param bits ulong64_t to count bits for.
* @returns uint8_t Count of bits in passed value.
*/
DSP_FW_API uint8_t countBits64(ulong64_t bits);
#endif // __UTILS_H__

@ -1,61 +1,83 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2015 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2018,2019 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2018,2019 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/CalDMR.h"
using namespace dmr;
#if defined(ENABLE_DMR)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
// Voice LC Header, CC: 1, srcID: 1, dstID: TG9
const uint8_t VH_1K[] = { 0x00U,
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xDEU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xDEU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
// Voice Term with LC, CC: 1, srcID: 1, dstID: TG9
const uint8_t VT_1K[] = { 0x00U,
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
// Voice LC MS Header, CC: 1, srcID: 1, dstID: TG9
const uint8_t VH_DMO1K[] = { 0x00U,
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x7EU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x7EU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
// Voice Term MS with LC, CC: 1, srcID: 1, dstID: TG9
const uint8_t VT_DMO1K[] = { 0x00U,
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x79U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x79U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
// Voice coding data + FEC, 1031 Hz Test Pattern
const uint8_t VOICE_1K[] = { 0x00U,
0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU, 0xCEU, 0xA8U,
0xFEU, 0x83U, 0xA0U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x0CU, 0xC4U, 0x58U,
0x20U, 0x0AU, 0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU };
0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU, 0xCEU, 0xA8U,
0xFEU, 0x83U, 0xA0U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x0CU, 0xC4U, 0x58U,
0x20U, 0x0AU, 0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU };
// Embedded LC: CC: 1, srcID: 1, dstID: TG9
const uint8_t SYNCEMB_1K[6][7] = {
{ 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U }, // BS VOICE SYNC (audio seq 0)
{ 0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U }, // EMB + Embedded LC1 (audio seq 1)
{ 0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U }, // EMB + Embedded LC2 (audio seq 2)
{ 0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U }, // EMB + Embedded LC3 (audio seq 3)
{ 0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U }, // EMB + Embedded LC4 (audio seq 4)
{ 0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U } }; // EMB (audio seq 5)
{ 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U }, // BS VOICE SYNC (audio seq 0)
{ 0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U }, // EMB + Embedded LC1 (audio seq 1)
{ 0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U }, // EMB + Embedded LC2 (audio seq 2)
{ 0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U }, // EMB + Embedded LC3 (audio seq 3)
{ 0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U }, // EMB + Embedded LC4 (audio seq 4)
{ 0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U } }; // EMB (audio seq 5)
// Embedded LC MS: CC: 1, srcID: 1, dstID: TG9
const uint8_t SYNCEMB_DMO1K[6][7] = {
@ -75,8 +97,9 @@ const uint8_t SHORTLC_1K[] = { 0x33U, 0x3AU, 0xA0U, 0x30U, 0x00U, 0x55U, 0xA6U,
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the CalDMR class. */
/// <summary>
/// Initializes a new instance of the CalDMR class.
/// </summary>
CalDMR::CalDMR() :
m_transmit(false),
m_state(DMRCAL1K_IDLE),
@ -88,8 +111,9 @@ CalDMR::CalDMR() :
::memcpy(m_dmr1k, VOICE_1K, DMR_FRAME_LENGTH_BYTES + 1U);
}
/* Process local state and transmit on the air interface. */
/// <summary>
/// Process local state and transmit on the air interface.
/// </summary>
void CalDMR::process()
{
switch (m_modemState) {
@ -127,8 +151,10 @@ void CalDMR::process()
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
void CalDMR::createData1k(uint8_t n)
{
for (uint8_t i = 0; i < 5U; i++)
@ -140,8 +166,10 @@ void CalDMR::createData1k(uint8_t n)
m_dmr1k[20U] |= SYNCEMB_1K[n][6] & 0xF0U;
}
/* */
/// <summary>
///
/// </summary>
/// <param name="n"></param>
void CalDMR::createDataDMO1k(uint8_t n)
{
for (uint8_t i = 0; i < 5U; i++)
@ -153,8 +181,9 @@ void CalDMR::createDataDMO1k(uint8_t n)
m_dmr1k[20U] |= SYNCEMB_DMO1K[n][6] & 0xF0U;
}
/* */
/// <summary>
///
/// </summary>
void CalDMR::dmr1kcal()
{
#if defined(DUPLEX)
@ -203,8 +232,9 @@ void CalDMR::dmr1kcal()
#endif
}
/* */
/// <summary>
///
/// </summary>
void CalDMR::dmrDMO1kcal()
{
dmrDMOTX.process();
@ -240,8 +270,12 @@ void CalDMR::dmrDMO1kcal()
}
}
/* Write DMR calibration state. */
/// <summary>
/// Write DMR calibration state.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t CalDMR::write(const uint8_t* data, uint8_t length)
{
if (length != 1U)
@ -257,3 +291,5 @@ uint8_t CalDMR::write(const uint8_t* data, uint8_t length)
return RSN_OK;
}
#endif // defined(ENABLE_DMR)

@ -1,95 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2015 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2018 Andy Uribe, CA6JAU
*
*/
/**
* @file CalDMR.h
* @ingroup dmr_hfw
* @file CalDMR.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__CAL_DMR_H__)
#define __CAL_DMR_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
#if defined(ENABLE_DMR)
namespace dmr
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Calibration States
* @ingroup dmr_mfw
*/
enum DMR1KCAL {
DMRCAL1K_IDLE, //! Idle
DMRCAL1K_VH, //! Voice Header
DMRCAL1K_VOICE, //! Voice
DMRCAL1K_VT, //! Voice Terminator
DMRCAL1K_WAIT //!
enum DMRCAL1K {
DMRCAL1K_IDLE,
DMRCAL1K_VH,
DMRCAL1K_VOICE,
DMRCAL1K_VT,
DMRCAL1K_WAIT
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements logic for DMR calibration mode.
// ---------------------------------------------------------------------------
/**
* @brief Implements logic for DMR calibration mode.
* @ingroup dmr_hfw
*/
class DSP_FW_API CalDMR {
public:
/**
* @brief Initializes a new instance of the CalDMR class.
*/
/// <summary>Initializes a new instance of the CalDMR class.</summary>
CalDMR();
/**
* @brief Process local state and transmit on the air interface.
*/
/// <summary>Process local state and transmit on the air interface.</summary>
void process();
/**
* @brief
* @param n
*/
/// <summary></summary>
void createData1k(uint8_t n);
/**
* @brief
* @param n
*/
/// <summary></summary>
void createDataDMO1k(uint8_t n);
/**
* @brief
*/
/// <summary></summary>
void dmr1kcal();
/**
* @brief
*/
/// <summary></summary>
void dmrDMO1kcal();
/**
* @brief Write DMR calibration state.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write DMR calibration state.</summary>
uint8_t write(const uint8_t* data, uint8_t length);
private:
bool m_transmit;
DMR1KCAL m_state;
DMRCAL1K m_state;
uint32_t m_frameStart;
uint8_t m_dmr1k[DMR_FRAME_LENGTH_BYTES + 1U];
@ -99,4 +89,6 @@ namespace dmr
};
} // namespace dmr
#endif // defined(ENABLE_DMR)
#endif // __CAL_DMR_H__

@ -1,14 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRDMORX.h"
#include "dmr/DMRSlotType.h"
@ -16,6 +36,8 @@
using namespace dmr;
#if defined(ENABLE_DMR)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -34,8 +56,9 @@ const uint8_t CONTROL_DATA = 0x40U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRDMORX class. */
/// <summary>
/// Initializes a new instance of the DMRDMORX class.
/// </summary>
DMRDMORX::DMRDMORX() :
m_bitBuffer(0x00U),
m_buffer(),
@ -53,8 +76,9 @@ DMRDMORX::DMRDMORX() :
/* stub */
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void DMRDMORX::reset()
{
m_syncPtr = 0U;
@ -65,8 +89,10 @@ void DMRDMORX::reset()
m_endPtr = NOENDPTR;
}
/* Sample DMR bits from the air interface. */
/// <summary>
/// Sample DMR bits from the air interface.
/// </summary>
/// <param name="bit"></param>
void DMRDMORX::databit(bool bit)
{
_WRITE_BIT(m_buffer, m_dataPtr, bit);
@ -117,7 +143,7 @@ void DMRDMORX::databit(bool bit)
switch (dataType) {
case DT_DATA_HEADER:
DEBUG2("DMRDMORX::databit() data header found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): data header found pos", m_syncPtr);
writeRSSIData(frame);
m_state = DMORXS_DATA;
m_type = 0x00U;
@ -126,32 +152,32 @@ void DMRDMORX::databit(bool bit)
case DT_RATE_34_DATA:
case DT_RATE_1_DATA:
if (m_state == DMORXS_DATA) {
DEBUG2("DMRDMORX::databit() data payload found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): data payload found pos", m_syncPtr);
writeRSSIData(frame);
m_type = dataType;
}
break;
case DT_VOICE_LC_HEADER:
DEBUG2("DMRDMORX::databit() voice header found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): voice header found pos", m_syncPtr);
writeRSSIData(frame);
m_state = DMORXS_VOICE;
break;
case DT_VOICE_PI_HEADER:
if (m_state == DMORXS_VOICE) {
DEBUG2("DMRDMORX::databit() voice pi header found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): voice pi header found pos", m_syncPtr);
writeRSSIData(frame);
}
m_state = DMORXS_VOICE;
break;
case DT_TERMINATOR_WITH_LC:
if (m_state == DMORXS_VOICE) {
DEBUG2("DMRDMORX::databit() voice terminator found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): voice terminator found pos", m_syncPtr);
writeRSSIData(frame);
reset();
}
break;
default: // DT_CSBK
DEBUG2("DMRDMORX::databit() csbk found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): csbk found pos", m_syncPtr);
writeRSSIData(frame);
reset();
break;
@ -160,7 +186,7 @@ void DMRDMORX::databit(bool bit)
}
else if (m_control == CONTROL_VOICE) {
// Voice sync
DEBUG2("DMRDMORX::databit() voice sync found pos", m_syncPtr);
DEBUG2("DMRDMORX: databit(): voice sync found pos", m_syncPtr);
writeRSSIData(frame);
m_state = DMORXS_VOICE;
@ -171,7 +197,7 @@ void DMRDMORX::databit(bool bit)
if (m_state != DMORXS_NONE) {
m_syncCount++;
if (m_syncCount >= MAX_SYNC_LOST_FRAMES) {
DEBUG1("DMRDMORX::databit() sync timeout, lost lock");
DEBUG1("DMRDMORX: databit(): sync timeout, lost lock");
serial.writeDMRLost(true);
reset();
}
@ -207,8 +233,10 @@ void DMRDMORX::databit(bool bit)
io.setDecode(m_state != DMORXS_NONE);
}
/* Sets the DMR color code. */
/// <summary>
/// Sets the DMR color code.
/// </summary>
/// <param name="colorCode">Color code.</param>
void DMRDMORX::setColorCode(uint8_t colorCode)
{
m_colorCode = colorCode;
@ -218,8 +246,9 @@ void DMRDMORX::setColorCode(uint8_t colorCode)
// Private Class Members
// ---------------------------------------------------------------------------
/* Frame synchronization correlator. */
/// <summary>
/// Frame synchronization correlator.
/// </summary>
void DMRDMORX::correlateSync()
{
// unpack sync bytes
@ -238,11 +267,11 @@ void DMRDMORX::correlateSync()
for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++)
errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_DATA_SYNC_BYTES[i]);
DEBUG2("DMRDMORX::correlateSync() sync errs", errs);
DEBUG2("DMRDMORX: correlateSync(): correlateSync errs", errs);
DEBUG4("DMRDMORX::correlateSync() sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRDMORX::correlateSync() sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRDMORX::correlateSync() sync [b6]", sync[6]);
DEBUG4("DMRDMORX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRDMORX: correlateSync(): sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRDMORX: correlateSync(): sync [b6]", sync[6]);
m_control = CONTROL_DATA;
m_syncPtr = m_dataPtr;
@ -255,18 +284,18 @@ void DMRDMORX::correlateSync()
if (m_endPtr >= DMO_BUFFER_LENGTH_BITS)
m_endPtr -= DMO_BUFFER_LENGTH_BITS;
DEBUG4("DMRDMORX::correlateSync() dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
DEBUG4("DMRDMORX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
} else if ((countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) ||
(countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_S2_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS)) {
uint8_t errs = 0U;
for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++)
errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_VOICE_SYNC_BYTES[i]);
DEBUG2("DMRDMORX::correlateSync() correlateSync errs", errs);
DEBUG2("DMRDMORX: correlateSync(): correlateSync errs", errs);
DEBUG4("DMRDMORX::correlateSync() sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRDMORX::correlateSync() sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRDMORX::correlateSync() sync [b6]", sync[6]);
DEBUG4("DMRDMORX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRDMORX: correlateSync(): sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRDMORX: correlateSync(): sync [b6]", sync[6]);
m_control = CONTROL_VOICE;
m_syncPtr = m_dataPtr;
@ -279,12 +308,16 @@ void DMRDMORX::correlateSync()
if (m_endPtr >= DMO_BUFFER_LENGTH_BITS)
m_endPtr -= DMO_BUFFER_LENGTH_BITS;
DEBUG4("DMRDMORX::correlateSync() dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
DEBUG4("DMRDMORX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="start"></param>
/// <param name="count"></param>
/// <param name="buffer"></param>
void DMRDMORX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
{
for (uint8_t i = 0U; i < count; i++) {
@ -331,8 +364,10 @@ void DMRDMORX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="frame"></param>
void DMRDMORX::writeRSSIData(uint8_t* frame)
{
#if defined(SEND_RSSI_DATA)
@ -346,3 +381,5 @@ void DMRDMORX::writeRSSIData(uint8_t* frame)
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
}
#endif // defined(ENABLE_DMR)

@ -1,26 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file DMRDMORX.h
* @ingroup dmr_hfw
* @file DMRDMORX.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_DMO_RX_H__)
#define __DMR_DMO_RX_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
#if defined(ENABLE_DMR)
namespace dmr
{
// ---------------------------------------------------------------------------
@ -29,46 +45,29 @@ namespace dmr
const uint16_t DMO_BUFFER_LENGTH_BITS = 576U;
/**
* @brief DMR DMO Receiver State
* @ingroup dmr_hfw
*/
enum DMORX_STATE {
DMORXS_NONE, //! None
DMORXS_VOICE, //! Voice Data
DMORXS_DATA //! PDU Data
DMORXS_NONE,
DMORXS_VOICE,
DMORXS_DATA
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for DMR DMO mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for DMR DMO mode operation.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRDMORX {
public:
/**
* @brief Initializes a new instance of the DMRDMORX class.
*/
/// <summary>Initializes a new instance of the DMRDMORX class.</summary>
DMRDMORX();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample DMR bits from the air interface.
* @param bit
*/
/// <summary>Sample DMR bits from the air interface.</summary>
void databit(bool bit);
/**
* @brief Sets the DMR color code.
* @param colorCode
*/
/// <summary>Sets the DMR color code.</summary>
void setColorCode(uint8_t colorCode);
private:
@ -93,24 +92,16 @@ namespace dmr
uint8_t m_type;
/**
* @brief Frame synchronization correlator.
*/
/// <summary>Frame synchronization correlator.</summary>
void correlateSync();
/**
* @brief
* @param start
* @param count
* @param buffer
*/
/// <summary></summary>
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
/**
* @brief
* @param frame
*/
/// <summary></summary>
void writeRSSIData(uint8_t* frame);
};
} // namespace dmr
#endif // defined(ENABLE_DMR)
#endif // __DMR_DMO_RX_H__

@ -1,20 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRSlotType.h"
using namespace dmr;
#if defined(ENABLE_DMR)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -30,8 +52,9 @@ const uint8_t PR_FILL[] =
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRDMOTX class. */
/// <summary>
/// Initializes a new instance of the DMRDMOTX class.
/// </summary>
DMRDMOTX::DMRDMOTX() :
m_fifo(DMR_TX_BUFFER_LEN),
m_poBuffer(),
@ -42,8 +65,9 @@ DMRDMOTX::DMRDMOTX() :
/* stub */
}
/* Process local buffer and transmit on the air interface. */
/// <summary>
/// Process local buffer and transmit on the air interface.
/// </summary>
void DMRDMOTX::process()
{
if (m_poLen == 0U && m_fifo.getData() > 0U) {
@ -63,6 +87,7 @@ void DMRDMOTX::process()
m_poLen = 72U;
}
DEBUG2("DMRDMOTX: process(): poLen", m_poLen);
m_poPtr = 0U;
}
@ -85,15 +110,19 @@ void DMRDMOTX::process()
}
}
/* Write data to the local buffer. */
/// <summary>
/// Write data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t DMRDMOTX::writeData(const uint8_t* data, uint8_t length)
{
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
return RSN_ILLEGAL_LENGTH;
uint16_t space = m_fifo.getSpace();
DEBUG3("DMRDMOTX::writeData() dataLength/fifoLength", length, space);
DEBUG3("DMRDMOTX: writeData(): dataLength/fifoLength", length, space);
if (space < DMR_FRAME_LENGTH_BYTES)
return RSN_RINGBUFF_FULL;
@ -103,28 +132,24 @@ uint8_t DMRDMOTX::writeData(const uint8_t* data, uint8_t length)
return RSN_OK;
}
/* Sets the FDMA preamble count. */
/// <summary>
/// Sets the FDMA preamble count.
/// </summary>
/// <param name="preambleCnt">Count of preambles.</param>
void DMRDMOTX::setPreambleCount(uint8_t preambleCnt)
{
uint32_t preambles = (uint32_t)((float)preambleCnt / 0.2083F);
m_preambleCnt = DMRDMO_FIXED_DELAY + preambles;
// clamp preamble count to 16ms maximum
if (m_preambleCnt > 80U)
m_preambleCnt = 80U;
}
/* Helper to resize the FIFO buffer. */
void DMRDMOTX::resizeBuffer(uint16_t size)
{
m_fifo.reset();
m_fifo.reinitialize(size);
// clamp preamble count to 250ms maximum
if (m_preambleCnt > 1200U)
m_preambleCnt = 1200U;
}
/* Helper to get how much space the ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint16_t DMRDMOTX::getSpace() const
{
return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
@ -134,8 +159,10 @@ uint16_t DMRDMOTX::getSpace() const
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to write a raw byte to the DAC. */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
void DMRDMOTX::writeByte(uint8_t c)
{
uint8_t bit;
@ -150,3 +177,5 @@ void DMRDMOTX::writeByte(uint8_t c)
io.write(&bit, 1);
}
}
#endif // defined(ENABLE_DMR)

@ -1,21 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file DMRDMOTX.h
* @ingroup dmr_hfw
* @file DMRDMOTX.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_DMO_TX_H__)
#define __DMR_DMO_TX_H__
@ -23,6 +37,8 @@
#include "dmr/DMRDefines.h"
#include "SerialBuffer.h"
#if defined(ENABLE_DMR)
namespace dmr
{
// ---------------------------------------------------------------------------
@ -34,48 +50,24 @@ namespace dmr
// ---------------------------------------------------------------------------
// Class Declaration
// Implements transmitter logic for DMR DMO mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements transmitter logic for DMR DMO mode operation.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRDMOTX {
public:
/**
* @brief Initializes a new instance of the DMRDMOTX class.
*/
/// <summary>Initializes a new instance of the DMRDMOTX class.</summary>
DMRDMOTX();
/**
* @brief Process local buffer and transmit on the air interface.
*/
/// <summary>Process local buffer and transmit on the air interface.</summary>
void process();
/**
* @brief Write data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write data to the local buffer.</summary>
uint8_t writeData(const uint8_t* data, uint8_t length);
/**
* @brief Sets the FDMA preamble count.
* @param preambleCnt FDMA preamble count.
*/
/// <summary>Sets the FDMA preamble count.</summary>
void setPreambleCount(uint8_t preambleCnt);
/**
* @brief Helper to resize the FIFO buffer.
* @param size
*/
void resizeBuffer(uint16_t size);
/**
* @brief Helper to get how much space the ring buffer has for samples.
* @returns uint8_t Amount of space in ring buffer for samples.
*/
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
uint16_t getSpace() const;
private:
@ -87,12 +79,11 @@ namespace dmr
uint32_t m_preambleCnt;
/**
* @brief Helper to write a raw byte to the DAC.
* @param c Byte.
*/
/// <summary></summary>
void writeByte(uint8_t c);
};
} // namespace dmr
#endif // defined(ENABLE_DMR)
#endif // __DMR_DMO_TX_H__

@ -1,20 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2016 Jonathan Naylor, G4KLX
*
*/
/**
* @defgroup dmr_hfw Digital Mobile Radio
* @brief Implementation for the ETSI TS-102 Digital Mobile Radio (DMR) standard.
* @ingroup hotspot_fw
*
* @file DMRDefines.h
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_DEFINES_H__)
#define __DMR_DEFINES_H__
@ -26,11 +38,6 @@ namespace dmr
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup dmr_hfw
* @{
*/
const uint32_t DMR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const uint32_t DMR_FRAME_LENGTH_BYTES = 33U;
@ -119,8 +126,7 @@ namespace dmr
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 };
// 505 = DMR_FRAME_LENGTH_BYTES * 15 + 10 (BUFFER_LEN = DMR_FRAME_LENGTH_BYTES * NO_OF_FRAMES + 10)
const uint32_t DMR_TX_BUFFER_LEN = 505U; // 15 frames + pad
const uint32_t DMR_TX_BUFFER_LEN = 538U; // 538 = DMR_FRAME_LENGTH_BYTES * 16 + 10 (BUFFER_LEN = DMR_FRAME_LENGTH_BYTES * NO_OF_FRAMES + 10)
// Data Type(s)
const uint8_t DT_VOICE_PI_HEADER = 0U;
@ -132,8 +138,6 @@ namespace dmr
const uint8_t DT_RATE_34_DATA = 8U;
const uint8_t DT_IDLE = 9U;
const uint8_t DT_RATE_1_DATA = 10U;
/** @} */
} // namespace dmr
#endif // __DMR_DEFINES_H__

@ -1,13 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2018 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRIdleRX.h"
#include "dmr/DMRSlotType.h"
@ -15,7 +35,7 @@
using namespace dmr;
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
// ---------------------------------------------------------------------------
// Constants
@ -32,8 +52,9 @@ const uint8_t CONTROL_DATA = 0x40U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRIdleRX class. */
/// <summary>
/// Initializes a new instance of the DMRIdleRX class.
/// </summary>
DMRIdleRX::DMRIdleRX() :
m_bitBuffer(0U),
m_buffer(),
@ -44,16 +65,19 @@ DMRIdleRX::DMRIdleRX() :
/* stub */
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void DMRIdleRX::reset()
{
m_dataPtr = 0U;
m_endPtr = NOENDPTR;
}
/* Sample DMR bits from the air interface. */
/// <summary>
/// Sample DMR bits from the air interface.
/// </summary>
/// <param name="bit"></param>
void DMRIdleRX::databit(bool bit)
{
_WRITE_BIT(m_buffer, m_dataPtr, bit);
@ -67,7 +91,7 @@ void DMRIdleRX::databit(bool bit)
if (m_endPtr >= DMR_IDLE_LENGTH_BITS)
m_endPtr -= DMR_IDLE_LENGTH_BITS;
DEBUG3("DMRIdleRx::databit() dataPtr/endPtr", m_dataPtr, m_endPtr);
DEBUG3("DMRIdleRx: databit(): dataPtr/endPtr", m_dataPtr, m_endPtr);
}
if (m_dataPtr == m_endPtr) {
@ -96,8 +120,10 @@ void DMRIdleRX::databit(bool bit)
m_dataPtr = 0U;
}
/* Sets the DMR color code. */
/// <summary>
/// Sets the DMR color code.
/// </summary>
/// <param name="colorCode">Color code.</param>
void DMRIdleRX::setColorCode(uint8_t colorCode)
{
m_colorCode = colorCode;
@ -107,8 +133,12 @@ void DMRIdleRX::setColorCode(uint8_t colorCode)
// Private Class Members
// ---------------------------------------------------------------------------
/* */
/// <summary>
///
/// </summary>
/// <param name="start"></param>
/// <param name="count"></param>
/// <param name="buffer"></param>
void DMRIdleRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
{
for (uint8_t i = 0U; i < count; i++) {
@ -155,4 +185,4 @@ void DMRIdleRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
}
}
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)

@ -1,26 +1,40 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2018 Andy Uribe, CA6JAU
*
*/
/**
* @file DMRIdleRX.h
* @ingroup dmr_mfw
* @file DMRIdleRX.cpp
* @ingroup dmr_mfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_IDLE_RX_H__)
#define __DMR_IDLE_RX_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
namespace dmr
{
@ -32,34 +46,21 @@ namespace dmr
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for idle DMR mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for idle DMR mode operation.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRIdleRX {
public:
/**
* @brief Initializes a new instance of the DMRIdleRX class.
*/
/// <summary>Initializes a new instance of the DMRIdleRX class.</summary>
DMRIdleRX();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample DMR bits from the air interface.
* @param bit
*/
/// <summary>Sample DMR bits from the air interface.</summary>
void databit(bool bit);
/**
* @brief Sets the DMR color code.
* @param colorCode
*/
/// <summary>Sets the DMR color code.</summary>
void setColorCode(uint8_t colorCode);
private:
@ -71,15 +72,11 @@ namespace dmr
uint8_t m_colorCode;
/**
* @brief
* @param start
* @param count
* @param buffer
*/
/// <summary></summary>
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
};
} // namespace dmr
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)
#endif // __DMR_IDLE_RX_H__

@ -1,27 +1,48 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2017 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRRX.h"
using namespace dmr;
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRRX class. */
/// <summary>
/// Initializes a new instance of the DMRRX class.
/// </summary>
DMRRX::DMRRX() :
m_slot1RX(false),
m_slot2RX(true)
@ -30,16 +51,19 @@ DMRRX::DMRRX() :
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void DMRRX::reset()
{
m_slot1RX.reset();
m_slot2RX.reset();
}
/* Sample DMR bits from the air interface. */
/// <summary>
/// Sample DMR bits from the air interface.
/// </summary>
/// <param name="bit"></param>
void DMRRX::databit(bool bit, const uint8_t control)
{
bool dcd1 = false;
@ -62,20 +86,24 @@ void DMRRX::databit(bool bit, const uint8_t control)
io.setDecode(dcd1 || dcd2);
}
/* Sets the DMR color code. */
/// <summary>
/// Sets the DMR color code.
/// </summary>
/// <param name="colorCode">Color code.</param>
void DMRRX::setColorCode(uint8_t colorCode)
{
m_slot1RX.setColorCode(colorCode);
m_slot2RX.setColorCode(colorCode);
}
/* Sets the number of samples to delay before processing. */
/// <summary>
/// Sets the number of samples to delay before processing.
/// </summary>
/// <param name="delay">Number of samples to delay.</param>
void DMRRX::setRxDelay(uint8_t delay)
{
m_slot1RX.setRxDelay(delay);
m_slot2RX.setRxDelay(delay);
}
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)

@ -1,66 +1,63 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2017 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file DMRRX.h
* @ingroup dmr_hfw
* @file DMRRX.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_RX_H__)
#define __DMR_RX_H__
#include "Defines.h"
#include "dmr/DMRSlotRX.h"
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for duplex DMR mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for duplex DMR mode operation.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRRX {
public:
/**
* @brief Initializes a new instance of the DMRRX class.
*/
/// <summary>Initializes a new instance of the DMRRX class.</summary>
DMRRX();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample DMR bits from the air interface.
* @param bit
* @param[in] control
*/
/// <summary>Sample DMR bits from the air interface.</summary>
void databit(bool bit, const uint8_t control);
/**
* @brief Sets the DMR color code.
* @param colorCode
*/
/// <summary>Sets the DMR color code.</summary>
void setColorCode(uint8_t colorCode);
/**
* @brief Sets the number of samples to delay before processing.
* @param delay
*/
/// <summary>Sets the number of samples to delay before processing.</summary>
void setRxDelay(uint8_t delay);
private:
@ -69,5 +66,6 @@ namespace dmr
};
} // namespace dmr
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)
#endif // __DMR_RX_H__

@ -1,14 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRSlotRX.h"
#include "dmr/DMRSlotType.h"
@ -16,7 +36,7 @@
using namespace dmr;
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
// ---------------------------------------------------------------------------
// Constants
@ -36,10 +56,11 @@ const uint8_t CONTROL_DATA = 0x40U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRSlotRX class. */
/// <summary>
/// Initializes a new instance of the DMRSlotRX class.
/// </summary>
DMRSlotRX::DMRSlotRX(bool slot) :
m_slot(slot),
m_slot(false),
m_bitBuffer(0x00U),
m_buffer(),
m_dataPtr(0U),
@ -58,8 +79,9 @@ DMRSlotRX::DMRSlotRX(bool slot) :
/* stub */
}
/* Helper to set data values for start of Rx. */
/// <summary>
/// Helper to set data values for start of Rx.
/// </summary>
void DMRSlotRX::start()
{
m_dataPtr = 0U;
@ -67,20 +89,28 @@ void DMRSlotRX::start()
m_control = CONTROL_NONE;
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void DMRSlotRX::reset()
{
m_syncPtr = 0U;
m_dataPtr = 0U;
m_delayPtr = 0U;
m_bitBuffer = 0U;
resetSlot();
m_control = CONTROL_NONE;
m_syncCount = 0U;
m_state = DMRRXS_NONE;
m_startPtr = 0U;
m_endPtr = NOENDPTR;
}
/* Sample DMR bits from the air interface. */
/// <summary>
/// Sample DMR bits from the air interface.
/// </summary>
/// <param name="bit"></param>
bool DMRSlotRX::databit(bool bit)
{
uint16_t min, max;
@ -141,7 +171,7 @@ bool DMRSlotRX::databit(bool bit)
switch (dataType) {
case DT_DATA_HEADER:
DEBUG3("DMRSlotRX::databit() data header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): data header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_state = DMRRXS_DATA;
m_type = 0x00U;
@ -150,33 +180,33 @@ bool DMRSlotRX::databit(bool bit)
case DT_RATE_34_DATA:
case DT_RATE_1_DATA:
if (m_state == DMRRXS_DATA) {
DEBUG3("DMRSlotRX::databit() data payload found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): data payload found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_type = dataType;
}
break;
case DT_VOICE_LC_HEADER:
DEBUG3("DMRSlotRX::databit() voice header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): voice header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_state = DMRRXS_VOICE;
break;
case DT_VOICE_PI_HEADER:
if (m_state == DMRRXS_VOICE) {
DEBUG3("DMRSlotRX::databit() voice pi header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): voice pi header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
}
m_state = DMRRXS_VOICE;
break;
case DT_TERMINATOR_WITH_LC:
if (m_state == DMRRXS_VOICE) {
DEBUG3("DMRSlotRX::databit() voice terminator found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): voice terminator found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
}
break;
default: // DT_CSBK
DEBUG3("DMRSlotRX::databit() csbk found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): csbk found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
@ -186,7 +216,7 @@ bool DMRSlotRX::databit(bool bit)
}
else if (m_control == CONTROL_VOICE) {
// Voice sync
DEBUG3("DMRSlotRX::databit() voice sync found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
DEBUG3("DMRSlotRX: databit(): voice sync found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
writeRSSIData(frame);
m_state = DMRRXS_VOICE;
m_syncCount = 0U;
@ -196,9 +226,10 @@ bool DMRSlotRX::databit(bool bit)
if (m_state != DMRRXS_NONE) {
m_syncCount++;
if (m_syncCount >= MAX_SYNC_LOST_FRAMES) {
DEBUG1("DMRSlotRX::databit() sync timeout, lost lock");
DEBUG1("DMRSlotRX: databit(): sync timeout, lost lock");
serial.writeDMRLost(m_slot);
resetSlot();
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
}
}
@ -220,9 +251,6 @@ bool DMRSlotRX::databit(bool bit)
}
}
}
// end of this slot, reset some items for the next slot
m_control = CONTROL_NONE;
}
m_dataPtr++;
@ -232,15 +260,19 @@ bool DMRSlotRX::databit(bool bit)
return m_state != DMRRXS_NONE;
}
/* Sets the DMR color code. */
/// <summary>
/// Sets the DMR color code.
/// </summary>
/// <param name="colorCode">Color code.</param>
void DMRSlotRX::setColorCode(uint8_t colorCode)
{
m_colorCode = colorCode;
}
/* Sets the number of samples to delay before processing. */
/// <summary>
/// Sets the number of samples to delay before processing.
/// </summary>
/// <param name="delay">Number of samples to delay.</param>
void DMRSlotRX::setRxDelay(uint8_t delay)
{
m_delay = delay;
@ -250,8 +282,10 @@ void DMRSlotRX::setRxDelay(uint8_t delay)
// Private Class Members
// ---------------------------------------------------------------------------
/* Frame synchronization correlator. */
/// <summary>
/// Frame synchronization correlator.
/// </summary>
/// <param name="first"></param>
void DMRSlotRX::correlateSync()
{
// unpack sync bytes
@ -269,11 +303,11 @@ void DMRSlotRX::correlateSync()
for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++)
errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_DATA_SYNC_BYTES[i]);
DEBUG2("DMRSlotRX::correlateSync() sync errs", errs);
DEBUG2("DMRSlotRX: correlateSync(): correlateSync errs", errs);
DEBUG4("DMRSlotRX::correlateSync() sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRSlotRX::correlateSync() sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRSlotRX::correlateSync() sync [b6]", sync[6]);
DEBUG4("DMRSlotRX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRSlotRX: correlateSync(): sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRSlotRX: correlateSync(): sync [b6]", sync[6]);
m_control = CONTROL_DATA;
m_syncPtr = m_dataPtr;
@ -286,17 +320,17 @@ void DMRSlotRX::correlateSync()
if (m_endPtr >= DMR_BUFFER_LENGTH_BITS)
m_endPtr -= DMR_BUFFER_LENGTH_BITS;
DEBUG4("DMRSlotRX::correlateSync() dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
DEBUG4("DMRSlotRX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
} else if (countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) {
uint8_t errs = 0U;
for (uint8_t i = 0U; i < DMR_SYNC_BYTES_LENGTH; i++)
errs += countBits8((sync[i] & DMR_SYNC_BYTES_MASK[i]) ^ DMR_MS_VOICE_SYNC_BYTES[i]);
DEBUG2("DMRSlotRX::correlateSync() sync errs", errs);
DEBUG2("DMRSlotRX: correlateSync(): correlateSync errs", errs);
DEBUG4("DMRSlotRX::correlateSync() sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRSlotRX::correlateSync() sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRSlotRX::correlateSync() sync [b6]", sync[6]);
DEBUG4("DMRSlotRX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("DMRSlotRX: correlateSync(): sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG2("DMRSlotRX: correlateSync(): sync [b6]", sync[6]);
m_control = CONTROL_VOICE;
m_syncPtr = m_dataPtr;
@ -309,27 +343,16 @@ void DMRSlotRX::correlateSync()
if (m_endPtr >= DMR_BUFFER_LENGTH_BITS)
m_endPtr -= DMR_BUFFER_LENGTH_BITS;
DEBUG4("DMRSlotRX::correlateSync() dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
DEBUG4("DMRSlotRX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
}
}
/* */
void DMRSlotRX::resetSlot()
{
m_syncPtr = 0U;
m_control = CONTROL_NONE;
m_syncCount = 0U;
m_state = DMRRXS_NONE;
m_startPtr = 0U;
m_endPtr = NOENDPTR;
m_type = 0U;
m_n = 0U;
}
/* */
/// <summary>
///
/// </summary>
/// <param name="start"></param>
/// <param name="count"></param>
/// <param name="buffer"></param>
void DMRSlotRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
{
for (uint8_t i = 0U; i < count; i++) {
@ -376,8 +399,10 @@ void DMRSlotRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
}
}
/* */
/// <summary>
///
/// </summary>
/// <param name="frame"></param>
void DMRSlotRX::writeRSSIData(uint8_t* frame)
{
#if defined(SEND_RSSI_DATA)
@ -392,4 +417,4 @@ void DMRSlotRX::writeRSSIData(uint8_t* frame)
#endif
}
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)

@ -1,27 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file DMRSlotRX.h
* @ingroup dmr_hfw
* @file DMRSlotRX.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_SLOT_RX_H__)
#define __DMR_SLOT_RX_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
#if defined(DUPLEX)
#if defined(ENABLE_DMR) && defined(DUPLEX)
namespace dmr
{
@ -31,56 +45,33 @@ namespace dmr
const uint16_t DMR_BUFFER_LENGTH_BITS = 576U;
/**
* @brief DMR Slot Receiver State
* @ingroup dmr_hfw
*/
enum DMRRX_STATE {
DMRRXS_NONE, //! None
DMRRXS_VOICE, //! Voice Data
DMRRXS_DATA //! PDU Data
DMRRXS_NONE,
DMRRXS_VOICE,
DMRRXS_DATA
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for DMR slots.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for DMR slots.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRSlotRX {
public:
/**
* @brief Initializes a new instance of the DMRSlotRX class.
* @param slot
*/
/// <summary>Initializes a new instance of the DMRSlotRX class.</summary>
DMRSlotRX(bool slot);
/**
* @brief Helper to set data values for start of Rx.
*/
/// <summary>Helper to set data values for start of Rx.</summary>
void start();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample DMR bits from the air interface.
* @param bit
*/
/// <summary>Sample DMR bits from the air interface.</summary>
bool databit(bool bit);
/**
* @brief Sets the DMR color code.
* @param colorCode
*/
/// <summary>Sets the DMR color code.</summary>
void setColorCode(uint8_t colorCode);
/**
* @brief Sets the number of samples to delay before processing.
* @param delay
*/
/// <summary>Sets the number of samples to delay before processing.</summary>
void setRxDelay(uint8_t delay);
@ -109,29 +100,16 @@ namespace dmr
uint8_t m_type;
/**
* @brief Frame synchronization correlator.
*/
/// <summary>Frame synchronization correlator.</summary>
void correlateSync();
/**
* @brief
*/
void resetSlot();
/**
* @brief
* @param start
* @param count
* @param buffer
*/
/// <summary></summary>
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
/**
* @brief
* @param frame
*/
/// <summary></summary>
void writeRSSIData(uint8_t* frame);
};
} // namespace dmr
#endif // DUPLEX
#endif // defined(ENABLE_DMR) && defined(DUPLEX)
#endif // __DMR_SLOT_RX_H__

@ -1,17 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015 Jonathan Naylor, G4KLX
*
*/
* Copyright (C) 2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRSlotType.h"
using namespace dmr;
#if defined(ENABLE_DMR)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -209,15 +231,20 @@ const uint32_t DECODING_TABLE_1987[] = {
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRSlotType class. */
/// <summary>
/// Initializes a new instance of the DMRSlotType class.
/// </summary>
DMRSlotType::DMRSlotType()
{
/* stub */
}
/* Decodes DMR slot type. */
/// <summary>
/// Decodes DMR slot type.
/// </summary>
/// <param name="frame"></param>
/// <param name="colorCode"></param>
/// <param name="dataType"></param>
void DMRSlotType::decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const
{
uint8_t slotType[3U];
@ -236,8 +263,12 @@ void DMRSlotType::decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& data
dataType = (code >> 0) & 0x0FU;
}
/* Encodes DMR slot type. */
/// <summary>
/// Encodes DMR slot type.
/// </summary>
/// <param name="colorCode"></param>
/// <param name="dataType"></param>
/// <param name="frame"></param>
void DMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const
{
uint8_t slotType[3U];
@ -259,8 +290,11 @@ void DMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) co
// Private Class Members
// ---------------------------------------------------------------------------
/* */
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
uint8_t DMRSlotType::decode2087(const uint8_t* data) const
{
uint32_t code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5);
@ -273,8 +307,20 @@ uint8_t DMRSlotType::decode2087(const uint8_t* data) const
return code >> 11;
}
/* */
/// <summary>
///
/// </summary>
/// <remarks>
/// Compute the syndrome corresponding to the given pattern, i.e., the
/// remainder after dividing the pattern (when considering it as the vector
/// representation of a polynomial) by the generator polynomial, GENPOL.
/// In the program this pattern has several meanings: (1) pattern = infomation
/// bits, when constructing the encoding table; (2) pattern = error pattern,
/// when constructing the decoding table; and (3) pattern = received vector, to
/// obtain its syndrome in decoding.
/// </remarks>
/// <param name="pattern"></param>
/// <returns></returns>
uint32_t DMRSlotType::getSyndrome1987(uint32_t pattern) const
{
unsigned int aux = X18;
@ -290,3 +336,5 @@ uint32_t DMRSlotType::getSyndrome1987(uint32_t pattern) const
return pattern;
}
#endif // defined(ENABLE_DMR)

@ -1,69 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015 Jonathan Naylor, G4KLX
*
*/
/**
* @file DMRSlotType.h
* @ingroup dmr_hfw
* @file DMRSlotType.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_SLOT_TYPE_H__)
#define __DMR_SLOT_TYPE_H__
#include "Defines.h"
#if defined(ENABLE_DMR)
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Declaration
//
// ---------------------------------------------------------------------------
/**
* @brief Represents DMR slot type.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRSlotType {
public:
/**
* @brief Initializes a new instance of the DMRSlotType class.
*/
/// <summary>Initializes a new instance of the DMRSlotType class.</summary>
DMRSlotType();
/**
* @brief Decodes DMR slot type.
* @param[in] frame
* @param[out] colorCode
* @param[out] dataType
*/
/// <summary>Decodes DMR slot type.</summary>
void decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const;
/**
* @brief Encodes DMR slot type.
* @param colorCode
* @param dataType
* @param[out] frame
*/
/// <summary>Encodes DMR slot type.</summary>
void encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const;
private:
/**
* @brief
* @param[in] data
* @returns uint8_t
*/
/// <summary></summary>
uint8_t decode2087(const uint8_t* data) const;
/**
* @brief
* @param pattern
* @returns uint32_t
*/
/// <summary></summary>
uint32_t getSyndrome1987(uint32_t pattern) const;
};
} // namespace dmr
#endif // defined(ENABLE_DMR)
#endif // __DMR_SLOT_TYPE_H__

@ -1,20 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2009-2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2017 Andy Uribe, CA6JAU
* Copyright (C) 2021-2022 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2021-2022 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "dmr/DMRSlotType.h"
using namespace dmr;
#if defined(ENABLE_DMR)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -44,8 +66,9 @@ const uint32_t ABORT_COUNT = 6U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the DMRTX class. */
/// <summary>
/// Initializes a new instance of the DMRTX class.
/// </summary>
DMRTX::DMRTX() :
m_fifo(),
m_state(DMRTXSTATE_IDLE),
@ -76,8 +99,9 @@ DMRTX::DMRTX() :
m_abortCount[1U] = 0U;
}
/* Process local buffer and transmit on the air interface. */
/// <summary>
/// Process local buffer and transmit on the air interface.
/// </summary>
void DMRTX::process()
{
if (m_state == DMRTXSTATE_IDLE)
@ -109,6 +133,8 @@ void DMRTX::process()
m_state = DMRTXSTATE_SLOT1;
break;
}
DEBUG2("DMRTX: process(): poLen", m_poLen);
}
if (m_poLen > 0U) {
@ -132,15 +158,19 @@ void DMRTX::process()
}
}
/* Write slot 1 data to the local buffer. */
/// <summary>
/// Write slot 1 data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t DMRTX::writeData1(const uint8_t* data, uint8_t length)
{
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
return RSN_ILLEGAL_LENGTH;
uint16_t space = m_fifo[0U].getSpace();
DEBUG3("DMRTX::writeData1() dataLength/fifoLength", length, space);
DEBUG3("DMRTX: writeData1(): dataLength/fifoLength", length, space);
if (space < DMR_FRAME_LENGTH_BYTES)
return RSN_RINGBUFF_FULL;
@ -159,15 +189,19 @@ uint8_t DMRTX::writeData1(const uint8_t* data, uint8_t length)
return RSN_OK;
}
/* Write slot 2 data to the local buffer. */
/// <summary>
/// Write slot 2 data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t DMRTX::writeData2(const uint8_t* data, uint8_t length)
{
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
return RSN_ILLEGAL_LENGTH;
uint16_t space = m_fifo[1U].getSpace();
DEBUG3("DMRTX::writeData2() dataLength/fifoLength", length, space);
DEBUG3("DMRTX: writeData2(): dataLength/fifoLength", length, space);
if (space < DMR_FRAME_LENGTH_BYTES)
return RSN_RINGBUFF_FULL;
@ -186,8 +220,12 @@ uint8_t DMRTX::writeData2(const uint8_t* data, uint8_t length)
return RSN_OK;
}
/* Write short LC data to the local buffer. */
/// <summary>
/// Write short LC data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t DMRTX::writeShortLC(const uint8_t* data, uint8_t length)
{
if (length != 9U)
@ -204,8 +242,12 @@ uint8_t DMRTX::writeShortLC(const uint8_t* data, uint8_t length)
return RSN_OK;
}
/* Write abort data to the local buffer. */
/// <summary>
/// Write abort data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t DMRTX::writeAbort(const uint8_t* data, uint8_t length)
{
if (length != 1U)
@ -227,8 +269,10 @@ uint8_t DMRTX::writeAbort(const uint8_t* data, uint8_t length)
}
}
/* Helper to set the start state for Tx. */
/// <summary>
/// Helper to set the start state for Tx.
/// </summary>
/// <param name="start"></param>
void DMRTX::setStart(bool start)
{
m_state = start ? DMRTXSTATE_SLOT1 : DMRTXSTATE_IDLE;
@ -241,29 +285,37 @@ void DMRTX::setStart(bool start)
m_abort[1U] = false;
}
/* Helper to set the calibration state for Tx. */
/// <summary>
/// Helper to set the calibration state for Tx.
/// </summary>
/// <param name="start"></param>
void DMRTX::setCal(bool start)
{
m_state = start ? DMRTXSTATE_CAL : DMRTXSTATE_IDLE;
}
/* Helper to get how much space the slot 1 ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the slot 1 ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint8_t DMRTX::getSpace1() const
{
return m_fifo[0U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
}
/* Helper to get how much space the slot 2 ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the slot 2 ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint8_t DMRTX::getSpace2() const
{
return m_fifo[1U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
}
/* Sets the ignore flags for setting the CACH Access Type bit. */
/// <summary>
/// Sets the ignore flags for setting the CACH Access Type bit.
/// </summary>
/// <param name="slot"></param>
void DMRTX::setIgnoreCACH_AT(uint8_t slot)
{
m_cachATControl = slot;
@ -272,8 +324,10 @@ void DMRTX::setIgnoreCACH_AT(uint8_t slot)
}
}
/* Sets the DMR color code. */
/// <summary>
/// Sets the DMR color code.
/// </summary>
/// <param name="colorCode">Color code.</param>
void DMRTX::setColorCode(uint8_t colorCode)
{
::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES);
@ -282,32 +336,26 @@ void DMRTX::setColorCode(uint8_t colorCode)
slotType.encode(colorCode, DT_IDLE, m_idle);
}
/* Helper to reset data values to defaults for slot 1 FIFO. */
/// <summary>
/// Helper to reset data values to defaults for slot 1 FIFO.
/// </summary>
void DMRTX::resetFifo1()
{
m_fifo[0U].reset();
}
/* Helper to reset data values to defaults for slot 2 FIFO. */
/// <summary>
/// Helper to reset data values to defaults for slot 2 FIFO.
/// </summary>
void DMRTX::resetFifo2()
{
m_fifo[1U].reset();
}
/* Helper to resize the FIFO buffer. */
void DMRTX::resizeBuffer(uint16_t size)
{
m_fifo[0U].reset();
m_fifo[1U].reset();
m_fifo[0U].reinitialize(size);
m_fifo[1U].reinitialize(size);
}
/* */
/// <summary>
///
/// </summary>
/// <returns></returns>
uint32_t DMRTX::getFrameCount()
{
return m_frameCount;
@ -317,8 +365,10 @@ uint32_t DMRTX::getFrameCount()
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to generate data. */
/// <summary>
///
/// </summary>
/// <param name="slotIndex"></param>
void DMRTX::createData(uint8_t slotIndex)
{
if (m_fifo[slotIndex].getData() > 0U && m_frameCount >= STARTUP_COUNT) {
@ -346,8 +396,47 @@ void DMRTX::createData(uint8_t slotIndex)
m_poPtr = 0U;
}
/* Helper to generate the common access channel. */
/// <summary>
///
/// </summary>
void DMRTX::createCal()
{
// 1.2 kHz sine wave generation
if (m_modemState == STATE_DMR_CAL) {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = DMR_START_SYNC;
m_markBuffer[i] = MARK_NONE;
}
m_poLen = DMR_FRAME_LENGTH_BYTES;
}
// 80 Hz square wave generation
if (m_modemState == STATE_DMR_LF_CAL) {
for (unsigned int i = 0U; i < 7U; i++) {
m_poBuffer[i] = 0x55U; // +3, +3, ... pattern
m_markBuffer[i] = MARK_NONE;
}
m_poBuffer[7U] = 0x5FU; // +3, +3, -3, -3 pattern
for (unsigned int i = 8U; i < 15U; i++) {
m_poBuffer[i] = 0xFFU; // -3, -3, ... pattern
m_markBuffer[i] = MARK_NONE;
}
m_poLen = 15U;
}
m_poLen = DMR_FRAME_LENGTH_BYTES;
m_poPtr = 0U;
}
/// <summary>
///
/// </summary>
/// <param name="txSlotIndex"></param>
/// <param name="rxSlotIndex"></param>
void DMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
{
m_frameCount++;
@ -407,43 +496,11 @@ void DMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
m_cachPtr += 3U;
}
/* Helper to generate calibration data. */
void DMRTX::createCal()
{
// 1.2 kHz sine wave generation
if (m_modemState == STATE_DMR_CAL) {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = DMR_START_SYNC;
m_markBuffer[i] = MARK_NONE;
}
m_poLen = DMR_FRAME_LENGTH_BYTES;
}
// 80 Hz square wave generation
if (m_modemState == STATE_DMR_LF_CAL) {
for (unsigned int i = 0U; i < 7U; i++) {
m_poBuffer[i] = 0x55U; // +3, +3, ... pattern
m_markBuffer[i] = MARK_NONE;
}
m_poBuffer[7U] = 0x5FU; // +3, +3, -3, -3 pattern
for (unsigned int i = 8U; i < 15U; i++) {
m_poBuffer[i] = 0xFFU; // -3, -3, ... pattern
m_markBuffer[i] = MARK_NONE;
}
m_poLen = 15U;
}
m_poLen = DMR_FRAME_LENGTH_BYTES;
m_poPtr = 0U;
}
/* Helper to write a raw byte to the DAC. */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
/// <param name="control"></param>
void DMRTX::writeByte(uint8_t c, uint8_t control)
{
uint8_t bit;
@ -468,3 +525,5 @@ void DMRTX::writeByte(uint8_t c, uint8_t control)
io.write(&bit, 1, &controlToWrite);
}
}
#endif // defined(ENABLE_DMR)

@ -1,21 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016 Colin Durbridge, G4EML
* Copyright (C) 2017 Andy Uribe, CA6JAU
* Copyright (C) 2021-2022 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file DMRTX.h
* @ingroup dmr_hfw
* @file DMRTX.cpp
* @ingroup dmr_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2021-2022 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__DMR_TX_H__)
#define __DMR_TX_H__
@ -23,127 +37,66 @@
#include "dmr/DMRDefines.h"
#include "SerialBuffer.h"
#if defined(ENABLE_DMR)
namespace dmr
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief DMR Duplex Transmitter State
* @ingroup dmr_hfw
*/
enum DMRTXSTATE {
DMRTXSTATE_IDLE, //! Idle
DMRTXSTATE_SLOT1, //! Slot 1
DMRTXSTATE_CACH1, //! Common Access Channel 1
DMRTXSTATE_SLOT2, //! Slot 2
DMRTXSTATE_CACH2, //! Common Access Channel 2
DMRTXSTATE_CAL //! Calibration
DMRTXSTATE_IDLE,
DMRTXSTATE_SLOT1,
DMRTXSTATE_CACH1,
DMRTXSTATE_SLOT2,
DMRTXSTATE_CACH2,
DMRTXSTATE_CAL
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for duplex DMR mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for duplex DMR mode operation.
* @ingroup dmr_hfw
*/
class DSP_FW_API DMRTX {
public:
/**
* @brief Initializes a new instance of the DMRTX class.
*/
/// <summary>Initializes a new instance of the DMRTX class.</summary>
DMRTX();
/**
* @brief Process local buffer and transmit on the air interface.
*/
/// <summary>Process local buffer and transmit on the air interface.</summary>
void process();
/**
* @brief Write slot 1 data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write slot 1 data to the local buffer.</summary>
uint8_t writeData1(const uint8_t* data, uint8_t length);
/**
* @brief Write slot 2 data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write slot 2 data to the local buffer.</summary>
uint8_t writeData2(const uint8_t* data, uint8_t length);
/**
* @brief Write short LC data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write short LC data to the local buffer.</summary>
uint8_t writeShortLC(const uint8_t* data, uint8_t length);
/**
* @brief Write abort data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write abort data to the local buffer.</summary>
uint8_t writeAbort(const uint8_t* data, uint8_t length);
/**
* @brief Helper to set the start state for Tx.
* @param start
*/
/// <summary>Helper to set the start state for Tx.</summary>
void setStart(bool start);
/**
* @brief Helper to set the calibration state for Tx.
* @param start
*/
/// <summary>Helper to set the calibration state for Tx.</summary>
void setCal(bool start);
/**
* @brief Helper to get how much space the slot 1 ring buffer has for samples.
* @returns uint8_t Amount of space in the slot 1 ring buffer.
*/
/// <summary>Helper to get how much space the slot 1 ring buffer has for samples.</summary>
uint8_t getSpace1() const;
/**
* @brief Helper to get how much space the slot 2 ring buffer has for samples.
* @returns uint8_t Amount of space in the slot 2 ring buffer.
*/
/// <summary>Helper to get how much space the slot 2 ring buffer has for samples.</summary>
uint8_t getSpace2() const;
/**
* @brief Sets the ignore flags for setting the CACH Access Type bit.
* @param slot DMR slot number.
*/
/// <summary>Sets the ignore flags for setting the CACH Access Type bit.</summary>
void setIgnoreCACH_AT(uint8_t slot);
/**
* @brief Sets the DMR color code.
* @param colorCode Color code.
*/
/// <summary>Sets the DMR color code.</summary>
void setColorCode(uint8_t colorCode);
/**
* @brief Helper to reset data values to defaults for slot 1 FIFO.
*/
/// <summary>Helper to reset data values to defaults for slot 1 FIFO.</summary>
void resetFifo1();
/**
* @brief Helper to reset data values to defaults for slot 2 FIFO.
*/
/// <summary>Helper to reset data values to defaults for slot 2 FIFO.</summary>
void resetFifo2();
/**
* @brief Helper to resize the FIFO buffer.
* @param size
*/
void resizeBuffer(uint16_t size);
/**
* @brief
* @returns uint32_t
*/
/// <summary></summary>
uint32_t getFrameCount();
private:
@ -172,29 +125,18 @@ namespace dmr
uint8_t m_controlPrev;
/**
* @brief Helper to generate data.
* @param slotIndex
*/
/// <summary></summary>
void createData(uint8_t slotIndex);
/**
* @brief Helper to generate the common access channel.
* @param txSlotIndex
* @param rxSlotIndex
*/
/// <summary></summary>
void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex);
/**
* @brief Helper to generate calibration data.
*/
/// <summary></summary>
void createCal();
/**
* @brief Helper to write a raw byte to the DAC.
* @param c Byte.
* @param control
*/
/// <summary></summary>
void writeByte(uint8_t c, uint8_t control);
};
} // namespace dmr
#endif // defined(ENABLE_DMR)
#endif // __DMR_TX_H__

@ -1,18 +1,40 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2018 by Andy Uribe CA6JAU
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2020 Jonathan Naylor, G4KLX
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "nxdn/CalNXDN.h"
using namespace nxdn;
#if defined(ENABLE_NXDN)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -52,8 +74,9 @@ const uint8_t NXDN_CAL1K[4][49] = {
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the CalNXDN class. */
/// <summary>
/// Initializes a new instance of the CalNXDN class.
/// </summary>
CalNXDN::CalNXDN() :
m_transmit(false),
m_state(NXDNCAL1K_IDLE),
@ -62,8 +85,9 @@ CalNXDN::CalNXDN() :
/* stub */
}
/* Process local state and transmit on the air interface. */
/// <summary>
/// Process local state and transmit on the air interface.
/// </summary>
void CalNXDN::process()
{
if (m_transmit) {
@ -98,8 +122,12 @@ void CalNXDN::process()
}
}
/* Write NXDN calibration data to the local buffer. */
/// <summary>
/// Write P25 calibration data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t CalNXDN::write(const uint8_t* data, uint16_t length)
{
if (length != 1U)
@ -112,3 +140,5 @@ uint8_t CalNXDN::write(const uint8_t* data, uint16_t length)
return RSN_OK;
}
#endif // defined(ENABLE_NXDN)

@ -1,66 +1,67 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - Hotspot Firmware
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2020 Jonathan Naylor, G4KLX
* @package DVM / DSP Firmware (Hotspot)
*
*/
/**
* @file CalNXDN.h
* @ingroup nxdn_hfw
* @file CalNXDN.cpp
* @ingroup nxdn_hfw
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2018 by Andy Uribe CA6JAU
* Copyright (C) 2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__CAL_NXDN_H__)
#define __CAL_NXDN_H__
#include "Defines.h"
#include "nxdn/NXDNDefines.h"
#if defined(ENABLE_NXDN)
namespace nxdn
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Calibration States
* @ingroup nxdn_hfw
*/
enum NXDNCAL1K {
NXDNCAL1K_IDLE, //! Idle
NXDNCAL1K_TX //! Transmit
NXDNCAL1K_IDLE,
NXDNCAL1K_TX
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements logic for NXDN calibration mode.
// ---------------------------------------------------------------------------
/**
* @brief Implements logic for NXDN calibration mode.
* @ingroup nxdn_hfw
*/
class DSP_FW_API CalNXDN {
public:
/**
* @brief Initializes a new instance of the CalNXDN class.
*/
/// <summary>Initializes a new instance of the CalNXDN class.</summary>
CalNXDN();
/**
* @brief Process local state and transmit on the air interface.
*/
/// <summary>Process local state and transmit on the air interface.</summary>
void process();
/**
* @brief Write NXDN calibration state.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write NXDN calibration state.</summary>
uint8_t write(const uint8_t* data, uint16_t length);
private:
@ -71,4 +72,6 @@ namespace nxdn
};
} // namespace nxdn
#endif // defined(ENABLE_NXDN)
#endif // __CAL_NXDN_H__

@ -1,19 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* Copyright (C) 2016,2017,2018 Jonathan Naylor, G4KLX
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
/**
* @defgroup nxdn_hfw Next Generation Digital Narrowband
* @brief Implementation for the NXDN standard.
* @ingroup hotspot_fw
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* @file NXDNDefines.h
* @ingroup nxdn_hfw
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__NXDN_DEFINES_H__)
#define __NXDN_DEFINES_H__
@ -26,11 +38,6 @@ namespace nxdn
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup nxdn_hfw
* @{
*/
const uint32_t NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate
const uint32_t NXDN_FRAME_LENGTH_BITS = 384U;
@ -61,10 +68,7 @@ namespace nxdn
const uint16_t NXDN_FSW_SYMBOLS = 0x014DU;
const uint16_t NXDN_FSW_SYMBOLS_MASK = 0x03FFU;
// 538 = NXDN_FRAME_LENGTH_BYTES * 11 + 10 (BUFFER_LEN = NXDN_FRAME_LENGTH_BYTES * NO_OF_FRAMES)
const uint32_t NXDN_TX_BUFFER_LEN = 538U; // 11 frames + pad
/** @} */
const uint32_t NXDN_TX_BUFFER_LEN = 1018U; // 2026 = NXDN_FRAME_LENGTH_BYTES * 21 + 10 (BUFFER_LEN = NXDN_FRAME_LENGTH_BYTES * NO_OF_FRAMES)
} // namespace nxdn
#endif // __NXDN_DEFINES_H__

@ -1,12 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2022 Bryan Biedenkapp N2PLL
*
* Copyright (C) 2009-2018,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "nxdn/NXDNRX.h"
@ -14,6 +34,8 @@
using namespace nxdn;
#if defined(ENABLE_NXDN)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -29,13 +51,15 @@ const uint16_t NOENDPTR = 9999U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the NXDNRX class. */
/// <summary>
/// Initializes a new instance of the NXDNRX class.
/// </summary>
NXDNRX::NXDNRX() :
m_bitBuffer(0x00U),
m_outBuffer(),
m_buffer(NULL),
m_dataPtr(0U),
m_endPtr(NOENDPTR),
m_lostCount(0U),
m_state(NXDNRXS_NONE)
{
@ -43,32 +67,48 @@ NXDNRX::NXDNRX() :
m_buffer = m_outBuffer + 1U;
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void NXDNRX::reset()
{
m_bitBuffer = 0x00U;
m_dataPtr = 0U;
m_endPtr = NOENDPTR;
m_lostCount = 0U;
m_state = NXDNRXS_NONE;
}
/* Sample NXDN bits from the air interface. */
/// <summary>
/// Sample NXDN bits from the air interface.
/// </summary>
/// <param name="bit"></param>
void NXDNRX::databit(bool bit)
{
m_bitBuffer <<= 1;
if (bit)
m_bitBuffer |= 0x01U;
if (m_state != NXDNRXS_NONE) {
_WRITE_BIT(m_buffer, m_dataPtr, bit);
m_dataPtr++;
if (m_dataPtr > NXDN_FRAME_LENGTH_BITS) {
reset();
}
}
if (m_state == NXDNRXS_DATA) {
processData(bit);
}
else {
m_bitBuffer <<= 1;
if (bit)
m_bitBuffer |= 0x01U;
bool ret = correlateSync(true);
if (ret) {
DEBUG3("NXDNRX: databit(): dataPtr/endPtr", m_dataPtr, m_endPtr);
m_state = NXDNRXS_DATA;
}
@ -80,35 +120,24 @@ void NXDNRX::databit(bool bit)
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to process NXDN data bits. */
/// <summary>
/// Helper to process NXDN data bits.
/// </summary>
/// <param name="bit"></param>
void NXDNRX::processData(bool bit)
{
m_bitBuffer <<= 1;
if (bit)
m_bitBuffer |= 0x01U;
_WRITE_BIT(m_buffer, m_dataPtr, bit);
m_dataPtr++;
if (m_dataPtr > NXDN_FRAME_LENGTH_BITS) {
reset();
}
// only search for a sync in the right place +-2 bits
if (m_dataPtr >= (NXDN_FSW_LENGTH_BITS - 2U) && m_dataPtr <= (NXDN_FSW_LENGTH_BITS + 2U)) {
if (correlateSync()) {
DEBUG2("NXDNRX::processData() sync found pos", m_dataPtr - NXDN_FSW_LENGTH_BITS);
}
correlateSync();
}
// process frame
if (m_dataPtr == NXDN_FRAME_LENGTH_BITS) {
if (m_dataPtr == m_endPtr) {
m_lostCount--;
// we've not seen a data sync for too long, signal sync lost and change to NXDNRXS_NONE
if (m_lostCount == 0U) {
DEBUG1("NXDNRX::processData() sync timed out, lost lock");
DEBUG1("NXDNRX: processData(): sync timed out, lost lock");
io.setDecode(false);
@ -116,6 +145,8 @@ void NXDNRX::processData(bool bit)
reset();
}
else {
DEBUG2("NXDNRX: processData(): sync found pos", m_dataPtr);
m_outBuffer[0U] = m_lostCount == (MAX_FSW_FRAMES - 1U) ? 0x01U : 0x00U; // set sync flag
serial.writeNXDNData(m_outBuffer, NXDN_FRAME_LENGTH_BYTES + 1U);
@ -125,8 +156,11 @@ void NXDNRX::processData(bool bit)
}
}
/* Frame synchronization correlator. */
/// <summary>
/// Frame synchronization correlator.
/// </summary>
/// <param name="first"></param>
/// <returns></returns>
bool NXDNRX::correlateSync(bool first)
{
uint8_t maxErrs;
@ -138,7 +172,7 @@ bool NXDNRX::correlateSync(bool first)
// fuzzy matching of the data sync bit sequence
uint8_t errs = countBits64((m_bitBuffer & NXDN_FSW_BITS_MASK) ^ NXDN_FSW_BITS);
if (errs <= maxErrs) {
DEBUG2("NXDNRX::correlateSync() sync errs", errs);
DEBUG2("NXDNRX: correlateSync(): correlateSync errs", errs);
if (first) {
// unpack sync bytes
@ -147,19 +181,22 @@ bool NXDNRX::correlateSync(bool first)
sync[1U] = (uint8_t)((m_bitBuffer >> 8) & NXDN_FSW_BYTES_MASK[1U]);
sync[2U] = (uint8_t)((m_bitBuffer >> 0) & NXDN_FSW_BYTES_MASK[2U]);
DEBUG4("NXDNRX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
m_buffer[i] = sync[i];
DEBUG4("NXDNRX::correlateSync() sync [b0 - b2]", m_buffer[0], m_buffer[1], m_buffer[2]);
}
m_lostCount = MAX_FSW_FRAMES;
m_dataPtr = NXDN_FSW_LENGTH_BITS;
m_endPtr = NXDN_FRAME_LENGTH_BITS;
DEBUG2("NXDNRX::correlateSync() dataPtr", m_dataPtr - NXDN_FSW_LENGTH_BITS);
DEBUG3("NXDNRX: correlateSync(): dataPtr/endPtr", m_dataPtr, m_endPtr);
return true;
}
return false;
}
#endif // defined(ENABLE_NXDN)

@ -1,18 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2022 Bryan Biedenkapp N2PLL
*
* Copyright (C) 2015,2016,2017,2018,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
/**
* @file NXDNRX.h
* @ingroup nxdn_hfw
* @file NXDNRX.cpp
* @ingroup nxdn_hfw
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__NXDN_RX_H__)
#define __NXDN_RX_H__
@ -20,45 +34,32 @@
#include "Defines.h"
#include "nxdn/NXDNDefines.h"
#if defined(ENABLE_NXDN)
namespace nxdn
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief NXDN Receiver State
* @ingroup nxdn_hfw
*/
enum NXDNRX_STATE {
NXDNRXS_NONE, //! None
NXDNRXS_DATA //! Data
NXDNRXS_NONE,
NXDNRXS_DATA
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for DMR slots.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for NXDN mode operation.
* @ingroup nxdn_mfw
*/
class DSP_FW_API NXDNRX {
public:
/**
* @brief Initializes a new instance of the NXDNRX class.
*/
/// <summary>Initializes a new instance of the NXDNRX class.</summary>
NXDNRX();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample NXDN bits from the air interface.
* @param bit
*/
/// <summary>Sample NXDN bits from the air interface.</summary>
void databit(bool bit);
private:
@ -68,22 +69,19 @@ namespace nxdn
uint16_t m_dataPtr;
uint16_t m_endPtr;
uint16_t m_lostCount;
NXDNRX_STATE m_state;
/**
* @brief Helper to process NXDN data bits.
* @param bit
*/
/// <summary>Helper to process NXDN data bits.</summary>
void processData(bool bit);
/**
* @brief Frame synchronization correlator.
* @param first
*/
/// <summary>Frame synchronization correlator.</summary>
bool correlateSync(bool first = false);
};
} // namespace nxdn
#endif // defined(ENABLE_NXDN)
#endif // __NXDN_RX_H__

@ -1,13 +1,33 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
*
* Copyright (C) 2009-2018,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2017 Andy Uribe, CA6JAU
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "nxdn/NXDNTX.h"
@ -15,12 +35,15 @@
using namespace nxdn;
#if defined(ENABLE_NXDN)
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the NXDNTX class. */
/// <summary>
/// Initializes a new instance of the NXDNTX class.
/// </summary>
NXDNTX::NXDNTX() :
m_fifo(NXDN_TX_BUFFER_LEN),
m_state(NXDNTXSTATE_NORMAL),
@ -34,8 +57,9 @@ NXDNTX::NXDNTX() :
/* stub */
}
/* Process local buffer and transmit on the air interface. */
/// <summary>
/// Process local buffer and transmit on the air interface.
/// </summary>
void NXDNTX::process()
{
if (m_fifo.getData() == 0U && m_poLen == 0U && m_tailCnt > 0U &&
@ -69,6 +93,8 @@ void NXDNTX::process()
return;
createData();
DEBUG2("NXDNTX: process(): poLen", m_poLen);
}
if (m_poLen > 0U) {
@ -91,15 +117,19 @@ void NXDNTX::process()
}
}
/* Write data to the local buffer. */
/// <summary>
/// Write data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t NXDNTX::writeData(const uint8_t* data, uint16_t length)
{
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
return RSN_ILLEGAL_LENGTH;
uint16_t space = m_fifo.getSpace();
DEBUG3("NXDNTX::writeData() dataLength/fifoLength", length, space);
DEBUG3("NXDNTX: writeData(): dataLength/fifoLength", length, space);
if (space < NXDN_FRAME_LENGTH_BYTES)
return RSN_RINGBUFF_FULL;
@ -109,48 +139,48 @@ uint8_t NXDNTX::writeData(const uint8_t* data, uint16_t length)
return RSN_OK;
}
/* Clears the local buffer. */
/// <summary>
/// Clears the local buffer.
/// </summary>
void NXDNTX::clear()
{
m_fifo.reset();
}
/* Sets the FDMA preamble count. */
/// <summary>
/// Sets the FDMA preamble count.
/// </summary>
/// <param name="preambleCnt">Count of preambles.</param>
void NXDNTX::setPreambleCount(uint8_t preambleCnt)
{
m_preambleCnt = 300U + uint16_t(preambleCnt) * 6U; // 500ms + tx delay
// clamp preamble count
if (m_preambleCnt > 60U)
m_preambleCnt = 60U;
if (m_preambleCnt > 1200U)
m_preambleCnt = 1200U;
}
/* Sets the Tx hang time. */
/// <summary>
/// Sets the Tx hang time.
/// </summary>
/// <param name="txHang">Transmit hang time in seconds.</param>
void NXDNTX::setTxHang(uint8_t txHang)
{
m_txHang = txHang * NXDN_FIXED_TX_HANG;
}
/* Helper to set the calibration state for Tx. */
/// <summary>
/// Helper to set the calibration state for Tx.
/// </summary>
/// <param name="start"></param>
void NXDNTX::setCal(bool start)
{
m_state = start ? NXDNTXSTATE_CAL : NXDNTXSTATE_NORMAL;
}
/* Helper to resize the FIFO buffer. */
void NXDNTX::resizeBuffer(uint16_t size)
{
m_fifo.reset();
m_fifo.reinitialize(size);
}
/* Helper to get how much space the ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint8_t NXDNTX::getSpace() const
{
return m_fifo.getSpace() / NXDN_FRAME_LENGTH_BYTES;
@ -160,8 +190,9 @@ uint8_t NXDNTX::getSpace() const
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to generate data. */
/// <summary>
///
/// </summary>
void NXDNTX::createData()
{
if (!m_tx) {
@ -173,7 +204,7 @@ void NXDNTX::createData()
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
}
else {
DEBUG2("NXDNTX::createData() fifoSpace", m_fifo.getSpace());
DEBUG2("NXDNTX: createData(): fifoSpace", m_fifo.getSpace());
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[m_poLen++] = m_fifo.get();
}
@ -182,8 +213,10 @@ void NXDNTX::createData()
m_poPtr = 0U;
}
/* Helper to write a raw byte to the DAC. */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
void NXDNTX::writeByte(uint8_t c)
{
uint8_t bit;
@ -199,8 +232,9 @@ void NXDNTX::writeByte(uint8_t c)
}
}
/* */
/// <summary>
///
/// </summary>
void NXDNTX::writeSilence()
{
uint8_t bit;
@ -209,3 +243,5 @@ void NXDNTX::writeSilence()
io.write(&bit, 1);
}
}
#endif // defined(ENABLE_NXDN)

@ -1,25 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
*
* Copyright (C) 2015,2016,2017,2018,2020 Jonathan Naylor, G4KLX
* Copyright (C) 2022 Bryan Biedenkapp, N2PLL
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file NXDNTX.h
* @ingroup nxdn_hfw
* @file NXDNTX.cpp
* @ingroup nxdn_hfw
*/
#if !defined(__NXDN_TX_H__)
#define __NXDN_TX_H__
#include "Defines.h"
#include "SerialBuffer.h"
#if defined(ENABLE_NXDN)
namespace nxdn
{
// ---------------------------------------------------------------------------
@ -28,74 +45,38 @@ namespace nxdn
#define NXDN_FIXED_TX_HANG 600
/**
* @brief NXDN Transmitter States
* @ingroup nxdn_hfw
*/
enum NXDNTXSTATE {
NXDNTXSTATE_NORMAL, //! Normal
NXDNTXSTATE_CAL //! Calibration
NXDNTXSTATE_NORMAL,
NXDNTXSTATE_CAL
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements transmitter logic for NXDN mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements transmitter logic for NXDN mode operation.
* @ingroup nxdn_hfw
*/
class DSP_FW_API NXDNTX {
public:
/**
* @brief Initializes a new instance of the NXDNTX class.
*/
/// <summary>Initializes a new instance of the NXDNTX class.</summary>
NXDNTX();
/**
* @brief Process local buffer and transmit on the air interface.
*/
/// <summary>Process local buffer and transmit on the air interface.</summary>
void process();
/**
* @brief Write data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write data to the local buffer.</summary>
uint8_t writeData(const uint8_t* data, uint16_t length);
/**
* @brief Clears the local buffer.
*/
/// <summary>Clears the local buffer.</summary>
void clear();
/**
* @brief Sets the FDMA preamble count.
* @param preambleCnt FDMA preamble count.
*/
/// <summary>Sets the FDMA preamble count.</summary>
void setPreambleCount(uint8_t preambleCnt);
/**
* @brief Sets the transmit hang time.
* @param txHang Transmit hang time.
*/
/// <summary>Sets the transmit hang time.</summary>
void setTxHang(uint8_t txHang);
/**
* @brief Helper to set the calibration state for Tx.
* @param start
*/
/// <summary>Helper to set the calibration state for Tx.</summary>
void setCal(bool start);
/**
* @brief Helper to resize the FIFO buffer.
* @param size
*/
void resizeBuffer(uint16_t size);
/**
* @brief Helper to get how much space the ring buffer has for samples.
* @returns uint8_t Amount of space in ring buffer for samples.
*/
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
uint8_t getSpace() const;
private:
@ -111,21 +92,16 @@ namespace nxdn
uint32_t m_txHang;
uint32_t m_tailCnt;
/**
* @brief Helper to generate data.
*/
/// <summary></summary>
void createData();
/**
* @brief Helper to write a raw byte to the DAC.
* @param c Byte.
*/
/// <summary></summary>
void writeByte(uint8_t c);
/**
* @brief
*/
/// <summary></summary>
void writeSilence();
};
} // namespace nxdn
#endif // defined(ENABLE_NXDN)
#endif // __NXDN_TX_H__

@ -1,17 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2018 Andy Uribe, CA6JAU
*
*/
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "p25/CalP25.h"
using namespace p25;
#if defined(ENABLE_P25)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -50,8 +72,9 @@ unsigned char LDU2_1K[] = { 0x00,
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the CalP25 class. */
/// <summary>
/// Initializes a new instance of the CalP25 class.
/// </summary>
CalP25::CalP25() :
m_transmit(false),
m_state(P25CAL1K_IDLE)
@ -59,8 +82,9 @@ CalP25::CalP25() :
/* stub */
}
/* Process local state and transmit on the air interface. */
/// <summary>
/// Process local state and transmit on the air interface.
/// </summary>
void CalP25::process()
{
if (m_modemState == STATE_P25_CAL) {
@ -100,8 +124,12 @@ void CalP25::process()
}
}
/* Write P25 calibration data to the local buffer. */
/// <summary>
/// Write P25 calibration data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t CalP25::write(const uint8_t* data, uint8_t length)
{
if (length != 1U)
@ -117,3 +145,5 @@ uint8_t CalP25::write(const uint8_t* data, uint8_t length)
return RSN_OK;
}
#endif // defined(ENABLE_P25)

@ -1,66 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - Hotspot Firmware
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2018 Andy Uribe, CA6JAU
* @package DVM / DSP Firmware (Hotspot)
*
*/
/**
* @file CalP25.h
* @ingroup p25_hfw
* @file CalP25.cpp
* @ingroup p25_hfw
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__CAL_P25_H__)
#define __CAL_P25_H__
#include "Defines.h"
#include "p25/P25Defines.h"
#if defined(ENABLE_P25)
namespace p25
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief Calibration States
* @ingroup p25_hfw
*/
enum P25CAL1K {
P25CAL1K_IDLE, //! Idle
P25CAL1K_LDU1, //! LDU1
P25CAL1K_LDU2 //! LDU2
P25CAL1K_IDLE,
P25CAL1K_LDU1,
P25CAL1K_LDU2
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements logic for P25 calibration mode.
// ---------------------------------------------------------------------------
/**
* @brief Implements logic for P25 calibration mode.
* @ingroup p25_hfw
*/
class DSP_FW_API CalP25 {
public:
/**
* @brief Initializes a new instance of the CalP25 class.
*/
/// <summary>Initializes a new instance of the CalP25 class.</summary>
CalP25();
/**
* @brief Process local state and transmit on the air interface.
*/
/// <summary>Process local state and transmit on the air interface.</summary>
void process();
/**
* @brief Write P25 calibration state.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
/// <summary>Write P25 calibration state.</summary>
uint8_t write(const uint8_t* data, uint8_t length);
private:
@ -69,4 +69,6 @@ namespace p25
};
} // namespace p25
#endif // defined(ENABLE_P25)
#endif // __CAL_P25_H__

@ -1,21 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Andy Uribe CA6JAU
* Copyright (C) 2017-2018 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Andy Uribe CA6JAU
*
* Copyright (C) 2009-2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018 Andy Uribe, CA6JAU
* Copyright (C) 2017-2024 Bryan Biedenkapp, N2PLL
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
/**
* @defgroup p25_hfw Project 25
* @brief Implementation for the TIA-102 Project 25 standard.
* @ingroup hotspot_fw
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* @file P25Defines.h
* @ingroup p25_hfw
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__P25_DEFINES_H__)
#define __P25_DEFINES_H__
@ -28,11 +58,6 @@ namespace p25
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup p25_hfw
* @{
*/
const uint32_t P25_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const uint32_t P25_HDU_FRAME_LENGTH_BYTES = 99U;
@ -55,11 +80,6 @@ namespace p25
const uint32_t P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_PDU_FRAME_LENGTH_BYTES = 512U;
const uint32_t P25_PDU_FRAME_LENGTH_BITS = P25_PDU_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_PDU_FRAME_LENGTH_SYMBOLS = P25_PDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_PDU_FRAME_LENGTH_SAMPLES = P25_PDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_TDULC_FRAME_LENGTH_BYTES = 54U;
const uint32_t P25_TDULC_FRAME_LENGTH_BITS = P25_TDULC_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_TDULC_FRAME_LENGTH_SYMBOLS = P25_TDULC_FRAME_LENGTH_BYTES * 4U;
@ -75,6 +95,11 @@ namespace p25
const uint32_t P25_NID_LENGTH_SYMBOLS = P25_NID_LENGTH_BYTES * 4U;
const uint32_t P25_NID_LENGTH_SAMPLES = P25_NID_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BYTES = 39U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BITS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 8U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SYMBOLS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 4U;
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SAMPLES = P25_PDU_HDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU };
const uint8_t P25_SYNC_BYTES_LENGTH = 6U;
const uint8_t P25_START_SYNC = 0x5FU;
@ -95,21 +120,16 @@ namespace p25
const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U;
const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU;
// 522 = P25_PDU_FRAME_LENGTH_BYTES + 10 (BUFFER_LEN = P25_PDU_FRAME_LENGTH_BYTES + 10)
const uint32_t P25_TX_BUFFER_LEN = 522U;
const uint32_t P25_TX_BUFFER_LEN = 1738U; // 2592 = P25_LDU_FRAME_LENGTH_BYTES * 8 + 10 (BUFFER_LEN = P25_LDU_FRAME_LENGTH_BYTES * NO_OF_FRAMES + 10)
// Data Unit ID(s)
const uint8_t P25_DUID_HDU = 0x00U; // Header Data Unit
const uint8_t P25_DUID_TDU = 0x03U; // Simple Terminator Data Unit
const uint8_t P25_DUID_LDU1 = 0x05U; // Logical Link Data Unit 1
const uint8_t P25_DUID_VSELP1 = 0x06U; // Motorola VSELP 1
const uint8_t P25_DUID_TSDU = 0x07U; // Trunking System Data Unit
const uint8_t P25_DUID_VSELP2 = 0x09U; // Motorola VSELP 2
const uint8_t P25_DUID_LDU2 = 0x0AU; // Logical Link Data Unit 2
const uint8_t P25_DUID_PDU = 0x0CU; // Packet Data Unit
const uint8_t P25_DUID_TDULC = 0x0FU; // Terminator Data Unit with Link Control
/** @} */
} // namespace p25
#endif // __P25_DEFINES_H__

@ -1,20 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021-2024 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "p25/P25RX.h"
#include "Utils.h"
using namespace p25;
#if defined(ENABLE_P25)
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
@ -30,14 +52,14 @@ const uint16_t NOENDPTR = 9999U;
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the P25RX class. */
/// <summary>
/// Initializes a new instance of the P25RX class.
/// </summary>
P25RX::P25RX() :
m_bitBuffer(0x00U),
m_buffer(),
m_dataPtr(0U),
m_endPtr(NOENDPTR),
m_pduEndPtr(NOENDPTR),
m_lostCount(0U),
m_nac(0xF7EU),
m_state(P25RXS_NONE),
@ -46,8 +68,9 @@ P25RX::P25RX() :
::memset(m_buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U);
}
/* Helper to reset data values to defaults. */
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void P25RX::reset()
{
m_bitBuffer = 0x00U;
@ -56,7 +79,6 @@ void P25RX::reset()
::memset(m_buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U);
m_endPtr = NOENDPTR;
m_pduEndPtr = NOENDPTR;
m_lostCount = 0U;
@ -65,8 +87,10 @@ void P25RX::reset()
m_duid = 0xFFU;
}
/* Sample P25 bits from the air interface. */
/// <summary>
/// Sample P25 bits from the air interface.
/// </summary>
/// <param name="bit"></param>
void P25RX::databit(bool bit)
{
m_bitBuffer <<= 1;
@ -77,14 +101,8 @@ void P25RX::databit(bool bit)
_WRITE_BIT(m_buffer, m_dataPtr, bit);
m_dataPtr++;
if (m_state != P25RXS_DATA) {
if (m_dataPtr > P25_LDU_FRAME_LENGTH_BITS) {
reset();
}
} else {
if (m_dataPtr > P25_PDU_FRAME_LENGTH_BITS) {
reset();
}
if (m_dataPtr > P25_LDU_FRAME_LENGTH_BITS) {
reset();
}
}
@ -108,8 +126,10 @@ void P25RX::databit(bool bit)
}
}
/* Sets the P25 NAC. */
/// <summary>
/// Sets the P25 NAC.
/// </summary>
/// <param name="nac">NAC.</param>
void P25RX::setNAC(uint16_t nac)
{
m_nac = nac;
@ -119,13 +139,15 @@ void P25RX::setNAC(uint16_t nac)
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to process P25 samples. */
/// <summary>
/// Helper to process P25 samples.
/// </summary>
/// <param name="bit"></param>
void P25RX::processBit(bool bit)
{
// process NID
if (m_dataPtr == P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS + 1) {
DEBUG3("P25RX::processBit() dataPtr/endPtr", m_dataPtr, m_endPtr);
DEBUG3("P25RX: processBit(): dataPtr/endPtr", m_dataPtr, m_endPtr);
if (!decodeNid()) {
io.setDecode(false);
@ -137,45 +159,43 @@ void P25RX::processBit(bool bit)
switch (m_duid) {
case P25_DUID_HDU:
{
DEBUG2("P25RX::processBit() sync found in HDU pos", m_dataPtr);
DEBUG2("P25RX: processBit(): sync found in HDU pos", m_dataPtr);
m_endPtr = P25_HDU_FRAME_LENGTH_BITS;
}
break;
case P25_DUID_TDU:
{
DEBUG2("P25RX::processBit() sync found in TDU pos", m_dataPtr);
DEBUG2("P25RX: processBit(): sync found in TDU pos", m_dataPtr);
m_endPtr = P25_TDU_FRAME_LENGTH_BITS;
}
break;
case P25_DUID_LDU1:
case P25_DUID_VSELP1:
m_state = P25RXS_VOICE;
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
return;
case P25_DUID_TSDU:
{
DEBUG2("P25RX::processBit() sync found in TSDU pos", m_dataPtr);
DEBUG2("P25RX: processBit(): sync found in TSDU pos", m_dataPtr);
m_endPtr = P25_TSDU_FRAME_LENGTH_BITS;
}
break;
case P25_DUID_LDU2:
case P25_DUID_VSELP2:
m_state = P25RXS_VOICE;
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
return;
case P25_DUID_PDU:
m_state = P25RXS_DATA;
m_endPtr = m_pduEndPtr = P25_PDU_FRAME_LENGTH_BITS;
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
return;
case P25_DUID_TDULC:
{
DEBUG2("P25RX::processBit() sync found in TDULC pos", m_dataPtr);
DEBUG2("P25RX: processBit(): sync found in TDULC pos", m_dataPtr);
m_endPtr = P25_TDULC_FRAME_LENGTH_BITS;
}
break;
default:
{
DEBUG3("P25RX::processBit() illegal DUID in NID", m_nac, m_duid);
DEBUG3("P25RX: processBit(): illegal DUID in NID", m_nac, m_duid);
reset();
}
return;
@ -183,40 +203,34 @@ void P25RX::processBit(bool bit)
}
}
if (m_state == P25RXS_SYNC) {
// only search for a sync in the right place +-2 bits
if (m_dataPtr >= (P25_SYNC_LENGTH_BITS - 2U) && m_dataPtr <= (P25_SYNC_LENGTH_BITS + 2U)) {
correlateSync();
}
if (m_state == P25RXS_VOICE) {
m_lostCount = MAX_SYNC_FRAMES;
processVoice(bit);
}
// since we aren't processing voice or data -- simply wait till we've reached the end pointer
if (m_dataPtr == m_endPtr) {
// DEBUG3("P25RX: m_buffer dump endPtr/endPtrB", m_endPtr, m_endPtr / 8U);
// DEBUG_DUMP(m_buffer, P25_LDU_FRAME_LENGTH_BYTES + 3U);
if (m_state == P25RXS_DATA) {
m_lostCount = MAX_SYNC_FRAMES;
processData(bit);
}
uint8_t frame[P25_HDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
// since we aren't processing voice or data -- simply wait till we've reached the end pointer
if (m_dataPtr == m_endPtr) {
// DEBUG3("P25RX: m_buffer dump endPtr/endPtrB", m_endPtr, m_endPtr / 8U);
// DEBUG_DUMP(m_buffer, P25_LDU_FRAME_LENGTH_BYTES + 3U);
frame[0U] = 0x01U; // has sync
serial.writeP25Data(frame, (m_endPtr / 8U) + 1U);
reset();
}
}
else {
if (m_state == P25RXS_VOICE) {
m_lostCount = MAX_SYNC_FRAMES;
processVoice(bit);
}
uint8_t frame[P25_HDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
if (m_state == P25RXS_DATA) {
m_lostCount = MAX_SYNC_FRAMES;
processData(bit);
}
frame[0U] = 0x01U; // has sync
serial.writeP25Data(frame, (m_endPtr / 8U) + 1U);
reset();
}
}
/* Helper to process LDU P25 bits. */
/// <summary>
/// Helper to process LDU P25 bits.
/// </summary>
/// <param name="bit"></param>
void P25RX::processVoice(bool bit)
{
// only search for a sync in the right place +-2 bits
@ -226,7 +240,7 @@ void P25RX::processVoice(bool bit)
// process NID
if (m_dataPtr == P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS + 1) {
DEBUG3("P25RX::processVoice() dataPtr/endPtr", m_dataPtr, m_endPtr);
DEBUG3("P25RX: processVoice(): dataPtr/endPtr", m_dataPtr, m_endPtr);
if (!decodeNid()) {
io.setDecode(false);
@ -238,7 +252,7 @@ void P25RX::processVoice(bool bit)
switch (m_duid) {
case P25_DUID_TDU:
{
DEBUG2("P25RX::processVoice() sync found in TDU pos", m_dataPtr);
DEBUG2("P25RX: processVoice(): sync found in TDU pos", m_dataPtr);
m_endPtr = P25_TDU_FRAME_LENGTH_BITS;
}
break;
@ -250,7 +264,7 @@ void P25RX::processVoice(bool bit)
return;
default:
{
DEBUG3("P25RX::processVoice() illegal DUID in NID", m_nac, m_duid);
DEBUG3("P25RX: processVoice(): illegal DUID in NID", m_nac, m_duid);
reset();
}
return;
@ -261,7 +275,7 @@ void P25RX::processVoice(bool bit)
// if we've reached the end pointer and the DUID is a TDU; send it
if (m_dataPtr == m_endPtr && m_duid == P25_DUID_TDU)
{
DEBUG2("P25RX::processVoice() sync found in TDU pos", m_dataPtr);
DEBUG2("P25RX: processVoice(): sync found in TDU pos", m_dataPtr);
uint8_t frame[P25_TDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
@ -281,7 +295,7 @@ void P25RX::processVoice(bool bit)
// we've not seen a data sync for too long, signal sync lost and change to P25RXS_NONE
if (m_lostCount == 0U) {
DEBUG1("P25RX::processVoice() sync timeout in LDU, lost lock");
DEBUG1("P25RX: processVoice(): sync timeout in LDU, lost lock");
io.setDecode(false);
@ -289,7 +303,7 @@ void P25RX::processVoice(bool bit)
reset();
}
else {
DEBUG2("P25RX::processVoice() sync found in LDU pos", m_dataPtr);
DEBUG2("P25RX: processVoice(): sync found in LDU pos", m_dataPtr);
uint8_t frame[P25_LDU_FRAME_LENGTH_BYTES + 3U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
@ -309,8 +323,10 @@ void P25RX::processVoice(bool bit)
}
}
/* Helper to process PDU P25 bits. */
/// <summary>
/// Helper to process PDU P25 bits.
/// </summary>
/// <param name="bit"></param>
void P25RX::processData(bool bit)
{
// only search for a sync in the right place +-2 bits
@ -320,7 +336,7 @@ void P25RX::processData(bool bit)
// process NID
if (m_dataPtr == P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS + 1) {
DEBUG3("P25RX::processData() dataPtr/pduEndPtr", m_dataPtr, m_pduEndPtr);
DEBUG3("P25RX: processVoice(): dataPtr/endPtr", m_dataPtr, m_endPtr);
if (!decodeNid()) {
io.setDecode(false);
@ -331,11 +347,11 @@ void P25RX::processData(bool bit)
else {
switch (m_duid) {
case P25_DUID_PDU:
m_endPtr = m_pduEndPtr = P25_PDU_FRAME_LENGTH_BITS;
m_endPtr = P25_LDU_FRAME_LENGTH_BITS;
return;
default:
{
DEBUG3("P25RX::processData() illegal DUID in NID", m_nac, m_duid);
DEBUG3("P25RX: processData(): illegal DUID in NID", m_nac, m_duid);
reset();
}
return;
@ -343,13 +359,13 @@ void P25RX::processData(bool bit)
}
}
// process data frame
if (m_dataPtr == m_pduEndPtr) {
// process voice frame
if (m_dataPtr == m_endPtr) {
m_lostCount--;
// we've not seen a data sync for too long, signal sync lost and change to P25RXS_NONE
if (m_lostCount == 0U) {
DEBUG1("P25RX::processData() sync timeout in PDU, lost lock");
DEBUG1("P25RX: processData(): sync timeout in PDU, lost lock");
io.setDecode(false);
@ -357,19 +373,21 @@ void P25RX::processData(bool bit)
reset();
}
else {
DEBUG2("P25RX::processData() sync found in PDU pos", m_dataPtr);
DEBUG2("P25RX: processData(): sync found in PDU pos", m_dataPtr);
uint8_t frame[P25_PDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_pduEndPtr / 8U);
uint8_t frame[P25_LDU_FRAME_LENGTH_BYTES + 1U];
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U; // set sync flag
serial.writeP25Data(frame, P25_PDU_FRAME_LENGTH_BYTES + 1U);
serial.writeP25Data(frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
}
}
}
/* Frame synchronization correlator. */
/// <summary>
/// Frame synchronization correlator.
/// </summary>
/// <returns></returns>
bool P25RX::correlateSync()
{
uint8_t maxErrs;
@ -383,7 +401,7 @@ bool P25RX::correlateSync()
if (errs <= maxErrs) {
::memset(m_buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U);
DEBUG2("P25RX::correlateSync() sync errs", errs);
DEBUG2("P25RX: correlateSync(): correlateSync errs", errs);
// unpack sync bytes
uint8_t sync[P25_SYNC_BYTES_LENGTH];
@ -394,8 +412,8 @@ bool P25RX::correlateSync()
sync[4U] = (uint8_t)((m_bitBuffer >> 8) & 0xFFU);
sync[5U] = (uint8_t)((m_bitBuffer >> 0) & 0xFFU);
DEBUG4("P25RX::correlateSync() sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("P25RX::correlateSync() sync [b3 - b5]", sync[3], sync[4], sync[5]);
DEBUG4("P25RX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
DEBUG4("P25RX: correlateSync(): sync [b3 - b5]", sync[3], sync[4], sync[5]);
for (uint8_t i = 0U; i < P25_SYNC_BYTES_LENGTH; i++)
m_buffer[i] = sync[i];
@ -406,14 +424,11 @@ bool P25RX::correlateSync()
m_endPtr = m_dataPtr + P25_LDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS;
if (m_endPtr >= P25_LDU_FRAME_LENGTH_BITS)
m_endPtr -= P25_LDU_FRAME_LENGTH_BITS;
m_pduEndPtr = m_dataPtr + P25_PDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS;
if (m_pduEndPtr >= P25_PDU_FRAME_LENGTH_BITS)
m_pduEndPtr -= P25_PDU_FRAME_LENGTH_BITS;
m_lostCount = MAX_SYNC_FRAMES;
m_dataPtr = P25_SYNC_LENGTH_BITS;
DEBUG4("P25RX::correlateSync() dataPtr/endPtr/pduEndPtr", m_dataPtr, m_endPtr, m_pduEndPtr);
DEBUG3("P25RX: correlateSync(): dataPtr/endPtr", m_dataPtr, m_endPtr);
return true;
}
@ -421,8 +436,9 @@ bool P25RX::correlateSync()
return false;
}
/* Helper to decode the P25 NID. */
/// <summary>
/// Helper to decode the P25 NID.
/// </summary>
bool P25RX::decodeNid()
{
uint8_t nid[P25_NID_LENGTH_BYTES];
@ -431,19 +447,21 @@ bool P25RX::decodeNid()
if (m_nac == 0xF7EU) {
m_duid = nid[1U] & 0x0FU;
DEBUG2("P25RX::decodeNid() DUID for xDU", m_duid);
DEBUG2("P25RX: decodeNid(): DUID for xDU", m_duid);
return true;
}
uint16_t nac = (nid[0U] << 4) | ((nid[1U] & 0xF0U) >> 4);
if (nac == m_nac) {
m_duid = nid[1U] & 0x0FU;
DEBUG2("P25RX::decodeNid() DUID for xDU", m_duid);
DEBUG2("P25RX: decodeNid(): DUID for xDU", m_duid);
return true;
}
else {
DEBUG3("P25RX::decodeNid() invalid NAC found; nac != m_nac", nac, m_nac);
DEBUG3("P25RX: decodeNid(): invalid NAC found; nac != m_nac", nac, m_nac);
}
return false;
}
#endif // defined(ENABLE_P25)

@ -1,83 +1,81 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017,2018 Andy Uribe, CA6JAU
* Copyright (C) 2021-2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file P25RX.h
* @ingroup p25_hfw
* @file P25RX.cpp
* @ingroup p25_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__P25_RX_H__)
#define __P25_RX_H__
#include "Defines.h"
#include "p25/P25Defines.h"
#if defined(ENABLE_P25)
namespace p25
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @brief P25 Receiver State
* @ingroup p25_hfw
*/
enum P25RX_STATE {
P25RXS_NONE, //! None
P25RXS_SYNC, //! Found Sync
P25RXS_VOICE, //! Voice Data
P25RXS_DATA //! PDU Data
P25RXS_NONE,
P25RXS_SYNC,
P25RXS_VOICE,
P25RXS_DATA
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements receiver logic for P25 mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements receiver logic for P25 mode operation.
* @ingroup p25_hfw
*/
class DSP_FW_API P25RX {
public:
/**
* @brief Initializes a new instance of the P25RX class.
*/
/// <summary>Initializes a new instance of the P25RX class.</summary>
P25RX();
/**
* @brief Helper to reset data values to defaults.
*/
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/**
* @brief Sample P25 bits from the air interface.
* @param bit
*/
/// <summary>Sample P25 bits from the air interface.</summary>
void databit(bool bit);
/**
* @brief Sets the P25 NAC.
* @param nac Network Access Code.
*/
/// <summary>Sets the P25 NAC.</summary>
void setNAC(uint16_t nac);
private:
uint64_t m_bitBuffer;
uint8_t m_buffer[P25_PDU_FRAME_LENGTH_BYTES + 3U];
uint8_t m_buffer[P25_LDU_FRAME_LENGTH_BYTES + 3U];
uint16_t m_dataPtr;
uint16_t m_endPtr;
uint16_t m_pduEndPtr;
uint16_t m_lostCount;
@ -87,34 +85,21 @@ namespace p25
uint8_t m_duid;
/**
* @brief Helper to process P25 bits.
* @param bit
*/
/// <summary>Helper to process P25 bits.</summary>
void processBit(bool bit);
/**
* @brief Helper to process LDU P25 bits.
* @param bit
*/
/// <summary>Helper to process LDU P25 bits.</summary>
void processVoice(bool bit);
/**
* @brief Helper to process PDU P25 bits.
* @param bit
*/
/// <summary>Helper to process PDU P25 bits.</summary>
void processData(bool bit);
/**
* @brief Frame synchronization correlator.
* @returns bool
*/
/// <summary>Frame synchronization correlator.</summary>
bool correlateSync();
/**
* @brief Helper to decode the P25 NID.
* @returns bool True, if P25 NID was decoded, otherwise false.
*/
/// <summary>Helper to decode the P25 NID.</summary>
bool decodeNid();
};
} // namespace p25
#endif // defined(ENABLE_P25)
#endif // __P25_RX_H__

@ -1,26 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017 Andy Uribe, CA6JAU
* Copyright (C) 2021-2022 Bryan Biedenkapp, N2PLL
*
*/
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* Copyright (C) 2021-2022 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Globals.h"
#include "p25/P25TX.h"
#include "p25/P25Defines.h"
using namespace p25;
#if defined(ENABLE_P25)
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/* Initializes a new instance of the P25TX class. */
/// <summary>
/// Initializes a new instance of the P25TX class.
/// </summary>
P25TX::P25TX() :
m_fifo(P25_TX_BUFFER_LEN),
m_state(P25TXSTATE_NORMAL),
@ -34,8 +57,9 @@ P25TX::P25TX() :
/* stub */
}
/* Process local buffer and transmit on the air interface. */
/// <summary>
/// Process local buffer and transmit on the air interface.
/// </summary>
void P25TX::process()
{
if (m_fifo.getData() == 0U && m_poLen == 0U && m_tailCnt > 0U &&
@ -72,6 +96,8 @@ void P25TX::process()
createData();
}
DEBUG2("P25TX: process(): poLen", m_poLen);
}
if (m_poLen > 0U) {
@ -94,44 +120,43 @@ void P25TX::process()
}
}
/* Write data to the local buffer. */
uint8_t P25TX::writeData(const uint8_t* data, uint16_t length)
/// <summary>
/// Write data to the local buffer.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
uint8_t P25TX::writeData(const uint8_t* data, uint8_t length)
{
if (length < (P25_TDU_FRAME_LENGTH_BYTES + 1U))
return RSN_ILLEGAL_LENGTH;
uint16_t space = m_fifo.getSpace();
DEBUG3("P25TX::writeData() dataLength/fifoLength", length, space);
DEBUG3("P25TX: writeData(): dataLength/fifoLength", length, space);
if (space < length) {
m_fifo.reset();
return RSN_RINGBUFF_FULL;
}
if (length <= 255U) {
m_fifo.put(DVM_SHORT_FRAME_START);
m_fifo.put(length - 1U);
} else {
m_fifo.put(DVM_LONG_FRAME_START);
m_fifo.put(((length - 1U) >> 8U) & 0xFFU);
m_fifo.put((length - 1U) & 0xFFU);
}
for (uint16_t i = 0U; i < (length - 1U); i++)
m_fifo.put(length - 1U);
for (uint8_t i = 0U; i < (length - 1U); i++)
m_fifo.put(data[i + 1U]);
return RSN_OK;
}
/* Clears the local buffer. */
/// <summary>
/// Clears the local buffer.
/// </summary>
void P25TX::clear()
{
m_fifo.reset();
}
/* Sets the FDMA preamble count. */
/// <summary>
/// Sets the FDMA preamble count.
/// </summary>
/// <param name="preambleCnt">Count of preambles.</param>
void P25TX::setPreambleCount(uint8_t preambleCnt)
{
m_preambleCnt = P25_FIXED_DELAY + preambleCnt;
@ -141,8 +166,10 @@ void P25TX::setPreambleCount(uint8_t preambleCnt)
m_preambleCnt = 1200U;
}
/* Sets the Tx hang time. */
/// <summary>
/// Sets the Tx hang time.
/// </summary>
/// <param name="txHang">Transmit hang time in seconds.</param>
void P25TX::setTxHang(uint8_t txHang)
{
if (txHang > 0U)
@ -155,23 +182,19 @@ void P25TX::setTxHang(uint8_t txHang)
m_txHang = 13U * 1200U;
}
/* Helper to set the calibration state for Tx. */
/// <summary>
/// Helper to set the calibration state for Tx.
/// </summary>
/// <param name="start"></param>
void P25TX::setCal(bool start)
{
m_state = start ? P25TXSTATE_CAL : P25TXSTATE_NORMAL;
}
/* Helper to resize the FIFO buffer. */
void P25TX::resizeBuffer(uint16_t size)
{
m_fifo.reset();
m_fifo.reinitialize(size);
}
/* Helper to get how much space the ring buffer has for samples. */
/// <summary>
/// Helper to get how much space the ring buffer has for samples.
/// </summary>
/// <returns></returns>
uint8_t P25TX::getSpace() const
{
return m_fifo.getSpace() / P25_LDU_FRAME_LENGTH_BYTES;
@ -181,8 +204,9 @@ uint8_t P25TX::getSpace() const
// Private Class Members
// ---------------------------------------------------------------------------
/* Helper to generate data. */
/// <summary>
///
/// </summary>
void P25TX::createData()
{
if (!m_tx) {
@ -190,19 +214,9 @@ void P25TX::createData()
m_poBuffer[m_poLen++] = P25_START_SYNC;
}
else {
uint8_t frameType = m_fifo.get();
uint16_t length = 0U;
switch (frameType) {
case DVM_SHORT_FRAME_START:
length = m_fifo.get();
break;
case DVM_LONG_FRAME_START:
length = ((m_fifo.get() & 0xFFU) << 8) + (m_fifo.get());
break;
}
DEBUG3("P25TX::createData() dataLength/fifoSpace", length, m_fifo.getSpace());
for (uint16_t i = 0U; i < length; i++) {
uint8_t length = m_fifo.get();
DEBUG3("P25TX: createData(): dataLength/fifoSpace", length, m_fifo.getSpace());
for (uint8_t i = 0U; i < length; i++) {
m_poBuffer[m_poLen++] = m_fifo.get();
}
}
@ -210,13 +224,14 @@ void P25TX::createData()
m_poPtr = 0U;
}
/* Helper to generate calibration data. */
/// <summary>
///
/// </summary>
void P25TX::createCal()
{
// 1.2 kHz sine wave generation
if (m_modemState == STATE_P25_CAL) {
for (uint8_t i = 0U; i < P25_LDU_FRAME_LENGTH_BYTES; i++) {
for (unsigned int i = 0U; i < P25_LDU_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = P25_START_SYNC;
}
@ -227,8 +242,10 @@ void P25TX::createCal()
m_poPtr = 0U;
}
/* Helper to write a raw byte to the DAC. */
/// <summary>
///
/// </summary>
/// <param name="c"></param>
void P25TX::writeByte(uint8_t c)
{
uint8_t bit;
@ -244,8 +261,9 @@ void P25TX::writeByte(uint8_t c)
}
}
/* */
/// <summary>
///
/// </summary>
void P25TX::writeSilence()
{
uint8_t bit;
@ -254,3 +272,5 @@ void P25TX::writeSilence()
io.write(&bit, 1);
}
}
#endif // defined(ENABLE_P25)

@ -1,26 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Hotspot Firmware
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2016,2017 Andy Uribe, CA6JAU
* Copyright (C) 2021-2022 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file P25TX.h
* @ingroup p25_hfw
* @file P25TX.cpp
* @ingroup p25_hfw
*/
* Digital Voice Modem - DSP Firmware (Hotspot)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / DSP Firmware (Hotspot)
*
*/
//
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* Copyright (C) 2021-2022 by Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__P25_TX_H__)
#define __P25_TX_H__
#include "Defines.h"
#include "SerialBuffer.h"
#if defined(ENABLE_P25)
namespace p25
{
// ---------------------------------------------------------------------------
@ -30,74 +46,38 @@ namespace p25
#define P25_FIXED_DELAY 90 // 90 = 20ms
#define P25_FIXED_TX_HANG 750 // 750 = 625ms
/**
* @brief P25 Transmitter State
* @ingroup p25_hfw
*/
enum P25TXSTATE {
P25TXSTATE_NORMAL, //! Normal
P25TXSTATE_CAL //! Calibration
P25TXSTATE_NORMAL,
P25TXSTATE_CAL
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements transmitter logic for P25 mode operation.
// ---------------------------------------------------------------------------
/**
* @brief Implements transmitter logic for P25 mode operation.
* @ingroup p25_hfw
*/
class DSP_FW_API P25TX {
public:
/**
* @brief Initializes a new instance of the P25TX class.
*/
/// <summary>Initializes a new instance of the P25TX class.</summary>
P25TX();
/**
* @brief Process local buffer and transmit on the air interface.
*/
/// <summary>Process local buffer and transmit on the air interface.</summary>
void process();
/**
* @brief Write data to the local buffer.
* @param[in] data Buffer.
* @param length Length of buffer.
* @returns uint8_t Reason code.
*/
uint8_t writeData(const uint8_t* data, uint16_t length);
/**
* @brief Clears the local buffer.
*/
/// <summary>Write data to the local buffer.</summary>
uint8_t writeData(const uint8_t* data, uint8_t length);
/// <summary>Clears the local buffer.</summary>
void clear();
/**
* @brief Sets the FDMA preamble count.
* @param preambleCnt FDMA preamble count.
*/
/// <summary>Sets the FDMA preamble count.</summary>
void setPreambleCount(uint8_t preambleCnt);
/**
* @brief Sets the transmit hang time.
* @param txHang Transmit hang time.
*/
/// <summary>Sets the transmit hang time.</summary>
void setTxHang(uint8_t txHang);
/**
* @brief Helper to set the calibration state for Tx.
* @param start
*/
/// <summary>Helper to set the calibration state for Tx.</summary>
void setCal(bool start);
/**
* @brief Helper to resize the FIFO buffer.
* @param size
*/
void resizeBuffer(uint16_t size);
/**
* @brief Helper to get how much space the ring buffer has for samples.
* @returns uint8_t Amount of space in ring buffer for samples.
*/
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
uint8_t getSpace() const;
private:
@ -113,25 +93,18 @@ namespace p25
uint32_t m_txHang;
uint32_t m_tailCnt;
/**
* @brief Helper to generate data.
*/
/// <summary></summary>
void createData();
/**
* @brief Helper to generate calibration data.
*/
/// <summary></summary>
void createCal();
/**
* @brief Helper to write a raw byte to the DAC.
* @param c Byte.
*/
/// <summary></summary>
void writeByte(uint8_t c);
/**
* @brief
*/
/// <summary></summary>
void writeSilence();
};
} // namespace p25
#endif // defined(ENABLE_P25)
#endif // __P25_TX_H__

@ -0,0 +1,26 @@
/*
* Copyright (C) 2016-2018 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Memory areas */
MEMORY
{
ROM (rx) : ORIGIN = 0x08002000, LENGTH = 120K /* FLASH */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* Main RAM */
}
INCLUDE stm32f10x_link.ld
Loading…
Cancel
Save

Powered by TurnKey Linux.