diff --git a/FM.cpp b/FM.cpp index d3e9a1a..33938d8 100644 --- a/FM.cpp +++ b/FM.cpp @@ -39,6 +39,7 @@ m_hangTimer(), m_filterStage1( 724, 1448, 724, 32768, -37895, 21352), m_filterStage2(32768, 0,-32768, 32768, -50339, 19052), m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460), +m_blanking(), m_useCOS(true), m_rxBoost(1U) { @@ -78,7 +79,9 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) } // Only let audio through when relaying audio - if (m_state != FS_RELAYING && m_state != FS_KERCHUNK) + if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) + currentSample = m_blanking.process(currentSample); + else currentSample = 0U; currentSample *= m_rxBoost; @@ -141,7 +144,7 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_ return m_rfAck.setParams(rfAck, speed, frequency, level, level); } -uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost) +uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost, uint8_t maxDev) { m_useCOS = useCOS; m_rxBoost = q15_t(rxBoost); @@ -151,6 +154,7 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque m_hangTimer.setTimeout(hangTime, 0U); m_timeoutTone.setParams(timeoutLevel); + m_blanking.setParams(maxDev, timeoutLevel); uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssThreshold); if (ret != 0U) diff --git a/FM.h b/FM.h index e451ed6..ad75877 100644 --- a/FM.h +++ b/FM.h @@ -21,6 +21,7 @@ #include "Config.h" +#include "FMBlanking.h" #include "FMCTCSSRX.h" #include "FMCTCSSTX.h" #include "FMTimeout.h" @@ -53,7 +54,7 @@ public: uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd); uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level); - uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost); + uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, uint8_t rxBoost, uint8_t maxDev); private: CFMKeyer m_callsign; @@ -74,6 +75,7 @@ private: CFMDirectFormI m_filterStage1; CFMDirectFormI m_filterStage2; CFMDirectFormI m_filterStage3; + CFMBlanking m_blanking; bool m_useCOS; q15_t m_rxBoost; diff --git a/FMBlanking.cpp b/FMBlanking.cpp new file mode 100644 index 0000000..4d8af80 --- /dev/null +++ b/FMBlanking.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "FMBlanking.h" + +// 2000 Hz sine wave at 24000 Hz sample rate +const q31_t TONE[] = {0, 16384, 28378, 32767, 28378, 16384, 0, -16383, -28377, -32767, -28377, -16383}; + +const uint8_t TONE_LEN = 12U; + +const uint32_t BLEEP_LEN = 2400U; // 100ms + +CFMBlanking::CFMBlanking() : +m_posValue(0), +m_negValue(0), +m_level(128 * 128), +m_running(false), +m_pos(0U), +m_n(0U) +{ +} + +void CFMBlanking::setParams(uint8_t value, uint8_t level) +{ + m_posValue = q15_t(value * 128); + m_negValue = -m_posValue; + + m_level = q15_t(level * 128); +} + +q15_t CFMBlanking::process(q15_t sample) +{ + if (m_posValue == 0) + return sample; + + if (!m_running) { + if (sample >= m_posValue) { + m_running = true; + m_pos = 0U; + m_n = 0U; + } else if (sample <= m_negValue) { + m_running = true; + m_pos = 0U; + m_n = 0U; + } + } + + if (!m_running) + return sample; + + if (m_pos <= BLEEP_LEN) { + q31_t value = TONE[m_n++] * m_level; + sample = q15_t(__SSAT((value >> 15), 16)); + if (m_n >= TONE_LEN) + m_n = 0U; + } else { + sample = 0; + } + + m_pos++; + if (m_pos >= 12000U) + m_running = false; + + return sample; +} diff --git a/FMBlanking.h b/FMBlanking.h new file mode 100644 index 0000000..2aacd4c --- /dev/null +++ b/FMBlanking.h @@ -0,0 +1,41 @@ +/* + * 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(FMBlanking_H) +#define FMBlanking_H + +#include "Config.h" + +class CFMBlanking { +public: + CFMBlanking(); + + void setParams(uint8_t value, uint8_t level); + + q15_t process(q15_t sample); + +private: + q15_t m_posValue; + q15_t m_negValue; + q15_t m_level; + bool m_running; + uint32_t m_pos; + uint8_t m_n; +}; + +#endif diff --git a/SerialPort.cpp b/SerialPort.cpp index aa71f32..4b0b5bc 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -408,7 +408,7 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length) uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) { - if (length < 9U) + if (length < 10U) return 4U; uint16_t timeout = data[0U] * 5U; @@ -424,8 +424,9 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) bool useCOS = (data[7U] & 0x01U) == 0x01U; uint8_t rxBoost = data[8U]; + uint8_t maxDev = data[9U]; - return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, rxBoost); + return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, rxBoost, maxDev); } uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)