diff --git a/FM.cpp b/FM.cpp index 4ac7117..bfb81cf 100644 --- a/FM.cpp +++ b/FM.cpp @@ -51,13 +51,14 @@ m_useCOS(true), m_cosInvert(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), -m_downsampler(128U), //Size might need adjustement +m_downsampler(128U),//Size might need adjustement m_extEnabled(false), -m_rxLevel(1) +m_rxLevel(1), +m_outputRB(2400U) // 100ms of audio { } -void CFM::samples(bool cos, q15_t* samples, uint8_t length) +void CFM::samples(bool cos, const q15_t* samples, uint8_t length) { if (m_useCOS) { if (m_cosInvert) @@ -135,15 +136,34 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) currentSample += m_ctcssTX.getAudio(); - samples[i] = currentSample; + if (m_modemState == STATE_FM) + m_outputRB.put(currentSample); } - - if (m_modemState == STATE_FM) - io.write(STATE_FM, samples, i);//only write the actual number of processed samples to IO } void CFM::process() { + if (m_modemState != STATE_FM) + return; + + uint16_t length = m_outputRB.getData(); + if (length == 0U) + return; + + uint16_t space = io.getSpace(); + if (space < 3U) + return; + + space -= 2U; + + if (space < length) + length = space; + + for (uint16_t i = 0U; i < length; i++) { + q15_t sample; + m_outputRB.get(sample); + io.write(STATE_FM, &sample, 1U); + } } void CFM::reset() @@ -162,6 +182,8 @@ void CFM::reset() m_extAck.stop(); m_callsign.stop(); m_timeoutTone.stop(); + + m_outputRB.reset(); } uint8_t CFM::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, bool callsignAtLatch) @@ -328,6 +350,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } + insertSilence(50U); + beginRelaying(); m_callsignTimer.start(); @@ -664,3 +688,11 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) return 0U; } + +void CFM::insertSilence(uint16_t ms) +{ + uint32_t nSamples = ms * 24U; + + for (uint32_t i = 0U; i < nSamples; i++) + m_outputRB.put(0); +} diff --git a/FM.h b/FM.h index aff5c48..1bf6cf1 100644 --- a/FM.h +++ b/FM.h @@ -27,6 +27,7 @@ #include "FMTimeout.h" #include "FMKeyer.h" #include "FMTimer.h" +#include "FMRB.h" #include "FMDirectForm1.h" #include "FMDownsampler.h" @@ -50,7 +51,7 @@ class CFM { public: CFM(); - void samples(bool cos, q15_t* samples, uint8_t length); + void samples(bool cos, const q15_t* samples, uint8_t length); void process(); @@ -94,6 +95,7 @@ private: CFMDownsampler m_downsampler; bool m_extEnabled; q15_t m_rxLevel; + CFMRB m_outputRB; void stateMachine(bool validRFSignal, bool validExtSignal); void listeningState(bool validRFSignal, bool validExtSignal); @@ -113,6 +115,7 @@ private: void sendCallsign(); void beginRelaying(); + void insertSilence(uint16_t ms); }; #endif diff --git a/FMDownsampleRB.h b/FMDownsampleRB.h index 6e8e466..df60daf 100644 --- a/FMDownsampleRB.h +++ b/FMDownsampleRB.h @@ -16,8 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(FMRB_H) -#define FMRB_H +#if !defined(FMDOWNSAMPLERB_H) +#define FMDOWNSAMPLERB_H #if defined(STM32F4XX) #include "stm32f4xx.h" diff --git a/FMDownsampler.h b/FMDownsampler.h index ad822a8..6c5fd03 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -40,4 +40,4 @@ private: uint8_t m_downSampleIndex; }; -#endif \ No newline at end of file +#endif diff --git a/FMRB.cpp b/FMRB.cpp new file mode 100644 index 0000000..0d8c6ef --- /dev/null +++ b/FMRB.cpp @@ -0,0 +1,110 @@ +/* +TX fifo control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX + +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 "FMRB.h" + +CFMRB::CFMRB(uint16_t length) : +m_length(length), +m_head(0U), +m_tail(0U), +m_full(false), +m_overflow(false) +{ + m_samples = new q15_t[length]; +} + +uint16_t CFMRB::getSpace() const +{ + uint16_t n = 0U; + + if (m_tail == m_head) + n = m_full ? 0U : m_length; + else if (m_tail < m_head) + n = m_length - m_head + m_tail; + else + n = m_tail - m_head; + + if (n > m_length) + n = 0U; + + return n; +} + +uint16_t CFMRB::getData() const +{ + if (m_tail == m_head) + return m_full ? m_length : 0U; + else if (m_tail < m_head) + return m_head - m_tail; + else + return m_length - m_tail + m_head; +} + +bool CFMRB::put(q15_t sample) +{ + if (m_full) { + m_overflow = true; + return false; + } + + m_samples[m_head] = sample; + + m_head++; + if (m_head >= m_length) + m_head = 0U; + + if (m_head == m_tail) + m_full = true; + + return true; +} + +bool CFMRB::get(q15_t& sample) +{ + if (m_head == m_tail && !m_full) + return false; + + sample = m_samples[m_tail]; + + m_full = false; + + m_tail++; + if (m_tail >= m_length) + m_tail = 0U; + + return true; +} + +bool CFMRB::hasOverflowed() +{ + bool overflow = m_overflow; + + m_overflow = false; + + return overflow; +} + +void CFMRB::reset() +{ + m_head = 0U; + m_tail = 0U; + m_full = false; + m_overflow = false; +} diff --git a/FMRB.h b/FMRB.h new file mode 100644 index 0000000..7cf6cf4 --- /dev/null +++ b/FMRB.h @@ -0,0 +1,72 @@ +/* +Serial fifo control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX + +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(FMRB_H) +#define FMRB_H + +#if defined(STM32F4XX) +#include "stm32f4xx.h" +#elif defined(STM32F7XX) +#include "stm32f7xx.h" +#elif defined(STM32F105xC) +#include "stm32f1xx.h" +#include +#else +#include +#endif + +#if defined(__SAM3X8E__) || defined(STM32F105xC) +#define ARM_MATH_CM3 +#elif defined(STM32F7XX) +#define ARM_MATH_CM7 +#elif defined(STM32F4XX) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) +#define ARM_MATH_CM4 +#else +#error "Unknown processor type" +#endif + +#include + +class CFMRB { +public: + CFMRB(uint16_t length); + + uint16_t getSpace() const; + + uint16_t getData() const; + + bool put(q15_t sample); + + bool get(q15_t& sample); + + bool hasOverflowed(); + + void reset(); + +private: + uint16_t m_length; + volatile q15_t* m_samples; + volatile uint16_t m_head; + volatile uint16_t m_tail; + volatile bool m_full; + bool m_overflow; +}; + +#endif