From a41caa3277d85a31c0dea23b573d7a598fd8fbd7 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Thu, 15 Feb 2018 14:27:04 -0300 Subject: [PATCH] Support for MMDVMCal and external deviation adjustment by MMDVM.ini --- ADF7021.cpp | 81 +++++++++++++++++++---------- CalDMR.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ CalDMR.h | 53 +++++++++++++++++++ DMRDMOTX.cpp | 57 ++++++++++++++------ DMRDMOTX.h | 7 ++- Globals.h | 9 +++- IO.h | 7 +-- MMDVM_HS.cpp | 8 ++- MMDVM_HS.ino | 8 ++- SerialPort.cpp | 88 +++++++++++++++++++++++-------- SerialPort.h | 1 + 11 files changed, 388 insertions(+), 68 deletions(-) create mode 100644 CalDMR.cpp create mode 100644 CalDMR.h diff --git a/ADF7021.cpp b/ADF7021.cpp index e9d81b9..0bd4a7a 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -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; @@ -323,11 +329,11 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) ADF7021_REG4 |= (uint32_t) ADF7021_POST_BW_DSTAR << 20; // Post dem BW ADF7021_REG4 |= (uint32_t) 0b00 << 30; // IF filter (12.5 kHz) - ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 + ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 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 @@ -506,7 +512,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) #if defined(TEST_TX) PTT_pin(HIGH); - AD7021_control_word = ADF7021_TX_REG0; + AD7021_control_word = ADF7021_TX_REG0; Send_AD7021_control(); // TEST MODE (TX carrier only) (15) AD7021_control_word = 0x000E010F; @@ -547,11 +553,11 @@ void CIO::ifConf2(MMDVM_STATE modemState) ADF7021_REG4 |= (uint32_t) ADF7021_POST_BW_DSTAR << 20; // Post dem BW ADF7021_REG4 |= (uint32_t) 0b00 << 30; // IF filter (12.5 kHz) - ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 + ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13 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()); } diff --git a/CalDMR.cpp b/CalDMR.cpp new file mode 100644 index 0000000..c5bc3ec --- /dev/null +++ b/CalDMR.cpp @@ -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; +} + diff --git a/CalDMR.h b/CalDMR.h new file mode 100644 index 0000000..33fec17 --- /dev/null +++ b/CalDMR.h @@ -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 + diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 524749a..deb4ff8 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -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,27 +29,36 @@ 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_poLen == 0U && m_fifo.getData() > 0U) { - if (!m_tx) { - m_delay = true; - m_poLen = m_txDelay; - } else { + if (m_cal) { + if (m_poLen == 0U) { m_delay = false; - - for (unsigned int i = 0U; i < 72U; i++) - m_poBuffer[m_poLen++] = DMR_SYNC; - - for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_fifo.get(); + createCal(); } + } + else { + if (m_poLen == 0U && m_fifo.getData() > 0U) { + if (!m_tx) { + m_delay = true; + m_poLen = m_txDelay; + } else { + m_delay = false; - m_poPtr = 0U; + for (unsigned int i = 0U; i < 72U; i++) + m_poBuffer[m_poLen++] = DMR_SYNC; + + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_fifo.get(); + } + m_poPtr = 0U; + } } if (m_poLen > 0U) { @@ -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); diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 585e565..010ba99 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -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 diff --git a/Globals.h b/Globals.h index a64a1df..45ef0ed 100644 --- a/Globals.h +++ b/Globals.h @@ -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 diff --git a/IO.h b/IO.h index 2c610a8..4ca2bb3 100644 --- a/IO.h +++ b/IO.h @@ -110,7 +110,9 @@ 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); #endif @@ -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(); diff --git a/MMDVM_HS.cpp b/MMDVM_HS.cpp index 728d8dc..4e8704e 100644 --- a/MMDVM_HS.cpp +++ b/MMDVM_HS.cpp @@ -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(); } diff --git a/MMDVM_HS.ino b/MMDVM_HS.ino index 0ae28c2..e24037d 100644 --- a/MMDVM_HS.ino +++ b/MMDVM_HS.ino @@ -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(); } diff --git a/SerialPort.cpp b/SerialPort.cpp index 8d4e9f9..2a590ea 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -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,14 +243,35 @@ 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; m_ysfEnable = ysfEnable; 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); @@ -268,21 +290,26 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) dmrDMORX.setColorCode(colorCode); io.setLoDevYSF(ysfLoDev); - - if(m_dstarEnable) - io.ifConf(STATE_DSTAR, true); - else if(m_dmrEnable) - io.ifConf(STATE_DMR, true); - else if(m_ysfEnable) - io.ifConf(STATE_YSF, true); - else if(m_p25Enable) - io.ifConf(STATE_P25, true); - else if(m_nxdnEnable) - io.ifConf(STATE_NXDN, true); - + + if (!m_firstCal || (modemState != STATE_DMRCAL && modemState != STATE_DMRDMO1K)) { + if(m_dstarEnable) + io.ifConf(STATE_DSTAR, true); + else if(m_dmrEnable) + io.ifConf(STATE_DMR, true); + else if(m_ysfEnable) + io.ifConf(STATE_YSF, true); + else if(m_p25Enable) + 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: @@ -710,7 +758,7 @@ void CSerialPort::process() m_ptr = 0U; m_len = 0U; } - + #if defined(SERIAL_REPEATER) || defined(SERIAL_REPEATER_USART1) // Drain any incoming serial data while (availableInt(3U)) diff --git a/SerialPort.h b/SerialPort.h index 2ee9765..23ad071 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -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);