Support for MMDVMCal and external deviation adjustment by MMDVM.ini

This commit is contained in:
Andy CA6JAU 2018-02-15 14:27:04 -03:00
parent 0256d3ce01
commit a41caa3277
11 changed files with 388 additions and 68 deletions

View file

@ -43,6 +43,12 @@ uint32_t ADF7021_REG1;
uint32_t div2;
uint32_t f_div;
uint16_t m_dstarDev;
uint16_t m_dmrDev;
uint16_t m_ysfDev;
uint16_t m_p25Dev;
uint16_t m_nxdnDev;
static void Send_AD7021_control_shift()
{
int AD7021_counter;
@ -327,7 +333,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_DSTAR << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b00 << 28; // clock normal
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_DSTAR / div2)<< 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_dstarDev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b001 << 4; // modulation (GMSK)
break;
@ -350,7 +356,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_DMR << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_DMR / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_dmrDev / div2) << 19; // deviation
#if defined(ADF7021_DISABLE_RC_4FSK)
ADF7021_REG2 |= (uint32_t) 0b011 << 4; // modulation (4FSK)
#else
@ -377,7 +383,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
ADF7021_REG13 |= (uint32_t) (m_LoDevYSF ? ADF7021_SLICER_TH_YSF_L : ADF7021_SLICER_TH_YSF_H) << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) ((m_LoDevYSF ? ADF7021_DEV_YSF_L : ADF7021_DEV_YSF_H) / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_ysfDev / div2) << 19; // deviation
#if defined(ADF7021_DISABLE_RC_4FSK)
ADF7021_REG2 |= (uint32_t) 0b011 << 4; // modulation (4FSK)
#else
@ -404,7 +410,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_P25 << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_P25 / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_p25Dev / div2) << 19; // deviation
#if defined(ENABLE_P25_WIDE) || defined(ADF7021_DISABLE_RC_4FSK)
ADF7021_REG2 |= (uint32_t) 0b011 << 4; // modulation (4FSK)
#else
@ -431,7 +437,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_NXDN << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_NXDN / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_nxdnDev / div2) << 19; // deviation
#if defined(ADF7021_DISABLE_RC_4FSK)
ADF7021_REG2 |= (uint32_t) 0b011 << 4; // modulation (4FSK)
#else
@ -551,7 +557,7 @@ void CIO::ifConf2(MMDVM_STATE modemState)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_DSTAR << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b00 << 28; // clock normal
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_DSTAR / div2)<< 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_dstarDev / div2)<< 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b001 << 4; // modulation (GMSK)
break;
@ -574,7 +580,7 @@ void CIO::ifConf2(MMDVM_STATE modemState)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_DMR << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_DMR / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_dmrDev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
break;
@ -597,7 +603,7 @@ void CIO::ifConf2(MMDVM_STATE modemState)
ADF7021_REG13 |= (uint32_t) (m_LoDevYSF ? ADF7021_SLICER_TH_YSF_L : ADF7021_SLICER_TH_YSF_H) << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) ((m_LoDevYSF ? ADF7021_DEV_YSF_L : ADF7021_DEV_YSF_H) / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_ysfDev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
break;
@ -620,7 +626,7 @@ void CIO::ifConf2(MMDVM_STATE modemState)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_P25 << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_P25 / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_p25Dev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
break;
@ -643,7 +649,7 @@ void CIO::ifConf2(MMDVM_STATE modemState)
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_NXDN << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (ADF7021_DEV_NXDN / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) (m_nxdnDev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
break;
@ -883,6 +889,35 @@ void CIO::setPower(uint8_t power)
m_power = power >> 2;
}
void CIO::setDeviations(uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, bool ysfLoDev)
{
m_dstarDev = uint16_t((ADF7021_DEV_DSTAR * uint16_t(dstarTXLevel)) / 128U);
m_dmrDev = uint16_t((ADF7021_DEV_DMR * uint16_t(dmrTXLevel)) / 128U);
if (ysfLoDev)
m_ysfDev = uint16_t((ADF7021_DEV_YSF_L * uint16_t(ysfTXLevel)) / 128U);
else
m_ysfDev = uint16_t((ADF7021_DEV_YSF_H * uint16_t(ysfTXLevel)) / 128U);
m_p25Dev = uint16_t((ADF7021_DEV_P25 * uint16_t(p25TXLevel)) / 128U);
m_nxdnDev = uint16_t((ADF7021_DEV_NXDN * uint16_t(nxdnTXLevel)) / 128U);
}
void CIO::updateCal()
{
uint32_t ADF7021_REG2;
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (m_dmrDev / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
ADF7021_REG2 |= (uint32_t) 0b0010; // register 2
ADF7021_REG2 |= (uint32_t) m_power << 13; // power level
ADF7021_REG2 |= (uint32_t) 0b110001 << 7; // PA
AD7021_control_word = ADF7021_REG2;
Send_AD7021_control();
}
uint32_t CIO::RXfreq()
{
return (uint32_t)((float)(ADF7021_PFD / f_div) * ((float)((32768 * m_RX_N_divider) + m_RX_F_divider) / 32768.0)) + 100000;
@ -895,32 +930,27 @@ uint32_t CIO::TXfreq()
uint16_t CIO::devDSTAR()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_DSTAR) / (f_div * 65536));
return (uint16_t)((ADF7021_PFD * m_dstarDev) / (f_div * 65536));
}
uint16_t CIO::devDMR()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_DMR) / (f_div * 65536));
return (uint16_t)((ADF7021_PFD * m_dmrDev) / (f_div * 65536));
}
uint16_t CIO::devYSF_H()
uint16_t CIO::devYSF()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_YSF_H) / (f_div * 65536));
}
uint16_t CIO::devYSF_L()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_YSF_L) / (f_div * 65536));
return (uint16_t)((ADF7021_PFD * m_ysfDev) / (f_div * 65536));
}
uint16_t CIO::devP25()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_P25) / (f_div * 65536));
return (uint16_t)((ADF7021_PFD * m_p25Dev) / (f_div * 65536));
}
uint16_t CIO::devNXDN()
{
return (uint16_t)((ADF7021_PFD * ADF7021_DEV_NXDN) / (f_div * 65536));
return (uint16_t)((ADF7021_PFD * m_nxdnDev) / (f_div * 65536));
}
void CIO::printConf()
@ -931,8 +961,7 @@ void CIO::printConf()
DEBUG2("Power set:", m_power);
DEBUG2("D-Star dev (Hz):", devDSTAR());
DEBUG2("DMR +1 sym dev (Hz):", devDMR());
DEBUG2("YSF_H +1 sym dev (Hz):", devYSF_H());
DEBUG2("YSF_L +1 sym dev (Hz):", devYSF_L());
DEBUG2("YSF +1 sym dev (Hz):", devYSF());
DEBUG2("P25 +1 sym dev (Hz):", devP25());
DEBUG2("NXDN +1 sym dev (Hz):", devNXDN());
}

137
CalDMR.cpp Normal file
View file

@ -0,0 +1,137 @@
/*
* 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.
*/
#include "Config.h"
#include "Globals.h"
#include "CalDMR.h"
// 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};
// 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};
// 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};
// Embedded LC MS: CC: 1, srcID: 1, dstID: TG9
const uint8_t SYNCEMB_DMO1K[6][7] = {
{0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U}, // MS 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)
CCalDMR::CCalDMR() :
m_transmit(false),
m_state(DMRCAL1K_IDLE),
m_dmr1k(),
m_audioSeq(0)
{
::memcpy(m_dmr1k, VOICE_1K, DMR_FRAME_LENGTH_BYTES + 1U);
}
void CCalDMR::process()
{
switch (m_calState) {
case STATE_DMRCAL:
if (m_transmit) {
dmrDMOTX.setCal(true);
dmrDMOTX.process();
} else {
dmrDMOTX.setCal(false);
}
break;
case STATE_DMRDMO1K:
dmrdmo1k();
break;
default:
break;
}
}
void CCalDMR::createDataDMO1k(uint8_t n)
{
for(uint8_t i = 0; i < 5U; i++)
m_dmr1k[i + 15U] = SYNCEMB_DMO1K[n][i + 1U];
m_dmr1k[14U] &= 0xF0U;
m_dmr1k[20U] &= 0x0FU;
m_dmr1k[14U] |= SYNCEMB_DMO1K[n][0] & 0x0FU;
m_dmr1k[20U] |= SYNCEMB_DMO1K[n][6] & 0xF0U;
}
void CCalDMR::dmrdmo1k()
{
dmrDMOTX.process();
uint16_t space = dmrDMOTX.getSpace();
if (space < 1U)
return;
switch (m_state) {
case DMRCAL1K_VH:
dmrDMOTX.writeData(VH_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRCAL1K_VOICE;
break;
case DMRCAL1K_VOICE:
createDataDMO1k(m_audioSeq);
dmrDMOTX.writeData(m_dmr1k, DMR_FRAME_LENGTH_BYTES + 1U);
if(m_audioSeq == 5U) {
m_audioSeq = 0U;
if(!m_transmit)
m_state = DMRCAL1K_VT;
} else
m_audioSeq++;
break;
case DMRCAL1K_VT:
dmrDMOTX.writeData(VT_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRCAL1K_IDLE;
break;
default:
m_state = DMRCAL1K_IDLE;
m_audioSeq = 0U;
break;
}
}
uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
{
if (length != 1U)
return 4U;
m_transmit = data[0U] == 1U;
if (m_transmit && m_state == DMRCAL1K_IDLE && m_calState == STATE_DMRDMO1K)
m_state = DMRCAL1K_VH;
return 0U;
}

53
CalDMR.h Normal file
View file

@ -0,0 +1,53 @@
/*
* 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(CALDMR_H)
#define CALDMR_H
#include "Config.h"
#include "DMRDefines.h"
enum DMRCAL1K {
DMRCAL1K_IDLE,
DMRCAL1K_VH,
DMRCAL1K_VOICE,
DMRCAL1K_VT,
DMRCAL1K_WAIT
};
class CCalDMR {
public:
CCalDMR();
void process();
void dmrdmo1k();
void createDataDMO1k(uint8_t n);
uint8_t write(const uint8_t* data, uint8_t length);
private:
bool m_transmit;
DMRCAL1K m_state;
uint8_t m_dmr1k[DMR_FRAME_LENGTH_BYTES + 1U];
uint8_t m_audioSeq;
};
#endif

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* Copyright (C) 2016,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
@ -29,12 +29,21 @@ m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(240U), // 200ms
m_count(0U)
m_count(0U),
m_delay(false),
m_cal(false)
{
}
void CDMRDMOTX::process()
{
if (m_cal) {
if (m_poLen == 0U) {
m_delay = false;
createCal();
}
}
else {
if (m_poLen == 0U && m_fifo.getData() > 0U) {
if (!m_tx) {
m_delay = true;
@ -48,9 +57,9 @@ void CDMRDMOTX::process()
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
m_poBuffer[i] = m_fifo.get();
}
m_poPtr = 0U;
}
}
if (m_poLen > 0U) {
uint16_t space = io.getSpace();
@ -72,7 +81,6 @@ void CDMRDMOTX::process()
}
}
}
}
uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length)
@ -105,6 +113,25 @@ void CDMRDMOTX::writeByte(uint8_t c)
}
}
void CDMRDMOTX::setCal(bool start)
{
m_cal = start ? true : false;
}
void CDMRDMOTX::createCal()
{
// 1.2 kHz sine wave generation
if (m_calState == STATE_DMRCAL) {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = 0x5FU; // +3, +3, -3, -3 pattern for deviation cal.
}
m_poLen = DMR_FRAME_LENGTH_BYTES;
}
m_poPtr = 0U;
}
uint16_t CDMRDMOTX::getSpace() const
{
return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* Copyright (C) 2016,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
@ -33,6 +33,8 @@ public:
void process();
void setCal(bool start);
void setTXDelay(uint8_t delay);
uint16_t getSpace() const;
@ -45,8 +47,11 @@ private:
uint16_t m_txDelay;
uint32_t m_count;
bool m_delay;
bool m_cal;
void writeByte(uint8_t c);
void createCal();
};
#endif

View file

@ -42,7 +42,10 @@ enum MMDVM_STATE {
STATE_NXDN = 5,
// Dummy states start at 90
STATE_CWID = 97
STATE_DMRDMO1K = 92,
STATE_CWID = 97,
STATE_DMRCAL = 98,
STATE_DSTARCAL = 99
};
const uint8_t MARK_SLOT1 = 0x08U;
@ -72,6 +75,7 @@ const uint8_t MARK_NONE = 0x00U;
#include "NXDNRX.h"
#include "NXDNTX.h"
#include "CWIdTX.h"
#include "CalDMR.h"
#include "Debug.h"
#include "Utils.h"
@ -79,6 +83,7 @@ const uint16_t TX_RINGBUFFER_SIZE = 1024U;
const uint16_t RX_RINGBUFFER_SIZE = 1024U;
extern MMDVM_STATE m_modemState;
extern MMDVM_STATE m_calState;
extern MMDVM_STATE m_modemState_prev;
extern bool m_cwid_state;
@ -123,6 +128,8 @@ extern CP25TX p25TX;
extern CNXDNRX nxdnRX;
extern CNXDNTX nxdnTX;
extern CCalDMR calDMR;
extern CCWIdTX cwIdTX;
#endif

5
IO.h
View file

@ -110,6 +110,8 @@ public:
#endif
void start(void);
void startInt(void);
void setDeviations(uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, bool ysfLoDev);
void updateCal(void);
#if defined(SEND_RSSI_DATA)
uint16_t readRSSI(void);
@ -124,8 +126,7 @@ public:
uint32_t TXfreq(void);
uint16_t devDSTAR(void);
uint16_t devDMR(void);
uint16_t devYSF_H(void);
uint16_t devYSF_L(void);
uint16_t devYSF(void);
uint16_t devP25(void);
uint16_t devNXDN(void);
void printConf();

View file

@ -27,6 +27,7 @@
// Global variables
MMDVM_STATE m_modemState = STATE_IDLE;
MMDVM_STATE m_calState = STATE_IDLE;
MMDVM_STATE m_modemState_prev = STATE_IDLE;
bool m_cwid_state = false;
@ -68,6 +69,8 @@ CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDMR calDMR;
CCWIdTX cwIdTX;
CSerialPort serial;
@ -88,7 +91,7 @@ void loop()
if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process();
if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_dmrEnable && m_modemState == STATE_DMR && m_calState == STATE_IDLE) {
#if defined(DUPLEX)
if (m_duplex)
dmrTX.process();
@ -108,6 +111,9 @@ void loop()
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_calState == STATE_DMRCAL || m_calState == STATE_DMRDMO1K)
calDMR.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}

View file

@ -23,6 +23,7 @@
// Global variables
MMDVM_STATE m_modemState = STATE_IDLE;
MMDVM_STATE m_calState = STATE_IDLE;
MMDVM_STATE m_modemState_prev = STATE_IDLE;
bool m_cwid_state = false;
@ -64,6 +65,8 @@ CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDMR calDMR;
CCWIdTX cwIdTX;
CSerialPort serial;
@ -83,7 +86,7 @@ void loop()
if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process();
if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_dmrEnable && m_modemState == STATE_DMR && m_calState == STATE_IDLE) {
#if defined(DUPLEX)
if (m_duplex)
dmrTX.process();
@ -103,6 +106,9 @@ void loop()
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_calState == STATE_DMRCAL || m_calState == STATE_DMRDMO1K)
calDMR.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}

View file

@ -75,7 +75,8 @@ CSerialPort::CSerialPort() :
m_buffer(),
m_ptr(0U),
m_len(0U),
m_debug(false)
m_debug(false),
m_firstCal(false)
{
}
@ -219,7 +220,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
MMDVM_STATE modemState = MMDVM_STATE(data[3U]);
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN)
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_DMRDMO1K)
return 4U;
if (modemState == STATE_DSTAR && !dstarEnable)
return 4U;
@ -242,7 +243,16 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
m_cwIdTXLevel = data[5U]>>2;
m_modemState = modemState;
uint8_t dstarTXLevel = data[9U];
uint8_t dmrTXLevel = data[10U];
uint8_t ysfTXLevel = data[11U];
uint8_t p25TXLevel = data[12U];
uint8_t nxdnTXLevel = 128U;
if (length >= 16U)
nxdnTXLevel = data[15U];
io.setDeviations(dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, ysfLoDev);
m_dstarEnable = dstarEnable;
m_dmrEnable = dmrEnable;
@ -250,6 +260,18 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
m_p25Enable = p25Enable;
m_nxdnEnable = nxdnEnable;
if (modemState == STATE_DMRCAL || modemState == STATE_DMRDMO1K) {
m_dmrEnable = true;
m_modemState = STATE_DMR;
m_calState = modemState;
if (m_firstCal)
io.updateCal();
}
else {
m_modemState = modemState;
m_calState = STATE_IDLE;
}
m_duplex = !simplex;
dstarTX.setTXDelay(txDelay);
@ -269,6 +291,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
io.setLoDevYSF(ysfLoDev);
if (!m_firstCal || (modemState != STATE_DMRCAL && modemState != STATE_DMRDMO1K)) {
if(m_dstarEnable)
io.ifConf(STATE_DSTAR, true);
else if(m_dmrEnable)
@ -279,10 +302,14 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
io.ifConf(STATE_P25, true);
else if(m_nxdnEnable)
io.ifConf(STATE_NXDN, true);
}
io.start();
io.printConf();
if (modemState == STATE_DMRCAL || modemState == STATE_DMRDMO1K)
m_firstCal = true;
return 0U;
}
@ -292,11 +319,12 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
return 4U;
MMDVM_STATE modemState = MMDVM_STATE(data[0U]);
MMDVM_STATE tmpState;
if (modemState == m_modemState)
return 0U;
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN)
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_DMRDMO1K)
return 4U;
if (modemState == STATE_DSTAR && !m_dstarEnable)
return 4U;
@ -309,7 +337,19 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
if (modemState == STATE_NXDN && !m_nxdnEnable)
return 4U;
setMode(modemState);
if (modemState == STATE_DMRCAL || modemState == STATE_DMRDMO1K) {
m_dmrEnable = true;
tmpState = STATE_DMR;
m_calState = modemState;
if (m_firstCal)
io.updateCal();
}
else {
tmpState = modemState;
m_calState = STATE_IDLE;
}
setMode(tmpState);
return 0U;
}
@ -490,6 +530,14 @@ void CSerialPort::process()
break;
case MMDVM_CAL_DATA:
if (m_calState == STATE_DMRCAL || m_calState == STATE_DMRDMO1K)
err = calDMR.write(m_buffer + 3U, m_len - 3U);
if (err == 0U) {
sendACK();
} else {
DEBUG2("Received invalid calibration data", err);
sendNAK(err);
}
break;
case MMDVM_SEND_CWID:

View file

@ -60,6 +60,7 @@ private:
uint8_t m_ptr;
uint8_t m_len;
bool m_debug;
bool m_firstCal;
void sendACK();
void sendNAK(uint8_t err);