From a816818e3f6335e1b5a35be21ca63f13f7a2b142 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 16:17:00 +0100 Subject: [PATCH 01/95] Beginnings of external audio for the FM controller. --- FM.h | 4 ++++ SerialPort.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- SerialPort.h | 4 +++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/FM.h b/FM.h index 9e15c8a..e559293 100644 --- a/FM.h +++ b/FM.h @@ -57,6 +57,10 @@ public: 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, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel); + uint8_t getSpace() const; + + uint8_t writeData(const uint8_t* data, uint8_t length); + private: CFMKeyer m_callsign; CFMKeyer m_rfAck; diff --git a/SerialPort.cpp b/SerialPort.cpp index 711ba6e..f7bde93 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -68,6 +68,7 @@ const uint8_t MMDVM_POCSAG_DATA = 0x50U; const uint8_t MMDVM_FM_PARAMS1 = 0x60U; const uint8_t MMDVM_FM_PARAMS2 = 0x61U; const uint8_t MMDVM_FM_PARAMS3 = 0x62U; +const uint8_t MMDVM_FM_DATA = 0x65U; const uint8_t MMDVM_ACK = 0x70U; const uint8_t MMDVM_NAK = 0x7FU; @@ -101,7 +102,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200506 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" +#define DESCRIPTION "20200507 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -156,7 +157,7 @@ void CSerialPort::getStatus() // Send all sorts of interesting internal values reply[0U] = MMDVM_FRAME_START; - reply[1U] = 13U; + reply[1U] = 14U; reply[2U] = MMDVM_GET_STATUS; reply[3U] = 0x00U; @@ -238,7 +239,12 @@ void CSerialPort::getStatus() else reply[12U] = 0U; - writeInt(1U, reply, 13); + if (m_fmEnable) + reply[13U] = fm.getSpace(); + else + reply[13U] = 0U; + + writeInt(1U, reply, 14); } void CSerialPort::getVersion() @@ -876,6 +882,20 @@ void CSerialPort::process() } break; + case MMDVM_FM_DATA: + if (m_fmEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_FM) + err = fm.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_FM); + } else { + DEBUG2("Received invalid FM data", err); + sendNAK(err); + } + break; + case MMDVM_TRANSPARENT: case MMDVM_QSO_INFO: // Do nothing on the MMDVM. @@ -1188,6 +1208,29 @@ void CSerialPort::writeNXDNLost() writeInt(1U, reply, 3); } +void CSerialPort::writeFMData(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) + return; + + if (!m_fmEnable) + return; + + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_FM_DATA; + + uint8_t count = 3U; + for (uint8_t i = 0U; i < length; i++, count++) + reply[count] = data[i]; + + reply[1U] = count; + + writeInt(1U, reply, count); +} + void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) { if (m_modemState != STATE_DSTARCAL) diff --git a/SerialPort.h b/SerialPort.h index cd09bbe..0e69752 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,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 @@ -50,6 +50,8 @@ public: void writeNXDNData(const uint8_t* data, uint8_t length); void writeNXDNLost(); + void writeFMData(const uint8_t* data, uint8_t length); + void writeCalData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length); From 96364dc18936ab3b597fddbc5a527159604cc10d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 22:01:48 +0100 Subject: [PATCH 02/95] Add the external audio parameters. --- FM.cpp | 14 +++++++++++++- FM.h | 6 ++++-- SerialPort.cpp | 30 ++++++++++++++++++++++++++++++ SerialPort.h | 1 + 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/FM.cpp b/FM.cpp index 70b6b6a..ba952b7 100644 --- a/FM.cpp +++ b/FM.cpp @@ -23,6 +23,7 @@ CFM::CFM() : m_callsign(), m_rfAck(), +m_extAck(), m_ctcssRX(), m_ctcssTX(), m_timeoutTone(), @@ -46,7 +47,9 @@ m_blanking(), m_useCOS(true), m_cosInvert(false), m_rfAudioBoost(1U), -m_downsampler(128)//Size might need adjustement +m_extAudioBoost(1U), +m_downsampler(128U), //Size might need adjustement +m_extEnabled(false) { } @@ -195,6 +198,15 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque return m_ctcssTX.setParams(ctcssFrequency, ctcssLevel); } +uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level) +{ + m_extEnabled = true; + + m_extAudioBoost = q15_t(audioBoost); + + return m_extAck.setParams(ack, speed, frequency, level, level); +} + void CFM::stateMachine(bool validSignal) { switch (m_state) { diff --git a/FM.h b/FM.h index e559293..cac2231 100644 --- a/FM.h +++ b/FM.h @@ -41,8 +41,6 @@ enum FM_STATE { }; - - class CFM { public: CFM(); @@ -56,6 +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, bool callsignAtLatch); 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, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel); + uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level); uint8_t getSpace() const; @@ -64,6 +63,7 @@ public: private: CFMKeyer m_callsign; CFMKeyer m_rfAck; + CFMKeyer m_extAck; CFMCTCSSRX m_ctcssRX; CFMCTCSSTX m_ctcssTX; CFMTimeout m_timeoutTone; @@ -87,7 +87,9 @@ private: bool m_useCOS; bool m_cosInvert; q15_t m_rfAudioBoost; + q15_t m_extAudioBoost; CFMDownsampler m_downsampler; + bool m_extEnabled; void stateMachine(bool validSignal); void listeningState(bool validSignal); diff --git a/SerialPort.cpp b/SerialPort.cpp index f7bde93..6cb8b37 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -68,6 +68,7 @@ const uint8_t MMDVM_POCSAG_DATA = 0x50U; const uint8_t MMDVM_FM_PARAMS1 = 0x60U; const uint8_t MMDVM_FM_PARAMS2 = 0x61U; const uint8_t MMDVM_FM_PARAMS3 = 0x62U; +const uint8_t MMDVM_FM_PARAMS4 = 0x63U; const uint8_t MMDVM_FM_DATA = 0x65U; const uint8_t MMDVM_ACK = 0x70U; @@ -438,6 +439,25 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); } +uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint8_t length) +{ + if (length < 4U) + return 4U; + + uint8_t audioBoost = data[0U]; + uint8_t speed = data[1U]; + uint16_t frequency = data[2U] * 10U; + uint8_t level = data[3U]; + + char ack[50U]; + uint8_t n = 0U; + for (uint8_t i = 4U; i < length; i++, n++) + ack[n] = data[i]; + ack[n] = '\0'; + + return fm.setExt(ack, audioBoost, speed, frequency, level); +} + uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length) { if (length < 1U) @@ -666,6 +686,16 @@ void CSerialPort::process() } break; + case MMDVM_FM_PARAMS4: + err = setFMParams4(m_buffer + 3U, m_len - 3U); + if (err == 0U) { + sendACK(); + } else { + DEBUG2("Received invalid FM params 4", err); + sendNAK(err); + } + break; + case MMDVM_CAL_DATA: if (m_modemState == STATE_DSTARCAL) err = calDStarTX.write(m_buffer + 3U, m_len - 3U); diff --git a/SerialPort.h b/SerialPort.h index 0e69752..004c626 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -78,6 +78,7 @@ private: uint8_t setFMParams1(const uint8_t* data, uint8_t length); uint8_t setFMParams2(const uint8_t* data, uint8_t length); uint8_t setFMParams3(const uint8_t* data, uint8_t length); + uint8_t setFMParams4(const uint8_t* data, uint8_t length); // Hardware versions void beginInt(uint8_t n, int speed); From 5d1b66dde330002103b99e618d9149510dce6cf7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 22:07:58 +0100 Subject: [PATCH 03/95] Add the missing functions. --- FM.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/FM.cpp b/FM.cpp index ba952b7..662291b 100644 --- a/FM.cpp +++ b/FM.cpp @@ -450,3 +450,15 @@ void CFM::beginRelaying() m_timeoutTimer.start(); m_ackMinTimer.start(); } + +uint8_t CFM::getSpace() const +{ + // The amount of free space for receiving external audio, in bytes. + return 0U; +} + +uint8_t CFM::writeData(const uint8_t* data, uint8_t length) +{ + // Handle incoming external audio, in 12-bit packed form. + return 0U; +} From d7cd7096d0db5b55d5f096513f7b78259f13b787 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 22:39:17 +0100 Subject: [PATCH 04/95] Add the external audio state machine and the beginnings of the audio processing. --- FM.cpp | 281 ++++++++++++++++++++++++++++++++++++++++++++++----------- FM.h | 36 +++++--- 2 files changed, 251 insertions(+), 66 deletions(-) diff --git a/FM.cpp b/FM.cpp index 662291b..38e5c88 100644 --- a/FM.cpp +++ b/FM.cpp @@ -76,43 +76,56 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) } else if (CTCSS_READY(ctcssState) && m_modemState != STATE_FM) { //we had enough samples for CTCSS and we are in some other mode than FM bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos); + // XXX Need to have somewhere to get the ext audio state + stateMachine(validCTCSS && cos, false); if (m_modemState != STATE_FM) continue; } else if (CTCSS_READY(ctcssState) && m_modemState == STATE_FM) { //We had enough samples for CTCSS and we are in FM mode, trigger the state machine bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos); + // XXX Need to have somewhere to get the ext audio state + stateMachine(validCTCSS && cos, false); if (m_modemState != STATE_FM) break; } else if (CTCSS_NOT_READY(ctcssState) && m_modemState == STATE_FM && i == length - 1) { //Not enough samples for CTCSS but we already are in FM, trigger the state machine //but do not trigger the state machine on every single sample, save CPU! bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos); + // XXX Need to have somewhere to get the ext audio state + stateMachine(validCTCSS && cos, false); } - // Only let audio through when relaying audio - if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) { + // Only let RF audio through when relaying RF audio + if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF) { // currentSample = m_deemphasis.filter(currentSample); - // m_downsampler.addSample(currentSample); + + if (m_extEnabled) + m_downsampler.addSample(currentSample); + currentSample = m_blanking.process(currentSample); currentSample *= m_rfAudioBoost; + } else if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { + // XXX Where do we receive the ext audio? + currentSample = m_blanking.process(currentSample); + currentSample *= m_extAudioBoost; } else { currentSample = 0; } - if (!m_callsign.isRunning()) + if (!m_callsign.isRunning() && !m_extAck.isRunning()) currentSample += m_rfAck.getHighAudio(); - - if (!m_rfAck.isRunning()) { + + if (!m_callsign.isRunning() && !m_rfAck.isRunning()) + currentSample += m_extAck.getHighAudio(); + + if (!m_rfAck.isRunning() && !m_extAck.isRunning()) { if (m_state == FS_LISTENING) currentSample += m_callsign.getHighAudio(); else currentSample += m_callsign.getLowAudio(); } - if (!m_callsign.isRunning() && !m_rfAck.isRunning()) + if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning()) currentSample += m_timeoutTone.getAudio(); currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample))); @@ -145,6 +158,7 @@ void CFM::reset() m_ctcssRX.reset(); m_rfAck.stop(); + m_extAck.stop(); m_callsign.stop(); m_timeoutTone.stop(); } @@ -207,36 +221,51 @@ uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t return m_extAck.setParams(ack, speed, frequency, level, level); } -void CFM::stateMachine(bool validSignal) +void CFM::stateMachine(bool validRFSignal, bool validExtSignal) { switch (m_state) { case FS_LISTENING: - listeningState(validSignal); + listeningState(validRFSignal, validExtSignal); break; - case FS_KERCHUNK: - kerchunkState(validSignal); + case FS_KERCHUNK_RF: + kerchunkRFState(validRFSignal); break; - case FS_RELAYING: - relayingState(validSignal); + case FS_RELAYING_RF: + relayingRFState(validRFSignal); break; - case FS_RELAYING_WAIT: - relayingWaitState(validSignal); + case FS_RELAYING_WAIT_RF: + relayingRFWaitState(validRFSignal); break; - case FS_TIMEOUT: - timeoutState(validSignal); + case FS_TIMEOUT_RF: + timeoutRFState(validRFSignal); break; - case FS_TIMEOUT_WAIT: - timeoutWaitState(validSignal); + case FS_TIMEOUT_WAIT_RF: + timeoutRFWaitState(validRFSignal); + break; + case FS_KERCHUNK_EXT: + kerchunkExtState(validExtSignal); + break; + case FS_RELAYING_EXT: + relayingExtState(validExtSignal); + break; + case FS_RELAYING_WAIT_EXT: + relayingExtWaitState(validExtSignal); + break; + case FS_TIMEOUT_EXT: + timeoutExtState(validExtSignal); + break; + case FS_TIMEOUT_WAIT_EXT: + timeoutExtWaitState(validExtSignal); break; case FS_HANG: - hangState(validSignal); + hangState(validRFSignal, validExtSignal); break; default: break; } if (m_state == FS_LISTENING && m_modemState == STATE_FM) { - if (!m_callsign.isRunning() && !m_rfAck.isRunning()) { + if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning()) { DEBUG1("Change to STATE_IDLE"); m_modemState = STATE_IDLE; m_callsignTimer.stop(); @@ -260,18 +289,38 @@ void CFM::clock(uint8_t length) m_hangTimer.clock(length); } -void CFM::listeningState(bool validSignal) +void CFM::listeningState(bool validRFSignal, bool validExtSignal) { - if (validSignal) { + if (validRFSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { - DEBUG1("State to KERCHUNK"); - m_state = FS_KERCHUNK; + DEBUG1("State to KERCHUNK_RF"); + m_state = FS_KERCHUNK_RF; m_kerchunkTimer.start(); if (m_callsignAtStart && !m_callsignAtLatch) sendCallsign(); } else { - DEBUG1("State to RELAYING"); - m_state = FS_RELAYING; + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; + if (m_callsignAtStart) + sendCallsign(); + } + + beginRelaying(); + + m_callsignTimer.start(); + + DEBUG1("Change to STATE_FM"); + m_modemState = STATE_FM; + } else if (validExtSignal) { + if (m_kerchunkTimer.getTimeout() > 0U) { + DEBUG1("State to KERCHUNK_EXT"); + m_state = FS_KERCHUNK_EXT; + m_kerchunkTimer.start(); + if (m_callsignAtStart && !m_callsignAtLatch) + sendCallsign(); + } else { + DEBUG1("State to RELAYING_EXT"); + m_state = FS_RELAYING_EXT; if (m_callsignAtStart) sendCallsign(); } @@ -285,12 +334,12 @@ void CFM::listeningState(bool validSignal) } } -void CFM::kerchunkState(bool validSignal) +void CFM::kerchunkRFState(bool validSignal) { if (validSignal) { if (m_kerchunkTimer.hasExpired()) { - DEBUG1("State to RELAYING"); - m_state = FS_RELAYING; + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; m_kerchunkTimer.stop(); if (m_callsignAtStart && m_callsignAtLatch) { sendCallsign(); @@ -307,19 +356,19 @@ void CFM::kerchunkState(bool validSignal) } } -void CFM::relayingState(bool validSignal) +void CFM::relayingRFState(bool validSignal) { if (validSignal) { if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { - DEBUG1("State to TIMEOUT"); - m_state = FS_TIMEOUT; + DEBUG1("State to TIMEOUT_RF"); + m_state = FS_TIMEOUT_RF; m_ackMinTimer.stop(); m_timeoutTimer.stop(); m_timeoutTone.start(); } } else { - DEBUG1("State to RELAYING_WAIT"); - m_state = FS_RELAYING_WAIT; + DEBUG1("State to RELAYING_WAIT_RF"); + m_state = FS_RELAYING_WAIT_RF; m_ackDelayTimer.start(); } @@ -329,11 +378,11 @@ void CFM::relayingState(bool validSignal) } } -void CFM::relayingWaitState(bool validSignal) +void CFM::relayingRFWaitState(bool validSignal) { if (validSignal) { - DEBUG1("State to RELAYING"); - m_state = FS_RELAYING; + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; m_ackDelayTimer.stop(); } else { if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { @@ -342,12 +391,12 @@ void CFM::relayingWaitState(bool validSignal) if (m_ackMinTimer.isRunning()) { if (m_ackMinTimer.hasExpired()) { - DEBUG1("Send ack"); + DEBUG1("Send RF ack"); m_rfAck.start(); m_ackMinTimer.stop(); } } else { - DEBUG1("Send ack"); + DEBUG1("Send RF ack"); m_rfAck.start(); m_ackMinTimer.stop(); } @@ -364,13 +413,100 @@ void CFM::relayingWaitState(bool validSignal) } } -void CFM::hangState(bool validSignal) +void CFM::kerchunkExtState(bool validSignal) { if (validSignal) { - DEBUG1("State to RELAYING"); - m_state = FS_RELAYING; + if (m_kerchunkTimer.hasExpired()) { + DEBUG1("State to RELAYING_EXT"); + m_state = FS_RELAYING_EXT; + m_kerchunkTimer.stop(); + if (m_callsignAtStart && m_callsignAtLatch) { + sendCallsign(); + m_callsignTimer.start(); + } + } + } else { + DEBUG1("State to LISTENING"); + m_state = FS_LISTENING; + m_kerchunkTimer.stop(); + m_timeoutTimer.stop(); + m_ackMinTimer.stop(); + m_callsignTimer.stop(); + } +} + +void CFM::relayingExtState(bool validSignal) +{ + if (validSignal) { + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { + DEBUG1("State to TIMEOUT_EXT"); + m_state = FS_TIMEOUT_EXT; + m_ackMinTimer.stop(); + m_timeoutTimer.stop(); + m_timeoutTone.start(); + } + } else { + DEBUG1("State to RELAYING_WAIT_EXT"); + m_state = FS_RELAYING_WAIT_EXT; + m_ackDelayTimer.start(); + } + + if (m_callsignTimer.isRunning() && m_callsignTimer.hasExpired()) { + sendCallsign(); + m_callsignTimer.start(); + } +} + +void CFM::relayingExtWaitState(bool validSignal) +{ + if (validSignal) { + DEBUG1("State to RELAYING_EXT"); + m_state = FS_RELAYING_EXT; + m_ackDelayTimer.stop(); + } else { + if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { + DEBUG1("State to HANG"); + m_state = FS_HANG; + + if (m_ackMinTimer.isRunning()) { + if (m_ackMinTimer.hasExpired()) { + DEBUG1("Send Ext ack"); + m_extAck.start(); + m_ackMinTimer.stop(); + } + } else { + DEBUG1("Send Ext ack"); + m_extAck.start(); + m_ackMinTimer.stop(); + } + + m_ackDelayTimer.stop(); + m_timeoutTimer.stop(); + m_hangTimer.start(); + } + } + + if (m_callsignTimer.isRunning() && m_callsignTimer.hasExpired()) { + sendCallsign(); + m_callsignTimer.start(); + } +} + +void CFM::hangState(bool validRFSignal, bool validExtSignal) +{ + if (validRFSignal) { + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; DEBUG1("Stop ack"); m_rfAck.stop(); + m_extAck.stop(); + beginRelaying(); + } else if (validExtSignal) { + DEBUG1("State to RELAYING_EXT"); + m_state = FS_RELAYING_EXT; + DEBUG1("Stop ack"); + m_rfAck.stop(); + m_extAck.stop(); beginRelaying(); } else { if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) { @@ -391,11 +527,11 @@ void CFM::hangState(bool validSignal) } } -void CFM::timeoutState(bool validSignal) +void CFM::timeoutRFState(bool validSignal) { if (!validSignal) { - DEBUG1("State to TIMEOUT_WAIT"); - m_state = FS_TIMEOUT_WAIT; + DEBUG1("State to TIMEOUT_WAIT_RF"); + m_state = FS_TIMEOUT_WAIT_RF; m_ackDelayTimer.start(); } @@ -405,18 +541,18 @@ void CFM::timeoutState(bool validSignal) } } -void CFM::timeoutWaitState(bool validSignal) +void CFM::timeoutRFWaitState(bool validSignal) { if (validSignal) { - DEBUG1("State to TIMEOUT"); - m_state = FS_TIMEOUT; + DEBUG1("State to TIMEOUT_RF"); + m_state = FS_TIMEOUT_RF; m_ackDelayTimer.stop(); } else { if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { DEBUG1("State to HANG"); m_state = FS_HANG; m_timeoutTone.stop(); - DEBUG1("Send ack"); + DEBUG1("Send RF ack"); m_rfAck.start(); m_ackDelayTimer.stop(); m_ackMinTimer.stop(); @@ -431,6 +567,45 @@ void CFM::timeoutWaitState(bool validSignal) } } +void CFM::timeoutExtState(bool validSignal) +{ + if (!validSignal) { + DEBUG1("State to TIMEOUT_WAIT_EXT"); + m_state = FS_TIMEOUT_WAIT_EXT; + m_ackDelayTimer.start(); + } + + if (m_callsignTimer.isRunning() && m_callsignTimer.hasExpired()) { + sendCallsign(); + m_callsignTimer.start(); + } +} + +void CFM::timeoutExtWaitState(bool validSignal) +{ + if (validSignal) { + DEBUG1("State to TIMEOUT_EXT"); + m_state = FS_TIMEOUT_EXT; + m_ackDelayTimer.stop(); + } else { + if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { + DEBUG1("State to HANG"); + m_state = FS_HANG; + m_timeoutTone.stop(); + DEBUG1("Send Ext ack"); + m_extAck.start(); + m_ackDelayTimer.stop(); + m_ackMinTimer.stop(); + m_timeoutTimer.stop(); + m_hangTimer.start(); + } + } + + if (m_callsignTimer.isRunning() && m_callsignTimer.hasExpired()) { + sendCallsign(); + m_callsignTimer.start(); + } +} void CFM::sendCallsign() { if (m_holdoffTimer.isRunning()) { diff --git a/FM.h b/FM.h index cac2231..51909bc 100644 --- a/FM.h +++ b/FM.h @@ -32,11 +32,16 @@ enum FM_STATE { FS_LISTENING, - FS_KERCHUNK, - FS_RELAYING, - FS_RELAYING_WAIT, - FS_TIMEOUT, - FS_TIMEOUT_WAIT, + FS_KERCHUNK_RF, + FS_RELAYING_RF, + FS_RELAYING_WAIT_RF, + FS_TIMEOUT_RF, + FS_TIMEOUT_WAIT_RF, + FS_KERCHUNK_EXT, + FS_RELAYING_EXT, + FS_RELAYING_WAIT_EXT, + FS_TIMEOUT_EXT, + FS_TIMEOUT_WAIT_EXT, FS_HANG }; @@ -91,14 +96,19 @@ private: CFMDownsampler m_downsampler; bool m_extEnabled; - void stateMachine(bool validSignal); - void listeningState(bool validSignal); - void kerchunkState(bool validSignal); - void relayingState(bool validSignal); - void relayingWaitState(bool validSignal); - void timeoutState(bool validSignal); - void timeoutWaitState(bool validSignal); - void hangState(bool validSignal); + void stateMachine(bool validRFSignal, bool validExtSignal); + void listeningState(bool validRFSignal, bool validExtSignal); + void kerchunkRFState(bool validSignal); + void relayingRFState(bool validSignal); + void relayingRFWaitState(bool validSignal); + void timeoutRFState(bool validSignal); + void timeoutRFWaitState(bool validSignal); + void kerchunkExtState(bool validSignal); + void relayingExtState(bool validSignal); + void relayingExtWaitState(bool validSignal); + void timeoutExtState(bool validSignal); + void timeoutExtWaitState(bool validSignal); + void hangState(bool validRFSignal, bool validExtSignal); void clock(uint8_t length); From 880df2536d917350e4eecce3f2e5a4e61af74a50 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 8 May 2020 12:30:15 +0100 Subject: [PATCH 05/95] Add audio packing code. --- FM.cpp | 35 ++++++++++++++++++++++++++++++++++- SerialPort.cpp | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/FM.cpp b/FM.cpp index 9a8a9b9..1ea79ea 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,6 +20,11 @@ #include "Globals.h" #include "FM.h" +const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define WRITE_BIT_AUDIO(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_AUDIO(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + CFM::CFM() : m_callsign(), m_rfAck(), @@ -632,6 +637,34 @@ uint8_t CFM::getSpace() const uint8_t CFM::writeData(const uint8_t* data, uint8_t length) { - // Handle incoming external audio, in 12-bit packed form. + q15_t samples[170U]; + uint8_t nSamples = 0U; + + for (uint8_t i = 0U; i < length; i += 3U) { + uint16_t sample1 = 0U; + uint16_t sample2 = 0U; + uint16_t MASK = 0x0001U; + + uint8_t* base = data + i; + for (uint8_t j = 0U; j < 12U; j++, MASK <<= 1) { + uint8_t pos1 = j; + uint8_t pos2 = j + 12U; + + bool b1 = READ_BIT_AUDIO(base, pos1) != 0U; + bool b2 = READ_BIT_AUDIO(base, pos2) != 0U; + + if (b1) + sample1 |= MASK; + if (b2) + sample2 |= MASK; + } + + // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047) + samples[nSamples++] = q15_t(sample1) - 2048; + samples[nSamples++] = q15_t(sample2) - 2048; + } + + // Received audio is now in Q15 format in samples, with length nSamples. + return 0U; } diff --git a/SerialPort.cpp b/SerialPort.cpp index 6cb8b37..d83ba63 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -103,7 +103,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200507 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" +#define DESCRIPTION "20200508 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From e7ff0d1898916b2acda6d4ff67e9384d5d128019 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 8 May 2020 13:29:50 +0100 Subject: [PATCH 06/95] Use const uint8_t instead of non-const. --- FM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index 1ea79ea..8dfde85 100644 --- a/FM.cpp +++ b/FM.cpp @@ -645,7 +645,7 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) uint16_t sample2 = 0U; uint16_t MASK = 0x0001U; - uint8_t* base = data + i; + const uint8_t* base = data + i; for (uint8_t j = 0U; j < 12U; j++, MASK <<= 1) { uint8_t pos1 = j; uint8_t pos2 = j + 12U; From b73bca237dbe545a478920b33baa901563c7500a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 15:06:08 +0200 Subject: [PATCH 07/95] Remove union, use pointer tricks instead --- FMDownsampler.cpp | 8 +++++--- FMDownsampler.h | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 51e9580..e44d251 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -23,10 +23,12 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length),//length might need tweaking +m_samplePack(0), +m_samplePackBytes(0), m_packIndex(0), m_downSampleIndex(0) { - m_samplePack = 0; + m_samplePackBytes = &m_samplePack; } void CFMDownsampler::addSample(q15_t sample) @@ -45,7 +47,7 @@ void CFMDownsampler::addSample(q15_t sample) m_ringBuffer.put(m_samplePackBytes[2]); m_ringBuffer.put(m_samplePackBytes[3]); - m_samplePack = 0; + m_samplePack = 0;//reset the sample pack } break; default: @@ -53,7 +55,7 @@ void CFMDownsampler::addSample(q15_t sample) break; } m_packIndex++; - if(m_packIndex >= 2) + if(m_packIndex >= 2)//did we pack to samples ? m_packIndex = 0; } diff --git a/FMDownsampler.h b/FMDownsampler.h index fd17e0a..46a5239 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -32,10 +32,10 @@ public: private: CFMDownsampleRB m_ringBuffer; - union { - int32_t m_samplePack; - int8_t m_samplePackBytes[4]; - }; + + int32_t m_samplePack; + int32_t *m_samplePackBytes; + uint8_t m_packIndex; uint8_t m_downSampleIndex; }; From f1a43ee520f7962f5c688760cd8da61d302e6670 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 15:06:08 +0200 Subject: [PATCH 08/95] Remove union, use pointer tricks instead --- FMDownsampler.cpp | 8 +++++--- FMDownsampler.h | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 51e9580..e44d251 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -23,10 +23,12 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length),//length might need tweaking +m_samplePack(0), +m_samplePackBytes(0), m_packIndex(0), m_downSampleIndex(0) { - m_samplePack = 0; + m_samplePackBytes = &m_samplePack; } void CFMDownsampler::addSample(q15_t sample) @@ -45,7 +47,7 @@ void CFMDownsampler::addSample(q15_t sample) m_ringBuffer.put(m_samplePackBytes[2]); m_ringBuffer.put(m_samplePackBytes[3]); - m_samplePack = 0; + m_samplePack = 0;//reset the sample pack } break; default: @@ -53,7 +55,7 @@ void CFMDownsampler::addSample(q15_t sample) break; } m_packIndex++; - if(m_packIndex >= 2) + if(m_packIndex >= 2)//did we pack to samples ? m_packIndex = 0; } diff --git a/FMDownsampler.h b/FMDownsampler.h index fd17e0a..46a5239 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -32,10 +32,10 @@ public: private: CFMDownsampleRB m_ringBuffer; - union { - int32_t m_samplePack; - int8_t m_samplePackBytes[4]; - }; + + int32_t m_samplePack; + int32_t *m_samplePackBytes; + uint8_t m_packIndex; uint8_t m_downSampleIndex; }; From c81d13395b69c9b1eb9bf16201385834def03586 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:12:30 +0200 Subject: [PATCH 09/95] Use correct types --- FMDownsampler.cpp | 30 +++++++++++++++--------------- FMDownsampler.h | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index e44d251..3e2e02d 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -23,29 +23,29 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length),//length might need tweaking -m_samplePack(0), -m_samplePackBytes(0), -m_packIndex(0), -m_downSampleIndex(0) +m_samplePack(0U), +m_samplePackPointer(0U), +m_packIndex(0U), +m_downSampleIndex(0U) { - m_samplePackBytes = &m_samplePack; + m_samplePackPointer = &m_samplePack; } void CFMDownsampler::addSample(q15_t sample) { //only take one of three samples - if(m_downSampleIndex == 0) { + if(m_downSampleIndex == 0U) { switch(m_packIndex){ case 0: - m_samplePack = int32_t(sample) << 12; + m_samplePack = uint32_t(sample) << 12; break; case 1:{ - m_samplePack |= int32_t(sample); + m_samplePack |= uint32_t(sample); //we did not use MSB; skip it - m_ringBuffer.put(m_samplePackBytes[1]); - m_ringBuffer.put(m_samplePackBytes[2]); - m_ringBuffer.put(m_samplePackBytes[3]); + m_ringBuffer.put(m_samplePackPointer[1U]); + m_ringBuffer.put(m_samplePackPointer[2U]); + m_ringBuffer.put(m_samplePackPointer[3U]); m_samplePack = 0;//reset the sample pack } @@ -55,11 +55,11 @@ void CFMDownsampler::addSample(q15_t sample) break; } m_packIndex++; - if(m_packIndex >= 2)//did we pack to samples ? - m_packIndex = 0; + if(m_packIndex >= 2U)//did we pack to samples ? + m_packIndex = 0U; } m_downSampleIndex++; - if(m_downSampleIndex >= 3) - m_downSampleIndex = 0; + if(m_downSampleIndex >= 3U) + m_downSampleIndex = 0U; } \ No newline at end of file diff --git a/FMDownsampler.h b/FMDownsampler.h index 46a5239..ad822a8 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -33,8 +33,8 @@ public: private: CFMDownsampleRB m_ringBuffer; - int32_t m_samplePack; - int32_t *m_samplePackBytes; + uint32_t m_samplePack; + uint32_t *m_samplePackPointer; uint8_t m_packIndex; uint8_t m_downSampleIndex; From bb731e7890c7f3e45db9a7cf01e53c99f6581dc1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:15:23 +0200 Subject: [PATCH 10/95] Init pointer with null --- FMDownsampler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 3e2e02d..381d2f4 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -24,7 +24,7 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length),//length might need tweaking m_samplePack(0U), -m_samplePackPointer(0U), +m_samplePackPointer(NULL), m_packIndex(0U), m_downSampleIndex(0U) { From 97192602d8ceb17c0cfa3c819fbdd06a75504b2c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:41:12 +0200 Subject: [PATCH 11/95] Use pointer/masking/shifting for sample unpacking --- FM.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/FM.cpp b/FM.cpp index 8dfde85..4ac7117 100644 --- a/FM.cpp +++ b/FM.cpp @@ -643,21 +643,17 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) for (uint8_t i = 0U; i < length; i += 3U) { uint16_t sample1 = 0U; uint16_t sample2 = 0U; - uint16_t MASK = 0x0001U; + uint32_t MASK = 0x00000FFFU; - const uint8_t* base = data + i; - for (uint8_t j = 0U; j < 12U; j++, MASK <<= 1) { - uint8_t pos1 = j; - uint8_t pos2 = j + 12U; + uint32_t pack = 0U; + uint8_t* packPointer = (uint8_t*)&pack; - bool b1 = READ_BIT_AUDIO(base, pos1) != 0U; - bool b2 = READ_BIT_AUDIO(base, pos2) != 0U; + packPointer[1U] = data[i]; + packPointer[2U] = data[i + 1U]; + packPointer[3U] = data[i + 2U]; - if (b1) - sample1 |= MASK; - if (b2) - sample2 |= MASK; - } + sample2 = uint16_t(pack & MASK); + sample1 = uint16_t(pack >> 12); // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047) samples[nSamples++] = q15_t(sample1) - 2048; From e3a951b33b9d6dcaa59098e5d0771423b7beea6f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 17:41:12 +0200 Subject: [PATCH 12/95] Use pointer/masking/shifting for sample unpacking --- FM.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/FM.cpp b/FM.cpp index 8dfde85..4ac7117 100644 --- a/FM.cpp +++ b/FM.cpp @@ -643,21 +643,17 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) for (uint8_t i = 0U; i < length; i += 3U) { uint16_t sample1 = 0U; uint16_t sample2 = 0U; - uint16_t MASK = 0x0001U; + uint32_t MASK = 0x00000FFFU; - const uint8_t* base = data + i; - for (uint8_t j = 0U; j < 12U; j++, MASK <<= 1) { - uint8_t pos1 = j; - uint8_t pos2 = j + 12U; + uint32_t pack = 0U; + uint8_t* packPointer = (uint8_t*)&pack; - bool b1 = READ_BIT_AUDIO(base, pos1) != 0U; - bool b2 = READ_BIT_AUDIO(base, pos2) != 0U; + packPointer[1U] = data[i]; + packPointer[2U] = data[i + 1U]; + packPointer[3U] = data[i + 2U]; - if (b1) - sample1 |= MASK; - if (b2) - sample2 |= MASK; - } + sample2 = uint16_t(pack & MASK); + sample1 = uint16_t(pack >> 12); // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047) samples[nSamples++] = q15_t(sample1) - 2048; From c0aad5effae7633ebb9d34801d211f3f4cb7066e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 8 May 2020 21:47:03 +0200 Subject: [PATCH 13/95] Add mising initilizer --- FM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/FM.cpp b/FM.cpp index 4e3269e..bfb81cf 100644 --- a/FM.cpp +++ b/FM.cpp @@ -52,6 +52,7 @@ m_cosInvert(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), m_downsampler(128U),//Size might need adjustement +m_extEnabled(false), m_rxLevel(1), m_outputRB(2400U) // 100ms of audio { From 0e2a83bc7b2ae31eab18f568614d91dcc81fe5d6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 07:57:45 +0200 Subject: [PATCH 14/95] Add incoming network data buffer --- FM.cpp | 22 +++++++++++++--------- FM.h | 1 + 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/FM.cpp b/FM.cpp index bfb81cf..36c1ecd 100644 --- a/FM.cpp +++ b/FM.cpp @@ -51,10 +51,11 @@ m_useCOS(true), m_cosInvert(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), -m_downsampler(128U),//Size might need adjustement +m_downsampler(1200U),// 100 ms of audio m_extEnabled(false), m_rxLevel(1), -m_outputRB(2400U) // 100ms of audio +m_outputRB(2400U), // 100ms of audio +m_incomingNetworkRB(2400U) //100ms of Audio { } @@ -656,14 +657,11 @@ void CFM::beginRelaying() uint8_t CFM::getSpace() const { // The amount of free space for receiving external audio, in bytes. - return 0U; + return m_incomingNetworkRB.getSpace(); } uint8_t CFM::writeData(const uint8_t* data, uint8_t length) { - q15_t samples[170U]; - uint8_t nSamples = 0U; - for (uint8_t i = 0U; i < length; i += 3U) { uint16_t sample1 = 0U; uint16_t sample2 = 0U; @@ -679,9 +677,15 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) sample2 = uint16_t(pack & MASK); sample1 = uint16_t(pack >> 12); - // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047) - samples[nSamples++] = q15_t(sample1) - 2048; - samples[nSamples++] = q15_t(sample2) - 2048; + // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047). + // Incoming data has sample rate 8kHz, just add 2 empty samples after + // every incoming sample to upsample to 24kHz + m_incomingNetworkRB.put(q15_t(sample1) - 2048); + m_incomingNetworkRB.put(0); + m_incomingNetworkRB.put(0); + m_incomingNetworkRB.put(q15_t(sample2) - 2048); + m_incomingNetworkRB.put(0); + m_incomingNetworkRB.put(0); } // Received audio is now in Q15 format in samples, with length nSamples. diff --git a/FM.h b/FM.h index 1bf6cf1..4e801bc 100644 --- a/FM.h +++ b/FM.h @@ -96,6 +96,7 @@ private: bool m_extEnabled; q15_t m_rxLevel; CFMRB m_outputRB; + CFMRB m_incomingNetworkRB; void stateMachine(bool validRFSignal, bool validExtSignal); void listeningState(bool validRFSignal, bool validExtSignal); From ff3e6feeb674efa04fa6b3fbc2073b7541c4c191 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 08:00:24 +0200 Subject: [PATCH 15/95] Use more explicit names --- FM.cpp | 30 +++++++++++++++--------------- FM.h | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/FM.cpp b/FM.cpp index 36c1ecd..96643c2 100644 --- a/FM.cpp +++ b/FM.cpp @@ -54,8 +54,8 @@ m_extAudioBoost(1U), m_downsampler(1200U),// 100 ms of audio m_extEnabled(false), m_rxLevel(1), -m_outputRB(2400U), // 100ms of audio -m_incomingNetworkRB(2400U) //100ms of Audio +m_outputRFRB(2400U), // 100ms of audio +m_inputExtRB(2400U) //100ms of Audio { } @@ -78,7 +78,7 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) uint8_t ctcssState = m_ctcssRX.process(currentSample); if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) { - //Not enough samples to determine if you have CTCSS, just carry on + //Not enough samples to determine if you have CTCSS, just carry on. continue; } else if (CTCSS_READY(ctcssState) && m_modemState != STATE_FM) { //we had enough samples for CTCSS and we are in some other mode than FM @@ -138,7 +138,7 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentSample += m_ctcssTX.getAudio(); if (m_modemState == STATE_FM) - m_outputRB.put(currentSample); + m_outputRFRB.put(currentSample); } } @@ -147,7 +147,7 @@ void CFM::process() if (m_modemState != STATE_FM) return; - uint16_t length = m_outputRB.getData(); + uint16_t length = m_outputRFRB.getData(); if (length == 0U) return; @@ -162,7 +162,7 @@ void CFM::process() for (uint16_t i = 0U; i < length; i++) { q15_t sample; - m_outputRB.get(sample); + m_outputRFRB.get(sample); io.write(STATE_FM, &sample, 1U); } } @@ -184,7 +184,7 @@ void CFM::reset() m_callsign.stop(); m_timeoutTone.stop(); - m_outputRB.reset(); + m_outputRFRB.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) @@ -657,7 +657,7 @@ void CFM::beginRelaying() uint8_t CFM::getSpace() const { // The amount of free space for receiving external audio, in bytes. - return m_incomingNetworkRB.getSpace(); + return m_inputExtRB.getSpace(); } uint8_t CFM::writeData(const uint8_t* data, uint8_t length) @@ -680,12 +680,12 @@ uint8_t CFM::writeData(const uint8_t* data, uint8_t length) // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047). // Incoming data has sample rate 8kHz, just add 2 empty samples after // every incoming sample to upsample to 24kHz - m_incomingNetworkRB.put(q15_t(sample1) - 2048); - m_incomingNetworkRB.put(0); - m_incomingNetworkRB.put(0); - m_incomingNetworkRB.put(q15_t(sample2) - 2048); - m_incomingNetworkRB.put(0); - m_incomingNetworkRB.put(0); + m_inputExtRB.put(q15_t(sample1) - 2048); + m_inputExtRB.put(0); + m_inputExtRB.put(0); + m_inputExtRB.put(q15_t(sample2) - 2048); + m_inputExtRB.put(0); + m_inputExtRB.put(0); } // Received audio is now in Q15 format in samples, with length nSamples. @@ -698,5 +698,5 @@ void CFM::insertSilence(uint16_t ms) uint32_t nSamples = ms * 24U; for (uint32_t i = 0U; i < nSamples; i++) - m_outputRB.put(0); + m_outputRFRB.put(0); } diff --git a/FM.h b/FM.h index 4e801bc..3e68e28 100644 --- a/FM.h +++ b/FM.h @@ -95,8 +95,8 @@ private: CFMDownsampler m_downsampler; bool m_extEnabled; q15_t m_rxLevel; - CFMRB m_outputRB; - CFMRB m_incomingNetworkRB; + CFMRB m_outputRFRB; + CFMRB m_inputExtRB; void stateMachine(bool validRFSignal, bool validExtSignal); void listeningState(bool validRFSignal, bool validExtSignal); From e91c4417cb944cec49a801a892cda5694771bb52 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 08:23:02 +0200 Subject: [PATCH 16/95] Handle incoming audio --- FM.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/FM.cpp b/FM.cpp index 96643c2..b2195e7 100644 --- a/FM.cpp +++ b/FM.cpp @@ -73,35 +73,38 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) uint8_t i = 0U; for (; i < length; i++) { // ARMv7-M has hardware integer division - q15_t currentSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel); + q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel); + uint8_t ctcssState = m_ctcssRX.process(currentRFSample); - uint8_t ctcssState = m_ctcssRX.process(currentSample); + q15_t currentExtSample; + bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow - if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) { + if ((!inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { //Not enough samples to determine if you have CTCSS, just carry on. continue; - } else if (CTCSS_READY(ctcssState) && m_modemState != STATE_FM) { + } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState != STATE_FM) { //we had enough samples for CTCSS and we are in some other mode than FM bool validCTCSS = CTCSS_VALID(ctcssState); - // XXX Need to have somewhere to get the ext audio state - stateMachine(validCTCSS && cos, false); + stateMachine(validCTCSS && cos, inputExt); if (m_modemState != STATE_FM) continue; - } else if (CTCSS_READY(ctcssState) && m_modemState == STATE_FM) { + } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState == STATE_FM) { //We had enough samples for CTCSS and we are in FM mode, trigger the state machine bool validCTCSS = CTCSS_VALID(ctcssState); - // XXX Need to have somewhere to get the ext audio state - stateMachine(validCTCSS && cos, false); + stateMachine(validCTCSS && cos, inputExt); if (m_modemState != STATE_FM) break; - } else if (CTCSS_NOT_READY(ctcssState) && m_modemState == STATE_FM && i == length - 1) { + } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) { //Not enough samples for CTCSS but we already are in FM, trigger the state machine //but do not trigger the state machine on every single sample, save CPU! bool validCTCSS = CTCSS_VALID(ctcssState); - // XXX Need to have somewhere to get the ext audio state - stateMachine(validCTCSS && cos, false); + stateMachine(validCTCSS && cos, inputExt); } + q15_t currentSample = currentRFSample; + if(m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) + currentSample = currentExtSample; + // Only let RF audio through when relaying RF audio if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF) { if (m_extEnabled) @@ -110,7 +113,6 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentSample = m_blanking.process(currentSample); currentSample *= m_rfAudioBoost; } else if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { - // XXX Where do we receive the ext audio? currentSample = m_blanking.process(currentSample); currentSample *= m_extAudioBoost; } else { From 5d45649096b4cc653823444fe49a342630eb72f0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 08:29:31 +0200 Subject: [PATCH 17/95] Simplify code --- FM.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/FM.cpp b/FM.cpp index b2195e7..3d47941 100644 --- a/FM.cpp +++ b/FM.cpp @@ -102,19 +102,19 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) } q15_t currentSample = currentRFSample; - if(m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) + q15_t currentBoost = m_rfAudioBoost; + if(m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT){ currentSample = currentExtSample; + currentBoost = m_extAudioBoost; + } // Only let RF audio through when relaying RF audio - if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF) { - if (m_extEnabled) + if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { + if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) m_downsampler.addSample(currentSample); currentSample = m_blanking.process(currentSample); - currentSample *= m_rfAudioBoost; - } else if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { - currentSample = m_blanking.process(currentSample); - currentSample *= m_extAudioBoost; + currentSample *= currentBoost; } else { currentSample = 0; } From 05775f0bfa018dc0b2b9f0dca5a429e35296f1ca Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 10:57:16 +0200 Subject: [PATCH 18/95] Add RingBuffer Template --- FM.cpp | 3 ++ FM.h | 6 +-- FMDownsampleRB.cpp | 101 ----------------------------------------- FMDownsampleRB.h | 68 ---------------------------- FMDownsampler.cpp | 13 +++++- FMDownsampler.h | 8 ++-- FMRB.cpp | 110 --------------------------------------------- FMRB.h | 72 ----------------------------- 8 files changed, 22 insertions(+), 359 deletions(-) delete mode 100644 FMDownsampleRB.cpp delete mode 100644 FMDownsampleRB.h delete mode 100644 FMRB.cpp delete mode 100644 FMRB.h diff --git a/FM.cpp b/FM.cpp index 3d47941..16a80c0 100644 --- a/FM.cpp +++ b/FM.cpp @@ -187,6 +187,9 @@ void CFM::reset() m_timeoutTone.stop(); m_outputRFRB.reset(); + m_inputExtRB.reset(); + + m_downsampler.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) diff --git a/FM.h b/FM.h index 3e68e28..eb1c84a 100644 --- a/FM.h +++ b/FM.h @@ -27,7 +27,7 @@ #include "FMTimeout.h" #include "FMKeyer.h" #include "FMTimer.h" -#include "FMRB.h" +#include "RingBuffer.h" #include "FMDirectForm1.h" #include "FMDownsampler.h" @@ -95,8 +95,8 @@ private: CFMDownsampler m_downsampler; bool m_extEnabled; q15_t m_rxLevel; - CFMRB m_outputRFRB; - CFMRB m_inputExtRB; + CRingBuffer m_outputRFRB; + CRingBuffer m_inputExtRB; void stateMachine(bool validRFSignal, bool validExtSignal); void listeningState(bool validRFSignal, bool validExtSignal); diff --git a/FMDownsampleRB.cpp b/FMDownsampleRB.cpp deleted file mode 100644 index 7d2cc2a..0000000 --- a/FMDownsampleRB.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 "FMDownsampleRB.h" - -CFMDownsampleRB::CFMDownsampleRB(uint16_t length) : -m_length(length), -m_head(0U), -m_tail(0U), -m_full(false), -m_overflow(false) -{ - m_samples = new uint8_t[length]; -} - -uint16_t CFMDownsampleRB::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 CFMDownsampleRB::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 CFMDownsampleRB::put(uint8_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 CFMDownsampleRB::get(uint8_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 CFMDownsampleRB::hasOverflowed() -{ - bool overflow = m_overflow; - - m_overflow = false; - - return overflow; -} diff --git a/FMDownsampleRB.h b/FMDownsampleRB.h deleted file mode 100644 index df60daf..0000000 --- a/FMDownsampleRB.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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(FMDOWNSAMPLERB_H) -#define FMDOWNSAMPLERB_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 CFMDownsampleRB { -public: - CFMDownsampleRB(uint16_t length); - - uint16_t getSpace() const; - - uint16_t getData() const; - - bool put(uint8_t sample); - - bool get(uint8_t& sample); - - bool hasOverflowed(); - -private: - uint16_t m_length; - volatile uint8_t* m_samples; - volatile uint16_t m_head; - volatile uint16_t m_tail; - volatile bool m_full; - bool m_overflow; -}; - -#endif diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 381d2f4..c2c3635 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -22,7 +22,7 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : -m_ringBuffer(length),//length might need tweaking +m_ringBuffer(length), m_samplePack(0U), m_samplePackPointer(NULL), m_packIndex(0U), @@ -62,4 +62,15 @@ void CFMDownsampler::addSample(q15_t sample) m_downSampleIndex++; if(m_downSampleIndex >= 3U) m_downSampleIndex = 0U; +} + +bool CFMDownsampler::getPackedData(uint8_t& data) +{ + return m_ringBuffer.get(data); +} + +void CFMDownsampler::reset() +{ + m_downSampleIndex = 0; + m_packIndex = 0; } \ No newline at end of file diff --git a/FMDownsampler.h b/FMDownsampler.h index 6c5fd03..9b576c4 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -21,17 +21,17 @@ #define FMDOWNSAMPLER_H #include "Config.h" -#include "FMDownsampleRB.h" +#include "RingBuffer.h" class CFMDownsampler { public: CFMDownsampler(uint16_t length); void addSample(q15_t sample); - inline bool getPackedData(uint8_t& data){ return m_ringBuffer.get(data); }; - inline bool hasOverflowed() { return m_ringBuffer.hasOverflowed(); }; + bool getPackedData(uint8_t& data); + void reset(); private: - CFMDownsampleRB m_ringBuffer; + CRingBuffer m_ringBuffer; uint32_t m_samplePack; uint32_t *m_samplePackPointer; diff --git a/FMRB.cpp b/FMRB.cpp deleted file mode 100644 index 0d8c6ef..0000000 --- a/FMRB.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -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 deleted file mode 100644 index 7cf6cf4..0000000 --- a/FMRB.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -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 From 61a69d85366636f4bf01488c9fe29f56d05f8066 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 11:01:28 +0200 Subject: [PATCH 19/95] Add missing file --- RingBuffer.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ RingBuffer.h | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 RingBuffer.cpp create mode 100644 RingBuffer.h diff --git a/RingBuffer.cpp b/RingBuffer.cpp new file mode 100644 index 0000000..f350023 --- /dev/null +++ b/RingBuffer.cpp @@ -0,0 +1,119 @@ +/* + * 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. + */ + +#include "RingBuffer.h" + +template CRingBuffer::CRingBuffer(uint16_t length) : +m_length(length), +m_head(0U), +m_tail(0U), +m_full(false), +m_overflow(false) +{ + m_buffer = new TDATATYPE[length]; +} + +template uint16_t CRingBuffer::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; +} + +template uint16_t CRingBuffer::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; +} + +template bool CRingBuffer::put(TDATATYPE sample) +{ + if (m_full) { + m_overflow = true; + return false; + } + + m_buffer[m_head] = sample; + + m_head++; + if (m_head >= m_length) + m_head = 0U; + + if (m_head == m_tail) + m_full = true; + + return true; +} + +template TDATATYPE CRingBuffer::peek() const +{ + return m_buffer[m_tail]; +} + +template bool CRingBuffer::get(TDATATYPE& sample) +{ + if (m_head == m_tail && !m_full) + return false; + + sample = m_buffer[m_tail]; + + m_full = false; + + m_tail++; + if (m_tail >= m_length) + m_tail = 0U; + + return true; +} + +template bool CRingBuffer::hasOverflowed() +{ + bool overflow = m_overflow; + + m_overflow = false; + + return overflow; +} + +template void CRingBuffer::reset() +{ + m_head = 0U; + m_tail = 0U; + m_full = false; + m_overflow = false; +} + +//Add here any declarations you need +template class CRingBuffer; +template class CRingBuffer; +template class CRingBuffer; \ No newline at end of file diff --git a/RingBuffer.h b/RingBuffer.h new file mode 100644 index 0000000..cfb8d53 --- /dev/null +++ b/RingBuffer.h @@ -0,0 +1,77 @@ +/* + * 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(RINGBUFFER_H) +#define RINGBUFFER_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 + +template +class CRingBuffer { +public: + CRingBuffer(uint16_t length); + + uint16_t getSpace() const; + + uint16_t getData() const; + + bool put(TDATATYPE sample); + + bool get(TDATATYPE& sample); + + TDATATYPE peek() const; + + bool hasOverflowed(); + + void reset(); + +private: + uint16_t m_length; + volatile TDATATYPE* m_buffer; + volatile uint16_t m_head; + volatile uint16_t m_tail; + volatile bool m_full; + bool m_overflow; +}; + + + +#endif \ No newline at end of file From 7302dc8bd71d05aa423554367b99b499c293be7b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 11:08:18 +0200 Subject: [PATCH 20/95] Replace RSSI RB with template RB --- IO.h | 10 +++--- RSSIRB.cpp | 102 ----------------------------------------------------- RSSIRB.h | 59 ------------------------------- 3 files changed, 5 insertions(+), 166 deletions(-) delete mode 100644 RSSIRB.cpp delete mode 100644 RSSIRB.h diff --git a/IO.h b/IO.h index 07ed700..49a6a16 100644 --- a/IO.h +++ b/IO.h @@ -22,7 +22,7 @@ #include "Globals.h" #include "SampleRB.h" -#include "RSSIRB.h" +#include "RingBuffer.h" class CIO { public: @@ -57,11 +57,11 @@ public: void selfTest(); private: - bool m_started; + bool m_started; - CSampleRB m_rxBuffer; - CSampleRB m_txBuffer; - CRSSIRB m_rssiBuffer; + CSampleRB m_rxBuffer; + CSampleRB m_txBuffer; + CRingBuffer m_rssiBuffer; arm_biquad_casd_df1_inst_q31 m_dcFilter; q31_t m_dcState[4]; diff --git a/RSSIRB.cpp b/RSSIRB.cpp deleted file mode 100644 index 7607773..0000000 --- a/RSSIRB.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -TX fifo control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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 "RSSIRB.h" - -CRSSIRB::CRSSIRB(uint16_t length) : -m_length(length), -m_head(0U), -m_tail(0U), -m_full(false), -m_overflow(false) -{ - m_rssi = new uint16_t[length]; -} - -uint16_t CRSSIRB::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 CRSSIRB::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 CRSSIRB::put(uint16_t rssi) -{ - if (m_full) { - m_overflow = true; - return false; - } - - m_rssi[m_head] = rssi; - - m_head++; - if (m_head >= m_length) - m_head = 0U; - - if (m_head == m_tail) - m_full = true; - - return true; -} - -bool CRSSIRB::get(uint16_t& rssi) -{ - if (m_head == m_tail && !m_full) - return false; - - rssi = m_rssi[m_tail]; - - m_full = false; - - m_tail++; - if (m_tail >= m_length) - m_tail = 0U; - - return true; -} - -bool CRSSIRB::hasOverflowed() -{ - bool overflow = m_overflow; - - m_overflow = false; - - return overflow; -} diff --git a/RSSIRB.h b/RSSIRB.h deleted file mode 100644 index f3db3de..0000000 --- a/RSSIRB.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Serial fifo control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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(RSSIRB_H) -#define RSSIRB_H - -#if defined(STM32F4XX) -#include "stm32f4xx.h" -#elif defined(STM32F7XX) -#include "stm32f7xx.h" -#elif defined(STM32F105xC) -#include "stm32f1xx.h" -#include -#else -#include -#endif - -class CRSSIRB { -public: - CRSSIRB(uint16_t length); - - uint16_t getSpace() const; - - uint16_t getData() const; - - bool put(uint16_t rssi); - - bool get(uint16_t& rssi); - - bool hasOverflowed(); - -private: - uint16_t m_length; - volatile uint16_t* m_rssi; - volatile uint16_t m_head; - volatile uint16_t m_tail; - volatile bool m_full; - bool m_overflow; -}; - -#endif - From c04e207821ddd67882a7b887357ef1290fd2918b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 9 May 2020 13:10:02 +0100 Subject: [PATCH 21/95] Insert the missing silence. --- FM.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FM.cpp b/FM.cpp index 55fd0f0..8bf2448 100644 --- a/FM.cpp +++ b/FM.cpp @@ -342,6 +342,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } + insertSilence(50U); + beginRelaying(); m_callsignTimer.start(); From 6c3dd265abe4cb880dadf18c6e2604119f6ec5bd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 13:33:05 +0200 Subject: [PATCH 22/95] No more need to specify each types for ringBuffer --- RingBuffer.h | 6 +++--- RingBuffer.cpp => RingBuffer.impl.h | 13 ++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) rename RingBuffer.cpp => RingBuffer.impl.h (89%) diff --git a/RingBuffer.h b/RingBuffer.h index cfb8d53..4878d8c 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -53,9 +53,9 @@ public: uint16_t getData() const; - bool put(TDATATYPE sample); + bool put(const TDATATYPE item); - bool get(TDATATYPE& sample); + bool get(TDATATYPE& item); TDATATYPE peek() const; @@ -72,6 +72,6 @@ private: bool m_overflow; }; - +#include "RingBuffer.impl.h" #endif \ No newline at end of file diff --git a/RingBuffer.cpp b/RingBuffer.impl.h similarity index 89% rename from RingBuffer.cpp rename to RingBuffer.impl.h index f350023..6839255 100644 --- a/RingBuffer.cpp +++ b/RingBuffer.impl.h @@ -56,7 +56,7 @@ template uint16_t CRingBuffer::getData() const return m_length - m_tail + m_head; } -template bool CRingBuffer::put(TDATATYPE sample) +template bool CRingBuffer::put(const TDATATYPE sample) { if (m_full) { m_overflow = true; @@ -80,12 +80,12 @@ template TDATATYPE CRingBuffer::peek() const return m_buffer[m_tail]; } -template bool CRingBuffer::get(TDATATYPE& sample) +template bool CRingBuffer::get(TDATATYPE& item) { if (m_head == m_tail && !m_full) return false; - sample = m_buffer[m_tail]; + item = m_buffer[m_tail]; m_full = false; @@ -111,9 +111,4 @@ template void CRingBuffer::reset() m_tail = 0U; m_full = false; m_overflow = false; -} - -//Add here any declarations you need -template class CRingBuffer; -template class CRingBuffer; -template class CRingBuffer; \ No newline at end of file +} \ No newline at end of file From 26a703c68c96bd5d54317260c9af3930c8b44ba8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 17:27:52 +0200 Subject: [PATCH 23/95] IO RXbuffer now uses template RingBuffer --- IO.cpp | 9 +++++---- IO.h | 15 ++++++++++++++- IODue.cpp | 2 +- IOSTM.cpp | 2 +- IOSTM_CMSIS.cpp | 2 +- IOTeensy.cpp | 2 +- RingBuffer.h | 4 ++-- RingBuffer.impl.h | 4 ++-- 8 files changed, 27 insertions(+), 13 deletions(-) diff --git a/IO.cpp b/IO.cpp index a737693..2e61358 100644 --- a/IO.cpp +++ b/IO.cpp @@ -272,15 +272,16 @@ void CIO::process() uint16_t rssi[RX_BLOCK_SIZE]; for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) { - uint16_t sample; - m_rxBuffer.get(sample, control[i]); + TSample sample; + m_rxBuffer.get(sample); + control[i] = sample.control; m_rssiBuffer.get(rssi[i]); // Detect ADC overflow - if (m_detect && (sample == 0U || sample == 4095U)) + if (m_detect && (sample.sample == 0U || sample.sample == 4095U)) m_adcOverflow++; - q15_t res1 = q15_t(sample) - m_rxDCOffset; + q15_t res1 = q15_t(sample.sample) - m_rxDCOffset; q31_t res2 = res1 * m_rxLevel; samples[i] = q15_t(__SSAT((res2 >> 15), 16)); } diff --git a/IO.h b/IO.h index 49a6a16..dd6dde9 100644 --- a/IO.h +++ b/IO.h @@ -24,6 +24,19 @@ #include "SampleRB.h" #include "RingBuffer.h" +struct TSample { + volatile uint16_t sample; + volatile uint8_t control; + + TSample operator=(const volatile TSample& other) volatile { + return {other.sample, other.control}; + } + + volatile TSample operator=(const TSample& other) volatile { + return {other.sample, other.control}; + } +}; + class CIO { public: CIO(); @@ -59,7 +72,7 @@ public: private: bool m_started; - CSampleRB m_rxBuffer; + CRingBuffer m_rxBuffer; CSampleRB m_txBuffer; CRingBuffer m_rssiBuffer; diff --git a/IODue.cpp b/IODue.cpp index b2aec0a..493d4e2 100644 --- a/IODue.cpp +++ b/IODue.cpp @@ -192,7 +192,7 @@ void CIO::interrupt() DACC->DACC_CDR = sample; sample = ADC->ADC_CDR[ADC_CDR_Chan]; - m_rxBuffer.put(sample, control); + m_rxBuffer.put({sample, control}); #if defined(SEND_RSSI_DATA) m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]); diff --git a/IOSTM.cpp b/IOSTM.cpp index 1d565fe..13a2e58 100644 --- a/IOSTM.cpp +++ b/IOSTM.cpp @@ -1346,7 +1346,7 @@ void CIO::interrupt() ADC_ClearFlag(ADC1, ADC_FLAG_EOC); ADC_SoftwareStartConv(ADC1); - m_rxBuffer.put(sample, control); + m_rxBuffer.put({sample, control}); m_rssiBuffer.put(rawRSSI); m_watchdog++; diff --git a/IOSTM_CMSIS.cpp b/IOSTM_CMSIS.cpp index 6cd92a2..c596a0f 100644 --- a/IOSTM_CMSIS.cpp +++ b/IOSTM_CMSIS.cpp @@ -420,7 +420,7 @@ void CIO::interrupt() // Read value from ADC1 and ADC2 sample = ADC1->DR; // read conversion result; EOC is cleared by this read - m_rxBuffer.put(sample, control); + m_rxBuffer.put({sample, control}); #if defined(SEND_RSSI_DATA) rawRSSI = ADC2->DR; m_rssiBuffer.put(rawRSSI); diff --git a/IOTeensy.cpp b/IOTeensy.cpp index aaece08..d501030 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -169,7 +169,7 @@ void CIO::interrupt() if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) { sample = ADC0_RA; - m_rxBuffer.put(sample, control); + m_rxBuffer.put({sample, control}); } #if defined(SEND_RSSI_DATA) diff --git a/RingBuffer.h b/RingBuffer.h index 4878d8c..ffd346e 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -53,9 +53,9 @@ public: uint16_t getData() const; - bool put(const TDATATYPE item); + bool put(const volatile TDATATYPE item) volatile; - bool get(TDATATYPE& item); + bool get(volatile TDATATYPE& item) volatile; TDATATYPE peek() const; diff --git a/RingBuffer.impl.h b/RingBuffer.impl.h index 6839255..13c52e6 100644 --- a/RingBuffer.impl.h +++ b/RingBuffer.impl.h @@ -56,7 +56,7 @@ template uint16_t CRingBuffer::getData() const return m_length - m_tail + m_head; } -template bool CRingBuffer::put(const TDATATYPE sample) +template bool CRingBuffer::put(const TDATATYPE sample) volatile { if (m_full) { m_overflow = true; @@ -80,7 +80,7 @@ template TDATATYPE CRingBuffer::peek() const return m_buffer[m_tail]; } -template bool CRingBuffer::get(TDATATYPE& item) +template bool CRingBuffer::get(volatile TDATATYPE& item) volatile { if (m_head == m_tail && !m_full) return false; From 05d21c0a14b79dbed754c8fd3d27301454fb96b5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 17:44:44 +0200 Subject: [PATCH 24/95] TX Buffer now using Templae RB --- IO.cpp | 4 +- IO.h | 3 +- IODue.cpp | 11 +++-- IOSTM.cpp | 15 ++++--- IOSTM_CMSIS.cpp | 11 +++-- IOTeensy.cpp | 11 +++-- SampleRB.cpp | 106 ------------------------------------------------ SampleRB.h | 60 --------------------------- 8 files changed, 25 insertions(+), 196 deletions(-) delete mode 100644 SampleRB.cpp delete mode 100644 SampleRB.h diff --git a/IO.cpp b/IO.cpp index 2e61358..7b000fb 100644 --- a/IO.cpp +++ b/IO.cpp @@ -493,9 +493,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t m_dacOverflow++; if (control == NULL) - m_txBuffer.put(res3, MARK_NONE); + m_txBuffer.put({res3, MARK_NONE}); else - m_txBuffer.put(res3, control[i]); + m_txBuffer.put({res3, control[i]}); } } diff --git a/IO.h b/IO.h index dd6dde9..5955d7a 100644 --- a/IO.h +++ b/IO.h @@ -21,7 +21,6 @@ #include "Globals.h" -#include "SampleRB.h" #include "RingBuffer.h" struct TSample { @@ -73,7 +72,7 @@ private: bool m_started; CRingBuffer m_rxBuffer; - CSampleRB m_txBuffer; + CRingBuffer m_txBuffer; CRingBuffer m_rssiBuffer; arm_biquad_casd_df1_inst_q31 m_dcFilter; diff --git a/IODue.cpp b/IODue.cpp index 493d4e2..2c76ef7 100644 --- a/IODue.cpp +++ b/IODue.cpp @@ -185,14 +185,13 @@ void CIO::startInt() void CIO::interrupt() { if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg - uint8_t control = MARK_NONE; - uint16_t sample = DC_OFFSET; + TSample sample = {DC_OFFSET, MARK_NONE}; - m_txBuffer.get(sample, control); - DACC->DACC_CDR = sample; + m_txBuffer.get(sample); + DACC->DACC_CDR = sample.sample; - sample = ADC->ADC_CDR[ADC_CDR_Chan]; - m_rxBuffer.put({sample, control}); + sample.sample = ADC->ADC_CDR[ADC_CDR_Chan]; + m_rxBuffer.put(sample); #if defined(SEND_RSSI_DATA) m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]); diff --git a/IOSTM.cpp b/IOSTM.cpp index 13a2e58..0c2a62a 100644 --- a/IOSTM.cpp +++ b/IOSTM.cpp @@ -1318,25 +1318,24 @@ void CIO::startInt() void CIO::interrupt() { - uint8_t control = MARK_NONE; - uint16_t sample = DC_OFFSET; + TSample sample = {DC_OFFSET, MARK_NONE}; uint16_t rawRSSI = 0U; - m_txBuffer.get(sample, control); + m_txBuffer.get(sample); // Send the value to the DAC #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) - DAC_SetChannel2Data(DAC_Align_12b_R, sample); + DAC_SetChannel2Data(DAC_Align_12b_R, sample.sample); #else - DAC_SetChannel1Data(DAC_Align_12b_R, sample); + DAC_SetChannel1Data(DAC_Align_12b_R, sample.sample); #endif // Read value from ADC1 and ADC2 if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)) { // shouldn't be still in reset at this point so null the sample value? - sample = 0U; + sample.sample = 0U; } else { - sample = ADC_GetConversionValue(ADC1); + sample.sample = ADC_GetConversionValue(ADC1); #if defined(SEND_RSSI_DATA) rawRSSI = ADC_GetConversionValue(ADC2); #endif @@ -1346,7 +1345,7 @@ void CIO::interrupt() ADC_ClearFlag(ADC1, ADC_FLAG_EOC); ADC_SoftwareStartConv(ADC1); - m_rxBuffer.put({sample, control}); + m_rxBuffer.put(sample); m_rssiBuffer.put(rawRSSI); m_watchdog++; diff --git a/IOSTM_CMSIS.cpp b/IOSTM_CMSIS.cpp index c596a0f..03339a5 100644 --- a/IOSTM_CMSIS.cpp +++ b/IOSTM_CMSIS.cpp @@ -397,8 +397,7 @@ void CIO::startInt() void CIO::interrupt() { - uint8_t control = MARK_NONE; - uint16_t sample = DC_OFFSET; + TSample sample = {DC_OFFSET, MARK_NONE}; #if defined(SEND_RSSI_DATA) uint16_t rawRSSI = 0U; #endif @@ -415,12 +414,12 @@ void CIO::interrupt() *rssi_adon = 1; #endif - m_txBuffer.get(sample, control); - DAC->DHR12R1 = sample; // Send the value to the DAC + m_txBuffer.get(sample); + DAC->DHR12R1 = sample.sample; // Send the value to the DAC // Read value from ADC1 and ADC2 - sample = ADC1->DR; // read conversion result; EOC is cleared by this read - m_rxBuffer.put({sample, control}); + sample.sample = ADC1->DR; // read conversion result; EOC is cleared by this read + m_rxBuffer.put(sample); #if defined(SEND_RSSI_DATA) rawRSSI = ADC2->DR; m_rssiBuffer.put(rawRSSI); diff --git a/IOTeensy.cpp b/IOTeensy.cpp index d501030..8cb285e 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -161,15 +161,14 @@ void CIO::startInt() void CIO::interrupt() { - uint8_t control = MARK_NONE; - uint16_t sample = DC_OFFSET; + TSample sample = {DC_OFFSET, MARK_NONE}; - m_txBuffer.get(sample, control); - *(int16_t *)&(DAC0_DAT0L) = sample; + m_txBuffer.get(sample); + *(int16_t *)&(DAC0_DAT0L) = sample.sample; if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) { - sample = ADC0_RA; - m_rxBuffer.put({sample, control}); + sample.sample = ADC0_RA; + m_rxBuffer.put(sample); } #if defined(SEND_RSSI_DATA) diff --git a/SampleRB.cpp b/SampleRB.cpp deleted file mode 100644 index 5fa2ef6..0000000 --- a/SampleRB.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -TX fifo control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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 "SampleRB.h" - -CSampleRB::CSampleRB(uint16_t length) : -m_length(length), -m_head(0U), -m_tail(0U), -m_full(false), -m_overflow(false) -{ - m_samples = new uint16_t[length]; - m_control = new uint8_t[length]; -} - -uint16_t CSampleRB::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 CSampleRB::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 CSampleRB::put(uint16_t sample, uint8_t control) -{ - if (m_full) { - m_overflow = true; - return false; - } - - m_samples[m_head] = sample; - m_control[m_head] = control; - - m_head++; - if (m_head >= m_length) - m_head = 0U; - - if (m_head == m_tail) - m_full = true; - - return true; -} - -bool CSampleRB::get(uint16_t& sample, uint8_t& control) -{ - if (m_head == m_tail && !m_full) - return false; - - sample = m_samples[m_tail]; - control = m_control[m_tail]; - - m_full = false; - - m_tail++; - if (m_tail >= m_length) - m_tail = 0U; - - return true; -} - -bool CSampleRB::hasOverflowed() -{ - bool overflow = m_overflow; - - m_overflow = false; - - return overflow; -} - diff --git a/SampleRB.h b/SampleRB.h deleted file mode 100644 index e0b6269..0000000 --- a/SampleRB.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -Serial fifo control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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(SAMPLERB_H) -#define SAMPLERB_H - -#if defined(STM32F4XX) -#include "stm32f4xx.h" -#elif defined(STM32F7XX) -#include "stm32f7xx.h" -#elif defined(STM32F105xC) -#include "stm32f1xx.h" -#include -#else -#include -#endif - -class CSampleRB { -public: - CSampleRB(uint16_t length); - - uint16_t getSpace() const; - - uint16_t getData() const; - - bool put(uint16_t sample, uint8_t control); - - bool get(uint16_t& sample, uint8_t& control); - - bool hasOverflowed(); - -private: - uint16_t m_length; - volatile uint16_t* m_samples; - volatile uint8_t* m_control; - volatile uint16_t m_head; - volatile uint16_t m_tail; - volatile bool m_full; - bool m_overflow; -}; - -#endif - From b0ba3b5dd8980f1bf0fee0f24c076343d7b00652 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 9 May 2020 19:57:40 +0200 Subject: [PATCH 25/95] SerialRB now inherits from RingBuffer --- RingBuffer.h | 2 +- SerialRB.cpp | 76 +++++----------------------------------------------- SerialRB.h | 30 ++------------------- 3 files changed, 9 insertions(+), 99 deletions(-) diff --git a/RingBuffer.h b/RingBuffer.h index ffd346e..7a066b9 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -56,7 +56,7 @@ public: bool put(const volatile TDATATYPE item) volatile; bool get(volatile TDATATYPE& item) volatile; - + TDATATYPE peek() const; bool hasOverflowed(); diff --git a/SerialRB.cpp b/SerialRB.cpp index f6b1578..ca3350d 100644 --- a/SerialRB.cpp +++ b/SerialRB.cpp @@ -21,80 +21,16 @@ Boston, MA 02110-1301, USA. #include "SerialRB.h" CSerialRB::CSerialRB(uint16_t length) : -m_length(length), -m_head(0U), -m_tail(0U), -m_full(false) +CRingBuffer(length) { - m_buffer = new uint8_t[length]; -} - -void CSerialRB::reset() -{ - m_head = 0U; - m_tail = 0U; - m_full = false; -} - -uint16_t CSerialRB::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 CSerialRB::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 CSerialRB::put(uint8_t c) -{ - if (m_full) - return false; - - m_buffer[m_head] = c; - - m_head++; - if (m_head >= m_length) - m_head = 0U; - - if (m_head == m_tail) - m_full = true; - - return true; -} - -uint8_t CSerialRB::peek() const -{ - return m_buffer[m_tail]; } uint8_t CSerialRB::get() { - uint8_t value = m_buffer[m_tail]; - - m_full = false; - - m_tail++; - if (m_tail >= m_length) - m_tail = 0U; - - return value; + uint8_t value; + if(CRingBuffer::get(value)) + return value; + + return 0U; } diff --git a/SerialRB.h b/SerialRB.h index 7b6b7b9..1357732 100644 --- a/SerialRB.h +++ b/SerialRB.h @@ -21,41 +21,15 @@ Boston, MA 02110-1301, USA. #if !defined(SERIALRB_H) #define SERIALRB_H -#if defined(STM32F4XX) -#include "stm32f4xx.h" -#elif defined(STM32F7XX) -#include "stm32f7xx.h" -#elif defined(STM32F105xC) -#include "stm32f1xx.h" -#include -#else -#include -#endif +#include "RingBuffer.h" const uint16_t SERIAL_RINGBUFFER_SIZE = 370U; -class CSerialRB { +class CSerialRB : public CRingBuffer{ public: CSerialRB(uint16_t length = SERIAL_RINGBUFFER_SIZE); - uint16_t getSpace() const; - - uint16_t getData() const; - - void reset(); - - bool put(uint8_t c); - - uint8_t peek() const; - uint8_t get(); - -private: - uint16_t m_length; - volatile uint8_t* m_buffer; - volatile uint16_t m_head; - volatile uint16_t m_tail; - volatile bool m_full; }; #endif From 55df5fe04c9d13ae286f1b954761bb6fe39d43f5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 00:03:05 +0200 Subject: [PATCH 26/95] Remove useless stuff --- IO.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/IO.h b/IO.h index 5955d7a..aec26a8 100644 --- a/IO.h +++ b/IO.h @@ -26,14 +26,6 @@ struct TSample { volatile uint16_t sample; volatile uint8_t control; - - TSample operator=(const volatile TSample& other) volatile { - return {other.sample, other.control}; - } - - volatile TSample operator=(const TSample& other) volatile { - return {other.sample, other.control}; - } }; class CIO { From 16c3d418eb48020fe92e405cfddaea486df1168f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 00:03:32 +0200 Subject: [PATCH 27/95] Buffer no longer volatile, not needed --- RingBuffer.h | 10 ++++++---- RingBuffer.impl.h | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/RingBuffer.h b/RingBuffer.h index 7a066b9..d8de703 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -47,15 +47,17 @@ template class CRingBuffer { public: - CRingBuffer(uint16_t length); + CRingBuffer(uint16_t length = 370U); uint16_t getSpace() const; uint16_t getData() const; - bool put(const volatile TDATATYPE item) volatile; + bool put(TDATATYPE item) volatile; - bool get(volatile TDATATYPE& item) volatile; + bool get(TDATATYPE& item); + + TDATATYPE get(); TDATATYPE peek() const; @@ -65,7 +67,7 @@ public: private: uint16_t m_length; - volatile TDATATYPE* m_buffer; + TDATATYPE* m_buffer; volatile uint16_t m_head; volatile uint16_t m_tail; volatile bool m_full; diff --git a/RingBuffer.impl.h b/RingBuffer.impl.h index 13c52e6..27bb8f6 100644 --- a/RingBuffer.impl.h +++ b/RingBuffer.impl.h @@ -56,14 +56,14 @@ template uint16_t CRingBuffer::getData() const return m_length - m_tail + m_head; } -template bool CRingBuffer::put(const TDATATYPE sample) volatile +template bool CRingBuffer::put(TDATATYPE item) volatile { if (m_full) { m_overflow = true; return false; } - m_buffer[m_head] = sample; + m_buffer[m_head] = item; m_head++; if (m_head >= m_length) @@ -80,7 +80,7 @@ template TDATATYPE CRingBuffer::peek() const return m_buffer[m_tail]; } -template bool CRingBuffer::get(volatile TDATATYPE& item) volatile +template bool CRingBuffer::get(TDATATYPE& item) { if (m_head == m_tail && !m_full) return false; @@ -111,4 +111,13 @@ template void CRingBuffer::reset() m_tail = 0U; m_full = false; m_overflow = false; -} \ No newline at end of file +} + +template TDATATYPE CRingBuffer::get() +{ + TDATATYPE value; + if(get(value)) + return value; + + //return 0U; +} From 03f18451f76dbfeada1fdeb6f7781a9450703171 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 06:50:35 +0200 Subject: [PATCH 28/95] Remove CSerialBuffer, use CRingBuffer --- DMRDMOTX.cpp | 2 +- DMRDMOTX.h | 4 ++-- DMRTX.cpp | 2 +- DMRTX.h | 4 ++-- DStarTX.cpp | 13 ++++++++----- DStarTX.h | 4 ++-- NXDNTX.cpp | 3 ++- NXDNTX.h | 4 ++-- P25TX.cpp | 6 ++++-- P25TX.h | 4 ++-- POCSAGTX.cpp | 3 ++- POCSAGTX.h | 4 ++-- RingBuffer.h | 2 -- RingBuffer.impl.h | 9 --------- SerialPort.h | 4 ++-- YSFTX.cpp | 3 ++- YSFTX.h | 4 ++-- 17 files changed, 36 insertions(+), 39 deletions(-) diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 141ed38..4cf458e 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -74,7 +74,7 @@ void CDMRDMOTX::process() m_poLen = m_txDelay; } else { for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) - m_poBuffer[i] = m_fifo.get(); + m_fifo.get(m_poBuffer[i]); for (unsigned int i = 0U; i < 39U; i++) m_poBuffer[i + DMR_FRAME_LENGTH_BYTES] = PR_FILL[i]; diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 62ef2c1..a5a3d6d 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -23,7 +23,7 @@ #include "Config.h" #include "DMRDefines.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CDMRDMOTX { public: @@ -38,7 +38,7 @@ public: uint8_t getSpace() const; private: - CSerialRB m_fifo; + CRingBuffer m_fifo; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare uint8_t m_poBuffer[1200U]; diff --git a/DMRTX.cpp b/DMRTX.cpp index 81437ec..2541671 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -293,7 +293,7 @@ void CDMRTX::createData(uint8_t slotIndex) { if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) { for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { - m_poBuffer[i] = m_fifo[slotIndex].get(); + m_fifo[slotIndex].get(m_poBuffer[i]); m_markBuffer[i] = MARK_NONE; } } else { diff --git a/DMRTX.h b/DMRTX.h index 1e2f617..8539e15 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -23,7 +23,7 @@ #include "Config.h" #include "DMRDefines.h" -#include "SerialRB.h" +#include "RingBuffer.h" enum DMRTXSTATE { DMRTXSTATE_IDLE, @@ -59,7 +59,7 @@ public: void setColorCode(uint8_t colorCode); private: - CSerialRB m_fifo[2U]; + CRingBuffer m_fifo[2U]; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare DMRTXSTATE m_state; diff --git a/DStarTX.cpp b/DStarTX.cpp index 63eb910..0489ba1 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -216,12 +216,13 @@ void CDStarTX::process() for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = BIT_SYNC; } else { + uint8_t dummy; // Pop the type byte off - m_buffer.get(); + m_buffer.get(dummy); uint8_t header[DSTAR_HEADER_LENGTH_BYTES]; for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++) - header[i] = m_buffer.get(); + m_buffer.get(header[i]); uint8_t buffer[86U]; txHeader(header, buffer + 2U); @@ -239,17 +240,19 @@ void CDStarTX::process() if (type == DSTAR_DATA && m_poLen == 0U) { // Pop the type byte off - m_buffer.get(); + uint8_t dummy; + m_buffer.get(dummy); for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++) - m_poBuffer[m_poLen++] = m_buffer.get(); + m_buffer.get(m_poBuffer[m_poLen++]); m_poPtr = 0U; } if (type == DSTAR_EOT && m_poLen == 0U) { // Pop the type byte off - m_buffer.get(); + uint8_t dummy; + m_buffer.get(dummy); for (uint8_t j = 0U; j < 3U; j++) { for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++) diff --git a/DStarTX.h b/DStarTX.h index 24876d7..47852c5 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CDStarTX { public: @@ -38,7 +38,7 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; + CRingBuffer m_buffer; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare uint8_t m_poBuffer[600U]; diff --git a/NXDNTX.cpp b/NXDNTX.cpp index 45d8ffa..c4f5845 100644 --- a/NXDNTX.cpp +++ b/NXDNTX.cpp @@ -82,7 +82,8 @@ void CNXDNTX::process() m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U]; } else { for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) { - uint8_t c = m_buffer.get(); + uint8_t c; + m_buffer.get(c); m_poBuffer[m_poLen++] = c; } } diff --git a/NXDNTX.h b/NXDNTX.h index eec74d4..f86279d 100644 --- a/NXDNTX.h +++ b/NXDNTX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CNXDNTX { public: @@ -36,7 +36,7 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; + CRingBuffer m_buffer; arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_instance_q15 m_sincFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare diff --git a/P25TX.cpp b/P25TX.cpp index 9db1747..6501f4e 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -76,9 +76,11 @@ void CP25TX::process() for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = P25_START_SYNC; } else { - uint8_t length = m_buffer.get(); + uint8_t length; + m_buffer.get(length); for (uint8_t i = 0U; i < length; i++) { - uint8_t c = m_buffer.get(); + uint8_t c; + m_buffer.get(c); m_poBuffer[m_poLen++] = c; } } diff --git a/P25TX.h b/P25TX.h index 1d542f9..75be712 100644 --- a/P25TX.h +++ b/P25TX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CP25TX { public: @@ -36,7 +36,7 @@ public: uint8_t getSpace() const; private: - CSerialRB m_buffer; + CRingBuffer m_buffer; arm_fir_interpolate_instance_q15 m_modFilter; arm_fir_instance_q15 m_lpFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare diff --git a/POCSAGTX.cpp b/POCSAGTX.cpp index d53f9b7..0c252d8 100644 --- a/POCSAGTX.cpp +++ b/POCSAGTX.cpp @@ -61,7 +61,8 @@ void CPOCSAGTX::process() m_poBuffer[m_poLen++] = POCSAG_SYNC; } else { for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) { - uint8_t c = m_buffer.get(); + uint8_t c; + m_buffer.get(c); m_poBuffer[m_poLen++] = c; } } diff --git a/POCSAGTX.h b/POCSAGTX.h index d640862..298a603 100644 --- a/POCSAGTX.h +++ b/POCSAGTX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CPOCSAGTX { public: @@ -40,7 +40,7 @@ public: bool busy(); private: - CSerialRB m_buffer; + CRingBuffer m_buffer; arm_fir_instance_q15 m_modFilter; q15_t m_modState[170U]; // NoTaps + BlockSize - 1, 6 + 160 - 1 plus some spare uint8_t m_poBuffer[200U]; diff --git a/RingBuffer.h b/RingBuffer.h index d8de703..c69a470 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -56,8 +56,6 @@ public: bool put(TDATATYPE item) volatile; bool get(TDATATYPE& item); - - TDATATYPE get(); TDATATYPE peek() const; diff --git a/RingBuffer.impl.h b/RingBuffer.impl.h index 27bb8f6..06374ba 100644 --- a/RingBuffer.impl.h +++ b/RingBuffer.impl.h @@ -112,12 +112,3 @@ template void CRingBuffer::reset() m_full = false; m_overflow = false; } - -template TDATATYPE CRingBuffer::get() -{ - TDATATYPE value; - if(get(value)) - return value; - - //return 0U; -} diff --git a/SerialPort.h b/SerialPort.h index 004c626..d123bc7 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -21,7 +21,7 @@ #include "Config.h" #include "Globals.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CSerialPort { @@ -66,7 +66,7 @@ private: uint8_t m_ptr; uint8_t m_len; bool m_debug; - CSerialRB m_repeat; + CRingBuffer m_repeat; void sendACK(); void sendNAK(uint8_t err); diff --git a/YSFTX.cpp b/YSFTX.cpp index 4f0400d..5328418 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -76,7 +76,8 @@ void CYSFTX::process() m_poBuffer[m_poLen++] = YSF_START_SYNC; } else { for (uint8_t i = 0U; i < YSF_FRAME_LENGTH_BYTES; i++) { - uint8_t c = m_buffer.get(); + uint8_t c; + m_buffer.get(c); m_poBuffer[m_poLen++] = c; } } diff --git a/YSFTX.h b/YSFTX.h index 647767c..0e88a8c 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "RingBuffer.h" class CYSFTX { public: @@ -38,7 +38,7 @@ public: void setParams(bool on, uint8_t txHang); private: - CSerialRB m_buffer; + CRingBuffer m_buffer; arm_fir_interpolate_instance_q15 m_modFilter; q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare uint8_t m_poBuffer[1200U]; From 807f01ba72ced995b092b60bb1d5c0bed4d60ebf Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 07:00:58 +0200 Subject: [PATCH 29/95] Get rid of annoying PI warning --- Globals.h | 1 + RingBuffer.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Globals.h b/Globals.h index 5cb147a..9a6bbf8 100644 --- a/Globals.h +++ b/Globals.h @@ -28,6 +28,7 @@ #include "STM32Utils.h" #else #include +#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h. #endif #if defined(__SAM3X8E__) || defined(STM32F105xC) diff --git a/RingBuffer.h b/RingBuffer.h index c69a470..7615de0 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -20,7 +20,6 @@ #if !defined(RINGBUFFER_H) #define RINGBUFFER_H - #if defined(STM32F4XX) #include "stm32f4xx.h" #elif defined(STM32F7XX) @@ -30,6 +29,7 @@ #include #else #include +#undef PI #endif #if defined(__SAM3X8E__) || defined(STM32F105xC) @@ -56,7 +56,7 @@ public: bool put(TDATATYPE item) volatile; bool get(TDATATYPE& item); - + TDATATYPE peek() const; bool hasOverflowed(); From 0b31c40c2b37d1df0ad5d156cc4644c287fc7ae4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 08:01:10 +0200 Subject: [PATCH 30/95] Made Get volatile --- RingBuffer.h | 2 +- RingBuffer.impl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/RingBuffer.h b/RingBuffer.h index 7615de0..79f7814 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -55,7 +55,7 @@ public: bool put(TDATATYPE item) volatile; - bool get(TDATATYPE& item); + bool get(TDATATYPE& item) volatile; TDATATYPE peek() const; diff --git a/RingBuffer.impl.h b/RingBuffer.impl.h index 06374ba..ddcb21c 100644 --- a/RingBuffer.impl.h +++ b/RingBuffer.impl.h @@ -80,7 +80,7 @@ template TDATATYPE CRingBuffer::peek() const return m_buffer[m_tail]; } -template bool CRingBuffer::get(TDATATYPE& item) +template bool CRingBuffer::get(TDATATYPE& item) volatile { if (m_head == m_tail && !m_full) return false; From 0e8fdb381ab8390e9ac9e427a3972ae41d984e67 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 09:07:21 +0200 Subject: [PATCH 31/95] Fix State machine not changing state --- FM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FM.cpp b/FM.cpp index 8bf2448..a6085c3 100644 --- a/FM.cpp +++ b/FM.cpp @@ -85,8 +85,8 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) q15_t currentExtSample; bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow - if ((!inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { - //Not enough samples to determine if you have CTCSS, just carry on. + if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { + //Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue continue; } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState != STATE_FM) { //we had enough samples for CTCSS and we are in some other mode than FM From 0f51ddd0bd7000fefcca493ad24fa0517ea3c4e8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 17:18:59 +0200 Subject: [PATCH 32/95] Fix repeater stuck on transmit --- FM.cpp | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/FM.cpp b/FM.cpp index a6085c3..3421d4d 100644 --- a/FM.cpp +++ b/FM.cpp @@ -152,25 +152,8 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) void CFM::process() { - if (m_modemState != STATE_FM) - return; - - uint16_t length = m_outputRFRB.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_outputRFRB.get(sample); + q15_t sample; + while(io.getSpace() >= 3U && m_outputRFRB.get(sample)) { io.write(STATE_FM, &sample, 1U); } } @@ -302,7 +285,7 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) } if (m_state == FS_LISTENING && m_modemState == STATE_FM) { - if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning() && m_outputRFRB.getData() == 0U) { + if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning()) { DEBUG1("Change to STATE_IDLE"); m_modemState = STATE_IDLE; m_callsignTimer.stop(); @@ -721,3 +704,4 @@ void CFM::insertSilence(uint16_t ms) for (uint32_t i = 0U; i < nSamples; i++) m_outputRFRB.put(0); } + From 3ad443dc2ac854563400288e3f49765f6acffd33 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 10 May 2020 17:13:10 +0100 Subject: [PATCH 33/95] Remove the delay when using COS. --- FM.cpp | 12 ++++++------ NXDNTX.cpp | 3 +-- P25TX.cpp | 2 +- POCSAGTX.cpp | 5 ++--- YSFTX.cpp | 5 ++--- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/FM.cpp b/FM.cpp index 3421d4d..ce40967 100644 --- a/FM.cpp +++ b/FM.cpp @@ -78,9 +78,11 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel); uint8_t ctcssState = m_ctcssRX.process(currentRFSample); - // Delay the audio by 100ms to better match the CTCSS detector output - m_inputRFRB.put(currentRFSample); - m_inputRFRB.get(currentRFSample); + if (!m_useCOS) { + // Delay the audio by 100ms to better match the CTCSS detector output + m_inputRFRB.put(currentRFSample); + m_inputRFRB.get(currentRFSample); + } q15_t currentExtSample; bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow @@ -153,9 +155,8 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) void CFM::process() { q15_t sample; - while(io.getSpace() >= 3U && m_outputRFRB.get(sample)) { + while(io.getSpace() >= 3U && m_outputRFRB.get(sample)) io.write(STATE_FM, &sample, 1U); - } } void CFM::reset() @@ -704,4 +705,3 @@ void CFM::insertSilence(uint16_t ms) for (uint32_t i = 0U; i < nSamples; i++) m_outputRFRB.put(0); } - diff --git a/NXDNTX.cpp b/NXDNTX.cpp index c4f5845..80ca120 100644 --- a/NXDNTX.cpp +++ b/NXDNTX.cpp @@ -82,7 +82,7 @@ void CNXDNTX::process() m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U]; } else { for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) { - uint8_t c; + uint8_t c = 0U; m_buffer.get(c); m_poBuffer[m_poLen++] = c; } @@ -168,4 +168,3 @@ uint8_t CNXDNTX::getSpace() const { return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES; } - diff --git a/P25TX.cpp b/P25TX.cpp index 6501f4e..fa2bfb6 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -79,7 +79,7 @@ void CP25TX::process() uint8_t length; m_buffer.get(length); for (uint8_t i = 0U; i < length; i++) { - uint8_t c; + uint8_t c = 0U; m_buffer.get(c); m_poBuffer[m_poLen++] = c; } diff --git a/POCSAGTX.cpp b/POCSAGTX.cpp index 0c252d8..335bd59 100644 --- a/POCSAGTX.cpp +++ b/POCSAGTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2018,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 @@ -61,7 +61,7 @@ void CPOCSAGTX::process() m_poBuffer[m_poLen++] = POCSAG_SYNC; } else { for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) { - uint8_t c; + uint8_t c = 0U; m_buffer.get(c); m_poBuffer[m_poLen++] = c; } @@ -147,4 +147,3 @@ uint8_t CPOCSAGTX::getSpace() const { return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES; } - diff --git a/YSFTX.cpp b/YSFTX.cpp index 5328418..15f3920 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX * Copyright (C) 2017 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify @@ -76,7 +76,7 @@ void CYSFTX::process() m_poBuffer[m_poLen++] = YSF_START_SYNC; } else { for (uint8_t i = 0U; i < YSF_FRAME_LENGTH_BYTES; i++) { - uint8_t c; + uint8_t c = 0U; m_buffer.get(c); m_poBuffer[m_poLen++] = c; } @@ -192,4 +192,3 @@ void CYSFTX::setParams(bool on, uint8_t txHang) m_loDev = on; m_txHang = txHang * 1200U; } - From c85978a4e35c8971aca91cec70b163fdb1d01e09 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 10 May 2020 17:33:50 +0100 Subject: [PATCH 34/95] Rescale the FM calibration level. --- CalFM.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CalFM.cpp b/CalFM.cpp index 3f847cc..21cf3ac 100644 --- a/CalFM.cpp +++ b/CalFM.cpp @@ -41,7 +41,7 @@ CCalFM::CCalFM() : m_frequency(0), m_length(0), m_tone(NULL), -m_level(128*32), +m_level(128 * 12), m_transmit(false), m_audioSeq(0), m_lastState(STATE_IDLE) @@ -52,29 +52,29 @@ void CCalFM::process() { const TONE_TABLE* entry = NULL; - if (m_modemState!=m_lastState) + if (m_modemState != m_lastState) { switch (m_modemState) { case STATE_FMCAL10K: - m_frequency=956U; + m_frequency = 956U; break; case STATE_FMCAL12K: - m_frequency=1039U; + m_frequency = 1039U; break; case STATE_FMCAL15K: - m_frequency=1247U; + m_frequency = 1247U; break; case STATE_FMCAL20K: - m_frequency=1633U; + m_frequency = 1633U; break; case STATE_FMCAL25K: - m_frequency=2079U; + m_frequency = 2079U; break; case STATE_FMCAL30K: - m_frequency=2495U; + m_frequency = 2495U; break; default: - m_frequency=0; + m_frequency = 0U; break; } From 36537c981c5dde31129b39add1c5ea7c82920553 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 10 May 2020 21:59:14 +0200 Subject: [PATCH 35/95] Write audio to serial port, blank to high audio, really ignore ext aduio when ext is disabled --- FM.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index ce40967..94eed85 100644 --- a/FM.cpp +++ b/FM.cpp @@ -86,6 +86,7 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) q15_t currentExtSample; bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow + inputExt = inputExt && m_extEnabled; if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { //Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue @@ -116,12 +117,15 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentBoost = m_extAudioBoost; } + + // Only let RF audio through when relaying RF audio if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { + currentSample = m_blanking.process(currentSample); + if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) m_downsampler.addSample(currentSample); - currentSample = m_blanking.process(currentSample); currentSample *= currentBoost; } else { currentSample = 0; @@ -157,6 +161,11 @@ void CFM::process() q15_t sample; while(io.getSpace() >= 3U && m_outputRFRB.get(sample)) io.write(STATE_FM, &sample, 1U); + + uint8_t serialSample; + //write data to serial port + while(m_downsampler.getPackedData(serialSample)) + serial.writeFMData(&serialSample, 1U); } void CFM::reset() From 89458a2c93de9377c95cf990713a514d7bcfe9c8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 10 May 2020 21:25:10 +0100 Subject: [PATCH 36/95] Release to STATE_IDLE under simpler conditions. --- FM.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/FM.cpp b/FM.cpp index 94eed85..d3cabfe 100644 --- a/FM.cpp +++ b/FM.cpp @@ -117,12 +117,10 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentBoost = m_extAudioBoost; } - - // Only let RF audio through when relaying RF audio if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { currentSample = m_blanking.process(currentSample); - + if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) m_downsampler.addSample(currentSample); @@ -159,12 +157,12 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) void CFM::process() { q15_t sample; - while(io.getSpace() >= 3U && m_outputRFRB.get(sample)) + while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) io.write(STATE_FM, &sample, 1U); uint8_t serialSample; //write data to serial port - while(m_downsampler.getPackedData(serialSample)) + while (m_downsampler.getPackedData(serialSample)) serial.writeFMData(&serialSample, 1U); } @@ -295,16 +293,14 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) } if (m_state == FS_LISTENING && m_modemState == STATE_FM) { - if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning()) { - DEBUG1("Change to STATE_IDLE"); - m_modemState = STATE_IDLE; - m_callsignTimer.stop(); - m_timeoutTimer.stop(); - m_kerchunkTimer.stop(); - m_ackMinTimer.stop(); - m_ackDelayTimer.stop(); - m_hangTimer.stop(); - } + DEBUG1("Change to STATE_IDLE"); + m_modemState = STATE_IDLE; + m_callsignTimer.stop(); + m_timeoutTimer.stop(); + m_kerchunkTimer.stop(); + m_ackMinTimer.stop(); + m_ackDelayTimer.stop(); + m_hangTimer.stop(); } } From 4bcc1e88c41bfbfb79396dbe2f7dc5833fd46bdb Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 07:52:27 +0200 Subject: [PATCH 37/95] Update to SAM 1.6.12 --- Makefile.Arduino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.Arduino b/Makefile.Arduino index 6046810..0afa96a 100644 --- a/Makefile.Arduino +++ b/Makefile.Arduino @@ -1,5 +1,5 @@ #!/usr/bin/make -# makefile for the arduino due (works with arduino IDE 1.6.11) +# makefile for the arduino due (works with arduino IDE 1.6.12) # # The original file can be found at https://github.com/pauldreik/arduino-due-makefile # @@ -34,7 +34,7 @@ OBJCOPY:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-n C:=$(CC) #SAM:=arduino/sam/ -SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.11 +SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.12 #CMSIS:=arduino/sam/system/CMSIS/ #LIBSAM:=arduino/sam/system/libsam TMPDIR:=$(PWD)/build From 4a5a260c2822997bd13c012c70c5011686bfcf61 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 11 May 2020 13:15:13 +0100 Subject: [PATCH 38/95] Perform FM mode changing in a more conventional manner. --- FM.cpp | 44 +++++++++++++++++++------------------------- FM.h | 1 + SerialPort.cpp | 18 ++++++++++++++++++ SerialPort.h | 1 + 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/FM.cpp b/FM.cpp index d3cabfe..ba0496a 100644 --- a/FM.cpp +++ b/FM.cpp @@ -43,6 +43,7 @@ m_kerchunkTimer(), m_ackMinTimer(), m_ackDelayTimer(), m_hangTimer(), +m_statusTimer(), m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz m_filterStage2(32768, 0,-32768, 32768, -50339, 19052), m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460), @@ -58,6 +59,8 @@ m_inputRFRB(4800U), // 200ms of audio m_outputRFRB(2400U), // 100ms of audio m_inputExtRB(2400U) // 100ms of Audio { + m_statusTimer.setTimeout(1U, 0U); + insertDelay(100U); } @@ -88,22 +91,18 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow inputExt = inputExt && m_extEnabled; - if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { + if (!inputExt && (CTCSS_NOT_READY(ctcssState))) { //Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue continue; - } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState != STATE_FM) { + } else if ((inputExt || CTCSS_READY(ctcssState))) { //we had enough samples for CTCSS and we are in some other mode than FM bool validCTCSS = CTCSS_VALID(ctcssState); stateMachine(validCTCSS && cos, inputExt); - if (m_modemState != STATE_FM) - continue; - } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState == STATE_FM) { + } else if ((inputExt || CTCSS_READY(ctcssState))) { //We had enough samples for CTCSS and we are in FM mode, trigger the state machine bool validCTCSS = CTCSS_VALID(ctcssState); stateMachine(validCTCSS && cos, inputExt); - if (m_modemState != STATE_FM) - break; - } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) { + } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && i == length - 1) { //Not enough samples for CTCSS but we already are in FM, trigger the state machine //but do not trigger the state machine on every single sample, save CPU! bool validCTCSS = CTCSS_VALID(ctcssState); @@ -149,8 +148,7 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentSample += m_ctcssTX.getAudio(); - if (m_modemState == STATE_FM) - m_outputRFRB.put(currentSample); + m_outputRFRB.put(currentSample); } } @@ -176,6 +174,7 @@ void CFM::reset() m_ackMinTimer.stop(); m_ackDelayTimer.stop(); m_hangTimer.stop(); + m_statusTimer.stop(); m_ctcssRX.reset(); m_rfAck.stop(); @@ -291,17 +290,6 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) default: break; } - - if (m_state == FS_LISTENING && m_modemState == STATE_FM) { - DEBUG1("Change to STATE_IDLE"); - m_modemState = STATE_IDLE; - m_callsignTimer.stop(); - m_timeoutTimer.stop(); - m_kerchunkTimer.stop(); - m_ackMinTimer.stop(); - m_ackDelayTimer.stop(); - m_hangTimer.stop(); - } } void CFM::clock(uint8_t length) @@ -313,6 +301,12 @@ void CFM::clock(uint8_t length) m_ackMinTimer.clock(length); m_ackDelayTimer.clock(length); m_hangTimer.clock(length); + m_statusTimer.clock(length); + + if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) { + serial.writeFMStatus(); + m_statusTimer.start(); + } } void CFM::listeningState(bool validRFSignal, bool validExtSignal) @@ -337,8 +331,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); - DEBUG1("Change to STATE_FM"); - m_modemState = STATE_FM; + m_statusTimer.start(); + serial.writeFMStatus(); } else if (validExtSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { DEBUG1("State to KERCHUNK_EXT"); @@ -359,8 +353,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); - DEBUG1("Change to STATE_FM"); - m_modemState = STATE_FM; + m_statusTimer.start(); + serial.writeFMStatus(); } } diff --git a/FM.h b/FM.h index 79c2935..daef1b1 100644 --- a/FM.h +++ b/FM.h @@ -84,6 +84,7 @@ private: CFMTimer m_ackMinTimer; CFMTimer m_ackDelayTimer; CFMTimer m_hangTimer; + CFMTimer m_statusTimer; CFMDirectFormI m_filterStage1; CFMDirectFormI m_filterStage2; CFMDirectFormI m_filterStage3; diff --git a/SerialPort.cpp b/SerialPort.cpp index d83ba63..0c33187 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -70,6 +70,7 @@ const uint8_t MMDVM_FM_PARAMS2 = 0x61U; const uint8_t MMDVM_FM_PARAMS3 = 0x62U; const uint8_t MMDVM_FM_PARAMS4 = 0x63U; const uint8_t MMDVM_FM_DATA = 0x65U; +const uint8_t MMDVM_FM_STATUS = 0x66U; const uint8_t MMDVM_ACK = 0x70U; const uint8_t MMDVM_NAK = 0x7FU; @@ -1261,6 +1262,23 @@ void CSerialPort::writeFMData(const uint8_t* data, uint8_t length) writeInt(1U, reply, count); } +void CSerialPort::writeFMStatus() +{ + if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) + return; + + if (!m_fmEnable) + return; + + uint8_t reply[10U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_FM_STATUS; + + writeInt(1U, reply, 3); +} + void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) { if (m_modemState != STATE_DSTARCAL) diff --git a/SerialPort.h b/SerialPort.h index d123bc7..9170368 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -51,6 +51,7 @@ public: void writeNXDNLost(); void writeFMData(const uint8_t* data, uint8_t length); + void writeFMStatus(); void writeCalData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length); From 99b853a97658123f1eed39c8b13c3211dca746ca Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 11 May 2020 15:00:53 +0100 Subject: [PATCH 39/95] Stop the status timer when leaving TX. --- FM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FM.cpp b/FM.cpp index ba0496a..4c8b45b 100644 --- a/FM.cpp +++ b/FM.cpp @@ -377,6 +377,7 @@ void CFM::kerchunkRFState(bool validSignal) m_timeoutTimer.stop(); m_ackMinTimer.stop(); m_callsignTimer.stop(); + m_statusTimer.stop(); } } @@ -456,6 +457,7 @@ void CFM::kerchunkExtState(bool validSignal) m_timeoutTimer.stop(); m_ackMinTimer.stop(); m_callsignTimer.stop(); + m_statusTimer.stop(); } } @@ -537,6 +539,7 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) DEBUG1("State to LISTENING"); m_state = FS_LISTENING; m_hangTimer.stop(); + m_statusTimer.stop(); if (m_callsignAtEnd) sendCallsign(); From 8cbd52aa726c43e5248d13ced9c05e0928cb5c26 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 07:52:27 +0200 Subject: [PATCH 40/95] Update to SAM 1.6.12 --- Makefile.Arduino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.Arduino b/Makefile.Arduino index 6046810..0afa96a 100644 --- a/Makefile.Arduino +++ b/Makefile.Arduino @@ -1,5 +1,5 @@ #!/usr/bin/make -# makefile for the arduino due (works with arduino IDE 1.6.11) +# makefile for the arduino due (works with arduino IDE 1.6.12) # # The original file can be found at https://github.com/pauldreik/arduino-due-makefile # @@ -34,7 +34,7 @@ OBJCOPY:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-n C:=$(CC) #SAM:=arduino/sam/ -SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.11 +SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.12 #CMSIS:=arduino/sam/system/CMSIS/ #LIBSAM:=arduino/sam/system/libsam TMPDIR:=$(PWD)/build From eac2aa4ac194205a284d1bc8e0613f7bc1677724 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 14:36:30 +0200 Subject: [PATCH 41/95] Write larger chunks of FM audio to the serial port --- FM.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/FM.cpp b/FM.cpp index 4c8b45b..9913863 100644 --- a/FM.cpp +++ b/FM.cpp @@ -158,10 +158,20 @@ void CFM::process() while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) io.write(STATE_FM, &sample, 1U); - uint8_t serialSample; - //write data to serial port - while (m_downsampler.getPackedData(serialSample)) - serial.writeFMData(&serialSample, 1U); + if(m_downsampler.getData() >= 127) { + uint8_t length = uint8_t(m_downsampler.getData()); + + if(length > 127U)//max message size on serial is 127 + length = 127U; + + uint8_t serialSamples[length]; + + for(uint8_t i = 0U; i < length; i++) { + uint8_t serialSample = 0U; + m_downsampler.getPackedData(serialSample); + } + serial.writeFMData(serialSamples, length); + } } void CFM::reset() From 5d4df6ffd975dc7afbd2a06b7e1578bdf16bfa18 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 16:04:58 +0200 Subject: [PATCH 42/95] Write larger chunks of data to IO --- FM.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/FM.cpp b/FM.cpp index 9913863..6fb513a 100644 --- a/FM.cpp +++ b/FM.cpp @@ -154,21 +154,36 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) void CFM::process() { - q15_t sample; - while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) - io.write(STATE_FM, &sample, 1U); + if (io.getSpace() > 2 && (m_outputRFRB.getData() >= 250 || m_state != STATE_FM)) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data + uint16_t length = m_outputRFRB.getData(); + uint16_t space = io.getSpace() - 2; - if(m_downsampler.getData() >= 127) { - uint8_t length = uint8_t(m_downsampler.getData()); + if(length > space) + length = space; + + q15_t samples[length]; + for(uint16_t i = 0; i < length; i++) { + q15_t sample = 0; + m_outputRFRB.get(sample); + samples[i] = sample; + } + + io.write(STATE_FM, samples, length); + } + + //Write audio to serial + if (m_downsampler.getData() >= 127 || m_state != STATE_FM) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data + uint16_t length = m_downsampler.getData(); if(length > 127U)//max message size on serial is 127 length = 127U; uint8_t serialSamples[length]; - for(uint8_t i = 0U; i < length; i++) { + for(uint16_t i = 0U; i < length; i++) { uint8_t serialSample = 0U; m_downsampler.getPackedData(serialSample); + serialSamples[i] = serialSample; } serial.writeFMData(serialSamples, length); } From 86ffc69b3088bd9b1d11aca0ddd8ade6ec58e851 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 19:01:05 +0200 Subject: [PATCH 43/95] Add getData --- FMDownsampler.cpp | 9 +++++++-- FMDownsampler.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index c2c3635..3209778 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -28,7 +28,7 @@ m_samplePackPointer(NULL), m_packIndex(0U), m_downSampleIndex(0U) { - m_samplePackPointer = &m_samplePack; + m_samplePackPointer = &m_samplePack; } void CFMDownsampler::addSample(q15_t sample) @@ -55,7 +55,7 @@ void CFMDownsampler::addSample(q15_t sample) break; } m_packIndex++; - if(m_packIndex >= 2U)//did we pack to samples ? + if(m_packIndex >= 2U)//did we pack two samples ? m_packIndex = 0U; } @@ -69,6 +69,11 @@ bool CFMDownsampler::getPackedData(uint8_t& data) return m_ringBuffer.get(data); } +uint16_t CFMDownsampler::getData() +{ + return m_ringBuffer.getData(); +} + void CFMDownsampler::reset() { m_downSampleIndex = 0; diff --git a/FMDownsampler.h b/FMDownsampler.h index 9b576c4..179493f 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -28,6 +28,7 @@ public: CFMDownsampler(uint16_t length); void addSample(q15_t sample); bool getPackedData(uint8_t& data); + uint16_t getData(); void reset(); private: From 6786b9b6b12bf827d981fa75e959b8f71f712464 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 19:01:50 +0200 Subject: [PATCH 44/95] Temporary revert to previous code --- FM.cpp | 70 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/FM.cpp b/FM.cpp index 6fb513a..9c25d83 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,10 +20,8 @@ #include "Globals.h" #include "FM.h" -const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; - -#define WRITE_BIT_AUDIO(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_AUDIO(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) +const uint16_t FM_TX_BLOCK_SIZE = 250U; +const uint16_t FM_SERIAL_BLOCK_SIZE = 127U; CFM::CFM() : m_callsign(), @@ -154,39 +152,51 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) void CFM::process() { - if (io.getSpace() > 2 && (m_outputRFRB.getData() >= 250 || m_state != STATE_FM)) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data - uint16_t length = m_outputRFRB.getData(); - uint16_t space = io.getSpace() - 2; + q15_t sample; + while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) + io.write(STATE_FM, &sample, 1U); - if(length > space) - length = space; + // if (io.getSpace() > 2 && (m_outputRFRB.getData() >= FM_TX_BLOCK_SIZE || m_state != STATE_FM)) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data + // uint16_t length = m_outputRFRB.getData(); + // uint16_t space = io.getSpace() - 2; - q15_t samples[length]; - for(uint16_t i = 0; i < length; i++) { - q15_t sample = 0; - m_outputRFRB.get(sample); - samples[i] = sample; - } + // if(length > FM_TX_BLOCK_SIZE) + // length = FM_TX_BLOCK_SIZE; + // if(space > FM_TX_BLOCK_SIZE) + // space = FM_TX_BLOCK_SIZE; + // if(length > space) + // length = space; - io.write(STATE_FM, samples, length); - } + // q15_t samples[FM_TX_BLOCK_SIZE]; + // for(uint16_t i = 0; i < length; i++) { + // q15_t sample = 0; + // m_outputRFRB.get(sample); + // samples[i] = sample; + // } - //Write audio to serial - if (m_downsampler.getData() >= 127 || m_state != STATE_FM) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data - uint16_t length = m_downsampler.getData(); + // io.write(STATE_FM, samples, length); + // } - if(length > 127U)//max message size on serial is 127 - length = 127U; + // //Write audio to serial + // if (m_downsampler.getData() >= 127 || m_state != STATE_FM) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data + // uint16_t length = m_downsampler.getData(); - uint8_t serialSamples[length]; + // if(length > FM_SERIAL_BLOCK_SIZE)//max message size on serial is 127 + // length = FM_SERIAL_BLOCK_SIZE; - for(uint16_t i = 0U; i < length; i++) { - uint8_t serialSample = 0U; - m_downsampler.getPackedData(serialSample); - serialSamples[i] = serialSample; - } - serial.writeFMData(serialSamples, length); - } + // if(length > FM_SERIAL_BLOCK_SIZE) + // length = FM_SERIAL_BLOCK_SIZE; + + // uint8_t serialSamples[FM_SERIAL_BLOCK_SIZE]; + + // for(uint16_t i = 0U; i < length; i++) { + // uint8_t serialSample = 0U; + // m_downsampler.getPackedData(serialSample); + // serialSamples[i] = serialSample; + // } + + // serial.writeFMData(serialSamples, length); + // } } void CFM::reset() From b4a125a75997bb09783f0e4f28cad77728d39197 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 22:31:50 +0200 Subject: [PATCH 45/95] Add debug info TX switching --- IO.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IO.cpp b/IO.cpp index 7b000fb..c668f1f 100644 --- a/IO.cpp +++ b/IO.cpp @@ -264,6 +264,7 @@ void CIO::process() if (m_txBuffer.getData() == 0U && m_tx) { m_tx = false; setPTTInt(m_pttInvert ? true : false); + DEBUG1("Process TX OFF"); } if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) { @@ -453,6 +454,7 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t if (!m_tx) { m_tx = true; setPTTInt(m_pttInvert ? false : true); + DEBUG1("Write TX ON"); } q15_t txLevel = 0; From 042c26b3bb29ab7b353594899f0a7b4a33717ea3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 22:32:24 +0200 Subject: [PATCH 46/95] Trying to fix no tx, WIP --- FM.cpp | 51 +++++++++++++++++++++++++++++---------------------- FM.h | 3 ++- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/FM.cpp b/FM.cpp index 9c25d83..1e1f5aa 100644 --- a/FM.cpp +++ b/FM.cpp @@ -62,7 +62,7 @@ m_inputExtRB(2400U) // 100ms of Audio insertDelay(100U); } -void CFM::samples(bool cos, const q15_t* samples, uint8_t length) +void CFM::samples(bool cos, q15_t* samples, uint8_t length) { if (m_useCOS) { if (m_cosInvert) @@ -147,35 +147,37 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length) currentSample += m_ctcssTX.getAudio(); m_outputRFRB.put(currentSample); + //samples[i] = currentSample; } + + // XXX This relays audio correctly, no t, process need to be commented + // if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) + // io.write(STATE_FM, samples, i); + } void CFM::process() { - q15_t sample; - while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) - io.write(STATE_FM, &sample, 1U); + uint16_t space = io.getSpace() - 2U; + uint16_t length = m_outputRFRB.getData(); + if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { - // if (io.getSpace() > 2 && (m_outputRFRB.getData() >= FM_TX_BLOCK_SIZE || m_state != STATE_FM)) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data - // uint16_t length = m_outputRFRB.getData(); - // uint16_t space = io.getSpace() - 2; + if(length > FM_TX_BLOCK_SIZE) + length = FM_TX_BLOCK_SIZE; + if(space > FM_TX_BLOCK_SIZE) + space = FM_TX_BLOCK_SIZE; + if(length > space) + length = space; - // if(length > FM_TX_BLOCK_SIZE) - // length = FM_TX_BLOCK_SIZE; - // if(space > FM_TX_BLOCK_SIZE) - // space = FM_TX_BLOCK_SIZE; - // if(length > space) - // length = space; + q15_t samples[FM_TX_BLOCK_SIZE]; + for(uint16_t i = 0U; i < length; i++) { + q15_t sample = 0; + m_outputRFRB.get(sample); + samples[i] = sample; + } - // q15_t samples[FM_TX_BLOCK_SIZE]; - // for(uint16_t i = 0; i < length; i++) { - // q15_t sample = 0; - // m_outputRFRB.get(sample); - // samples[i] = sample; - // } - - // io.write(STATE_FM, samples, length); - // } + io.write(STATE_FM, samples, length); + } // //Write audio to serial // if (m_downsampler.getData() >= 127 || m_state != STATE_FM) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data @@ -325,6 +327,11 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) default: break; } + + if (m_state == FS_LISTENING) { + m_outputRFRB.reset(); + m_downsampler.reset(); + } } void CFM::clock(uint8_t length) diff --git a/FM.h b/FM.h index daef1b1..a4c82f9 100644 --- a/FM.h +++ b/FM.h @@ -51,7 +51,7 @@ class CFM { public: CFM(); - void samples(bool cos, const q15_t* samples, uint8_t length); + void samples(bool cos, q15_t* samples, uint8_t length); void process(); @@ -117,6 +117,7 @@ private: void clock(uint8_t length); void sendCallsign(); + void sendBeeps(); void beginRelaying(); void insertDelay(uint16_t ms); From 1d04c1e90388e5e53d5081a60e614160497d3fda Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 11 May 2020 22:35:46 +0200 Subject: [PATCH 47/95] Typo --- FM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index 1e1f5aa..7eb7261 100644 --- a/FM.cpp +++ b/FM.cpp @@ -150,7 +150,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) //samples[i] = currentSample; } - // XXX This relays audio correctly, no t, process need to be commented + // XXX This relays audio correctly, no tones yet, process need to be commented // if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) // io.write(STATE_FM, samples, i); From a5aabd8fac4cafdb68f507c18c85bd04fae6f84d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 08:35:48 +0200 Subject: [PATCH 48/95] Update TX ON/OFF debug info --- IO.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IO.cpp b/IO.cpp index c668f1f..beea107 100644 --- a/IO.cpp +++ b/IO.cpp @@ -264,7 +264,7 @@ void CIO::process() if (m_txBuffer.getData() == 0U && m_tx) { m_tx = false; setPTTInt(m_pttInvert ? true : false); - DEBUG1("Process TX OFF"); + DEBUG1("TX OFF"); } if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) { @@ -454,7 +454,7 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t if (!m_tx) { m_tx = true; setPTTInt(m_pttInvert ? false : true); - DEBUG1("Write TX ON"); + DEBUG1("TX ON"); } q15_t txLevel = 0; From ca1cc7096a4fdb834cec1cd532b844d092e8870a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 08:36:38 +0200 Subject: [PATCH 49/95] Fix modem not goign on transmit, still some cleansing to be done --- FM.cpp | 22 ++++++++-------------- FM.h | 1 - 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/FM.cpp b/FM.cpp index 7eb7261..8a7d144 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,7 +20,7 @@ #include "Globals.h" #include "FM.h" -const uint16_t FM_TX_BLOCK_SIZE = 250U; +const uint16_t FM_TX_BLOCK_SIZE = 127U; const uint16_t FM_SERIAL_BLOCK_SIZE = 127U; CFM::CFM() : @@ -89,18 +89,18 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow inputExt = inputExt && m_extEnabled; - if (!inputExt && (CTCSS_NOT_READY(ctcssState))) { + if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { //Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue continue; - } else if ((inputExt || CTCSS_READY(ctcssState))) { + } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState != STATE_FM) { //we had enough samples for CTCSS and we are in some other mode than FM bool validCTCSS = CTCSS_VALID(ctcssState); stateMachine(validCTCSS && cos, inputExt); - } else if ((inputExt || CTCSS_READY(ctcssState))) { + } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState == STATE_FM) { //We had enough samples for CTCSS and we are in FM mode, trigger the state machine bool validCTCSS = CTCSS_VALID(ctcssState); stateMachine(validCTCSS && cos, inputExt); - } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && i == length - 1) { + } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) { //Not enough samples for CTCSS but we already are in FM, trigger the state machine //but do not trigger the state machine on every single sample, save CPU! bool validCTCSS = CTCSS_VALID(ctcssState); @@ -147,13 +147,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) currentSample += m_ctcssTX.getAudio(); m_outputRFRB.put(currentSample); - //samples[i] = currentSample; } - - // XXX This relays audio correctly, no tones yet, process need to be commented - // if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) - // io.write(STATE_FM, samples, i); - } void CFM::process() @@ -744,8 +738,8 @@ void CFM::insertDelay(uint16_t ms) void CFM::insertSilence(uint16_t ms) { - uint32_t nSamples = ms * 24U; + // uint32_t nSamples = ms * 24U; - for (uint32_t i = 0U; i < nSamples; i++) - m_outputRFRB.put(0); + // for (uint32_t i = 0U; i < nSamples; i++) + // m_outputRFRB.put(0); } diff --git a/FM.h b/FM.h index a4c82f9..3255c05 100644 --- a/FM.h +++ b/FM.h @@ -117,7 +117,6 @@ private: void clock(uint8_t length); void sendCallsign(); - void sendBeeps(); void beginRelaying(); void insertDelay(uint16_t ms); From 1b40044a2306f9ba8d06c4cc3d157f13b0992082 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 09:28:24 +0200 Subject: [PATCH 50/95] Re-enable write audio to serial --- FM.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/FM.cpp b/FM.cpp index 8a7d144..a335a60 100644 --- a/FM.cpp +++ b/FM.cpp @@ -173,26 +173,24 @@ void CFM::process() io.write(STATE_FM, samples, length); } - // //Write audio to serial - // if (m_downsampler.getData() >= 127 || m_state != STATE_FM) {//if we just left FM mode, so write all what is left in buffer, regardless of the amoutn of data - // uint16_t length = m_downsampler.getData(); + if (m_extEnabled) { + length = m_downsampler.getData(); + //Write audio to serial + if (length >= FM_SERIAL_BLOCK_SIZE) { + + if(length > FM_SERIAL_BLOCK_SIZE) + length = FM_SERIAL_BLOCK_SIZE; - // if(length > FM_SERIAL_BLOCK_SIZE)//max message size on serial is 127 - // length = FM_SERIAL_BLOCK_SIZE; + uint8_t serialSamples[FM_SERIAL_BLOCK_SIZE]; + for(uint16_t i = 0U; i < length; i++) { + uint8_t serialSample = 0U; + m_downsampler.getPackedData(serialSample); + serialSamples[i] = serialSample; + } - // if(length > FM_SERIAL_BLOCK_SIZE) - // length = FM_SERIAL_BLOCK_SIZE; - - // uint8_t serialSamples[FM_SERIAL_BLOCK_SIZE]; - - // for(uint16_t i = 0U; i < length; i++) { - // uint8_t serialSample = 0U; - // m_downsampler.getPackedData(serialSample); - // serialSamples[i] = serialSample; - // } - - // serial.writeFMData(serialSamples, length); - // } + serial.writeFMData(serialSamples, length); + } + } } void CFM::reset() From 0fad84b46dbdeef95cca87e49adb1bbc1ef61f9a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 09:29:01 +0200 Subject: [PATCH 51/95] Remove silence --- FM.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/FM.cpp b/FM.cpp index a335a60..1adb307 100644 --- a/FM.cpp +++ b/FM.cpp @@ -359,8 +359,6 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertSilence(50U); - beginRelaying(); m_callsignTimer.start(); @@ -381,8 +379,6 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertSilence(50U); - beginRelaying(); m_callsignTimer.start(); @@ -733,11 +729,3 @@ void CFM::insertDelay(uint16_t ms) for (uint32_t i = 0U; i < nSamples; i++) m_inputRFRB.put(0); } - -void CFM::insertSilence(uint16_t ms) -{ - // uint32_t nSamples = ms * 24U; - - // for (uint32_t i = 0U; i < nSamples; i++) - // m_outputRFRB.put(0); -} From a0a3080da2e7a023a7a53f282d579c0bcb034fe8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 14:15:04 +0200 Subject: [PATCH 52/95] Make sure downsampler always buffers 22 samples at a time --- FM.cpp | 102 +++++++++++++++++++++++++++++----------------- FM.h | 1 - FMDownsampler.cpp | 8 ++-- FMDownsampler.h | 10 ++++- 4 files changed, 77 insertions(+), 44 deletions(-) diff --git a/FM.cpp b/FM.cpp index 1adb307..69b25c0 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,8 +20,8 @@ #include "Globals.h" #include "FM.h" -const uint16_t FM_TX_BLOCK_SIZE = 127U; -const uint16_t FM_SERIAL_BLOCK_SIZE = 127U; +const uint16_t FM_TX_BLOCK_SIZE = 400U; +const uint16_t FM_SERIAL_BLOCK_SIZE = 126U; CFM::CFM() : m_callsign(), @@ -50,7 +50,7 @@ m_useCOS(true), m_cosInvert(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), -m_downsampler(1200U),// 100 ms of audio +m_downsampler(400U),// 100 ms of audio m_extEnabled(false), m_rxLevel(1), m_inputRFRB(4800U), // 200ms of audio @@ -117,10 +117,6 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) // Only let RF audio through when relaying RF audio if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { currentSample = m_blanking.process(currentSample); - - if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) - m_downsampler.addSample(currentSample); - currentSample *= currentBoost; } else { currentSample = 0; @@ -153,44 +149,75 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) void CFM::process() { uint16_t space = io.getSpace() - 2U; - uint16_t length = m_outputRFRB.getData(); - if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { - - if(length > FM_TX_BLOCK_SIZE) - length = FM_TX_BLOCK_SIZE; + uint16_t txLength = m_outputRFRB.getData(); + if (space > 2 && txLength >= FM_TX_BLOCK_SIZE ) { + + if(txLength > FM_TX_BLOCK_SIZE) + txLength = FM_TX_BLOCK_SIZE; if(space > FM_TX_BLOCK_SIZE) space = FM_TX_BLOCK_SIZE; - if(length > space) - length = space; + if(txLength > space) + txLength = space; q15_t samples[FM_TX_BLOCK_SIZE]; - for(uint16_t i = 0U; i < length; i++) { + + for (uint16_t i = 0U; i < txLength; i++) { q15_t sample = 0; m_outputRFRB.get(sample); samples[i] = sample; - } - io.write(STATE_FM, samples, length); - } - - if (m_extEnabled) { - length = m_downsampler.getData(); - //Write audio to serial - if (length >= FM_SERIAL_BLOCK_SIZE) { - - if(length > FM_SERIAL_BLOCK_SIZE) - length = FM_SERIAL_BLOCK_SIZE; - - uint8_t serialSamples[FM_SERIAL_BLOCK_SIZE]; - for(uint16_t i = 0U; i < length; i++) { - uint8_t serialSample = 0U; - m_downsampler.getPackedData(serialSample); - serialSamples[i] = serialSample; + if(m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) { + m_downsampler.addSample(sample); + uint16_t downSamplerLength = m_downsampler.getData(); + if(downSamplerLength >= FM_SERIAL_BLOCK_SIZE) { + TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; + for(uint16_t j = 0U; j < downSamplerLength; j++) { + m_downsampler.getPackedData(serialSamples[j]); + } + serial.writeFMData((uint8_t*)serialSamples, txLength * sizeof(TSamplePairPack)); + } } - - serial.writeFMData(serialSamples, length); } + + io.write(STATE_FM, samples, txLength); } + // if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { + + // if(length > FM_TX_BLOCK_SIZE) + // length = FM_TX_BLOCK_SIZE; + // if(space > FM_TX_BLOCK_SIZE) + // space = FM_TX_BLOCK_SIZE; + // if(length > space) + // length = space; + + // q15_t samples[FM_TX_BLOCK_SIZE]; + // for(uint16_t i = 0U; i < length; i++) { + // q15_t sample = 0; + // m_outputRFRB.get(sample); + // samples[i] = sample; + // } + + // io.write(STATE_FM, samples, length); + // } + + // if (m_extEnabled) { + // length = m_downsampler.getData(); + // //Write audio to serial + // if (length >= FM_SERIAL_BLOCK_SIZE) { + + // if(length > FM_SERIAL_BLOCK_SIZE) + // length = FM_SERIAL_BLOCK_SIZE; + + // TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; + // for(uint16_t i = 0U; i < length; i++) { + // TSamplePairPack samplePair = {0U, 0U, 0U}; + // m_downsampler.getPackedData(samplePair); + // serialSamples[i] = samplePair; + // } + + // serial.writeFMData((uint8_t*)&serialSamples, length * sizeof(TSamplePairPack)); + // } + // } } void CFM::reset() @@ -338,7 +365,7 @@ void CFM::clock(uint8_t length) m_statusTimer.clock(length); if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) { - serial.writeFMStatus(); + serial.writeFMStatus(false); m_statusTimer.start(); } } @@ -364,7 +391,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(); + serial.writeFMStatus(true); } else if (validExtSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { DEBUG1("State to KERCHUNK_EXT"); @@ -384,7 +411,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(); + serial.writeFMStatus(false); } } @@ -729,3 +756,4 @@ void CFM::insertDelay(uint16_t ms) for (uint32_t i = 0U; i < nSamples; i++) m_inputRFRB.put(0); } + diff --git a/FM.h b/FM.h index 3255c05..285c20b 100644 --- a/FM.h +++ b/FM.h @@ -120,7 +120,6 @@ private: void beginRelaying(); void insertDelay(uint16_t ms); - void insertSilence(uint16_t ms); }; #endif diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 3209778..4c6b733 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -43,9 +43,9 @@ void CFMDownsampler::addSample(q15_t sample) m_samplePack |= uint32_t(sample); //we did not use MSB; skip it - m_ringBuffer.put(m_samplePackPointer[1U]); - m_ringBuffer.put(m_samplePackPointer[2U]); - m_ringBuffer.put(m_samplePackPointer[3U]); + TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; + + m_ringBuffer.put(pair); m_samplePack = 0;//reset the sample pack } @@ -64,7 +64,7 @@ void CFMDownsampler::addSample(q15_t sample) m_downSampleIndex = 0U; } -bool CFMDownsampler::getPackedData(uint8_t& data) +bool CFMDownsampler::getPackedData(TSamplePairPack& data) { return m_ringBuffer.get(data); } diff --git a/FMDownsampler.h b/FMDownsampler.h index 179493f..677a315 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -23,16 +23,22 @@ #include "Config.h" #include "RingBuffer.h" +struct TSamplePairPack { + uint8_t byte0; + uint8_t byte1; + uint8_t byte2; +}; + class CFMDownsampler { public: CFMDownsampler(uint16_t length); void addSample(q15_t sample); - bool getPackedData(uint8_t& data); + bool getPackedData(TSamplePairPack& data); uint16_t getData(); void reset(); private: - CRingBuffer m_ringBuffer; + CRingBuffer m_ringBuffer; uint32_t m_samplePack; uint32_t *m_samplePackPointer; From d23c0900c18e7f4f4f777823d37865069aabeacd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 14:18:27 +0200 Subject: [PATCH 53/95] Fix compilation --- FM.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FM.cpp b/FM.cpp index 69b25c0..a73bd2f 100644 --- a/FM.cpp +++ b/FM.cpp @@ -365,7 +365,7 @@ void CFM::clock(uint8_t length) m_statusTimer.clock(length); if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) { - serial.writeFMStatus(false); + serial.writeFMStatus(); m_statusTimer.start(); } } @@ -391,7 +391,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(true); + serial.writeFMStatus(); } else if (validExtSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { DEBUG1("State to KERCHUNK_EXT"); @@ -411,7 +411,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(false); + serial.writeFMStatus(); } } From b64712f65720a99081381c5ee4468f3852550903 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 14:45:03 +0200 Subject: [PATCH 54/95] Restore silence --- FM.cpp | 49 ++++++++++++------------------------------------- FM.h | 1 + 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/FM.cpp b/FM.cpp index a73bd2f..06f6cfd 100644 --- a/FM.cpp +++ b/FM.cpp @@ -181,43 +181,6 @@ void CFM::process() io.write(STATE_FM, samples, txLength); } - // if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { - - // if(length > FM_TX_BLOCK_SIZE) - // length = FM_TX_BLOCK_SIZE; - // if(space > FM_TX_BLOCK_SIZE) - // space = FM_TX_BLOCK_SIZE; - // if(length > space) - // length = space; - - // q15_t samples[FM_TX_BLOCK_SIZE]; - // for(uint16_t i = 0U; i < length; i++) { - // q15_t sample = 0; - // m_outputRFRB.get(sample); - // samples[i] = sample; - // } - - // io.write(STATE_FM, samples, length); - // } - - // if (m_extEnabled) { - // length = m_downsampler.getData(); - // //Write audio to serial - // if (length >= FM_SERIAL_BLOCK_SIZE) { - - // if(length > FM_SERIAL_BLOCK_SIZE) - // length = FM_SERIAL_BLOCK_SIZE; - - // TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; - // for(uint16_t i = 0U; i < length; i++) { - // TSamplePairPack samplePair = {0U, 0U, 0U}; - // m_downsampler.getPackedData(samplePair); - // serialSamples[i] = samplePair; - // } - - // serial.writeFMData((uint8_t*)&serialSamples, length * sizeof(TSamplePairPack)); - // } - // } } void CFM::reset() @@ -386,6 +349,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } + insertDelay(50U); + beginRelaying(); m_callsignTimer.start(); @@ -406,6 +371,8 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } + insertDelay(50U); + beginRelaying(); m_callsignTimer.start(); @@ -757,3 +724,11 @@ void CFM::insertDelay(uint16_t ms) m_inputRFRB.put(0); } +void CFM::insertSilence(uint16_t ms) +{ + uint32_t nSamples = ms * 24U; + + for (uint32_t i = 0U; i < nSamples; i++) + m_outputRFRB.put(0); +} + diff --git a/FM.h b/FM.h index 285c20b..3255c05 100644 --- a/FM.h +++ b/FM.h @@ -120,6 +120,7 @@ private: void beginRelaying(); void insertDelay(uint16_t ms); + void insertSilence(uint16_t ms); }; #endif From 9467b10e5cbe81374356f3dbaa2eabaad297ce56 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 16:19:19 +0200 Subject: [PATCH 55/95] Fix silence --- FM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FM.cpp b/FM.cpp index 06f6cfd..3be1176 100644 --- a/FM.cpp +++ b/FM.cpp @@ -349,7 +349,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertDelay(50U); + insertSilence(50U); beginRelaying(); @@ -371,7 +371,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertDelay(50U); + insertSilence(50U); beginRelaying(); From 496afcb40e4c3bae1e29c4467da79b89f3916897 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 16:19:19 +0200 Subject: [PATCH 56/95] Fix silence --- FM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FM.cpp b/FM.cpp index 06f6cfd..3be1176 100644 --- a/FM.cpp +++ b/FM.cpp @@ -349,7 +349,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertDelay(50U); + insertSilence(50U); beginRelaying(); @@ -371,7 +371,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertDelay(50U); + insertSilence(50U); beginRelaying(); From 7dc420c8ffba0880440bfe61c406f1e4a7a43c00 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 12 May 2020 15:58:54 +0100 Subject: [PATCH 57/95] Add the FM controller status to the FM Status message. --- FM.cpp | 7 +++---- SerialPort.cpp | 7 ++++--- SerialPort.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/FM.cpp b/FM.cpp index 591aa38..664df88 100644 --- a/FM.cpp +++ b/FM.cpp @@ -328,7 +328,7 @@ void CFM::clock(uint8_t length) m_statusTimer.clock(length); if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) { - serial.writeFMStatus(); + serial.writeFMStatus(m_state); m_statusTimer.start(); } } @@ -356,7 +356,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(); + serial.writeFMStatus(m_state); } else if (validExtSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { DEBUG1("State to KERCHUNK_EXT"); @@ -378,7 +378,7 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); m_statusTimer.start(); - serial.writeFMStatus(); + serial.writeFMStatus(m_state); } } @@ -731,4 +731,3 @@ void CFM::insertSilence(uint16_t ms) for (uint32_t i = 0U; i < nSamples; i++) m_outputRFRB.put(0); } - diff --git a/SerialPort.cpp b/SerialPort.cpp index c7c6cc1..82913fa 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1263,7 +1263,7 @@ void CSerialPort::writeFMData(const uint8_t* data, uint8_t length) writeInt(1U, reply, count); } -void CSerialPort::writeFMStatus() +void CSerialPort::writeFMStatus(uint8_t status) { if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) return; @@ -1274,10 +1274,11 @@ void CSerialPort::writeFMStatus() uint8_t reply[10U]; reply[0U] = MMDVM_FRAME_START; - reply[1U] = 3U; + reply[1U] = 4U; reply[2U] = MMDVM_FM_STATUS; + reply[3U] = status; - writeInt(1U, reply, 3); + writeInt(1U, reply, 4); } void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) diff --git a/SerialPort.h b/SerialPort.h index 9170368..2b5eb9a 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -51,7 +51,7 @@ public: void writeNXDNLost(); void writeFMData(const uint8_t* data, uint8_t length); - void writeFMStatus(); + void writeFMStatus(uint8_t status); void writeCalData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length); From 66de35b6d8e4e01adb1d448e8cb05e209b44f287 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 17:55:24 +0200 Subject: [PATCH 58/95] Move downsamplig call back to samples --- FM.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/FM.cpp b/FM.cpp index 3be1176..085e03d 100644 --- a/FM.cpp +++ b/FM.cpp @@ -21,7 +21,8 @@ #include "FM.h" const uint16_t FM_TX_BLOCK_SIZE = 400U; -const uint16_t FM_SERIAL_BLOCK_SIZE = 126U; +const uint16_t FM_SERIAL_BLOCK_SIZE = 42U;//this is actually the number of sample pairs to send over serial. One sample pair is 3bytes. + //three times this vqlue shall never exceed 126 ! CFM::CFM() : m_callsign(), @@ -117,6 +118,9 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) // Only let RF audio through when relaying RF audio if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { currentSample = m_blanking.process(currentSample); + if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) + m_downsampler.addSample(currentSample); + currentSample *= currentBoost; } else { currentSample = 0; @@ -166,15 +170,17 @@ void CFM::process() m_outputRFRB.get(sample); samples[i] = sample; - if(m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF)) { - m_downsampler.addSample(sample); + if(m_extEnabled) { uint16_t downSamplerLength = m_downsampler.getData(); + if(downSamplerLength >= FM_SERIAL_BLOCK_SIZE) { TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; + for(uint16_t j = 0U; j < downSamplerLength; j++) { m_downsampler.getPackedData(serialSamples[j]); } - serial.writeFMData((uint8_t*)serialSamples, txLength * sizeof(TSamplePairPack)); + + serial.writeFMData((uint8_t*)serialSamples, downSamplerLength * sizeof(TSamplePairPack)); } } } From 994226e4b13f4448958ca292c3f5c723ded20ecc Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 12 May 2020 22:06:26 +0200 Subject: [PATCH 59/95] Tighten incoming data, Add FM UpSampler --- FM.cpp | 32 ++--------------- FM.h | 3 +- FMDownsampler.h | 7 +--- FMSamplePairPack.h | 29 +++++++++++++++ FMUpSampler.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++ FMUpSampler.h | 46 ++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 37 deletions(-) create mode 100644 FMSamplePairPack.h create mode 100644 FMUpSampler.cpp create mode 100644 FMUpSampler.h diff --git a/FM.cpp b/FM.cpp index 080f6b7..a5349f4 100644 --- a/FM.cpp +++ b/FM.cpp @@ -87,7 +87,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) } q15_t currentExtSample; - bool inputExt = m_inputExtRB.get(currentExtSample);//always consume the external input data so it does not overflow + bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow inputExt = inputExt && m_extEnabled; if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { @@ -691,35 +691,7 @@ uint8_t CFM::getSpace() const uint8_t CFM::writeData(const uint8_t* data, uint8_t length) { - for (uint8_t i = 0U; i < length; i += 3U) { - uint16_t sample1 = 0U; - uint16_t sample2 = 0U; - uint32_t MASK = 0x00000FFFU; - - uint32_t pack = 0U; - uint8_t* packPointer = (uint8_t*)&pack; - - packPointer[1U] = data[i]; - packPointer[2U] = data[i + 1U]; - packPointer[3U] = data[i + 2U]; - - sample2 = uint16_t(pack & MASK); - sample1 = uint16_t(pack >> 12); - - // Convert from uint16_t (0 - +4095) to Q15 (-2048 - +2047). - // Incoming data has sample rate 8kHz, just add 2 empty samples after - // every incoming sample to upsample to 24kHz - m_inputExtRB.put(q15_t(sample1) - 2048); - m_inputExtRB.put(0); - m_inputExtRB.put(0); - m_inputExtRB.put(q15_t(sample2) - 2048); - m_inputExtRB.put(0); - m_inputExtRB.put(0); - } - - // Received audio is now in Q15 format in samples, with length nSamples. - - return 0U; + m_inputExtRB.addData(data, length); } void CFM::insertDelay(uint16_t ms) diff --git a/FM.h b/FM.h index 05f08b6..a179fd3 100644 --- a/FM.h +++ b/FM.h @@ -30,6 +30,7 @@ #include "RingBuffer.h" #include "FMDirectForm1.h" #include "FMDownsampler.h" +#include "FMUpSampler.h" enum FM_STATE { FS_LISTENING, @@ -98,7 +99,7 @@ private: q15_t m_rxLevel; CRingBuffer m_inputRFRB; CRingBuffer m_outputRFRB; - CRingBuffer m_inputExtRB; + CFMUpSampler m_inputExtRB; void stateMachine(bool validRFSignal, bool validExtSignal); void listeningState(bool validRFSignal, bool validExtSignal); diff --git a/FMDownsampler.h b/FMDownsampler.h index 677a315..6ec7201 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -22,12 +22,7 @@ #include "Config.h" #include "RingBuffer.h" - -struct TSamplePairPack { - uint8_t byte0; - uint8_t byte1; - uint8_t byte2; -}; +#include "FMSamplePairPack.h" class CFMDownsampler { public: diff --git a/FMSamplePairPack.h b/FMSamplePairPack.h new file mode 100644 index 0000000..1301173 --- /dev/null +++ b/FMSamplePairPack.h @@ -0,0 +1,29 @@ +/* + * 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(TSAMPLEPACK_H) +#define TSAMPLEPACK_H + +struct TSamplePairPack { + uint8_t byte0; + uint8_t byte1; + uint8_t byte2; +}; + +#endif \ No newline at end of file diff --git a/FMUpSampler.cpp b/FMUpSampler.cpp new file mode 100644 index 0000000..d84f185 --- /dev/null +++ b/FMUpSampler.cpp @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#include "FMUpSampler.h" + +const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU; + +CFMUpSampler::CFMUpSampler(uint16_t length) : +m_upSampleIndex(0), +m_pack({0U, 0U, 0U}), +m_samples(length) +{ +} + +void CFMUpSampler::reset() +{ + m_upSampleIndex = 0U; + m_pack = {0U, 0U, 0U}; + m_samples.reset(); +} + +void CFMUpSampler::addData(const uint8_t* data, uint16_t length) +{ + for(uint16_t i = 0U; i < length; i++) { + switch (m_upSampleIndex) + { + case 0U: + m_pack.byte0 = data[i]; + break; + case 1U: + m_pack.byte1 = data[i]; + break; + case 2U: { + m_pack.byte2 = data[i]; + + uint32_t pack = 0U; + uint8_t* packPtr = (uint8_t*)&pack; + + packPtr[1] = m_pack.byte0; + packPtr[2] = m_pack.byte1; + packPtr[3] = m_pack.byte2; + + q15_t sample2 = q15_t(uint16_t(pack & FM_UPSAMPLE_MASK) - 2048); + q15_t sample1 = q15_t(uint16_t(pack >> 12) - 2048); + + m_samples.put(sample1); + m_samples.put(0); + m_samples.put(0); + m_samples.put(sample2); + m_samples.put(0); + m_samples.put(0); + } + break; + default: + //shoudl never happen + break; + } + + m_upSampleIndex ++; + if (m_upSampleIndex > 2U) + m_upSampleIndex = 0U; + } +} + +bool CFMUpSampler::getSample(q15_t& sample) +{ + return m_samples.get(sample); +} + +uint16_t CFMUpSampler::getSpace() const +{ + return m_samples.getSpace(); +} \ No newline at end of file diff --git a/FMUpSampler.h b/FMUpSampler.h new file mode 100644 index 0000000..cee671b --- /dev/null +++ b/FMUpSampler.h @@ -0,0 +1,46 @@ +/* + * 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(FMUPSAMPLER_H) +#define FMUPSAMPLER_H + +#include "Config.h" +#include "RingBuffer.h" +#include "FMSamplePairPack.h" + +class CFMUpSampler { +public: + CFMUpSampler(uint16_t length); + + void reset(); + + void addData(const uint8_t* data, uint16_t length); + + bool getSample(q15_t& sample); + + uint16_t getSpace() const; + +private: + uint8_t m_upSampleIndex; + TSamplePairPack m_pack; + CRingBuffer m_samples; +}; + +#endif \ No newline at end of file From 62f239ccc9f7ecca2ff9383af8e5422a0e16a523 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 08:31:59 +0200 Subject: [PATCH 60/95] Fix modem crash while writing to serial, Split IO write and serial write to 2 separate loops. --- FM.cpp | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/FM.cpp b/FM.cpp index a5349f4..82fdac1 100644 --- a/FM.cpp +++ b/FM.cpp @@ -22,7 +22,7 @@ const uint16_t FM_TX_BLOCK_SIZE = 400U; const uint16_t FM_SERIAL_BLOCK_SIZE = 42U;//this is actually the number of sample pairs to send over serial. One sample pair is 3bytes. - //three times this vqlue shall never exceed 126 ! + //three times this value shall never exceed 126 ! CFM::CFM() : m_callsign(), @@ -153,39 +153,42 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) void CFM::process() { uint16_t space = io.getSpace() - 2U; - uint16_t txLength = m_outputRFRB.getData(); - if (space > 2 && txLength >= FM_TX_BLOCK_SIZE ) { + uint16_t length = m_outputRFRB.getData(); + if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { - if(txLength > FM_TX_BLOCK_SIZE) - txLength = FM_TX_BLOCK_SIZE; + if(length > FM_TX_BLOCK_SIZE) + length = FM_TX_BLOCK_SIZE; if(space > FM_TX_BLOCK_SIZE) space = FM_TX_BLOCK_SIZE; - if(txLength > space) - txLength = space; + if(length > space) + length = space; q15_t samples[FM_TX_BLOCK_SIZE]; - for (uint16_t i = 0U; i < txLength; i++) { + for (uint16_t i = 0U; i < length; i++) { q15_t sample = 0; m_outputRFRB.get(sample); samples[i] = sample; - - if(m_extEnabled) { - uint16_t downSamplerLength = m_downsampler.getData(); - - if(downSamplerLength >= FM_SERIAL_BLOCK_SIZE) { - TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; - - for(uint16_t j = 0U; j < downSamplerLength; j++) { - m_downsampler.getPackedData(serialSamples[j]); - } - - serial.writeFMData((uint8_t*)serialSamples, downSamplerLength * sizeof(TSamplePairPack)); - } - } } - io.write(STATE_FM, samples, txLength); + io.write(STATE_FM, samples, length); + } + + if(m_extEnabled) { + length = m_downsampler.getData(); + + if(length >= FM_SERIAL_BLOCK_SIZE) { + if(length > FM_SERIAL_BLOCK_SIZE) + length = FM_SERIAL_BLOCK_SIZE; + + TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; + + for(uint16_t j = 0U; j < length; j++) { + m_downsampler.getPackedData(serialSamples[j]); + } + + serial.writeFMData((uint8_t*)serialSamples, length * sizeof(TSamplePairPack)); + } } } From df23e15c918b44ba463fc5c1ee76f5bf6ffe28a0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 11:52:59 +0200 Subject: [PATCH 61/95] Fix compilation warnings --- FM.cpp | 1 + FMDownsampler.cpp | 2 +- FMDownsampler.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/FM.cpp b/FM.cpp index 82fdac1..6315f36 100644 --- a/FM.cpp +++ b/FM.cpp @@ -695,6 +695,7 @@ uint8_t CFM::getSpace() const uint8_t CFM::writeData(const uint8_t* data, uint8_t length) { m_inputExtRB.addData(data, length); + return 0U;//maybe return an error if overflowing ? } void CFM::insertDelay(uint16_t ms) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 4c6b733..922657c 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -28,7 +28,7 @@ m_samplePackPointer(NULL), m_packIndex(0U), m_downSampleIndex(0U) { - m_samplePackPointer = &m_samplePack; + m_samplePackPointer = (uint8_t*)&m_samplePack; } void CFMDownsampler::addSample(q15_t sample) diff --git a/FMDownsampler.h b/FMDownsampler.h index 6ec7201..0254aab 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -36,7 +36,7 @@ private: CRingBuffer m_ringBuffer; uint32_t m_samplePack; - uint32_t *m_samplePackPointer; + uint8_t *m_samplePackPointer; uint8_t m_packIndex; uint8_t m_downSampleIndex; From 9023b6ae13e13763a23d0c4b15fa21a31d5661bf Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 12:03:52 +0200 Subject: [PATCH 62/95] Correct indentation --- FMDownsampler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index 922657c..a5a127f 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -40,14 +40,14 @@ void CFMDownsampler::addSample(q15_t sample) m_samplePack = uint32_t(sample) << 12; break; case 1:{ - m_samplePack |= uint32_t(sample); - - //we did not use MSB; skip it - TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; + m_samplePack |= uint32_t(sample); + + //we did not use MSB; skip it + TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; - m_ringBuffer.put(pair); + m_ringBuffer.put(pair); - m_samplePack = 0;//reset the sample pack + m_samplePack = 0;//reset the sample pack } break; default: From 81f6b6be531793a61f1e327e1400dd25fecdbf27 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 12:42:14 +0200 Subject: [PATCH 63/95] Send usigned data and simplify downdamplign code --- FMDownsampler.cpp | 52 +++++++++++++++++++++-------------------------- FMDownsampler.h | 3 +-- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index a5a127f..e5d8645 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -25,43 +25,38 @@ CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length), m_samplePack(0U), m_samplePackPointer(NULL), -m_packIndex(0U), -m_downSampleIndex(0U) +m_sampleIndex(0U) { m_samplePackPointer = (uint8_t*)&m_samplePack; } void CFMDownsampler::addSample(q15_t sample) { - //only take one of three samples - if(m_downSampleIndex == 0U) { - switch(m_packIndex){ - case 0: - m_samplePack = uint32_t(sample) << 12; - break; - case 1:{ - m_samplePack |= uint32_t(sample); - - //we did not use MSB; skip it - TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; + uint16_t usample = uint16_t(sample + 2048); + //only take one of three samples + switch(m_sampleIndex){ + case 0: + m_samplePack = uint32_t(usample) << 12; + break; + case 3:{ + m_samplePack |= uint32_t(usample); + + //we did not use MSB; skip it + TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; - m_ringBuffer.put(pair); + m_ringBuffer.put(pair); - m_samplePack = 0;//reset the sample pack - } - break; - default: - //should never happen - break; - } - m_packIndex++; - if(m_packIndex >= 2U)//did we pack two samples ? - m_packIndex = 0U; + m_samplePack = 0U;//reset the sample pack } + break; + default: + //Just skip this sample + break; + } - m_downSampleIndex++; - if(m_downSampleIndex >= 3U) - m_downSampleIndex = 0U; + m_sampleIndex++; + if(m_sampleIndex >= 6U)//did we pack two samples ? + m_sampleIndex = 0U; } bool CFMDownsampler::getPackedData(TSamplePairPack& data) @@ -76,6 +71,5 @@ uint16_t CFMDownsampler::getData() void CFMDownsampler::reset() { - m_downSampleIndex = 0; - m_packIndex = 0; + m_sampleIndex = 0U; } \ No newline at end of file diff --git a/FMDownsampler.h b/FMDownsampler.h index 0254aab..3118802 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -38,8 +38,7 @@ private: uint32_t m_samplePack; uint8_t *m_samplePackPointer; - uint8_t m_packIndex; - uint8_t m_downSampleIndex; + uint8_t m_sampleIndex; }; #endif From c47eacd010e743792d9567d8ddc81ba7cb64b56f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 21:02:19 +0200 Subject: [PATCH 64/95] Add define to use native port on Arduino --- Config.h | 5 +++++ SerialArduino.cpp | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Config.h b/Config.h index 73e716b..2715f49 100644 --- a/Config.h +++ b/Config.h @@ -52,6 +52,11 @@ #define ARDUINO_DUE_ZUM_V10 #endif +// Use the native USB port instead of the programming port +// The native port is recommended when using FM network +// as the rpogramming port does not have the required throughput +// #define ARDUINO_DUE_USE_NATIVE_USB_PORT + // For the SP8NTH board // #define ARDUINO_DUE_NTH diff --git a/SerialArduino.cpp b/SerialArduino.cpp index db49759..fb79861 100644 --- a/SerialArduino.cpp +++ b/SerialArduino.cpp @@ -30,7 +30,11 @@ void CSerialPort::beginInt(uint8_t n, int speed) { switch (n) { case 1U: +#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) + SerialUSB.begin(speed); +#else Serial.begin(speed); +#endif break; case 2U: Serial2.begin(speed); @@ -47,7 +51,11 @@ int CSerialPort::availableInt(uint8_t n) { switch (n) { case 1U: +#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) + return SerialUSB.available(); +#else return Serial.available(); +#endif case 2U: return Serial2.available(); case 3U: @@ -61,7 +69,11 @@ int CSerialPort::availableForWriteInt(uint8_t n) { switch (n) { case 1U: +#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) + return SerialUSB.availableForWrite(); +#else return Serial.availableForWrite(); +#endif case 2U: return Serial2.availableForWrite(); case 3U: @@ -75,7 +87,11 @@ uint8_t CSerialPort::readInt(uint8_t n) { switch (n) { case 1U: +#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) + return SerialUSB.read(); +#else return Serial.read(); +#endif case 2U: return Serial2.read(); case 3U: @@ -89,10 +105,17 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool { switch (n) { case 1U: +#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) + SerialUSB.write(data, length); + if (flush) + SerialUSB.flush(); + break; +#else Serial.write(data, length); if (flush) Serial.flush(); break; +#endif case 2U: Serial2.write(data, length); if (flush) From b245be464f93e2d930ea544405d60796cf3fec6c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 13 May 2020 22:57:42 +0200 Subject: [PATCH 65/95] Fix txbuffer overflows and bring back elegant while loop --- FM.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/FM.cpp b/FM.cpp index 6315f36..19e980f 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,7 +20,7 @@ #include "Globals.h" #include "FM.h" -const uint16_t FM_TX_BLOCK_SIZE = 400U; +const uint16_t FM_TX_BLOCK_SIZE = 100U; const uint16_t FM_SERIAL_BLOCK_SIZE = 42U;//this is actually the number of sample pairs to send over serial. One sample pair is 3bytes. //three times this value shall never exceed 126 ! @@ -152,30 +152,13 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) void CFM::process() { - uint16_t space = io.getSpace() - 2U; - uint16_t length = m_outputRFRB.getData(); - if (space > 2 && length >= FM_TX_BLOCK_SIZE ) { - - if(length > FM_TX_BLOCK_SIZE) - length = FM_TX_BLOCK_SIZE; - if(space > FM_TX_BLOCK_SIZE) - space = FM_TX_BLOCK_SIZE; - if(length > space) - length = space; - - q15_t samples[FM_TX_BLOCK_SIZE]; - - for (uint16_t i = 0U; i < length; i++) { - q15_t sample = 0; - m_outputRFRB.get(sample); - samples[i] = sample; - } - - io.write(STATE_FM, samples, length); + q15_t sample; + while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) { + io.write(STATE_FM, &sample, 1); } if(m_extEnabled) { - length = m_downsampler.getData(); + uint16_t length = m_downsampler.getData(); if(length >= FM_SERIAL_BLOCK_SIZE) { if(length > FM_SERIAL_BLOCK_SIZE) From cfcb7ed8524b65f83048f49f56432efaec3bddd4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 14 May 2020 09:10:11 +0200 Subject: [PATCH 66/95] Really fix TX Buffer ovrflows,, reduce delay buffer memory footprint --- FM.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/FM.cpp b/FM.cpp index 19e980f..f4174fc 100644 --- a/FM.cpp +++ b/FM.cpp @@ -54,7 +54,7 @@ m_extAudioBoost(1U), m_downsampler(400U),// 100 ms of audio m_extEnabled(false), m_rxLevel(1), -m_inputRFRB(4800U), // 200ms of audio +m_inputRFRB(2401U), // 100ms of audio + 1 sample m_outputRFRB(2400U), // 100ms of audio m_inputExtRB(2400U) // 100ms of Audio { @@ -152,9 +152,26 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) void CFM::process() { - q15_t sample; - while (io.getSpace() >= 3U && m_outputRFRB.get(sample)) { - io.write(STATE_FM, &sample, 1); + uint16_t space = io.getSpace(); + uint16_t length = m_outputRFRB.getData(); + if (space > FM_TX_BLOCK_SIZE && length >= FM_TX_BLOCK_SIZE ) { + + if(length > FM_TX_BLOCK_SIZE) + length = FM_TX_BLOCK_SIZE; + if(space > FM_TX_BLOCK_SIZE) + space = FM_TX_BLOCK_SIZE; + if(length > space) + length = space; + + q15_t samples[FM_TX_BLOCK_SIZE]; + + for (uint16_t i = 0U; i < length; i++) { + q15_t sample = 0; + m_outputRFRB.get(sample); + samples[i] = sample; + } + + io.write(STATE_FM, samples, length); } if(m_extEnabled) { From 388620b182392895d42a7fb79fcb600030dffa75 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 15 May 2020 18:53:34 +0200 Subject: [PATCH 67/95] Add FM EOT --- FM.cpp | 7 +++++++ SerialPort.cpp | 20 +++++++++++++++++++- SerialPort.h | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index f4174fc..a165fab 100644 --- a/FM.cpp +++ b/FM.cpp @@ -411,6 +411,8 @@ void CFM::kerchunkRFState(bool validSignal) m_ackMinTimer.stop(); m_callsignTimer.stop(); m_statusTimer.stop(); + + serial.writeFMEOT(); } } @@ -423,6 +425,8 @@ void CFM::relayingRFState(bool validSignal) m_ackMinTimer.stop(); m_timeoutTimer.stop(); m_timeoutTone.start(); + + serial.writeFMEOT(); } } else { DEBUG1("State to RELAYING_WAIT_RF"); @@ -574,10 +578,13 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) m_hangTimer.stop(); m_statusTimer.stop(); + serial.writeFMEOT(); + if (m_callsignAtEnd) sendCallsign(); m_callsignTimer.stop(); + } } diff --git a/SerialPort.cpp b/SerialPort.cpp index d0bf4fc..a320ed1 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -71,6 +71,7 @@ const uint8_t MMDVM_FM_PARAMS3 = 0x62U; const uint8_t MMDVM_FM_PARAMS4 = 0x63U; const uint8_t MMDVM_FM_DATA = 0x65U; const uint8_t MMDVM_FM_STATUS = 0x66U; +const uint8_t MMDVM_FM_EOT = 0x67U; const uint8_t MMDVM_ACK = 0x70U; const uint8_t MMDVM_NAK = 0x7FU; @@ -1286,7 +1287,24 @@ void CSerialPort::writeFMStatus(uint8_t status) reply[2U] = MMDVM_FM_STATUS; reply[3U] = status; - writeInt(1U, reply, 4); + writeInt(1U, reply, 4Us); +} + +void CSerialPort::writeFMEOT() +{ + if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) + return; + + if (!m_fmEnable) + return; + + uint8_t reply[10U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 4U; + reply[2U] = MMDVM_FM_EOT; + + writeInt(1U, reply, 3U); } void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) diff --git a/SerialPort.h b/SerialPort.h index 2b5eb9a..a75731a 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -52,6 +52,7 @@ public: void writeFMData(const uint8_t* data, uint8_t length); void writeFMStatus(uint8_t status); + void writeFMEOT(); void writeCalData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length); From e330c9f52acc9196e00d2d754b5fe7e4ee89d52c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 15 May 2020 21:05:57 +0200 Subject: [PATCH 68/95] Fix typo --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index a320ed1..6518ebf 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1287,7 +1287,7 @@ void CSerialPort::writeFMStatus(uint8_t status) reply[2U] = MMDVM_FM_STATUS; reply[3U] = status; - writeInt(1U, reply, 4Us); + writeInt(1U, reply, 4U); } void CSerialPort::writeFMEOT() From 7b915f9cacdc357a6688fc3c1c9ac2d6c35f20b9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 15 May 2020 21:06:16 +0200 Subject: [PATCH 69/95] Only send EOT when EXT is enabled --- FM.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/FM.cpp b/FM.cpp index a165fab..cfd7ba6 100644 --- a/FM.cpp +++ b/FM.cpp @@ -412,7 +412,8 @@ void CFM::kerchunkRFState(bool validSignal) m_callsignTimer.stop(); m_statusTimer.stop(); - serial.writeFMEOT(); + if(m_extEnabled) + serial.writeFMEOT(); } } @@ -426,7 +427,8 @@ void CFM::relayingRFState(bool validSignal) m_timeoutTimer.stop(); m_timeoutTone.start(); - serial.writeFMEOT(); + if(m_extEnabled) + serial.writeFMEOT(); } } else { DEBUG1("State to RELAYING_WAIT_RF"); @@ -578,7 +580,8 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) m_hangTimer.stop(); m_statusTimer.stop(); - serial.writeFMEOT(); + if(m_extEnabled) + serial.writeFMEOT(); if (m_callsignAtEnd) sendCallsign(); From 48e863d1d06479ff025d2b8f0bb019f776e35899 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 15 May 2020 21:19:26 +0200 Subject: [PATCH 70/95] Sent EOT on rf timeout --- FM.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FM.cpp b/FM.cpp index cfd7ba6..09f8c5d 100644 --- a/FM.cpp +++ b/FM.cpp @@ -602,6 +602,10 @@ void CFM::timeoutRFState(bool validSignal) if (!validSignal) { DEBUG1("State to TIMEOUT_WAIT_RF"); m_state = FS_TIMEOUT_WAIT_RF; + + if (m_callsignAtEnd) + sendCallsign(); + m_ackDelayTimer.start(); } From 296ac888425b4a13367d70bfc80bd41639174bf2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 16 May 2020 12:08:26 +0200 Subject: [PATCH 71/95] Correct length --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index 6518ebf..8d5040b 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1301,7 +1301,7 @@ void CSerialPort::writeFMEOT() uint8_t reply[10U]; reply[0U] = MMDVM_FRAME_START; - reply[1U] = 4U; + reply[1U] = 3U; reply[2U] = MMDVM_FM_EOT; writeInt(1U, reply, 3U); From 625749a5460bbe5c49d0843655a0a3849399751b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 16 May 2020 13:15:21 +0100 Subject: [PATCH 72/95] Fixed up the use of the writeFMEOT method. --- FM.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/FM.cpp b/FM.cpp index 09f8c5d..8adaa72 100644 --- a/FM.cpp +++ b/FM.cpp @@ -154,13 +154,13 @@ void CFM::process() { uint16_t space = io.getSpace(); uint16_t length = m_outputRFRB.getData(); + if (space > FM_TX_BLOCK_SIZE && length >= FM_TX_BLOCK_SIZE ) { - - if(length > FM_TX_BLOCK_SIZE) + if (length > FM_TX_BLOCK_SIZE) length = FM_TX_BLOCK_SIZE; - if(space > FM_TX_BLOCK_SIZE) + if (space > FM_TX_BLOCK_SIZE) space = FM_TX_BLOCK_SIZE; - if(length > space) + if (length > space) length = space; q15_t samples[FM_TX_BLOCK_SIZE]; @@ -174,18 +174,17 @@ void CFM::process() io.write(STATE_FM, samples, length); } - if(m_extEnabled) { + if (m_extEnabled) { uint16_t length = m_downsampler.getData(); - if(length >= FM_SERIAL_BLOCK_SIZE) { - if(length > FM_SERIAL_BLOCK_SIZE) + if (length >= FM_SERIAL_BLOCK_SIZE) { + if (length > FM_SERIAL_BLOCK_SIZE) length = FM_SERIAL_BLOCK_SIZE; TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; - for(uint16_t j = 0U; j < length; j++) { + for (uint16_t j = 0U; j < length; j++) m_downsampler.getPackedData(serialSamples[j]); - } serial.writeFMData((uint8_t*)serialSamples, length * sizeof(TSamplePairPack)); } @@ -412,7 +411,7 @@ void CFM::kerchunkRFState(bool validSignal) m_callsignTimer.stop(); m_statusTimer.stop(); - if(m_extEnabled) + if (m_extEnabled) serial.writeFMEOT(); } } @@ -427,13 +426,16 @@ void CFM::relayingRFState(bool validSignal) m_timeoutTimer.stop(); m_timeoutTone.start(); - if(m_extEnabled) + if (m_extEnabled) serial.writeFMEOT(); } } else { DEBUG1("State to RELAYING_WAIT_RF"); m_state = FS_RELAYING_WAIT_RF; m_ackDelayTimer.start(); + + if (m_extEnabled) + serial.writeFMEOT(); } if (m_callsignTimer.isRunning() && m_callsignTimer.hasExpired()) { @@ -580,9 +582,6 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) m_hangTimer.stop(); m_statusTimer.stop(); - if(m_extEnabled) - serial.writeFMEOT(); - if (m_callsignAtEnd) sendCallsign(); From e7a22482dbf122d5966786a9f35b952cf9de1674 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 13:45:17 +0100 Subject: [PATCH 73/95] Set the COS LED on incoming RF transmissions. --- FM.cpp | 21 +++++++++++++++++++++ SerialPort.cpp | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index 8adaa72..e78fd37 100644 --- a/FM.cpp +++ b/FM.cpp @@ -363,6 +363,9 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) m_callsignTimer.start(); + io.setDecode(true); + io.setADCDetection(true); + m_statusTimer.start(); serial.writeFMStatus(m_state); } else if (validExtSignal) { @@ -403,6 +406,9 @@ void CFM::kerchunkRFState(bool validSignal) } } } else { + io.setDecode(false); + io.setADCDetection(false); + DEBUG1("State to LISTENING"); m_state = FS_LISTENING; m_kerchunkTimer.stop(); @@ -430,6 +436,9 @@ void CFM::relayingRFState(bool validSignal) serial.writeFMEOT(); } } else { + io.setDecode(false); + io.setADCDetection(false); + DEBUG1("State to RELAYING_WAIT_RF"); m_state = FS_RELAYING_WAIT_RF; m_ackDelayTimer.start(); @@ -447,6 +456,9 @@ void CFM::relayingRFState(bool validSignal) void CFM::relayingRFWaitState(bool validSignal) { if (validSignal) { + io.setDecode(true); + io.setADCDetection(true); + DEBUG1("State to RELAYING_RF"); m_state = FS_RELAYING_RF; m_ackDelayTimer.stop(); @@ -562,6 +574,9 @@ void CFM::relayingExtWaitState(bool validSignal) void CFM::hangState(bool validRFSignal, bool validExtSignal) { if (validRFSignal) { + io.setDecode(true); + io.setADCDetection(true); + DEBUG1("State to RELAYING_RF"); m_state = FS_RELAYING_RF; DEBUG1("Stop ack"); @@ -599,6 +614,9 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) void CFM::timeoutRFState(bool validSignal) { if (!validSignal) { + io.setDecode(false); + io.setADCDetection(false); + DEBUG1("State to TIMEOUT_WAIT_RF"); m_state = FS_TIMEOUT_WAIT_RF; @@ -617,6 +635,9 @@ void CFM::timeoutRFState(bool validSignal) void CFM::timeoutRFWaitState(bool validSignal) { if (validSignal) { + io.setDecode(true); + io.setADCDetection(true); + DEBUG1("State to TIMEOUT_RF"); m_state = FS_TIMEOUT_RF; m_ackDelayTimer.stop(); diff --git a/SerialPort.cpp b/SerialPort.cpp index 8d5040b..54494cc 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -107,7 +107,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200512 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" +#define DESCRIPTION "20200519 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From a3ffa9ed368dcd21f364a659c72151fac95cd551 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 08:08:22 +0200 Subject: [PATCH 74/95] Remove no longer needed SerialRB class --- SerialRB.cpp | 36 ------------------------------------ SerialRB.h | 36 ------------------------------------ 2 files changed, 72 deletions(-) delete mode 100644 SerialRB.cpp delete mode 100644 SerialRB.h diff --git a/SerialRB.cpp b/SerialRB.cpp deleted file mode 100644 index ca3350d..0000000 --- a/SerialRB.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -Serial RB control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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 "SerialRB.h" - -CSerialRB::CSerialRB(uint16_t length) : -CRingBuffer(length) -{ -} - -uint8_t CSerialRB::get() -{ - uint8_t value; - if(CRingBuffer::get(value)) - return value; - - return 0U; -} - diff --git a/SerialRB.h b/SerialRB.h deleted file mode 100644 index 1357732..0000000 --- a/SerialRB.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -Serial fifo control - Copyright (C) KI6ZUM 2015 -Copyright (C) 2015,2016 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(SERIALRB_H) -#define SERIALRB_H - -#include "RingBuffer.h" - -const uint16_t SERIAL_RINGBUFFER_SIZE = 370U; - -class CSerialRB : public CRingBuffer{ -public: - CSerialRB(uint16_t length = SERIAL_RINGBUFFER_SIZE); - - uint8_t get(); -}; - -#endif - From 04982c25c09ed6e4b923d30a2de7f6f8ededc3df Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 11:06:02 +0200 Subject: [PATCH 75/95] Remove SerialUSB for Arduino --- Config.h | 5 ----- SerialArduino.cpp | 23 ----------------------- 2 files changed, 28 deletions(-) diff --git a/Config.h b/Config.h index 2715f49..73e716b 100644 --- a/Config.h +++ b/Config.h @@ -52,11 +52,6 @@ #define ARDUINO_DUE_ZUM_V10 #endif -// Use the native USB port instead of the programming port -// The native port is recommended when using FM network -// as the rpogramming port does not have the required throughput -// #define ARDUINO_DUE_USE_NATIVE_USB_PORT - // For the SP8NTH board // #define ARDUINO_DUE_NTH diff --git a/SerialArduino.cpp b/SerialArduino.cpp index fb79861..db49759 100644 --- a/SerialArduino.cpp +++ b/SerialArduino.cpp @@ -30,11 +30,7 @@ void CSerialPort::beginInt(uint8_t n, int speed) { switch (n) { case 1U: -#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) - SerialUSB.begin(speed); -#else Serial.begin(speed); -#endif break; case 2U: Serial2.begin(speed); @@ -51,11 +47,7 @@ int CSerialPort::availableInt(uint8_t n) { switch (n) { case 1U: -#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) - return SerialUSB.available(); -#else return Serial.available(); -#endif case 2U: return Serial2.available(); case 3U: @@ -69,11 +61,7 @@ int CSerialPort::availableForWriteInt(uint8_t n) { switch (n) { case 1U: -#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) - return SerialUSB.availableForWrite(); -#else return Serial.availableForWrite(); -#endif case 2U: return Serial2.availableForWrite(); case 3U: @@ -87,11 +75,7 @@ uint8_t CSerialPort::readInt(uint8_t n) { switch (n) { case 1U: -#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) - return SerialUSB.read(); -#else return Serial.read(); -#endif case 2U: return Serial2.read(); case 3U: @@ -105,17 +89,10 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool { switch (n) { case 1U: -#if defined(ARDUINO_DUE_USE_NATIVE_USB_PORT) - SerialUSB.write(data, length); - if (flush) - SerialUSB.flush(); - break; -#else Serial.write(data, length); if (flush) Serial.flush(); break; -#endif case 2U: Serial2.write(data, length); if (flush) From 489853f200bb42eb78d8aa6cc874aaa4af9cea96 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 20 May 2020 15:27:16 +0100 Subject: [PATCH 76/95] Fix the TX Hang. --- NXDNTX.cpp | 9 +++------ P25TX.cpp | 5 +---- SerialPort.cpp | 2 +- YSFTX.cpp | 5 +---- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/NXDNTX.cpp b/NXDNTX.cpp index 00eead0..68679b0 100644 --- a/NXDNTX.cpp +++ b/NXDNTX.cpp @@ -54,7 +54,7 @@ m_poBuffer(), m_poLen(0U), m_poPtr(0U), m_txDelay(240U), // 200ms -m_txHang(6000U), // 5s +m_txHang(3000U), // 5s m_txCount(0U) { ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); @@ -72,10 +72,7 @@ m_txCount(0U) void CNXDNTX::process() { - if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U) - return; - - if (m_poLen == 0U) { + if (m_poLen == 0U && m_buffer.getData() > 0U) { if (!m_tx) { for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = NXDN_SYNC; @@ -201,5 +198,5 @@ uint8_t CNXDNTX::getSpace() const void CNXDNTX::setParams(uint8_t txHang) { - m_txHang = txHang * 1200U; + m_txHang = txHang * 600U; } diff --git a/P25TX.cpp b/P25TX.cpp index cc148c1..7e24806 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -70,10 +70,7 @@ m_txCount(0U) void CP25TX::process() { - if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U) - return; - - if (m_poLen == 0U) { + if (m_poLen == 0U && m_buffer.getData() > 0U) { if (!m_tx) { for (uint16_t i = 0U; i < m_txDelay; i++) m_poBuffer[m_poLen++] = P25_START_SYNC; diff --git a/SerialPort.cpp b/SerialPort.cpp index 54494cc..2a9a241 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -107,7 +107,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200519 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" +#define DESCRIPTION "20200520 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" diff --git a/YSFTX.cpp b/YSFTX.cpp index 15f3920..527122e 100644 --- a/YSFTX.cpp +++ b/YSFTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2018 by Jonathan Naylor G4KLX * Copyright (C) 2017 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify @@ -66,9 +66,6 @@ m_txCount(0U) void CYSFTX::process() { - if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U) - return; - // If we have YSF data to transmit, do so. if (m_poLen == 0U && m_buffer.getData() > 0U) { if (!m_tx) { From 3f960f9fc5e8fc7279edc2fe4f8a550221d6bc56 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 22:30:55 +0200 Subject: [PATCH 77/95] Fix Callsignatend and simplify Samples --- FM.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/FM.cpp b/FM.cpp index e78fd37..31d7ad5 100644 --- a/FM.cpp +++ b/FM.cpp @@ -97,10 +97,8 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) //we had enough samples for CTCSS and we are in some other mode than FM bool validCTCSS = CTCSS_VALID(ctcssState); stateMachine(validCTCSS && cos, inputExt); - } else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState == STATE_FM) { - //We had enough samples for CTCSS and we are in FM mode, trigger the state machine - bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos, inputExt); + if (m_modemState != STATE_FM) + continue; } else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) { //Not enough samples for CTCSS but we already are in FM, trigger the state machine //but do not trigger the state machine on every single sample, save CPU! @@ -318,7 +316,7 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) break; } - if (m_state == FS_LISTENING) { + if (m_state == FS_LISTENING && !m_callsign.isRunning()) { m_outputRFRB.reset(); m_downsampler.reset(); } From 3cc5d676963de069db43f61bd35aedfc0a36b74d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 20 May 2020 22:51:22 +0200 Subject: [PATCH 78/95] check acks --- FM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index 31d7ad5..8660615 100644 --- a/FM.cpp +++ b/FM.cpp @@ -316,7 +316,7 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) break; } - if (m_state == FS_LISTENING && !m_callsign.isRunning()) { + if (m_state == FS_LISTENING && !m_rfAck.isRunning() && !m_extAck.isRunning()) { m_outputRFRB.reset(); m_downsampler.reset(); } From f9f81b9b8eda8321166808eabe79204cd51ea4eb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 18 May 2020 11:09:56 +0100 Subject: [PATCH 79/95] Try and make the closing callsign appear. (cherry picked from commit 063b21f9991e4da949d11ca901127da64c66f664) --- FM.cpp | 2 +- FMKeyer.cpp | 5 +++++ FMKeyer.h | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index 8660615..de26c10 100644 --- a/FM.cpp +++ b/FM.cpp @@ -316,7 +316,7 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) break; } - if (m_state == FS_LISTENING && !m_rfAck.isRunning() && !m_extAck.isRunning()) { + if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) { m_outputRFRB.reset(); m_downsampler.reset(); } diff --git a/FMKeyer.cpp b/FMKeyer.cpp index 8109fb0..851441e 100644 --- a/FMKeyer.cpp +++ b/FMKeyer.cpp @@ -205,6 +205,11 @@ void CFMKeyer::stop() m_audioPos = 0U; } +bool CFMKeyer::isWanted() const +{ + return m_wanted; +} + bool CFMKeyer::isRunning() const { return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U; diff --git a/FMKeyer.h b/FMKeyer.h index 799e85c..5b7bef5 100644 --- a/FMKeyer.h +++ b/FMKeyer.h @@ -35,6 +35,8 @@ public: bool isRunning() const; + bool isWanted() const; + private: bool m_wanted; uint8_t m_poBuffer[1000U]; From f14222e77d8e241d0f0faec2067e3566beeb18c2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 23 May 2020 08:25:51 +0200 Subject: [PATCH 80/95] Make sure buffer is continuously filled --- FM.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FM.cpp b/FM.cpp index de26c10..d7ef530 100644 --- a/FM.cpp +++ b/FM.cpp @@ -153,7 +153,8 @@ void CFM::process() uint16_t space = io.getSpace(); uint16_t length = m_outputRFRB.getData(); - if (space > FM_TX_BLOCK_SIZE && length >= FM_TX_BLOCK_SIZE ) { + if (space > 10U && length >= FM_TX_BLOCK_SIZE ) { + space -= 2U; if (length > FM_TX_BLOCK_SIZE) length = FM_TX_BLOCK_SIZE; if (space > FM_TX_BLOCK_SIZE) From 04d0b155455a05976d56335b4fd5e621f31fc7c7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 23 May 2020 08:28:23 +0200 Subject: [PATCH 81/95] Remove UART habndling Copy/Paste code --- STMUART.cpp | 100 ++++++++ STMUART.h | 91 ++++++++ SerialSTM.cpp | 634 ++++---------------------------------------------- 3 files changed, 240 insertions(+), 585 deletions(-) create mode 100644 STMUART.cpp create mode 100644 STMUART.h diff --git a/STMUART.cpp b/STMUART.cpp new file mode 100644 index 0000000..c2e779d --- /dev/null +++ b/STMUART.cpp @@ -0,0 +1,100 @@ +/* + * 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(STM32F4XX) || defined(STM32F7XX) + +#include "STMUART.h" + +CSTMUART::CSTMUART() : +m_usart(NULL) +{ + +} + +void CSTMUART::init(USART_TypeDef* usart) +{ + m_usart = usart; +} + +void CSTMUART::write(const uint8_t * data, uint16_t length) +{ + if(length == 0U || m_usart == NULL) + return; + + + m_txFifo.put(data[0]); + USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);//switch TX IRQ is on + + for(uint16_t i = 1U; i < length; i++) { + m_txFifo.put(data[i]); + } + + USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);//make sure TX IRQ is on +} + +uint8_t CSTMUART::read() +{ + return m_rxFifo.get(); +} + +void CSTMUART::handleIRQ() +{ + if(m_usart == NULL) + return; + + if (USART_GetITStatus(m_usart, USART_IT_RXNE)) { + if(!m_rxFifo.isFull()) + m_rxFifo.put((uint8_t) USART_ReceiveData(m_usart)); + USART_ClearITPendingBit(USART1, USART_IT_RXNE); + } + + if (USART_GetITStatus(m_usart, USART_IT_TXE)) { + if(!m_txFifo.isEmpty()) + USART_SendData(m_usart, m_txFifo.get()); + + USART_ClearITPendingBit(m_usart, USART_IT_TXE); + + if (m_txFifo.isEmpty()) // if there's no more data to transmit then turn off TX interrupts + USART_ITConfig(m_usart, USART_IT_TXE, DISABLE); + } +} + + // Flushes the transmit shift register +// warning: this call is blocking +void CSTMUART::flush() +{ + if(m_usart == NULL) + return; + + // wait until the TXE shows the shift register is empty + while (USART_GetITStatus(m_usart, USART_FLAG_TXE)) + ; +} + +uint16_t CSTMUART::available() +{ + return m_rxFifo.isEmpty() ? 0U : 1U; +} + +uint16_t CSTMUART::availableForWrite() +{ + return m_txFifo.isFull() ? 0U : 1U; +} + +#endif \ No newline at end of file diff --git a/STMUART.h b/STMUART.h new file mode 100644 index 0000000..8451aa2 --- /dev/null +++ b/STMUART.h @@ -0,0 +1,91 @@ +/* + * 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(STM32F4XX) || defined(STM32F7XX) +#if !defined(STMUART_H) +#define STMUART_H + +#if defined(STM32F4XX) +#include "stm32f4xx.h" +#elif defined(STM32F7XX) +#include "stm32f7xx.h" +#endif + +const uint16_t BUFFER_SIZE = 2048U; //needs to be a power of 2 ! +const uint16_t BUFFER_MASK = BUFFER_SIZE - 1; + +class CSTMUARTFIFO { +public: + CSTMUARTFIFO() : + m_head(0U), + m_tail(0U) + { + } + + void put(uint8_t data) + { + m_buffer[BUFFER_MASK & (m_head++)] = data; + } + + uint8_t get() + { + return m_buffer[BUFFER_MASK & (m_tail++)]; + } + + void reset() + { + m_tail = 0U; + m_head = 0U; + } + + bool isEmpty() + { + return m_tail == m_head; + } + + bool isFull() + { + return ((m_head + 1U) & BUFFER_MASK) == (m_tail & BUFFER_MASK); + } + +private: + volatile uint8_t m_buffer[BUFFER_SIZE]; + volatile uint16_t m_head; + volatile uint16_t m_tail; +}; + +class CSTMUART { +public: + CSTMUART(); + void init(USART_TypeDef* usart); + void write(const uint8_t * data, uint16_t length); + uint8_t read(); + void handleIRQ(); + void flush(); + uint16_t available(); + uint16_t availableForWrite(); + +private: + USART_TypeDef * m_usart; + CSTMUARTFIFO m_rxFifo; + CSTMUARTFIFO m_txFifo; +}; + +#endif +#endif \ No newline at end of file diff --git a/SerialSTM.cpp b/SerialSTM.cpp index 192f5bb..14e1b07 100644 --- a/SerialSTM.cpp +++ b/SerialSTM.cpp @@ -39,9 +39,7 @@ UART5 - TXD PC12 - RXD PD2 (Discovery, MMDVM-Pi, MMDVM-Pi F722 board, MMDVM-F4M #if defined(STM32F4XX) || defined(STM32F7XX) -#define TX_SERIAL_FIFO_SIZE 512U -#define RX_SERIAL_FIFO_SIZE 512U - +#include "STMUART.h" extern "C" { void USART1_IRQHandler(); void USART2_IRQHandler(); @@ -52,111 +50,12 @@ extern "C" { /* ************* USART1 ***************** */ #if defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_F7M) || defined(STM32F722_PI) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || (defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)) || defined(DRCC_DVM) -volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE]; -volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE]; -volatile uint16_t TXSerialfifohead1, TXSerialfifotail1; -volatile uint16_t RXSerialfifohead1, RXSerialfifotail1; -// Init queues -void TXSerialfifoinit1() -{ - TXSerialfifohead1 = 0U; - TXSerialfifotail1 = 0U; -} - -void RXSerialfifoinit1() -{ - RXSerialfifohead1 = 0U; - RXSerialfifotail1 = 0U; -} - -// How full is queue -// TODO decide if how full or how empty is preferred info to return -uint16_t TXSerialfifolevel1() -{ - uint32_t tail = TXSerialfifotail1; - uint32_t head = TXSerialfifohead1; - - if (tail > head) - return TX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -uint16_t RXSerialfifolevel1() -{ - uint32_t tail = RXSerialfifotail1; - uint32_t head = RXSerialfifohead1; - - if (tail > head) - return RX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -// Flushes the transmit shift register -// warning: this call is blocking -void TXSerialFlush1() -{ - // wait until the TXE shows the shift register is empty - while (USART_GetITStatus(USART1, USART_FLAG_TXE)) - ; -} - -uint8_t TXSerialfifoput1(uint8_t next) -{ - if (TXSerialfifolevel1() < TX_SERIAL_FIFO_SIZE) { - TXSerialfifo1[TXSerialfifohead1] = next; - - TXSerialfifohead1++; - if (TXSerialfifohead1 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifohead1 = 0U; - - // make sure transmit interrupts are enabled as long as there is data to send - USART_ITConfig(USART1, USART_IT_TXE, ENABLE); - return 1U; - } else { - return 0U; // signal an overflow occurred by returning a zero count - } -} +static CSTMUART m_USART1; void USART1_IRQHandler() { - uint8_t c; - - if (USART_GetITStatus(USART1, USART_IT_RXNE)) { - c = (uint8_t) USART_ReceiveData(USART1); - - if (RXSerialfifolevel1() < RX_SERIAL_FIFO_SIZE) { - RXSerialfifo1[RXSerialfifohead1] = c; - - RXSerialfifohead1++; - if (RXSerialfifohead1 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifohead1 = 0U; - } else { - // TODO - do something if rx fifo is full? - } - - USART_ClearITPendingBit(USART1, USART_IT_RXNE); - } - - if (USART_GetITStatus(USART1, USART_IT_TXE)) { - c = 0U; - - if (TXSerialfifohead1 != TXSerialfifotail1) { // if the fifo is not empty - c = TXSerialfifo1[TXSerialfifotail1]; - - TXSerialfifotail1++; - if (TXSerialfifotail1 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifotail1 = 0U; - - USART_SendData(USART1, c); - } else { // if there's no more data to transmit then turn off TX interrupts - USART_ITConfig(USART1, USART_IT_TXE, DISABLE); - } - - USART_ClearITPendingBit(USART1, USART_IT_TXE); - } + m_USART1.handleIRQ(); } void InitUSART1(int speed) @@ -184,7 +83,7 @@ void InitUSART1(int speed) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // Tx | Rx - GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed; + GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure USART baud rate @@ -201,41 +100,7 @@ void InitUSART1(int speed) USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); - // initialize the fifos - TXSerialfifoinit1(); - RXSerialfifoinit1(); -} - -uint8_t AvailUSART1() -{ - if (RXSerialfifolevel1() > 0U) - return 1U; - else - return 0U; -} - -int AvailForWriteUSART1() -{ - return TX_SERIAL_FIFO_SIZE - TXSerialfifolevel1(); -} - -uint8_t ReadUSART1() -{ - uint8_t data_c = RXSerialfifo1[RXSerialfifotail1]; - - RXSerialfifotail1++; - if (RXSerialfifotail1 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifotail1 = 0U; - - return data_c; -} - -void WriteUSART1(const uint8_t* data, uint16_t length) -{ - for (uint16_t i = 0U; i < length; i++) - TXSerialfifoput1(data[i]); - - USART_ITConfig(USART1, USART_IT_TXE, ENABLE); + m_USART1.init(USART1); } #endif @@ -243,111 +108,12 @@ void WriteUSART1(const uint8_t* data, uint16_t length) /* ************* USART2 ***************** */ #if defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO) || defined(DRCC_DVM) -volatile uint8_t TXSerialfifo2[TX_SERIAL_FIFO_SIZE]; -volatile uint8_t RXSerialfifo2[RX_SERIAL_FIFO_SIZE]; -volatile uint16_t TXSerialfifohead2, TXSerialfifotail2; -volatile uint16_t RXSerialfifohead2, RXSerialfifotail2; +static CSTMUART m_USART2; -// Init queues -void TXSerialfifoinit2() -{ - TXSerialfifohead2 = 0U; - TXSerialfifotail2 = 0U; -} - -void RXSerialfifoinit2() -{ - RXSerialfifohead2 = 0U; - RXSerialfifotail2 = 0U; -} - -// How full is queue -// TODO decide if how full or how empty is preferred info to return -uint16_t TXSerialfifolevel2() -{ - uint32_t tail = TXSerialfifotail2; - uint32_t head = TXSerialfifohead2; - - if (tail > head) - return TX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -uint16_t RXSerialfifolevel2() -{ - uint32_t tail = RXSerialfifotail2; - uint32_t head = RXSerialfifohead2; - - if (tail > head) - return RX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -// Flushes the transmit shift register -// warning: this call is blocking -void TXSerialFlush2() -{ - // wait until the TXE shows the shift register is empty - while (USART_GetITStatus(USART2, USART_FLAG_TXE)) - ; -} - -uint8_t TXSerialfifoput2(uint8_t next) -{ - if (TXSerialfifolevel2() < TX_SERIAL_FIFO_SIZE) { - TXSerialfifo2[TXSerialfifohead2] = next; - - TXSerialfifohead2++; - if (TXSerialfifohead2 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifohead2 = 0U; - - // make sure transmit interrupts are enabled as long as there is data to send - USART_ITConfig(USART2, USART_IT_TXE, ENABLE); - return 1U; - } else { - return 0U; // signal an overflow occurred by returning a zero count - } -} void USART2_IRQHandler() { - uint8_t c; - - if (USART_GetITStatus(USART2, USART_IT_RXNE)) { - c = (uint8_t) USART_ReceiveData(USART2); - - if (RXSerialfifolevel2() < RX_SERIAL_FIFO_SIZE) { - RXSerialfifo2[RXSerialfifohead2] = c; - - RXSerialfifohead2++; - if (RXSerialfifohead2 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifohead2 = 0U; - } else { - // TODO - do something if rx fifo is full? - } - - USART_ClearITPendingBit(USART2, USART_IT_RXNE); - } - - if (USART_GetITStatus(USART2, USART_IT_TXE)) { - c = 0U; - - if (TXSerialfifohead2 != TXSerialfifotail2) { // if the fifo is not empty - c = TXSerialfifo2[TXSerialfifotail2]; - - TXSerialfifotail2++; - if (TXSerialfifotail2 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifotail2 = 0U; - - USART_SendData(USART2, c); - } else { // if there's no more data to transmit then turn off TX interrupts - USART_ITConfig(USART2, USART_IT_TXE, DISABLE); - } - - USART_ClearITPendingBit(USART2, USART_IT_TXE); - } + m_USART2.handleIRQ(); } void InitUSART2(int speed) @@ -392,41 +158,7 @@ void InitUSART2(int speed) USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); - // initialize the fifos - TXSerialfifoinit2(); - RXSerialfifoinit2(); -} - -uint8_t AvailUSART2() -{ - if (RXSerialfifolevel2() > 0U) - return 1U; - else - return 0U; -} - -int AvailForWriteUSART2() -{ - return TX_SERIAL_FIFO_SIZE - TXSerialfifolevel2(); -} - -uint8_t ReadUSART2() -{ - uint8_t data_c = RXSerialfifo2[RXSerialfifotail2]; - - RXSerialfifotail2++; - if (RXSerialfifotail2 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifotail2 = 0U; - - return data_c; -} - -void WriteUSART2(const uint8_t* data, uint16_t length) -{ - for (uint16_t i = 0U; i < length; i++) - TXSerialfifoput2(data[i]); - - USART_ITConfig(USART2, USART_IT_TXE, ENABLE); + m_USART2.init(USART2); } #endif @@ -434,111 +166,11 @@ void WriteUSART2(const uint8_t* data, uint16_t length) /* ************* USART3 ***************** */ #if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO) -volatile uint8_t TXSerialfifo3[TX_SERIAL_FIFO_SIZE]; -volatile uint8_t RXSerialfifo3[RX_SERIAL_FIFO_SIZE]; -volatile uint16_t TXSerialfifohead3, TXSerialfifotail3; -volatile uint16_t RXSerialfifohead3, RXSerialfifotail3; - -// Init queues -void TXSerialfifoinit3() -{ - TXSerialfifohead3 = 0U; - TXSerialfifotail3 = 0U; -} - -void RXSerialfifoinit3() -{ - RXSerialfifohead3 = 0U; - RXSerialfifotail3 = 0U; -} - -// How full is queue -// TODO decide if how full or how empty is preferred info to return -uint16_t TXSerialfifolevel3() -{ - uint32_t tail = TXSerialfifotail3; - uint32_t head = TXSerialfifohead3; - - if (tail > head) - return TX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -uint16_t RXSerialfifolevel3() -{ - uint32_t tail = RXSerialfifotail3; - uint32_t head = RXSerialfifohead3; - - if (tail > head) - return RX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -// Flushes the transmit shift register -// warning: this call is blocking -void TXSerialFlush3() -{ - // wait until the TXE shows the shift register is empty - while (USART_GetITStatus(USART3, USART_FLAG_TXE)) - ; -} - -uint8_t TXSerialfifoput3(uint8_t next) -{ - if (TXSerialfifolevel3() < TX_SERIAL_FIFO_SIZE) { - TXSerialfifo3[TXSerialfifohead3] = next; - - TXSerialfifohead3++; - if (TXSerialfifohead3 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifohead3 = 0U; - - // make sure transmit interrupts are enabled as long as there is data to send - USART_ITConfig(USART3, USART_IT_TXE, ENABLE); - return 1U; - } else { - return 0U; // signal an overflow occurred by returning a zero count - } -} +static CSTMUART m_USART3; void USART3_IRQHandler() { - uint8_t c; - - if (USART_GetITStatus(USART3, USART_IT_RXNE)) { - c = (uint8_t) USART_ReceiveData(USART3); - - if (RXSerialfifolevel3() < RX_SERIAL_FIFO_SIZE) { - RXSerialfifo3[RXSerialfifohead3] = c; - - RXSerialfifohead3++; - if (RXSerialfifohead3 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifohead3 = 0U; - } else { - // TODO - do something if rx fifo is full? - } - - USART_ClearITPendingBit(USART3, USART_IT_RXNE); - } - - if (USART_GetITStatus(USART3, USART_IT_TXE)) { - c = 0U; - - if (TXSerialfifohead3 != TXSerialfifotail3) { // if the fifo is not empty - c = TXSerialfifo3[TXSerialfifotail3]; - - TXSerialfifotail3++; - if (TXSerialfifotail3 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifotail3 = 0U; - - USART_SendData(USART3, c); - } else { // if there's no more data to transmit then turn off TX interrupts - USART_ITConfig(USART3, USART_IT_TXE, DISABLE); - } - - USART_ClearITPendingBit(USART3, USART_IT_TXE); - } + m_USART3.handleIRQ(); } #if defined(STM32F7_NUCLEO) @@ -600,41 +232,7 @@ void InitUSART3(int speed) USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); - // initialize the fifos - TXSerialfifoinit3(); - RXSerialfifoinit3(); -} - -uint8_t AvailUSART3() -{ - if (RXSerialfifolevel3() > 0U) - return 1U; - else - return 0U; -} - -int AvailForWriteUSART3() -{ - return TX_SERIAL_FIFO_SIZE - TXSerialfifolevel3(); -} - -uint8_t ReadUSART3() -{ - uint8_t data_c = RXSerialfifo3[RXSerialfifotail3]; - - RXSerialfifotail3++; - if (RXSerialfifotail3 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifotail3 = 0U; - - return data_c; -} - -void WriteUSART3(const uint8_t* data, uint16_t length) -{ - for (uint16_t i = 0U; i < length; i++) - TXSerialfifoput3(data[i]); - - USART_ITConfig(USART3, USART_IT_TXE, ENABLE); + m_USART3.init(USART3); } #endif @@ -642,111 +240,11 @@ void WriteUSART3(const uint8_t* data, uint16_t length) /* ************* UART5 ***************** */ #if !(defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)) -volatile uint8_t TXSerialfifo5[TX_SERIAL_FIFO_SIZE]; -volatile uint8_t RXSerialfifo5[RX_SERIAL_FIFO_SIZE]; -volatile uint16_t TXSerialfifohead5, TXSerialfifotail5; -volatile uint16_t RXSerialfifohead5, RXSerialfifotail5; - -// Init queues -void TXSerialfifoinit5() -{ - TXSerialfifohead5 = 0U; - TXSerialfifotail5 = 0U; -} - -void RXSerialfifoinit5() -{ - RXSerialfifohead5 = 0U; - RXSerialfifotail5 = 0U; -} - -// How full is queue -// TODO decide if how full or how empty is preferred info to return -uint16_t TXSerialfifolevel5() -{ - uint32_t tail = TXSerialfifotail5; - uint32_t head = TXSerialfifohead5; - - if (tail > head) - return TX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -uint16_t RXSerialfifolevel5() -{ - uint32_t tail = RXSerialfifotail5; - uint32_t head = RXSerialfifohead5; - - if (tail > head) - return RX_SERIAL_FIFO_SIZE + head - tail; - else - return head - tail; -} - -// Flushes the transmit shift register -// warning: this call is blocking -void TXSerialFlush5() -{ - // wait until the TXE shows the shift register is empty - while (USART_GetITStatus(UART5, USART_FLAG_TXE)) - ; -} - -uint8_t TXSerialfifoput5(uint8_t next) -{ - if (TXSerialfifolevel5() < TX_SERIAL_FIFO_SIZE) { - TXSerialfifo5[TXSerialfifohead5] = next; - - TXSerialfifohead5++; - if (TXSerialfifohead5 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifohead5 = 0U; - - // make sure transmit interrupts are enabled as long as there is data to send - USART_ITConfig(UART5, USART_IT_TXE, ENABLE); - return 1U; - } else { - return 0U; // signal an overflow occurred by returning a zero count - } -} +static CSTMUART m_UART5; void UART5_IRQHandler() { - uint8_t c; - - if (USART_GetITStatus(UART5, USART_IT_RXNE)) { - c = (uint8_t) USART_ReceiveData(UART5); - - if (RXSerialfifolevel5() < RX_SERIAL_FIFO_SIZE) { - RXSerialfifo5[RXSerialfifohead5] = c; - - RXSerialfifohead5++; - if (RXSerialfifohead5 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifohead5 = 0U; - } else { - // TODO - do something if rx fifo is full? - } - - USART_ClearITPendingBit(UART5, USART_IT_RXNE); - } - - if (USART_GetITStatus(UART5, USART_IT_TXE)) { - c = 0U; - - if (TXSerialfifohead5 != TXSerialfifotail5) { // if the fifo is not empty - c = TXSerialfifo5[TXSerialfifotail5]; - - TXSerialfifotail5++; - if (TXSerialfifotail5 >= TX_SERIAL_FIFO_SIZE) - TXSerialfifotail5 = 0U; - - USART_SendData(UART5, c); - } else { // if there's no more data to transmit then turn off TX interrupts - USART_ITConfig(UART5, USART_IT_TXE, DISABLE); - } - - USART_ClearITPendingBit(UART5, USART_IT_TXE); - } + m_UART5.handleIRQ(); } void InitUART5(int speed) @@ -795,41 +293,7 @@ void InitUART5(int speed) USART_ITConfig(UART5, USART_IT_RXNE, ENABLE); - // initialize the fifos - TXSerialfifoinit5(); - RXSerialfifoinit5(); -} - -uint8_t AvailUART5() -{ - if (RXSerialfifolevel5() > 0U) - return 1U; - else - return 0U; -} - -int AvailForWriteUART5() -{ - return TX_SERIAL_FIFO_SIZE - TXSerialfifolevel5(); -} - -uint8_t ReadUART5() -{ - uint8_t data_c = RXSerialfifo5[RXSerialfifotail5]; - - RXSerialfifotail5++; - if (RXSerialfifotail5 >= RX_SERIAL_FIFO_SIZE) - RXSerialfifotail5 = 0U; - - return data_c; -} - -void WriteUART5(const uint8_t* data, uint16_t length) -{ - for (uint16_t i = 0U; i < length; i++) - TXSerialfifoput5(data[i]); - - USART_ITConfig(UART5, USART_IT_TXE, ENABLE); + m_UART5.init(UART5); } #endif @@ -868,21 +332,21 @@ int CSerialPort::availableInt(uint8_t n) switch (n) { case 1U: #if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO) - return AvailUSART3(); + return m_USART3.availble();//AvailUSART3(); #elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) - return AvailUSART1(); + return m_USART1.available();//AvailUSART1(); #elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO) - return AvailUSART2(); + return m_USART2.available();//AvailUSART2(); #elif defined(DRCC_DVM) - return AvailUSART1(); + return m_USART1.available();//AvailUSART1(); #endif case 3U: #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) - return AvailUSART1(); + return m_USART1.available(); //AvailUSART1(); #elif defined(DRCC_DVM) - return AvailUSART2(); + return m_USART2.available(); //AvailUSART2(); #else - return AvailUART5(); + return m_UART5.available();//AvailUART5(); #endif default: return 0; @@ -894,21 +358,21 @@ int CSerialPort::availableForWriteInt(uint8_t n) switch (n) { case 1U: #if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO) - return AvailForWriteUSART3(); + return m_USART3.availableForWrite(); //AvailForWriteUSART3(); #elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) - return AvailForWriteUSART1(); + return m_USART1.availableForWrite(); //AvailForWriteUSART1(); #elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO) - return AvailForWriteUSART2(); + return m_USART2.availableForWrite();//AvailForWriteUSART2(); #elif defined(DRCC_DVM) - return AvailForWriteUSART1(); + return m_USART1.availableForWrite();//AvailForWriteUSART1(); #endif case 3U: #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) - return AvailForWriteUSART1(); + return m_USART1.availableForWrite(); //AvailForWriteUSART1(); #elif defined(DRCC_DVM) - AvailForWriteUSART2(); + return m_USART2.availableForWrite();//AvailForWriteUSART2(); #else - return AvailForWriteUART5(); + return m_UART5.availableForWrite();//AvailForWriteUART5(); #endif default: return 0; @@ -920,21 +384,21 @@ uint8_t CSerialPort::readInt(uint8_t n) switch (n) { case 1U: #if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO) - return ReadUSART3(); + return m_USART3.read();//ReadUSART3(); #elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) - return ReadUSART1(); + return m_USART1.read();//ReadUSART1(); #elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO) - return ReadUSART2(); + return m_USART2.read();//ReadUSART2(); #elif defined(DRCC_DVM) - return ReadUSART1(); + return m_USART1.read();//ReadUSART1(); #endif case 3U: #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) - return ReadUSART1(); + return m_USART1.read();//ReadUSART1(); #elif defined(DRCC_DVM) - return ReadUSART2(); + return m_USART2.read();//ReadUSART2(); #else - return ReadUART5(); + return m_UART5.read();//ReadUART5(); #endif default: return 0U; @@ -946,36 +410,36 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool switch (n) { case 1U: #if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO) - WriteUSART3(data, length); + m_USART3.write(data, length); //WriteUSART3(data, length); if (flush) - TXSerialFlush3(); + m_USART3.flush();//TXSerialFlush3(); #elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) - WriteUSART1(data, length); + m_USART1.write(data, length);//WriteUSART1(data, length); if (flush) - TXSerialFlush1(); + m_USART1.flush();//TXSerialFlush1(); #elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO) - WriteUSART2(data, length); + m_USART2.write(data, length);//WriteUSART2(data, length); if (flush) - TXSerialFlush2(); + m_USART2.flush();//TXSerialFlush2(); #elif defined(DRCC_DVM) - WriteUSART1(data, length); + m_USART1.write(data, length);//WriteUSART1(data, length); if (flush) - TXSerialFlush1(); + m_USART1.flush();//TXSerialFlush1(); #endif break; case 3U: #if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER) - WriteUSART1(data, length); + m_USART1.write(data, length); //WriteUSART1(data, length); if (flush) - TXSerialFlush1(); + m_USART1.flush(); #elif defined(DRCC_DVM) - WriteUSART2(data, length); + m_USART2.write(data, length);//WriteUSART2(data, length); if (flush) - TXSerialFlush2(); + m_USART2.flush();//TXSerialFlush2(); #else - WriteUART5(data, length); + m_UART5.write(data, length);//WriteUART5(data, length); if (flush) - TXSerialFlush5(); + m_UART5.flush();//TXSerialFlush5(); #endif break; default: From 31f0e24588395472c5cde55bcd08ae56bb3a1126 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 23 May 2020 08:57:30 +0200 Subject: [PATCH 82/95] Make serial speed a compile option --- Config.h | 3 +++ SerialPort.cpp | 2 +- SerialPort.h | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Config.h b/Config.h index 73e716b..c540fa1 100644 --- a/Config.h +++ b/Config.h @@ -35,6 +35,9 @@ // For 19.2 MHz // #define EXTERNAL_OSC 19200000 +// Use a higher baudrate for host communication. Required for FM network ! +// #define SERIAL_SPEED 230400 + // Allow the use of the COS line to lockout the modem // #define USE_COS_AS_LOCKOUT diff --git a/SerialPort.cpp b/SerialPort.cpp index 2a9a241..8b56099 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -602,7 +602,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState) void CSerialPort::start() { - beginInt(1U, 115200); + beginInt(1U, SERIAL_SPEED); #if defined(SERIAL_REPEATER) beginInt(3U, 9600); diff --git a/SerialPort.h b/SerialPort.h index a75731a..b8838b5 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -23,6 +23,10 @@ #include "Globals.h" #include "RingBuffer.h" +#if !defined(SERIAL_SPEED) +#define SERIAL_SPEED 115200 +#endif + class CSerialPort { public: From f86b5435bb4635d30c7d1b87ddc31d712f0f7751 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 23 May 2020 15:30:00 +0200 Subject: [PATCH 83/95] Remove unneeded include --- FMDirectForm1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMDirectForm1.h b/FMDirectForm1.h index 450274d..b3dccb7 100644 --- a/FMDirectForm1.h +++ b/FMDirectForm1.h @@ -29,7 +29,7 @@ THE SOFTWARE. // based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h -#include "Globals.h" +#include #ifndef DIRECTFORMI_H_ #define DIRECTFORMI_H_ From 5db1adb5ea1937cf3343f0d4347a61f5cabd20ed Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 23 May 2020 21:01:21 +0200 Subject: [PATCH 84/95] #defines for serial speeds --- Config.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Config.h b/Config.h index c540fa1..572f0e0 100644 --- a/Config.h +++ b/Config.h @@ -36,7 +36,9 @@ // #define EXTERNAL_OSC 19200000 // Use a higher baudrate for host communication. Required for FM network ! -// #define SERIAL_SPEED 230400 +#define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this ! +// #define SERIAL_SPEED 230400 //Only works on newer board M4, M7, Teensy. External FM will works with this +// #define SERIAL_SPEED 460800 // Experimantal // Allow the use of the COS line to lockout the modem // #define USE_COS_AS_LOCKOUT From 26d055a67bf27188e93c3e1859ccbab56cc3dc12 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 07:44:38 +0200 Subject: [PATCH 85/95] Update filter generation script --- Tools/FMGenerateFilterCoefficients.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tools/FMGenerateFilterCoefficients.py b/Tools/FMGenerateFilterCoefficients.py index 7d8a3db..4eb81d8 100644 --- a/Tools/FMGenerateFilterCoefficients.py +++ b/Tools/FMGenerateFilterCoefficients.py @@ -17,30 +17,30 @@ f2 = 2700 rp = 0.2 # scaling factor in bits, do not change ! -q = 0 +q = 15 # scaling factor as facor... scaling_factor = 2**q # let's generate a sequence of 2nd order IIR filters sos = signal.cheby1(3,rp,[f1, f2],'bandpass', output='sos', fs=fs) -#sos = signal.cheby1(1, rp, 2122, 'lowpass', output='sos', fs=fs) #deemphasis filter +#os = signal.cheby1(4, rp, f2, 'lowpass', output='sos', fs=fs) #deemphasis filter #sos = signal.cheby1(1, rp, 2122, 'highpass', output='sos', fs=fs) #deemphasis filter -#sos = np.round((sos) * scaling_factor) +sosrounded = np.round((sos) * scaling_factor) # print coefficients -for biquad in sos: +for biquad in sosrounded: for coeff in biquad: - #print(int(coeff),",",sep="",end="") - print((coeff),",",sep="",end="") + print(int(coeff),",",sep="",end="") + #print((coeff),",",sep="",end="") print("") # plot the frequency response b,a = signal.sos2tf(sos) -w,h = signal.freqz(b,a) +w,h = signal.freqz(b,a, worN=2048) pl.plot(w/np.pi/2*fs,20*np.log(np.abs(h))) pl.xlabel('frequency/Hz'); pl.ylabel('gain/dB'); -pl.ylim(top=1,bottom=-20); +pl.ylim(top=1,bottom=-30); pl.xlim(left=250, right=12000); pl.show() \ No newline at end of file From 0bd79fa440f4c1cf700363b45fa58e0cf7736dd2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 07:45:50 +0200 Subject: [PATCH 86/95] Fix sample packing --- FMDownsampler.cpp | 9 ++++----- FMDownsampler.h | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/FMDownsampler.cpp b/FMDownsampler.cpp index e5d8645..b5303f6 100644 --- a/FMDownsampler.cpp +++ b/FMDownsampler.cpp @@ -20,7 +20,6 @@ #include "Config.h" #include "FMDownsampler.h" - CFMDownsampler::CFMDownsampler(uint16_t length) : m_ringBuffer(length), m_samplePack(0U), @@ -32,17 +31,17 @@ m_sampleIndex(0U) void CFMDownsampler::addSample(q15_t sample) { - uint16_t usample = uint16_t(sample + 2048); + uint32_t usample = uint32_t(int32_t(sample) + 2048); //only take one of three samples switch(m_sampleIndex){ case 0: - m_samplePack = uint32_t(usample) << 12; + m_samplePack = usample << 12; break; case 3:{ - m_samplePack |= uint32_t(usample); + m_samplePack |= usample; //we did not use MSB; skip it - TSamplePairPack pair{m_samplePackPointer[1U], m_samplePackPointer[2U], m_samplePackPointer[3U]}; + TSamplePairPack pair{m_samplePackPointer[0U], m_samplePackPointer[1U], m_samplePackPointer[2U]}; m_ringBuffer.put(pair); diff --git a/FMDownsampler.h b/FMDownsampler.h index 3118802..4427565 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -23,6 +23,7 @@ #include "Config.h" #include "RingBuffer.h" #include "FMSamplePairPack.h" +#include "FMDirectForm1.h" class CFMDownsampler { public: @@ -34,11 +35,9 @@ public: private: CRingBuffer m_ringBuffer; - - uint32_t m_samplePack; - uint8_t *m_samplePackPointer; - - uint8_t m_sampleIndex; + uint32_t m_samplePack; + uint8_t* m_samplePackPointer; + uint8_t m_sampleIndex; }; #endif From 47649171fc724f56c6ab97bbec9d2b3c90bb9d0e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 08:01:59 +0200 Subject: [PATCH 87/95] Fix sample unpacking --- FMUpSampler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FMUpSampler.cpp b/FMUpSampler.cpp index d84f185..d0a0027 100644 --- a/FMUpSampler.cpp +++ b/FMUpSampler.cpp @@ -52,9 +52,9 @@ void CFMUpSampler::addData(const uint8_t* data, uint16_t length) uint32_t pack = 0U; uint8_t* packPtr = (uint8_t*)&pack; - packPtr[1] = m_pack.byte0; - packPtr[2] = m_pack.byte1; - packPtr[3] = m_pack.byte2; + packPtr[0U] = m_pack.byte0; + packPtr[1U] = m_pack.byte1; + packPtr[2U] = m_pack.byte2; q15_t sample2 = q15_t(uint16_t(pack & FM_UPSAMPLE_MASK) - 2048); q15_t sample1 = q15_t(uint16_t(pack >> 12) - 2048); From 4dfab06a5012f648840a25fd4d9f5a1d02678c4f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 08:11:32 +0200 Subject: [PATCH 88/95] Revert to GPIO_Fast_Speed --- SerialSTM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialSTM.cpp b/SerialSTM.cpp index 14e1b07..d4c4766 100644 --- a/SerialSTM.cpp +++ b/SerialSTM.cpp @@ -83,7 +83,7 @@ void InitUSART1(int speed) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // Tx | Rx - GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; + GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed; GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure USART baud rate From cdfe3d0ec9e4eda70967faeafbdbd09730228962 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 24 May 2020 08:20:03 +0200 Subject: [PATCH 89/95] Clean up includes --- FMDownsampler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/FMDownsampler.h b/FMDownsampler.h index 4427565..ab91bd0 100644 --- a/FMDownsampler.h +++ b/FMDownsampler.h @@ -23,7 +23,6 @@ #include "Config.h" #include "RingBuffer.h" #include "FMSamplePairPack.h" -#include "FMDirectForm1.h" class CFMDownsampler { public: From 72cd2ce03e8edb5b1aec9e46eb55f80d1554d6dd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 30 May 2020 20:05:34 +0200 Subject: [PATCH 90/95] Ensure we have at least 75ms of audio before transmitting --- FM.cpp | 5 +-- FMUpSampler.cpp | 95 ++++++++++++++++++++++++++----------------------- FMUpSampler.h | 8 +++-- 3 files changed, 59 insertions(+), 49 deletions(-) diff --git a/FM.cpp b/FM.cpp index d7ef530..4f6b93f 100644 --- a/FM.cpp +++ b/FM.cpp @@ -56,7 +56,7 @@ m_extEnabled(false), m_rxLevel(1), m_inputRFRB(2401U), // 100ms of audio + 1 sample m_outputRFRB(2400U), // 100ms of audio -m_inputExtRB(2400U) // 100ms of Audio +m_inputExtRB() { m_statusTimer.setTimeout(1U, 0U); @@ -727,8 +727,9 @@ uint8_t CFM::getSpace() const uint8_t CFM::writeData(const uint8_t* data, uint8_t length) { + //todo check if length is a multiple of 3 m_inputExtRB.addData(data, length); - return 0U;//maybe return an error if overflowing ? + return 0U; } void CFM::insertDelay(uint16_t ms) diff --git a/FMUpSampler.cpp b/FMUpSampler.cpp index d0a0027..04fe705 100644 --- a/FMUpSampler.cpp +++ b/FMUpSampler.cpp @@ -21,69 +21,76 @@ const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU; -CFMUpSampler::CFMUpSampler(uint16_t length) : +CFMUpSampler::CFMUpSampler() : m_upSampleIndex(0), -m_pack({0U, 0U, 0U}), -m_samples(length) +m_pack(0U), +m_packPointer(NULL), +m_samples(3600U), //300ms of 12 bit 8kHz audio +m_running(false) { + m_packPointer = (uint8_t*)&m_pack; } void CFMUpSampler::reset() { m_upSampleIndex = 0U; - m_pack = {0U, 0U, 0U}; + m_pack = 0U; m_samples.reset(); + m_running = false; } void CFMUpSampler::addData(const uint8_t* data, uint16_t length) { - for(uint16_t i = 0U; i < length; i++) { - switch (m_upSampleIndex) - { - case 0U: - m_pack.byte0 = data[i]; - break; - case 1U: - m_pack.byte1 = data[i]; - break; - case 2U: { - m_pack.byte2 = data[i]; - - uint32_t pack = 0U; - uint8_t* packPtr = (uint8_t*)&pack; - - packPtr[0U] = m_pack.byte0; - packPtr[1U] = m_pack.byte1; - packPtr[2U] = m_pack.byte2; - - q15_t sample2 = q15_t(uint16_t(pack & FM_UPSAMPLE_MASK) - 2048); - q15_t sample1 = q15_t(uint16_t(pack >> 12) - 2048); - - m_samples.put(sample1); - m_samples.put(0); - m_samples.put(0); - m_samples.put(sample2); - m_samples.put(0); - m_samples.put(0); - } - break; - default: - //shoudl never happen - break; - } - - m_upSampleIndex ++; - if (m_upSampleIndex > 2U) - m_upSampleIndex = 0U; + TSamplePairPack* packPointer = (TSamplePairPack*)data; + TSamplePairPack* packPointerEnd = packPointer + (length / 3U); + while(packPointer != packPointerEnd) { + m_samples.put(*packPointer); + packPointer++; } + if(!m_running) + m_running = m_samples.getData() > 300U;//75ms of audio } bool CFMUpSampler::getSample(q15_t& sample) { - return m_samples.get(sample); + if(!m_running) + return false; + + switch (m_upSampleIndex) + { + case 0: { + TSamplePairPack pairPack; + if(!m_samples.get(pairPack)) { + m_running = false; + return false; + } + + m_pack = 0U; + m_packPointer = (uint8_t*)&m_pack; + + m_packPointer[0U] = pairPack.byte0; + m_packPointer[1U] = pairPack.byte1; + m_packPointer[2U] = pairPack.byte2; + + sample = q15_t(m_pack >> 12) - 2048; + break; + } + case 3: + sample = q15_t(m_pack & FM_UPSAMPLE_MASK) - 2048; + break; + default: + sample = 0; + break; + } + + m_upSampleIndex++; + if(m_upSampleIndex >= 6U) + m_upSampleIndex = 0U; + + return true; } uint16_t CFMUpSampler::getSpace() const { - return m_samples.getSpace(); + return m_samples.getSpace(); } \ No newline at end of file diff --git a/FMUpSampler.h b/FMUpSampler.h index cee671b..b76982f 100644 --- a/FMUpSampler.h +++ b/FMUpSampler.h @@ -27,7 +27,7 @@ class CFMUpSampler { public: - CFMUpSampler(uint16_t length); + CFMUpSampler(); void reset(); @@ -39,8 +39,10 @@ public: private: uint8_t m_upSampleIndex; - TSamplePairPack m_pack; - CRingBuffer m_samples; + uint32_t m_pack; + uint8_t * m_packPointer; + CRingBuffer m_samples; + bool m_running; }; #endif \ No newline at end of file From f414288c9b0fb3186d4fa42baafd86a9038fd328 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 11:45:17 +0200 Subject: [PATCH 91/95] Update speed comments --- Config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config.h b/Config.h index 572f0e0..978f35f 100644 --- a/Config.h +++ b/Config.h @@ -37,8 +37,8 @@ // Use a higher baudrate for host communication. Required for FM network ! #define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this ! -// #define SERIAL_SPEED 230400 //Only works on newer board M4, M7, Teensy. External FM will works with this -// #define SERIAL_SPEED 460800 // Experimantal +// #define SERIAL_SPEED 230400 // Only works on newer board M4, M7, Teensy. External FM might work with this +// #define SERIAL_SPEED 460800 // Only works on newer board M4, M7, Teensy. External FM should work with this // Allow the use of the COS line to lockout the modem // #define USE_COS_AS_LOCKOUT From 4f060c00477ce4284da233082b30f88b7cdf00d1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 21:50:06 +0200 Subject: [PATCH 92/95] Esnure frame size is 84 samples, correctly report space as number of frames --- FM.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/FM.cpp b/FM.cpp index 4f6b93f..8449e23 100644 --- a/FM.cpp +++ b/FM.cpp @@ -20,9 +20,11 @@ #include "Globals.h" #include "FM.h" + const uint16_t FM_TX_BLOCK_SIZE = 100U; -const uint16_t FM_SERIAL_BLOCK_SIZE = 42U;//this is actually the number of sample pairs to send over serial. One sample pair is 3bytes. - //three times this value shall never exceed 126 ! +const uint16_t FM_SERIAL_BLOCK_SIZE = 84U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes. + //three times this value shall never exceed 252 +const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U; CFM::CFM() : m_callsign(), @@ -721,8 +723,8 @@ void CFM::beginRelaying() uint8_t CFM::getSpace() const { - // The amount of free space for receiving external audio, in bytes. - return m_inputExtRB.getSpace(); + // The amount of free space for receiving external audio, in frames. + return m_inputExtRB.getSpace() / FM_SERIAL_BLOCK_SIZE_BYTES; } uint8_t CFM::writeData(const uint8_t* data, uint8_t length) From 2a4b28c35e225c26ddedaf5cff0f90aa21b6819f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 31 May 2020 21:50:39 +0200 Subject: [PATCH 93/95] return space as number of bytes --- FMUpSampler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FMUpSampler.cpp b/FMUpSampler.cpp index 04fe705..80cba37 100644 --- a/FMUpSampler.cpp +++ b/FMUpSampler.cpp @@ -92,5 +92,6 @@ bool CFMUpSampler::getSample(q15_t& sample) uint16_t CFMUpSampler::getSpace() const { - return m_samples.getSpace(); + //return available space in bytes + return m_samples.getSpace() * sizeof(TSamplePairPack); } \ No newline at end of file From 411d439d78a1671674b33f3e657cdea37b8e5f17 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 1 Jun 2020 10:29:05 +0200 Subject: [PATCH 94/95] Add forgotten file for large frame handling --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index 8b56099..3977b3a 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1257,7 +1257,7 @@ void CSerialPort::writeFMData(const uint8_t* data, uint8_t length) if (!m_fmEnable) return; - uint8_t reply[130U]; + uint8_t reply[255U]; reply[0U] = MMDVM_FRAME_START; reply[1U] = 0U; From 0ea732780d35feaf50e980a6758ba9374fb73957 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 21:03:11 +0100 Subject: [PATCH 95/95] Implement Kerchunk TX option. --- FM.cpp | 63 +++++++++++++++++++++++++++++++++++++------------- FM.h | 3 ++- SerialPort.cpp | 5 ++-- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/FM.cpp b/FM.cpp index 8449e23..01fa209 100644 --- a/FM.cpp +++ b/FM.cpp @@ -41,6 +41,7 @@ m_callsignTimer(), m_timeoutTimer(), m_holdoffTimer(), m_kerchunkTimer(), +m_kerchunkTX(true), m_ackMinTimer(), m_ackDelayTimer(), m_hangTimer(), @@ -109,10 +110,10 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) } q15_t currentSample = currentRFSample; - q15_t currentBoost = m_rfAudioBoost; - if(m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT){ + q15_t currentBoost = m_rfAudioBoost; + if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { currentSample = currentExtSample; - currentBoost = m_extAudioBoost; + currentBoost = m_extAudioBoost; } // Only let RF audio through when relaying RF audio @@ -244,7 +245,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 ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel) +uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, bool kerchunkTX, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel) { m_useCOS = useCOS; m_cosInvert = cosInvert; @@ -252,7 +253,10 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque m_rfAudioBoost = q15_t(rfAudioBoost); m_timeoutTimer.setTimeout(timeout, 0U); + m_kerchunkTimer.setTimeout(kerchunkTime, 0U); + m_kerchunkTX = kerchunkTX; + m_hangTimer.setTimeout(hangTime, 0U); m_timeoutTone.setParams(timeoutLevel); @@ -358,17 +362,19 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertSilence(50U); + if (m_state == FS_RELAYING_RF || (m_state == FS_KERCHUNK_RF && m_kerchunkTX)) { + insertSilence(50U); - beginRelaying(); + beginRelaying(); - m_callsignTimer.start(); + m_callsignTimer.start(); - io.setDecode(true); - io.setADCDetection(true); + io.setDecode(true); + io.setADCDetection(true); - m_statusTimer.start(); - serial.writeFMStatus(m_state); + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } } else if (validExtSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { DEBUG1("State to KERCHUNK_EXT"); @@ -383,14 +389,16 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) sendCallsign(); } - insertSilence(50U); + if (m_state == FS_RELAYING_EXT || (m_state == FS_KERCHUNK_EXT && m_kerchunkTX)) { + insertSilence(50U); - beginRelaying(); + beginRelaying(); - m_callsignTimer.start(); + m_callsignTimer.start(); - m_statusTimer.start(); - serial.writeFMStatus(m_state); + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } } } @@ -401,6 +409,19 @@ void CFM::kerchunkRFState(bool validSignal) DEBUG1("State to RELAYING_RF"); m_state = FS_RELAYING_RF; m_kerchunkTimer.stop(); + if (!m_kerchunkTX) { + insertSilence(50U); + + beginRelaying(); + + m_callsignTimer.start(); + + io.setDecode(true); + io.setADCDetection(true); + + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } if (m_callsignAtStart && m_callsignAtLatch) { sendCallsign(); m_callsignTimer.start(); @@ -499,6 +520,16 @@ void CFM::kerchunkExtState(bool validSignal) DEBUG1("State to RELAYING_EXT"); m_state = FS_RELAYING_EXT; m_kerchunkTimer.stop(); + if (!m_kerchunkTX) { + insertSilence(50U); + + beginRelaying(); + + m_callsignTimer.start(); + + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } if (m_callsignAtStart && m_callsignAtLatch) { sendCallsign(); m_callsignTimer.start(); diff --git a/FM.h b/FM.h index a179fd3..6b691c9 100644 --- a/FM.h +++ b/FM.h @@ -60,7 +60,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, bool callsignAtLatch); 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 ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel); + uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, bool kerchunkTX, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel); uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level); uint8_t getSpace() const; @@ -82,6 +82,7 @@ private: CFMTimer m_timeoutTimer; CFMTimer m_holdoffTimer; CFMTimer m_kerchunkTimer; + bool m_kerchunkTX; CFMTimer m_ackMinTimer; CFMTimer m_ackDelayTimer; CFMTimer m_hangTimer; diff --git a/SerialPort.cpp b/SerialPort.cpp index 3977b3a..fd5c188 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -107,7 +107,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200520 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" +#define DESCRIPTION "20200620 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -442,12 +442,13 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) bool useCOS = (data[8U] & 0x01U) == 0x01U; bool cosInvert = (data[8U] & 0x02U) == 0x02U; + bool kerchunkTX = (data[8U] & 0x04U) == 0x04U; uint8_t rfAudioBoost = data[9U]; uint8_t maxDev = data[10U]; uint8_t rxLevel = data[11U]; - return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); + return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, kerchunkTX, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); } uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint8_t length)