From a816818e3f6335e1b5a35be21ca63f13f7a2b142 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 7 May 2020 16:17:00 +0100 Subject: [PATCH 001/139] 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 002/139] 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 003/139] 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 004/139] 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 005/139] 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 006/139] 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 007/139] 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 008/139] 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 009/139] 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 010/139] 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 011/139] 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 012/139] 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 013/139] 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 014/139] 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 015/139] 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 016/139] 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 017/139] 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 018/139] 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 019/139] 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 020/139] 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 021/139] 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 022/139] 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 023/139] 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 024/139] 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 025/139] 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 026/139] 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 027/139] 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 028/139] 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 029/139] 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 030/139] 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 031/139] 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 032/139] 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 033/139] 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 034/139] 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 035/139] 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 036/139] 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 037/139] 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 038/139] 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 039/139] 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 040/139] 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 041/139] 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 042/139] 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 043/139] 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 044/139] 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 045/139] 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 046/139] 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 047/139] 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 048/139] 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 049/139] 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 050/139] 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 051/139] 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 052/139] 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 053/139] 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 054/139] 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 055/139] 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 056/139] 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 057/139] 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 058/139] 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 059/139] 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 060/139] 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 061/139] 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 062/139] 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 063/139] 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 064/139] 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 065/139] 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 066/139] 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 067/139] 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 068/139] 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 069/139] 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 070/139] 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 071/139] 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 072/139] 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 073/139] 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 074/139] 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 075/139] 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 076/139] 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 077/139] 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 078/139] 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 079/139] 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 080/139] 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 081/139] 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 082/139] 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 083/139] 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 084/139] #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 085/139] 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 086/139] 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 087/139] 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 088/139] 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 089/139] 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 090/139] 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 091/139] 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 092/139] 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 093/139] 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 094/139] 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 a2e2853241361cae2a406949fc51ba50b5d88c3f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 8 Jun 2020 15:02:12 +0100 Subject: [PATCH 095/139] Begin AX.25 development. --- AX25RX.cpp | 33 +++++++++++++++++++++++++++++++++ AX25RX.h | 34 ++++++++++++++++++++++++++++++++++ Config.h | 2 +- Globals.h | 7 ++++++- IO.cpp | 12 ++++++++++++ MMDVM.cpp | 2 ++ MMDVM.ino | 2 ++ SerialPort.cpp | 31 ++++++++++++++++++++++++++++++- SerialPort.h | 4 +++- 9 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 AX25RX.cpp create mode 100644 AX25RX.h diff --git a/AX25RX.cpp b/AX25RX.cpp new file mode 100644 index 0000000..8305407 --- /dev/null +++ b/AX25RX.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "AX25RX.h" + +CAX25RX::CAX25RX() +{ +} + +void CAX25RX::samples(const q15_t* samples, uint8_t length) +{ + for (uint8_t i = 0U; i < length; i++) { + q15_t sample = samples[i]; + } +} + diff --git a/AX25RX.h b/AX25RX.h new file mode 100644 index 0000000..bbb2779 --- /dev/null +++ b/AX25RX.h @@ -0,0 +1,34 @@ +/* + * 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(AX25RX_H) +#define AX25RX_H + +#include "Config.h" + +class CAX25RX { +public: + CAX25RX(); + + void samples(const q15_t* samples, uint8_t length); + +private: +}; + +#endif + diff --git a/Config.h b/Config.h index 73e716b..cdebe56 100644 --- a/Config.h +++ b/Config.h @@ -39,7 +39,7 @@ // #define USE_COS_AS_LOCKOUT // Use pins to output the current mode via LEDs -// #define MODE_LEDS +#define MODE_LEDS // For the original Arduino Due pin layout // #define ARDUINO_DUE_PAPA diff --git a/Globals.h b/Globals.h index 5cb147a..4d25617 100644 --- a/Globals.h +++ b/Globals.h @@ -51,6 +51,7 @@ enum MMDVM_STATE { STATE_NXDN = 5, STATE_POCSAG = 6, STATE_FM = 10, + STATE_AX25 = 11, // Dummy states start at 90 STATE_NXDNCAL1K = 91, @@ -96,6 +97,7 @@ enum MMDVM_STATE { #include "CalPOCSAG.h" #include "CalRSSI.h" #include "CWIdTX.h" +#include "AX25RX.h" #include "Debug.h" #include "IO.h" #include "FM.h" @@ -124,6 +126,7 @@ extern bool m_p25Enable; extern bool m_nxdnEnable; extern bool m_pocsagEnable; extern bool m_fmEnable; +extern bool m_ax25Enable; extern bool m_duplex; @@ -154,7 +157,8 @@ extern CNXDNTX nxdnTX; extern CPOCSAGTX pocsagTX; -extern CFM fm; +extern CFM fm; +extern CAX25RX ax25RX; extern CCalDStarRX calDStarRX; extern CCalDStarTX calDStarTX; @@ -168,3 +172,4 @@ extern CCalRSSI calRSSI; extern CCWIdTX cwIdTX; #endif + diff --git a/IO.cpp b/IO.cpp index a737693..6962f08 100644 --- a/IO.cpp +++ b/IO.cpp @@ -362,6 +362,14 @@ void CIO::process() fm.samples(cos, dcSamples, RX_BLOCK_SIZE); #else fm.samples(cos, samples, RX_BLOCK_SIZE); +#endif + } + + if (m_ax25Enable) { +#if defined(USE_DCBLOCKER) + ax25RX.samples(dcSamples, RX_BLOCK_SIZE); +#else + ax25RX.samples(samples, RX_BLOCK_SIZE); #endif } } else if (m_modemState == STATE_DSTAR) { @@ -426,8 +434,12 @@ void CIO::process() bool cos = getCOSInt(); #if defined(USE_DCBLOCKER) fm.samples(cos, dcSamples, RX_BLOCK_SIZE); + if (m_ax25Enable) + ax25RX.samples(dcSamples, RX_BLOCK_SIZE); #else fm.samples(cos, samples, RX_BLOCK_SIZE); + if (m_ax25Enable) + ax25RX.samples(samples, RX_BLOCK_SIZE); #endif } else if (m_modemState == STATE_DSTARCAL) { q15_t GMSKVals[RX_BLOCK_SIZE]; diff --git a/MMDVM.cpp b/MMDVM.cpp index a6d4577..5b5bc4b 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -33,6 +33,7 @@ bool m_p25Enable = true; bool m_nxdnEnable = true; bool m_pocsagEnable = true; bool m_fmEnable = true; +bool m_ax25Enable = true; bool m_duplex = true; @@ -61,6 +62,7 @@ CNXDNTX nxdnTX; CPOCSAGTX pocsagTX; CFM fm; +CAX25RX ax25RX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; diff --git a/MMDVM.ino b/MMDVM.ino index 17c4ad8..f1073dd 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -30,6 +30,7 @@ bool m_p25Enable = true; bool m_nxdnEnable = true; bool m_pocsagEnable = true; bool m_fmEnable = true; +bool m_ax25Enable = true; bool m_duplex = true; @@ -58,6 +59,7 @@ CNXDNTX nxdnTX; CPOCSAGTX pocsagTX; CFM fm; +CAX25RX ax25RX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; diff --git a/SerialPort.cpp b/SerialPort.cpp index 338f5f9..f906bc0 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -65,6 +65,8 @@ const uint8_t MMDVM_NXDN_LOST = 0x41U; const uint8_t MMDVM_POCSAG_DATA = 0x50U; +const uint8_t MMDVM_AX25_DATA = 0x55U; + const uint8_t MMDVM_FM_PARAMS1 = 0x60U; const uint8_t MMDVM_FM_PARAMS2 = 0x61U; const uint8_t MMDVM_FM_PARAMS3 = 0x62U; @@ -103,7 +105,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 "20200608 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -176,6 +178,8 @@ void CSerialPort::getStatus() reply[3U] |= 0x20U; if (m_fmEnable) reply[3U] |= 0x40U; + if (m_ax25Enable) + reply[3U] |= 0x80U; reply[4U] = uint8_t(m_modemState); @@ -282,6 +286,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) bool nxdnEnable = (data[1U] & 0x10U) == 0x10U; bool pocsagEnable = (data[1U] & 0x20U) == 0x20U; bool fmEnable = (data[1U] & 0x40U) == 0x40U; + bool ax25Enable = (data[1U] & 0x80U) == 0x80U; uint8_t txDelay = data[2U]; if (txDelay > 50U) @@ -344,6 +349,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) m_nxdnEnable = nxdnEnable; m_pocsagEnable = pocsagEnable; m_fmEnable = fmEnable; + m_ax25Enable = ax25Enable; m_duplex = !simplex; dstarTX.setTXDelay(txDelay); @@ -1197,6 +1203,29 @@ void CSerialPort::writeNXDNLost() writeInt(1U, reply, 3); } +void CSerialPort::writeAX25Data(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) + return; + + if (!m_ax25Enable) + return; + + uint8_t reply[300U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_AX25_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..e8b9d58 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 writeAX25Data(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 64fe59382f54770a95562c4f21a6d8da7880c5ab Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 9 Jun 2020 14:57:06 +0100 Subject: [PATCH 096/139] Start on the actual AX.25 demodulator. --- AX25Demodulator.cpp | 31 +++++++++++++++++++++++++++++++ AX25Demodulator.h | 35 +++++++++++++++++++++++++++++++++++ AX25RX.cpp | 9 ++++++++- AX25RX.h | 5 +++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 AX25Demodulator.cpp create mode 100644 AX25Demodulator.h diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp new file mode 100644 index 0000000..b1a9d84 --- /dev/null +++ b/AX25Demodulator.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "AX25Demodulator.h" + +CAX25Demodulator::CAX25Demodulator(uint16_t n) : +m_n(n) +{ +} + +void CAX25Demodulator::process(q15_t sample) +{ +} + diff --git a/AX25Demodulator.h b/AX25Demodulator.h new file mode 100644 index 0000000..d26aa32 --- /dev/null +++ b/AX25Demodulator.h @@ -0,0 +1,35 @@ +/* + * 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(AX25Demodulator_H) +#define AX25Demodulator_H + +#include "Config.h" + +class CAX25Demodulator { +public: + CAX25Demodulator(uint16_t n); + + void process(q15_t sample); + +private: + uint16_t m_n; +}; + +#endif + diff --git a/AX25RX.cpp b/AX25RX.cpp index 8305407..260d549 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -20,7 +20,10 @@ #include "Globals.h" #include "AX25RX.h" -CAX25RX::CAX25RX() +CAX25RX::CAX25RX() : +m_demod1(1U), +m_demod2(2U), +m_demod3(3U) { } @@ -28,6 +31,10 @@ void CAX25RX::samples(const q15_t* samples, uint8_t length) { for (uint8_t i = 0U; i < length; i++) { q15_t sample = samples[i]; + + m_demod1.process(sample); + m_demod2.process(sample); + m_demod3.process(sample); } } diff --git a/AX25RX.h b/AX25RX.h index bbb2779..feab90a 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -21,6 +21,8 @@ #include "Config.h" +#include "AX25Demodulator.h" + class CAX25RX { public: CAX25RX(); @@ -28,6 +30,9 @@ public: void samples(const q15_t* samples, uint8_t length); private: + CAX25Demodulator m_demod1; + CAX25Demodulator m_demod2; + CAX25Demodulator m_demod3; }; #endif From e1d1ac4a4d2483bde003e356b6cae202d03a7a2c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 10 Jun 2020 12:07:04 +0100 Subject: [PATCH 097/139] More work on adding AX.25 decoding. --- AX25Demodulator.cpp | 16 +++++++++++++--- AX25Demodulator.h | 14 +++++++++++--- AX25RX.cpp | 38 ++++++++++++++++++++++++++++++-------- AX25RX.h | 1 + 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index b1a9d84..8df7833 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -20,12 +20,22 @@ #include "Globals.h" #include "AX25Demodulator.h" -CAX25Demodulator::CAX25Demodulator(uint16_t n) : -m_n(n) +CAX25Demodulator::CAX25Demodulator() : +m_nrziState(false) { } -void CAX25Demodulator::process(q15_t sample) +bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, AX25Frame& frame) { + return false; +} + +bool CAX25Demodulator::NRZI(bool b) +{ + bool result = (b == m_nrziState); + + m_nrziState = b; + + return result; } diff --git a/AX25Demodulator.h b/AX25Demodulator.h index d26aa32..16abc7e 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -21,14 +21,22 @@ #include "Config.h" +struct AX25Frame { + uint8_t m_data[300U]; + uint16_t m_length; + uint16_t m_fcs; +}; + class CAX25Demodulator { public: - CAX25Demodulator(uint16_t n); + CAX25Demodulator(); - void process(q15_t sample); + bool process(const q15_t* samples, uint8_t length, AX25Frame& frame); private: - uint16_t m_n; + bool m_nrziState; + + bool NRZI(bool b); }; #endif diff --git a/AX25RX.cpp b/AX25RX.cpp index 260d549..2fea46e 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -21,20 +21,42 @@ #include "AX25RX.h" CAX25RX::CAX25RX() : -m_demod1(1U), -m_demod2(2U), -m_demod3(3U) +m_demod1(), +m_demod2(), +m_demod3(), +m_lastFCS(0U) { } void CAX25RX::samples(const q15_t* samples, uint8_t length) { - for (uint8_t i = 0U; i < length; i++) { - q15_t sample = samples[i]; + AX25Frame frame; - m_demod1.process(sample); - m_demod2.process(sample); - m_demod3.process(sample); + bool ret = m_demod1.process(samples, length, frame); + if (ret) { + if (m_lastFCS != frame.m_fcs) { + DEBUG1("Decoder 1 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length); + } + } + + ret = m_demod2.process(samples, length, frame); + if (ret) { + if (m_lastFCS != frame.m_fcs) { + DEBUG1("Decoder 2 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length); + } + } + + ret = m_demod3.process(samples, length, frame); + if (ret) { + if (m_lastFCS != frame.m_fcs) { + DEBUG1("Decoder 3 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length); + } } } diff --git a/AX25RX.h b/AX25RX.h index feab90a..68f3532 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -33,6 +33,7 @@ private: CAX25Demodulator m_demod1; CAX25Demodulator m_demod2; CAX25Demodulator m_demod3; + uint16_t m_lastFCS; }; #endif From 57e18e337f766aa931e552c8cb884fb8f0124893 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 10 Jun 2020 13:53:18 +0100 Subject: [PATCH 098/139] Add the seperate AX25Frame class. --- AX25Demodulator.cpp | 22 +++++++++++- AX25Demodulator.h | 14 ++++---- AX25Frame.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++++ AX25Frame.h | 36 +++++++++++++++++++ AX25RX.cpp | 2 +- 5 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 AX25Frame.cpp create mode 100644 AX25Frame.h diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 8df7833..e824cc1 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -20,16 +20,36 @@ #include "Globals.h" #include "AX25Demodulator.h" +const float DELAY = 0.000448F; +const float SAMPLE_RATE = 24000.0F; + +const uint16_t DELAY_LEN = uint16_t((DELAY / (1.0F / SAMPLE_RATE)) + 0.5F); + CAX25Demodulator::CAX25Demodulator() : +m_delayLine(NULL), +m_delayPos(0U), m_nrziState(false) { + m_delayLine = new bool[2U * DELAY_LEN]; } -bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, AX25Frame& frame) +bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& frame) { return false; } +bool CAX25Demodulator::delay(bool b) +{ + bool r = m_delayLine[m_delayPos]; + + m_delayLine[m_delayPos++] = b; + + if (m_delayPos >= DELAY_LEN) + m_delayPos = 0U; + + return r; +} + bool CAX25Demodulator::NRZI(bool b) { bool result = (b == m_nrziState); diff --git a/AX25Demodulator.h b/AX25Demodulator.h index 16abc7e..550ec8b 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -21,21 +21,21 @@ #include "Config.h" -struct AX25Frame { - uint8_t m_data[300U]; - uint16_t m_length; - uint16_t m_fcs; -}; +#include "AX25Frame.h" + class CAX25Demodulator { public: CAX25Demodulator(); - bool process(const q15_t* samples, uint8_t length, AX25Frame& frame); + bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame); private: - bool m_nrziState; + bool* m_delayLine; + uint16_t m_delayPos; + bool m_nrziState; + bool delay(bool b); bool NRZI(bool b); }; diff --git a/AX25Frame.cpp b/AX25Frame.cpp new file mode 100644 index 0000000..2540cb3 --- /dev/null +++ b/AX25Frame.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "AX25Frame.h" + +const uint16_t CCITT_TABLE[] = { + 0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU, + 0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U, + 0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU, + 0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U, + 0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU, + 0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U, + 0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU, + 0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U, + 0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU, + 0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U, + 0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU, + 0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U, + 0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U, + 0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U, + 0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U, + 0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U, + 0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U, + 0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU, + 0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U, + 0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU, + 0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U, + 0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU, + 0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U, + 0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU, + 0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U, + 0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU, + 0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U, + 0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU, + 0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U, + 0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U, + 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, + 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U}; + +CAX25Frame::CAX25Frame() : +m_data(), +m_length(0U), +m_fcs(0U) +{ +} + +bool CAX25Frame::checkCRC() +{ + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0xFFFFU; + for (uint16_t i = 0U; i < (m_length - 2U); i++) + crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]]; + + crc16 = ~crc16; + + if (crc8[0U] == m_data[m_length - 2U] && crc8[1U] == m_data[m_length - 1U]) { + m_fcs = crc16; + return true; + } else { + return false; + } +} + diff --git a/AX25Frame.h b/AX25Frame.h new file mode 100644 index 0000000..30e08f7 --- /dev/null +++ b/AX25Frame.h @@ -0,0 +1,36 @@ +/* + * 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(AX25Frame_H) +#define AX25Frame_H + +#include "Config.h" + +class CAX25Frame { +public: + CAX25Frame(); + + bool checkCRC(); + + uint8_t m_data[300U]; + uint16_t m_length; + uint16_t m_fcs; +}; + +#endif + diff --git a/AX25RX.cpp b/AX25RX.cpp index 2fea46e..538e014 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -30,7 +30,7 @@ m_lastFCS(0U) void CAX25RX::samples(const q15_t* samples, uint8_t length) { - AX25Frame frame; + CAX25Frame frame; bool ret = m_demod1.process(samples, length, frame); if (ret) { From 22cb16f831e4a504d16b8b75c1ef5948fdefced2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 10 Jun 2020 16:09:45 +0100 Subject: [PATCH 099/139] Add more frame processing. --- AX25Demodulator.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++-- AX25Demodulator.h | 18 +++++-- 2 files changed, 129 insertions(+), 9 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index e824cc1..f1bcddf 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -20,22 +20,102 @@ #include "Globals.h" #include "AX25Demodulator.h" -const float DELAY = 0.000448F; -const float SAMPLE_RATE = 24000.0F; +const float32_t DELAY = 0.000448F; +const float32_t SAMPLE_RATE = 24000.0F; +const float32_t SYMBOL_RATE = 1200.0F; const uint16_t DELAY_LEN = uint16_t((DELAY / (1.0F / SAMPLE_RATE)) + 0.5F); -CAX25Demodulator::CAX25Demodulator() : +const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE; +const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; + +// XXX This is for the wrong sample rate +const uint32_t LPF_FILTER_LEN = 96; + +q15_t lpfCoeffs[] = { + 0, 1, 3, 5, 8, 11, 14, 17, 19, 20, 18, 14, + 7, -2, -16, -33, -53, -76, -101, -126, -151, -174, -194, -208, + -215, -212, -199, -173, -133, -79, -10, 74, 173, 287, 413, 549, + 693, 842, 993, 1142, 1287, 1423, 1547, 1656, 1747, 1817, 1865, 1889, + 1889, 1865, 1817, 1747, 1656, 1547, 1423, 1287, 1142, 993, 842, 693, + 549, 413, 287, 173, 74, -10, -79, -133, -173, -199, -212, -215, + -208, -194, -174, -151, -126, -101, -76, -53, -33, -16, -2, 7, + 14, 18, 20, 19, 17, 14, 11, 8, 5, 3, 1, 0, +}; + +// 64 Hz loop filter. +// scipy.signal: +// loop_coeffs = firwin(9, [64.0/(1200/2)], width = None, +// pass_zero = True, scale = True, window='hann') +// +float32_t pllLoopCoeffs[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; + +CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : +m_audioFilter(), +m_audioState(), +m_lpfFilter(), +m_lpfState(), m_delayLine(NULL), m_delayPos(0U), -m_nrziState(false) +m_nrziState(false), +m_pllFilter(), +m_pllState(), +m_pllLast(false), +m_pllBits(1U), +m_pllCount(0.0F) { m_delayLine = new bool[2U * DELAY_LEN]; + + m_audioFilter.numTaps = length; + m_audioFilter.pState = m_audioState; + m_audioFilter.pCoeffs = coeffs; + + m_lpfFilter.numTaps = LPF_FILTER_LEN; + m_lpfFilter.pState = m_lpfState; + m_lpfFilter.pCoeffs = lpfCoeffs; + + m_pllFilter.numTaps = 7U; + m_pllFilter.pState = m_pllState; + m_pllFilter.pCoeffs = pllLoopCoeffs; } bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& frame) { - return false; + bool result = false; + + float32_t input[RX_BLOCK_SIZE]; + for (size_t i = 0; i < length; i++) + input[i] = float(samples[i]); + + float32_t fa[RX_BLOCK_SIZE]; + ::arm_fir_f32(&m_audioFilter, input, fa, RX_BLOCK_SIZE); + + int16_t buffer[RX_BLOCK_SIZE]; + for (uint8_t i = 0; i < length; i++) { + int16_t sample = int16_t(fa[i]); + bool level = (sample >= 0); + bool delayed = delay(level); + buffer[i] = (int16_t(level ^ delayed) << 1) - 1; + } + + q15_t fc[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE); + + for (uint8_t i = 0; i < length; i++) { + bool bit = fc[i] >= 0; + bool sample = PLL(bit); + + if (sample) { + // We will only ever get one frame because there are + // not enough bits in a block for more than one. + if (result) + hdlc_decoder_(NRZI(bit), true); + else + result = hdlc_decoder_(NRZI(bit), true); + } + } + + return result; } bool CAX25Demodulator::delay(bool b) @@ -59,3 +139,33 @@ bool CAX25Demodulator::NRZI(bool b) return result; } +bool CAX25Demodulator::PLL(bool input) +{ + bool sample = false; + + if (input != m_pllLast or m_pllBits > 16U) { + // Record transition. + m_pllLast = input; + + if (m_pllCount > PLL_LIMIT) + m_pllCount -= SAMPLES_PER_SYMBOL; + + float32_t offset = m_pllCount / float32_t(m_pllBits); + float32_t jitter; + ::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U); + + m_pllCount -= jitter / 2.0F; + m_pllBits = 1U; + } else { + if (m_pllCount > PLL_LIMIT) { + sample = true; + m_pllCount -= SAMPLES_PER_SYMBOL; + m_pllBits++; + } + } + + m_pllCount += 1.0F; + + return sample; +} + diff --git a/AX25Demodulator.h b/AX25Demodulator.h index 550ec8b..c897c24 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -26,17 +26,27 @@ class CAX25Demodulator { public: - CAX25Demodulator(); + CAX25Demodulator(float32_t* coeffs, uint16_t length); bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame); private: - bool* m_delayLine; - uint16_t m_delayPos; - bool m_nrziState; + arm_fir_instance_f32 m_audioFilter; + float32_t m_audioState[20U]; + arm_fir_instance_q15 m_lpfFilter; + q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 20 - 1 plus some spare + bool* m_delayLine; + uint16_t m_delayPos; + bool m_nrziState; + arm_fir_instance_f32 m_pllFilter; + float32_t m_pllState[7U]; + bool m_pllLast; + uint8_t m_pllBits; + float32_t m_pllCount; bool delay(bool b); bool NRZI(bool b); + bool PLL(bool b); }; #endif From 121c76f3d8ef2cf6205970f99474f74a52294ed5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 10 Jun 2020 16:38:10 +0100 Subject: [PATCH 100/139] More filtering added. --- AX25Demodulator.cpp | 14 ++++--- AX25RX.cpp | 95 +++++++++++++++++++++++++++++++++++++++++---- AX25RX.h | 12 +++--- 3 files changed, 103 insertions(+), 18 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index f1bcddf..71e61ee 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -30,9 +30,9 @@ const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE; const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; // XXX This is for the wrong sample rate -const uint32_t LPF_FILTER_LEN = 96; +const uint32_t LPF_FILTER_LEN = 96U; -q15_t lpfCoeffs[] = { +q15_t LPF_FILTER_COEFFS[] = { 0, 1, 3, 5, 8, 11, 14, 17, 19, 20, 18, 14, 7, -2, -16, -33, -53, -76, -101, -126, -151, -174, -194, -208, -215, -212, -199, -173, -133, -79, -10, 74, 173, 287, 413, 549, @@ -48,7 +48,9 @@ q15_t lpfCoeffs[] = { // loop_coeffs = firwin(9, [64.0/(1200/2)], width = None, // pass_zero = True, scale = True, window='hann') // -float32_t pllLoopCoeffs[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; +const uint32_t PLL_FILTER_LEN = 7U; + +float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : m_audioFilter(), @@ -72,11 +74,11 @@ m_pllCount(0.0F) m_lpfFilter.numTaps = LPF_FILTER_LEN; m_lpfFilter.pState = m_lpfState; - m_lpfFilter.pCoeffs = lpfCoeffs; + m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS; - m_pllFilter.numTaps = 7U; + m_pllFilter.numTaps = PLL_FILTER_LEN; m_pllFilter.pState = m_pllState; - m_pllFilter.pCoeffs = pllLoopCoeffs; + m_pllFilter.pCoeffs = PLL_FILTER_COEFFS; } bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& frame) diff --git a/AX25RX.cpp b/AX25RX.cpp index 538e014..99aa1a5 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -20,19 +20,100 @@ #include "Globals.h" #include "AX25RX.h" +// XXX There are for the wrong sample rate + +// 1200Hz = -9dB, 2200Hz = 0dB; 3252Hz cutoff, 3.7 gain; cosine. +float32_t dB9[] = { + -0.00232554104135, + -0.142858725752, + -0.449053780255, + -0.770264863826, + 2.77651146344, + -0.770264863826, + -0.449053780255, + -0.142858725752, + -0.00232554104135}; + +// 1200Hz = -6dB, 2200Hz = 0dB; 2640Hz cutoff, 2.59 gain; cosine. +float32_t dB6[] = { + -0.0209448226653, + -0.130107651829, + -0.299004731072, + -0.45336946386, + 2.0629448761, + -0.45336946386, + -0.299004731072, + -0.130107651829, + -0.0209448226653}; + +// 1200Hz = -3dB, 2200Hz = 0dB; 1700Hz cutoff, 1.68 gain; cosine. +float32_t dB3[] = { + -0.0231416146776, + -0.0833375337803, + -0.147937602401, + -0.197411259519, + 1.46066084756, + -0.197411259519, + -0.147937602401, + -0.0833375337803, + -0.0231416146776}; + +/* + * Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass, + * Hann window, starting and ending 0 value coefficients removed. + * + * np.array( + * firwin2(152, + * [ + * 0.0, + * 1000.0/(sample_rate/2), + * 1100.0/(sample_rate/2), + * 2350.0/(sample_rate/2), + * 2500.0/(sample_rate/2), + * 1.0 + * ], + * [0,0,1,1,0,0], + * antisymmetric = False, + * window='hann') * 32768, + * dtype=int)[10:-10] + */ +const uint32_t FILTER_LEN = 132U; + +// XXX This is for the wrong sample rate +q15_t FILTER_COEFFS[] = { + 4, 0, -5, -10, -13, -12, -9, -4, -2, -4, -12, -26, + -41, -52, -51, -35, -3, 39, 83, 117, 131, 118, 83, 36, + -6, -32, -30, -3, 36, 67, 66, 19, -74, -199, -323, -408, + -421, -344, -187, 17, 218, 364, 417, 369, 247, 106, 14, 26, + 166, 407, 676, 865, 866, 605, 68, -675, -1484, -2171, -2547, -2471, +-1895, -882, 394, 1692, 2747, 3337, 3337, 2747, 1692, 394, -882, -1895, +-2471, -2547, -2171, -1484, -675, 68, 605, 866, 865, 676, 407, 166, + 26, 14, 106, 247, 369, 417, 364, 218, 17, -187, -344, -421, + -408, -323, -199, -74, 19, 66, 67, 36, -3, -30, -32, -6, + 36, 83, 118, 131, 117, 83, 39, -3, -35, -51, -52, -41, + -26, -12, -4, -2, -4, -9, -12, -13, -10, -5, 0, 4}; + CAX25RX::CAX25RX() : -m_demod1(), -m_demod2(), -m_demod3(), +m_filter(), +m_state(), +m_demod1(dB3, 9U), +m_demod2(dB6, 9U), +m_demod3(dB9, 9U), m_lastFCS(0U) { + m_filter.numTaps = FILTER_LEN; + m_filter.pState = m_state; + m_filter.pCoeffs = FILTER_COEFFS; } -void CAX25RX::samples(const q15_t* samples, uint8_t length) +void CAX25RX::samples(q15_t* samples, uint8_t length) { + q15_t output[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE); + CAX25Frame frame; - bool ret = m_demod1.process(samples, length, frame); + bool ret = m_demod1.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 1 reported"); @@ -41,7 +122,7 @@ void CAX25RX::samples(const q15_t* samples, uint8_t length) } } - ret = m_demod2.process(samples, length, frame); + ret = m_demod2.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 2 reported"); @@ -50,7 +131,7 @@ void CAX25RX::samples(const q15_t* samples, uint8_t length) } } - ret = m_demod3.process(samples, length, frame); + ret = m_demod3.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 3 reported"); diff --git a/AX25RX.h b/AX25RX.h index 68f3532..6ab6d1c 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -27,13 +27,15 @@ class CAX25RX { public: CAX25RX(); - void samples(const q15_t* samples, uint8_t length); + void samples(q15_t* samples, uint8_t length); private: - CAX25Demodulator m_demod1; - CAX25Demodulator m_demod2; - CAX25Demodulator m_demod3; - uint16_t m_lastFCS; + arm_fir_instance_q15 m_filter; + q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare + CAX25Demodulator m_demod1; + CAX25Demodulator m_demod2; + CAX25Demodulator m_demod3; + uint16_t m_lastFCS; }; #endif From c2959466fd806524dca9158fd87924df864e41bc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 11 Jun 2020 10:02:11 +0100 Subject: [PATCH 101/139] Code complete, but untested. --- AX25Demodulator.cpp | 103 +++++++++++++++++++++++++++++++++++++++++--- AX25Demodulator.h | 12 ++++++ AX25Frame.cpp | 10 +++++ AX25Frame.h | 6 ++- AX25RX.cpp | 12 +++--- 5 files changed, 131 insertions(+), 12 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 71e61ee..32dbcb4 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -53,6 +53,7 @@ const uint32_t PLL_FILTER_LEN = 7U; float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : +m_frame(), m_audioFilter(), m_audioState(), m_lpfFilter(), @@ -64,7 +65,12 @@ m_pllFilter(), m_pllState(), m_pllLast(false), m_pllBits(1U), -m_pllCount(0.0F) +m_pllCount(0.0F), +m_hdlcOnes(0U), +m_hdlcFlag(false), +m_hdlcBuffer(0U), +m_hdlcBits(0U), +m_hdlcState(AX25_IDLE) { m_delayLine = new bool[2U * DELAY_LEN]; @@ -110,10 +116,17 @@ bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& if (sample) { // We will only ever get one frame because there are // not enough bits in a block for more than one. - if (result) - hdlc_decoder_(NRZI(bit), true); - else - result = hdlc_decoder_(NRZI(bit), true); + if (result) { + HDLC(NRZI(bit)); + } else { + result = HDLC(NRZI(bit)); + if (result) { + ::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN); + frame.m_length = frame.m_length; + frame.m_fcs = m_frame.m_fcs; + m_frame.m_length = 0U; + } + } } } @@ -171,3 +184,83 @@ bool CAX25Demodulator::PLL(bool input) return sample; } +bool CAX25Demodulator::HDLC(bool b) +{ + bool result = false; + + if (m_hdlcOnes == 5U) { + if (b) { + // flag byte + m_hdlcFlag = true; + } else { + // bit stuffing... + m_hdlcFlag = false; + m_hdlcOnes = 0U; + return result; + } + } + + m_hdlcBuffer >>= 1; + m_hdlcBuffer |= b ? 128U : 0U; + m_hdlcBits++; // Free-running until Sync byte. + + if (b) + m_hdlcOnes++; + else + m_hdlcOnes = 0U; + + if (m_hdlcFlag) { + switch (m_hdlcBuffer) { + case 0x7E: + if (m_frame.m_length > 0U) { + result = m_frame.checkCRC(); + if (!result) + m_frame.m_length = 0U; + } + m_hdlcState = AX25_SYNC; + m_hdlcFlag = false; + m_hdlcBits = 0U; + break; + + case 0xFE: + // Frame aborted + m_frame.m_length = 0U; + m_hdlcState = AX25_IDLE; + m_hdlcFlag = false; + m_hdlcBits = 0U; + break; + + default: + break; + } + + return result; + } + + switch (m_hdlcState) { + case AX25_IDLE: + break; + + case AX25_SYNC: + if (m_hdlcBits == 8U) { // 8th bit. + // Start of frame data. + m_hdlcState = AX25_RECEIVE; + m_frame.append(m_hdlcBuffer); + m_hdlcBits = 0U; + } + break; + + case AX25_RECEIVE: + if (m_hdlcBits == 8U) { // 8th bit. + m_frame.append(m_hdlcBuffer); + m_hdlcBits = 0U; + } + break; + + default: + break; + } + + return result; +} + diff --git a/AX25Demodulator.h b/AX25Demodulator.h index c897c24..e12d4c6 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -23,6 +23,11 @@ #include "AX25Frame.h" +enum AX25_STATE { + AX25_IDLE, + AX25_SYNC, + AX25_RECEIVE +}; class CAX25Demodulator { public: @@ -31,6 +36,7 @@ public: bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame); private: + CAX25Frame m_frame; arm_fir_instance_f32 m_audioFilter; float32_t m_audioState[20U]; arm_fir_instance_q15 m_lpfFilter; @@ -43,10 +49,16 @@ private: bool m_pllLast; uint8_t m_pllBits; float32_t m_pllCount; + uint16_t m_hdlcOnes; + bool m_hdlcFlag; + uint16_t m_hdlcBuffer; + uint16_t m_hdlcBits; + AX25_STATE m_hdlcState; bool delay(bool b); bool NRZI(bool b); bool PLL(bool b); + bool HDLC(bool b); }; #endif diff --git a/AX25Frame.cpp b/AX25Frame.cpp index 2540cb3..3d3bb9f 100644 --- a/AX25Frame.cpp +++ b/AX25Frame.cpp @@ -61,6 +61,16 @@ m_fcs(0U) { } +bool CAX25Frame::append(uint16_t c) +{ + if (m_length == AX25_MAX_PACKET_LEN) + return false; + + m_data[m_length++] = uint8_t(c); + + return true; +} + bool CAX25Frame::checkCRC() { union { diff --git a/AX25Frame.h b/AX25Frame.h index 30e08f7..eaf770c 100644 --- a/AX25Frame.h +++ b/AX25Frame.h @@ -21,13 +21,17 @@ #include "Config.h" +const uint16_t AX25_MAX_PACKET_LEN = 300U; + class CAX25Frame { public: CAX25Frame(); + bool append(uint16_t c); + bool checkCRC(); - uint8_t m_data[300U]; + uint8_t m_data[AX25_MAX_PACKET_LEN]; uint16_t m_length; uint16_t m_fcs; }; diff --git a/AX25RX.cpp b/AX25RX.cpp index 99aa1a5..de20709 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -114,29 +114,29 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) CAX25Frame frame; bool ret = m_demod1.process(output, length, frame); - if (ret) { + if (ret && frame.m_length > 10U) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 1 reported"); m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length); + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } } ret = m_demod2.process(output, length, frame); - if (ret) { + if (ret && frame.m_length > 10U) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 2 reported"); m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length); + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } } ret = m_demod3.process(output, length, frame); - if (ret) { + if (ret && frame.m_length > 10U) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 3 reported"); m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length); + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } } } From c896cf823e3946a6a44726f7c0bf07a56e0434a7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 11 Jun 2020 10:04:09 +0100 Subject: [PATCH 102/139] Add mobilinkd copyright. --- AX25Demodulator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 32dbcb4..4e635af 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2020 by Jonathan Naylor G4KLX + * Copyright 2015-2019 Mobilinkd LLC * * 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 From 746d915bf9e16b120179a1771b0937c85a67ec81 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 11 Jun 2020 12:14:36 +0100 Subject: [PATCH 103/139] Rescale one of the filters for the MMDVM sample rate. --- AX25Demodulator.cpp | 11 ++++++----- AX25RX.cpp | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 4e635af..692a63a 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -122,6 +122,7 @@ bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& } else { result = HDLC(NRZI(bit)); if (result) { + // Copy the frame data. ::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN); frame.m_length = frame.m_length; frame.m_fcs = m_frame.m_fcs; @@ -187,8 +188,6 @@ bool CAX25Demodulator::PLL(bool input) bool CAX25Demodulator::HDLC(bool b) { - bool result = false; - if (m_hdlcOnes == 5U) { if (b) { // flag byte @@ -197,7 +196,7 @@ bool CAX25Demodulator::HDLC(bool b) // bit stuffing... m_hdlcFlag = false; m_hdlcOnes = 0U; - return result; + return false; } } @@ -211,9 +210,11 @@ bool CAX25Demodulator::HDLC(bool b) m_hdlcOnes = 0U; if (m_hdlcFlag) { + bool result = false; + switch (m_hdlcBuffer) { case 0x7E: - if (m_frame.m_length > 0U) { + if (m_frame.m_length > 2U) { result = m_frame.checkCRC(); if (!result) m_frame.m_length = 0U; @@ -262,6 +263,6 @@ bool CAX25Demodulator::HDLC(bool b) break; } - return result; + return false; } diff --git a/AX25RX.cpp b/AX25RX.cpp index de20709..c138333 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -60,7 +60,7 @@ float32_t dB3[] = { /* * Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass, - * Hann window, starting and ending 0 value coefficients removed. + * Hann window. * * np.array( * firwin2(152, @@ -79,19 +79,22 @@ float32_t dB3[] = { */ const uint32_t FILTER_LEN = 132U; -// XXX This is for the wrong sample rate q15_t FILTER_COEFFS[] = { - 4, 0, -5, -10, -13, -12, -9, -4, -2, -4, -12, -26, - -41, -52, -51, -35, -3, 39, 83, 117, 131, 118, 83, 36, - -6, -32, -30, -3, 36, 67, 66, 19, -74, -199, -323, -408, - -421, -344, -187, 17, 218, 364, 417, 369, 247, 106, 14, 26, - 166, 407, 676, 865, 866, 605, 68, -675, -1484, -2171, -2547, -2471, --1895, -882, 394, 1692, 2747, 3337, 3337, 2747, 1692, 394, -882, -1895, --2471, -2547, -2171, -1484, -675, 68, 605, 866, 865, 676, 407, 166, - 26, 14, 106, 247, 369, 417, 364, 218, 17, -187, -344, -421, - -408, -323, -199, -74, 19, 66, 67, 36, -3, -30, -32, -6, - 36, 83, 118, 131, 117, 83, 39, -3, -35, -51, -52, -41, - -26, -12, -4, -2, -4, -9, -12, -13, -10, -5, 0, 4}; + 0, 5, 12, 18, 21, 19, 11, -2, -15, + -25, -27, -21, -11, -3, -5, -19, -43, -69, + -83, -73, -35, 27, 98, 155, 180, 163, 109, + 39, -20, -45, -26, 23, 74, 89, 39, -81, + -247, -407, -501, -480, -334, -92, 175, 388, 479, + 429, 275, 99, 5, 68, 298, 626, 913, 994, + 740, 115, -791, -1770, -2544, -2847, -2509, -1527, -76, + 1518, 2875, 3653, 3653, 2875, 1518, -76, -1527, -2509, + -2847, -2544, -1770, -791, 115, 740, 994, 913, 626, + 298, 68, 5, 99, 275, 429, 479, 388, 175, + -92, -334, -480, -501, -407, -247, -81, 39, 89, + 74, 23, -26, -45, -20, 39, 109, 163, 180, + 155, 98, 27, -35, -73, -83, -69, -43, -19, + -5, -3, -11, -21, -27, -25, -15, -2, 11, + 19, 21, 18, 12, 5, 0}; CAX25RX::CAX25RX() : m_filter(), From e332dbba8e7cf9265433f660687b6214d96ba46c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 11 Jun 2020 12:59:30 +0100 Subject: [PATCH 104/139] Add the correct CCITT checksum table. --- AX25Frame.cpp | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/AX25Frame.cpp b/AX25Frame.cpp index 3d3bb9f..9740dd5 100644 --- a/AX25Frame.cpp +++ b/AX25Frame.cpp @@ -21,38 +21,38 @@ #include "AX25Frame.h" const uint16_t CCITT_TABLE[] = { - 0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU, - 0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U, - 0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU, - 0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U, - 0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU, - 0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U, - 0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU, - 0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U, - 0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU, - 0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U, - 0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU, - 0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U, - 0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U, - 0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U, - 0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U, - 0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U, - 0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U, - 0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU, - 0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U, - 0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU, - 0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U, - 0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU, - 0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U, - 0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU, - 0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U, - 0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU, - 0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U, - 0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU, - 0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U, - 0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U, - 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, - 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U}; + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; CAX25Frame::CAX25Frame() : m_data(), From af11be16dc8417d81dc9d94ae887add4a6ccea62 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 17 Jun 2020 15:28:41 +0100 Subject: [PATCH 105/139] First woring AX.25 decoder (in simulation). --- AX25Demodulator.cpp | 49 +++---- AX25Demodulator.h | 10 +- AX25Frame.cpp | 64 ++++----- AX25RX.cpp | 342 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 332 insertions(+), 133 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 692a63a..d378e59 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -21,27 +21,27 @@ #include "Globals.h" #include "AX25Demodulator.h" -const float32_t DELAY = 0.000448F; const float32_t SAMPLE_RATE = 24000.0F; const float32_t SYMBOL_RATE = 1200.0F; -const uint16_t DELAY_LEN = uint16_t((DELAY / (1.0F / SAMPLE_RATE)) + 0.5F); +const uint16_t DELAY_LEN = 11U; const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE; const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; -// XXX This is for the wrong sample rate const uint32_t LPF_FILTER_LEN = 96U; q15_t LPF_FILTER_COEFFS[] = { - 0, 1, 3, 5, 8, 11, 14, 17, 19, 20, 18, 14, - 7, -2, -16, -33, -53, -76, -101, -126, -151, -174, -194, -208, - -215, -212, -199, -173, -133, -79, -10, 74, 173, 287, 413, 549, - 693, 842, 993, 1142, 1287, 1423, 1547, 1656, 1747, 1817, 1865, 1889, - 1889, 1865, 1817, 1747, 1656, 1547, 1423, 1287, 1142, 993, 842, 693, - 549, 413, 287, 173, 74, -10, -79, -133, -173, -199, -212, -215, - -208, -194, -174, -151, -126, -101, -76, -53, -33, -16, -2, 7, - 14, 18, 20, 19, 17, 14, 11, 8, 5, 3, 1, 0, + 0, 0, 0, 1, 2, 5, 8, 12, 18, 23, + 29, 33, 36, 36, 33, 25, 13, -5, -28, -57, + -89, -123, -159, -194, -225, -249, -264, -267, -254, -224, + -175, -104, -12, 102, 236, 389, 557, 738, 926, 1117, + 1306, 1486, 1654, 1802, 1927, 2025, 2092, 2126, 2126, 2092, + 2025, 1927, 1802, 1654, 1486, 1306, 1117, 926, 738, 557, + 389, 236, 102, -12, -104, -175, -224, -254, -267, -264, + -249, -225, -194, -159, -123, -89, -57, -28, -5, 13, + 25, 33, 36, 36, 33, 29, 23, 18, 12, 8, + 5, 2, 1, 0, 0, 0 }; // 64 Hz loop filter. @@ -53,7 +53,7 @@ const uint32_t PLL_FILTER_LEN = 7U; float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; -CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : +CAX25Demodulator::CAX25Demodulator(q15_t* coeffs, uint16_t length) : m_frame(), m_audioFilter(), m_audioState(), @@ -73,7 +73,7 @@ m_hdlcBuffer(0U), m_hdlcBits(0U), m_hdlcState(AX25_IDLE) { - m_delayLine = new bool[2U * DELAY_LEN]; + m_delayLine = new bool[DELAY_LEN]; m_audioFilter.numTaps = length; m_audioFilter.pState = m_audioState; @@ -88,22 +88,17 @@ m_hdlcState(AX25_IDLE) m_pllFilter.pCoeffs = PLL_FILTER_COEFFS; } -bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& frame) +bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame) { bool result = false; - float32_t input[RX_BLOCK_SIZE]; - for (size_t i = 0; i < length; i++) - input[i] = float(samples[i]); - - float32_t fa[RX_BLOCK_SIZE]; - ::arm_fir_f32(&m_audioFilter, input, fa, RX_BLOCK_SIZE); + q15_t fa[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_audioFilter, samples, fa, RX_BLOCK_SIZE); int16_t buffer[RX_BLOCK_SIZE]; for (uint8_t i = 0; i < length; i++) { - int16_t sample = int16_t(fa[i]); - bool level = (sample >= 0); - bool delayed = delay(level); + bool level = (fa[i] >= 0); + bool delayed = delay(level); buffer[i] = (int16_t(level ^ delayed) << 1) - 1; } @@ -124,7 +119,7 @@ bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& if (result) { // Copy the frame data. ::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN); - frame.m_length = frame.m_length; + frame.m_length = m_frame.m_length; frame.m_fcs = m_frame.m_fcs; m_frame.m_length = 0U; } @@ -160,7 +155,7 @@ bool CAX25Demodulator::PLL(bool input) { bool sample = false; - if (input != m_pllLast or m_pllBits > 16U) { + if (input != m_pllLast || m_pllBits > 16U) { // Record transition. m_pllLast = input; @@ -214,9 +209,11 @@ bool CAX25Demodulator::HDLC(bool b) switch (m_hdlcBuffer) { case 0x7E: - if (m_frame.m_length > 2U) { + if (m_frame.m_length >= 13U) { result = m_frame.checkCRC(); if (!result) + m_frame.m_length = 0U; + } else { m_frame.m_length = 0U; } m_hdlcState = AX25_SYNC; diff --git a/AX25Demodulator.h b/AX25Demodulator.h index e12d4c6..7e9063e 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -31,21 +31,21 @@ enum AX25_STATE { class CAX25Demodulator { public: - CAX25Demodulator(float32_t* coeffs, uint16_t length); + CAX25Demodulator(q15_t* coeffs, uint16_t length); - bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame); + bool process(q15_t* samples, uint8_t length, CAX25Frame& frame); private: CAX25Frame m_frame; - arm_fir_instance_f32 m_audioFilter; - float32_t m_audioState[20U]; + arm_fir_instance_q15 m_audioFilter; + q15_t m_audioState[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare arm_fir_instance_q15 m_lpfFilter; q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 20 - 1 plus some spare bool* m_delayLine; uint16_t m_delayPos; bool m_nrziState; arm_fir_instance_f32 m_pllFilter; - float32_t m_pllState[7U]; + float32_t m_pllState[20U]; // NoTaps + BlockSize - 1, 7 + 1 - 1 plus some spare bool m_pllLast; uint8_t m_pllBits; float32_t m_pllCount; diff --git a/AX25Frame.cpp b/AX25Frame.cpp index 9740dd5..905682e 100644 --- a/AX25Frame.cpp +++ b/AX25Frame.cpp @@ -21,38 +21,38 @@ #include "AX25Frame.h" const uint16_t CCITT_TABLE[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; + 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, + 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, + 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, + 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, + 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, + 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, + 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, + 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, + 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, + 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, + 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, + 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, + 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, + 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, + 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, + 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, + 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, + 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, + 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, + 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, + 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, + 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, + 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, + 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, + 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, + 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, + 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, + 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, + 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, + 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, + 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, + 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 }; CAX25Frame::CAX25Frame() : m_data(), diff --git a/AX25RX.cpp b/AX25RX.cpp index c138333..25b533b 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -20,47 +20,255 @@ #include "Globals.h" #include "AX25RX.h" -// XXX There are for the wrong sample rate +// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine. +q15_t dB12[] = { + 176, + -812, + -3916, + -7586, + 23536, + -7586, + -3916, + -812, + 176 +}; -// 1200Hz = -9dB, 2200Hz = 0dB; 3252Hz cutoff, 3.7 gain; cosine. -float32_t dB9[] = { - -0.00232554104135, - -0.142858725752, - -0.449053780255, - -0.770264863826, - 2.77651146344, - -0.770264863826, - -0.449053780255, - -0.142858725752, - -0.00232554104135}; +// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine. +q15_t dB11[] = { + 121, + -957, + -3959, + -7383, + 23871, + -7383, + -3959, + -957, + 121 +}; -// 1200Hz = -6dB, 2200Hz = 0dB; 2640Hz cutoff, 2.59 gain; cosine. -float32_t dB6[] = { - -0.0209448226653, - -0.130107651829, - -0.299004731072, - -0.45336946386, - 2.0629448761, - -0.45336946386, - -0.299004731072, - -0.130107651829, - -0.0209448226653}; +// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine. +q15_t dB10[] = { + 56, + -1110, + -3987, + -7141, + 24254, + -7141, + -3987, + -1110, + 56 +}; -// 1200Hz = -3dB, 2200Hz = 0dB; 1700Hz cutoff, 1.68 gain; cosine. -float32_t dB3[] = { - -0.0231416146776, - -0.0833375337803, - -0.147937602401, - -0.197411259519, - 1.46066084756, - -0.197411259519, - -0.147937602401, - -0.0833375337803, - -0.0231416146776}; +// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine. +q15_t dB9[] = { + -19, + -1268, + -3994, + -6856, + 24688, + -6856, + -3994, + -1268, + -19 +}; + +// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine. +q15_t dB8[] = { + -104, + -1424, + -3968, + -6516, + 25182, + -6516, + -3968, + -1424, + -104 +}; + +// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine. +q15_t dB7[] = { + -196, + -1565, + -3896, + -6114, + 25742, + -6114, + -3896, + -1565, + -196 +}; + +// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine. +q15_t dB6[] = { + -288, + -1676, + -3761, + -5642, + 26370, + -5642, + -3761, + -1676, + -288 +}; + +// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine. +q15_t dB5[] = { + -370, + -1735, + -3545, + -5088, + 27075, + -5088, + -3545, + -1735, + -370 +}; + +// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine. +q15_t dB4[] = { + -432, + -1715, + -3220, + -4427, + 27880, + -4427, + -3220, + -1715, + -432 +}; + +// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine. +q15_t dB3[] = { + -452, + -1582, + -2759, + -3646, + 28792, + -3646, + -2759, + -1582, + -452 +}; + +// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine. +q15_t dB2[] = { + -408, + -1295, + -2123, + -2710, + 29846, + -2710, + -2123, + -1295, + -408 +}; + +// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine. +q15_t dB1[] = { + -268, + -795, + -1244, + -1546, + 31116, + -1546, + -1244, + -795, + -268 +}; + +q15_t dB0[] = { + 0, + 0, + 0, + 0, + 32767, + 0, + 0, + 0, + 0, +}; + +// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine. +q15_t dB_1[] = { + -419, + -177, + 3316, + 8650, + 11278, + 8650, + 3316, + -177, + -419 +}; + +// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine. +q15_t dB_2[] = { + -90, + 1033, + 3975, + 7267, + 8711, + 7267, + 3975, + 1033, + -90 +}; + +// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine. +q15_t dB_3[] = { + 292, + 1680, + 3752, + 5615, + 6362, + 5615, + 3752, + 1680, + 292 +}; + +// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar. +q15_t dB_4[] = { + 917, + 3024, + 5131, + 6684, + 7255, + 6684, + 5131, + 3024, + 917 +}; + +// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar. +q15_t dB_5[] = { + 1620, + 3339, + 4925, + 6042, + 6444, + 6042, + 4925, + 3339, + 1620 +}; + +// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar. +q15_t dB_6[] = { + 2161, + 3472, + 4605, + 5373, + 5644, + 5373, + 4605, + 3472, + 2161 +}; /* * Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass, - * Hann window. + * Hann window, starting and ending 0 value coefficients removed. * * np.array( * firwin2(152, @@ -77,24 +285,23 @@ float32_t dB3[] = { * window='hann') * 32768, * dtype=int)[10:-10] */ -const uint32_t FILTER_LEN = 132U; - +const uint32_t FILTER_LEN = 132; q15_t FILTER_COEFFS[] = { - 0, 5, 12, 18, 21, 19, 11, -2, -15, - -25, -27, -21, -11, -3, -5, -19, -43, -69, - -83, -73, -35, 27, 98, 155, 180, 163, 109, - 39, -20, -45, -26, 23, 74, 89, 39, -81, - -247, -407, -501, -480, -334, -92, 175, 388, 479, - 429, 275, 99, 5, 68, 298, 626, 913, 994, - 740, 115, -791, -1770, -2544, -2847, -2509, -1527, -76, - 1518, 2875, 3653, 3653, 2875, 1518, -76, -1527, -2509, - -2847, -2544, -1770, -791, 115, 740, 994, 913, 626, - 298, 68, 5, 99, 275, 429, 479, 388, 175, - -92, -334, -480, -501, -407, -247, -81, 39, 89, - 74, 23, -26, -45, -20, 39, 109, 163, 180, - 155, 98, 27, -35, -73, -83, -69, -43, -19, - -5, -3, -11, -21, -27, -25, -15, -2, 11, - 19, 21, 18, 12, 5, 0}; + 0, 5, 12, 18, 21, 19, 11, -2, -15, -25, + -27, -21, -11, -3, -5, -19, -43, -69, -83, -73, + -35, 27, 98, 155, 180, 163, 109, 39, -20, -45, + -26, 23, 74, 89, 39, -81, -247, -407, -501, -480, + -334, -92, 175, 388, 479, 429, 275, 99, 5, 68, + 298, 626, 913, 994, 740, 115, -791, -1770, -2544, -2847, + -2509, -1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76, + -1527, -2509, -2847, -2544, -1770, -791, 115, 740, 994, 913, + 626, 298, 68, 5, 99, 275, 429, 479, 388, 175, + -92, -334, -480, -501, -407, -247, -81, 39, 89, 74, + 23, -26, -45, -20, 39, 109, 163, 180, 155, 98, + 27, -35, -73, -83, -69, -43, -19, -5, -3, -11, + -21, -27, -25, -15, -2, 11, 19, 21, 18, 12, + 5, 0 +}; CAX25RX::CAX25RX() : m_filter(), @@ -114,33 +321,28 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) q15_t output[RX_BLOCK_SIZE]; ::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE); + m_lastFCS = 0U; CAX25Frame frame; bool ret = m_demod1.process(output, length, frame); - if (ret && frame.m_length > 10U) { - if (m_lastFCS != frame.m_fcs) { - DEBUG1("Decoder 1 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); - } + if (ret && frame.m_fcs != m_lastFCS) { + DEBUG1("Decoder 1 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } ret = m_demod2.process(output, length, frame); - if (ret && frame.m_length > 10U) { - if (m_lastFCS != frame.m_fcs) { - DEBUG1("Decoder 2 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); - } + if (ret && frame.m_fcs != m_lastFCS) { + DEBUG1("Decoder 2 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } ret = m_demod3.process(output, length, frame); - if (ret && frame.m_length > 10U) { - if (m_lastFCS != frame.m_fcs) { - DEBUG1("Decoder 3 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); - } + if (ret && frame.m_fcs != m_lastFCS) { + DEBUG1("Decoder 3 reported"); + m_lastFCS = frame.m_fcs; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } } From 0e8f20e1ccb5de94c24b5a8c780e118d15e8a232 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 17 Jun 2020 16:02:15 +0100 Subject: [PATCH 106/139] Bump the version date. --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index f906bc0..65ad4c2 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -105,7 +105,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200608 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200617 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From 6a80d0ec0987e434945a491c0b7d56aeaf6e888e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 17 Jun 2020 22:33:13 +0100 Subject: [PATCH 107/139] Fix minimum packet size. --- AX25Demodulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index d378e59..89eff0a 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -209,7 +209,7 @@ bool CAX25Demodulator::HDLC(bool b) switch (m_hdlcBuffer) { case 0x7E: - if (m_frame.m_length >= 13U) { + if (m_frame.m_length >= 15U) { result = m_frame.checkCRC(); if (!result) m_frame.m_length = 0U; From 6dbda2795a07e01e75648659713b7d5ab8fd51b9 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 17 Jun 2020 22:40:09 +0100 Subject: [PATCH 108/139] Miscalculated the address length. --- AX25Demodulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 89eff0a..14f1415 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -209,7 +209,7 @@ bool CAX25Demodulator::HDLC(bool b) switch (m_hdlcBuffer) { case 0x7E: - if (m_frame.m_length >= 15U) { + if (m_frame.m_length >= 17U) { result = m_frame.checkCRC(); if (!result) m_frame.m_length = 0U; From 114c2bcb15c2451780f04035f8706c2e946324e1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 19 Jun 2020 13:16:47 +0100 Subject: [PATCH 109/139] Handle extended packet lengths. --- CWIdTX.cpp | 4 +- CWIdTX.h | 4 +- CalDMR.cpp | 4 +- CalDMR.h | 4 +- CalDStarTX.cpp | 4 +- CalDStarTX.h | 4 +- CalFM.cpp | 4 +- CalFM.h | 4 +- CalNXDN.cpp | 3 +- CalNXDN.h | 3 +- CalP25.cpp | 3 +- CalP25.h | 3 +- CalPOCSAG.cpp | 3 +- CalPOCSAG.h | 3 +- DMRDMOTX.cpp | 4 +- DMRDMOTX.h | 4 +- DMRTX.cpp | 10 +- DMRTX.h | 10 +- DStarTX.cpp | 6 +- DStarTX.h | 6 +- NXDNTX.cpp | 2 +- NXDNTX.h | 2 +- P25TX.cpp | 2 +- P25TX.h | 2 +- POCSAGTX.cpp | 4 +- POCSAGTX.h | 4 +- SerialPort.cpp | 657 +++++++++++++++++++++++++------------------------ SerialPort.h | 19 +- YSFTX.cpp | 4 +- YSFTX.h | 4 +- 30 files changed, 410 insertions(+), 380 deletions(-) diff --git a/CWIdTX.cpp b/CWIdTX.cpp index 641b374..aef04b0 100644 --- a/CWIdTX.cpp +++ b/CWIdTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -125,7 +125,7 @@ void CCWIdTX::process() } } -uint8_t CCWIdTX::write(const uint8_t* data, uint8_t length) +uint8_t CCWIdTX::write(const uint8_t* data, uint16_t length) { ::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t)); diff --git a/CWIdTX.h b/CWIdTX.h index 70f67ea..a0480e0 100644 --- a/CWIdTX.h +++ b/CWIdTX.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX - * Copyright (C) 2016 by Colin Durbridge G4EML + * Copyright (C) 2016,2020 by Colin Durbridge G4EML * * 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 @@ -28,7 +28,7 @@ public: void process(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); void reset(); diff --git a/CalDMR.cpp b/CalDMR.cpp index 5a92fb0..949a8e9 100644 --- a/CalDMR.cpp +++ b/CalDMR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -208,7 +208,7 @@ void CCalDMR::dmrdmo1k() } } -uint8_t CCalDMR::write(const uint8_t* data, uint8_t length) +uint8_t CCalDMR::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalDMR.h b/CalDMR.h index 06ff6e6..9ba5f2c 100644 --- a/CalDMR.h +++ b/CalDMR.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -41,7 +41,7 @@ public: void createData1k(uint8_t n); void createDataDMO1k(uint8_t n); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); private: bool m_transmit; diff --git a/CalDStarTX.cpp b/CalDStarTX.cpp index 1c1a3a4..9680cdc 100644 --- a/CalDStarTX.cpp +++ b/CalDStarTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2016,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 @@ -162,7 +162,7 @@ void CCalDStarTX::process() m_count = (m_count + 1U) % (30U * 21U); } -uint8_t CCalDStarTX::write(const uint8_t* data, uint8_t length) +uint8_t CCalDStarTX::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalDStarTX.h b/CalDStarTX.h index c411317..86f6625 100644 --- a/CalDStarTX.h +++ b/CalDStarTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,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 @@ -26,7 +26,7 @@ class CCalDStarTX { public: CCalDStarTX(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); void process(); diff --git a/CalFM.cpp b/CalFM.cpp index e89f0be..9841725 100644 --- a/CalFM.cpp +++ b/CalFM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2020 by Phil Taylor M0VSE * @@ -116,7 +116,7 @@ void CCalFM::process() } -uint8_t CCalFM::write(const uint8_t* data, uint8_t length) +uint8_t CCalFM::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalFM.h b/CalFM.h index 0dd8887..9665bcc 100644 --- a/CalFM.h +++ b/CalFM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2020 by Phil Taylor M0VSE * @@ -35,7 +35,7 @@ public: void fm25kcal(); void fm30kcal(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); private: uint16_t m_frequency; diff --git a/CalNXDN.cpp b/CalNXDN.cpp index c223f59..3e46f3e 100644 --- a/CalNXDN.cpp +++ b/CalNXDN.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 by Andy Uribe CA6JAU + * 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 @@ -79,7 +80,7 @@ void CCalNXDN::process() } } -uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length) +uint8_t CCalNXDN::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalNXDN.h b/CalNXDN.h index f0051ef..cad88a4 100644 --- a/CalNXDN.h +++ b/CalNXDN.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 by Andy Uribe CA6JAU + * 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 @@ -32,7 +33,7 @@ public: void process(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); private: bool m_transmit; diff --git a/CalP25.cpp b/CalP25.cpp index b1b9b6d..6f3d4c0 100644 --- a/CalP25.cpp +++ b/CalP25.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 by Andy Uribe CA6JAU + * 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 @@ -82,7 +83,7 @@ void CCalP25::process() } } -uint8_t CCalP25::write(const uint8_t* data, uint8_t length) +uint8_t CCalP25::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalP25.h b/CalP25.h index 6374ed2..75bfe0d 100644 --- a/CalP25.h +++ b/CalP25.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 by Andy Uribe CA6JAU + * 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 @@ -34,7 +35,7 @@ public: void process(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); private: bool m_transmit; diff --git a/CalPOCSAG.cpp b/CalPOCSAG.cpp index bf88a51..b66eb69 100644 --- a/CalPOCSAG.cpp +++ b/CalPOCSAG.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2019 by Florian Wolters DF2ET + * 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 @@ -38,7 +39,7 @@ void CCalPOCSAG::process() pocsagTX.writeByte(0xAAU); } -uint8_t CCalPOCSAG::write(const uint8_t* data, uint8_t length) +uint8_t CCalPOCSAG::write(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/CalPOCSAG.h b/CalPOCSAG.h index 291e360..d49eb81 100644 --- a/CalPOCSAG.h +++ b/CalPOCSAG.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2019 by Florian Wolters DF2ET + * 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 @@ -32,7 +33,7 @@ public: void process(); - uint8_t write(const uint8_t* data, uint8_t length); + uint8_t write(const uint8_t* data, uint16_t length); private: POCSAGCAL m_state; diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp index 141ed38..ca3159c 100644 --- a/DMRDMOTX.cpp +++ b/DMRDMOTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2017 by Andy Uribe CA6JAU * @@ -104,7 +104,7 @@ void CDMRDMOTX::process() } } -uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint16_t length) { if (length != (DMR_FRAME_LENGTH_BYTES + 1U)) return 4U; diff --git a/DMRDMOTX.h b/DMRDMOTX.h index 62ef2c1..076212d 100644 --- a/DMRDMOTX.h +++ b/DMRDMOTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -29,7 +29,7 @@ class CDMRDMOTX { public: CDMRDMOTX(); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); void process(); diff --git a/DMRTX.cpp b/DMRTX.cpp index 81437ec..21bfb44 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2017 by Andy Uribe CA6JAU * @@ -144,7 +144,7 @@ void CDMRTX::process() } } -uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length) +uint8_t CDMRTX::writeData1(const uint8_t* data, uint16_t length) { if (length != (DMR_FRAME_LENGTH_BYTES + 1U)) return 4U; @@ -168,7 +168,7 @@ uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length) return 0U; } -uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length) +uint8_t CDMRTX::writeData2(const uint8_t* data, uint16_t length) { if (length != (DMR_FRAME_LENGTH_BYTES + 1U)) return 4U; @@ -192,7 +192,7 @@ uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length) return 0U; } -uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length) +uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint16_t length) { if (length != 9U) return 4U; @@ -208,7 +208,7 @@ uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length) return 0U; } -uint8_t CDMRTX::writeAbort(const uint8_t* data, uint8_t length) +uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length) { if (length != 1U) return 4U; diff --git a/DMRTX.h b/DMRTX.h index 1e2f617..ef7fdcb 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * * This program is free software; you can redistribute it and/or modify @@ -38,11 +38,11 @@ class CDMRTX { public: CDMRTX(); - uint8_t writeData1(const uint8_t* data, uint8_t length); - uint8_t writeData2(const uint8_t* data, uint8_t length); + uint8_t writeData1(const uint8_t* data, uint16_t length); + uint8_t writeData2(const uint8_t* data, uint16_t length); - uint8_t writeShortLC(const uint8_t* data, uint8_t length); - uint8_t writeAbort(const uint8_t* data, uint8_t length); + uint8_t writeShortLC(const uint8_t* data, uint16_t length); + uint8_t writeAbort(const uint8_t* data, uint16_t length); void setStart(bool start); void setCal(bool start); diff --git a/DStarTX.cpp b/DStarTX.cpp index 63eb910..e1dc81c 100644 --- a/DStarTX.cpp +++ b/DStarTX.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2017 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify @@ -277,7 +277,7 @@ void CDStarTX::process() } } -uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length) +uint8_t CDStarTX::writeHeader(const uint8_t* header, uint16_t length) { if (length != DSTAR_HEADER_LENGTH_BYTES) return 4U; @@ -296,7 +296,7 @@ uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length) return 0U; } -uint8_t CDStarTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CDStarTX::writeData(const uint8_t* data, uint16_t length) { if (length != DSTAR_DATA_LENGTH_BYTES) return 4U; diff --git a/DStarTX.h b/DStarTX.h index 24876d7..8470746 100644 --- a/DStarTX.h +++ b/DStarTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,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 @@ -27,8 +27,8 @@ class CDStarTX { public: CDStarTX(); - uint8_t writeHeader(const uint8_t* header, uint8_t length); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeHeader(const uint8_t* header, uint16_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); uint8_t writeEOT(); void process(); diff --git a/NXDNTX.cpp b/NXDNTX.cpp index b6ef616..9aba8ef 100644 --- a/NXDNTX.cpp +++ b/NXDNTX.cpp @@ -122,7 +122,7 @@ void CNXDNTX::process() } } -uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CNXDNTX::writeData(const uint8_t* data, uint16_t length) { if (length != (NXDN_FRAME_LENGTH_BYTES + 1U)) return 4U; diff --git a/NXDNTX.h b/NXDNTX.h index bd65818..7c4f937 100644 --- a/NXDNTX.h +++ b/NXDNTX.h @@ -27,7 +27,7 @@ class CNXDNTX { public: CNXDNTX(); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); void process(); diff --git a/P25TX.cpp b/P25TX.cpp index 009a0f2..76dfe3c 100644 --- a/P25TX.cpp +++ b/P25TX.cpp @@ -118,7 +118,7 @@ void CP25TX::process() } } -uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length) +uint8_t CP25TX::writeData(const uint8_t* data, uint16_t length) { if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U)) return 4U; diff --git a/P25TX.h b/P25TX.h index a7cd27d..45bd05a 100644 --- a/P25TX.h +++ b/P25TX.h @@ -27,7 +27,7 @@ class CP25TX { public: CP25TX(); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); void process(); diff --git a/POCSAGTX.cpp b/POCSAGTX.cpp index d53f9b7..e673e01 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 @@ -95,7 +95,7 @@ bool CPOCSAGTX::busy() return false; } -uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint16_t length) { if (length != POCSAG_FRAME_LENGTH_BYTES) return 4U; diff --git a/POCSAGTX.h b/POCSAGTX.h index d640862..1fe9bbb 100644 --- a/POCSAGTX.h +++ b/POCSAGTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-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 @@ -27,7 +27,7 @@ class CPOCSAGTX { public: CPOCSAGTX(); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); void writeByte(uint8_t c); diff --git a/SerialPort.cpp b/SerialPort.cpp index 65ad4c2..b1775b8 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -266,7 +266,7 @@ void CSerialPort::getVersion() writeInt(1U, reply, count); } -uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) +uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) { if (length < 21U) return 4U; @@ -376,7 +376,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) return 0U; } -uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint8_t length) +uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint16_t length) { if (length < 8U) return 4U; @@ -401,7 +401,7 @@ uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint8_t length) return fm.setCallsign(callsign, speed, frequency, time, holdoff, highLevel, lowLevel, callAtStart, callAtEnd, callAtLatch); } -uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length) +uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint16_t length) { if (length < 6U) return 4U; @@ -421,7 +421,7 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length) return fm.setAck(ack, speed, frequency, minTime, delay, level); } -uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) +uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length) { if (length < 12U) return 4U; @@ -447,7 +447,7 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length) return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); } -uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length) +uint8_t CSerialPort::setMode(const uint8_t* data, uint16_t length) { if (length < 1U) return 4U; @@ -598,321 +598,33 @@ void CSerialPort::process() m_buffer[0U] = c; m_ptr = 1U; m_len = 0U; - } - else { + } else { m_ptr = 0U; m_len = 0U; } } else if (m_ptr == 1U) { - // Handle the frame length + // Handle the frame length, 1/2 m_len = m_buffer[m_ptr] = c; m_ptr = 2U; + } else if (m_ptr == 2U) { + // Handle the frame length, 2/2 + m_buffer[m_ptr] = c; + m_ptr = 3U; + + if (m_len == 0U) + m_len = c + 255U; + + // The full packet has been received, process it + if (m_ptr == m_len) + processMessage(); } else { // Any other bytes are added to the buffer m_buffer[m_ptr] = c; m_ptr++; // The full packet has been received, process it - if (m_ptr == m_len) { - uint8_t err = 2U; - - switch (m_buffer[2U]) { - case MMDVM_GET_STATUS: - getStatus(); - break; - - case MMDVM_GET_VERSION: - getVersion(); - break; - - case MMDVM_SET_CONFIG: - err = setConfig(m_buffer + 3U, m_len - 3U); - if (err == 0U) - sendACK(); - else - sendNAK(err); - break; - - case MMDVM_SET_MODE: - err = setMode(m_buffer + 3U, m_len - 3U); - if (err == 0U) - sendACK(); - else - sendNAK(err); - break; - - case MMDVM_SET_FREQ: - sendACK(); - break; - - case MMDVM_FM_PARAMS1: - err = setFMParams1(m_buffer + 3U, m_len - 3U); - if (err == 0U) { - sendACK(); - } else { - DEBUG2("Received invalid FM params 1", err); - sendNAK(err); - } - break; - - case MMDVM_FM_PARAMS2: - err = setFMParams2(m_buffer + 3U, m_len - 3U); - if (err == 0U) { - sendACK(); - } else { - DEBUG2("Received invalid FM params 2", err); - sendNAK(err); - } - break; - - case MMDVM_FM_PARAMS3: - err = setFMParams3(m_buffer + 3U, m_len - 3U); - if (err == 0U) { - sendACK(); - } else { - DEBUG2("Received invalid FM params 3", err); - sendNAK(err); - } - break; - - case MMDVM_CAL_DATA: - if (m_modemState == STATE_DSTARCAL) - err = calDStarTX.write(m_buffer + 3U, m_len - 3U); - if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K) - err = calDMR.write(m_buffer + 3U, m_len - 3U); - if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K) - err = calFM.write(m_buffer + 3U, m_len - 3U); - if (m_modemState == STATE_P25CAL1K) - err = calP25.write(m_buffer + 3U, m_len - 3U); - if (m_modemState == STATE_NXDNCAL1K) - err = calNXDN.write(m_buffer + 3U, m_len - 3U); - if (m_modemState == STATE_POCSAGCAL) - err = calPOCSAG.write(m_buffer + 3U, m_len - 3U); - if (err == 0U) { - sendACK(); - } else { - DEBUG2("Received invalid calibration data", err); - sendNAK(err); - } - break; - - case MMDVM_SEND_CWID: - err = 5U; - if (m_modemState == STATE_IDLE) - err = cwIdTX.write(m_buffer + 3U, m_len - 3U); - if (err != 0U) { - DEBUG2("Invalid CW Id data", err); - sendNAK(err); - } - break; - - case MMDVM_DSTAR_HEADER: - if (m_dstarEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) - err = dstarTX.writeHeader(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_DSTAR); - } else { - DEBUG2("Received invalid D-Star header", err); - sendNAK(err); - } - break; - - case MMDVM_DSTAR_DATA: - if (m_dstarEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) - err = dstarTX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_DSTAR); - } else { - DEBUG2("Received invalid D-Star data", err); - sendNAK(err); - } - break; - - case MMDVM_DSTAR_EOT: - if (m_dstarEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) - err = dstarTX.writeEOT(); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_DSTAR); - } else { - DEBUG2("Received invalid D-Star EOT", err); - sendNAK(err); - } - break; - - case MMDVM_DMR_DATA1: - if (m_dmrEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { - if (m_duplex) - err = dmrTX.writeData1(m_buffer + 3U, m_len - 3U); - } - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_DMR); - } else { - DEBUG2("Received invalid DMR data", err); - sendNAK(err); - } - break; - - case MMDVM_DMR_DATA2: - if (m_dmrEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { - if (m_duplex) - err = dmrTX.writeData2(m_buffer + 3U, m_len - 3U); - else - err = dmrDMOTX.writeData(m_buffer + 3U, m_len - 3U); - } - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_DMR); - } else { - DEBUG2("Received invalid DMR data", err); - sendNAK(err); - } - break; - - case MMDVM_DMR_START: - if (m_dmrEnable) { - err = 4U; - if (m_len == 4U) { - if (m_buffer[3U] == 0x01U && m_modemState == STATE_DMR) { - if (!m_tx) - dmrTX.setStart(true); - err = 0U; - } else if (m_buffer[3U] == 0x00U && m_modemState == STATE_DMR) { - if (m_tx) - dmrTX.setStart(false); - err = 0U; - } - } - } - if (err != 0U) { - DEBUG2("Received invalid DMR start", err); - sendNAK(err); - } - break; - - case MMDVM_DMR_SHORTLC: - if (m_dmrEnable) - err = dmrTX.writeShortLC(m_buffer + 3U, m_len - 3U); - if (err != 0U) { - DEBUG2("Received invalid DMR Short LC", err); - sendNAK(err); - } - break; - - case MMDVM_DMR_ABORT: - if (m_dmrEnable) - err = dmrTX.writeAbort(m_buffer + 3U, m_len - 3U); - if (err != 0U) { - DEBUG2("Received invalid DMR Abort", err); - sendNAK(err); - } - break; - - case MMDVM_YSF_DATA: - if (m_ysfEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF) - err = ysfTX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_YSF); - } else { - DEBUG2("Received invalid System Fusion data", err); - sendNAK(err); - } - break; - - case MMDVM_P25_HDR: - if (m_p25Enable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) - err = p25TX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_P25); - } else { - DEBUG2("Received invalid P25 header", err); - sendNAK(err); - } - break; - - case MMDVM_P25_LDU: - if (m_p25Enable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) - err = p25TX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_P25); - } else { - DEBUG2("Received invalid P25 LDU", err); - sendNAK(err); - } - break; - - case MMDVM_NXDN_DATA: - if (m_nxdnEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN) - err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_NXDN); - } else { - DEBUG2("Received invalid NXDN data", err); - sendNAK(err); - } - break; - - case MMDVM_POCSAG_DATA: - if (m_pocsagEnable) { - if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG) - err = pocsagTX.writeData(m_buffer + 3U, m_len - 3U); - } - if (err == 0U) { - if (m_modemState == STATE_IDLE) - setMode(STATE_POCSAG); - } else { - DEBUG2("Received invalid POCSAG data", err); - sendNAK(err); - } - break; - - case MMDVM_TRANSPARENT: - case MMDVM_QSO_INFO: - // Do nothing on the MMDVM. - break; - -#if defined(SERIAL_REPEATER) - case MMDVM_SERIAL: { - for (uint8_t i = 3U; i < m_len; i++) - m_repeat.put(m_buffer[i]); - } - break; -#endif - - default: - // Handle this, send a NAK back - sendNAK(1U); - break; - } - - m_ptr = 0U; - m_len = 0U; - } + if (m_ptr == m_len) + processMessage(); } } @@ -941,6 +653,308 @@ void CSerialPort::process() #endif } +void CSerialPort::processMessage() +{ + uint8_t err = 2U; + + switch (m_buffer[2U]) { + case MMDVM_GET_STATUS: + getStatus(); + break; + + case MMDVM_GET_VERSION: + getVersion(); + break; + + case MMDVM_SET_CONFIG: + err = setConfig(m_buffer + 3U, m_len - 3U); + if (err == 0U) + sendACK(); + else + sendNAK(err); + break; + + case MMDVM_SET_MODE: + err = setMode(m_buffer + 3U, m_len - 3U); + if (err == 0U) + sendACK(); + else + sendNAK(err); + break; + + case MMDVM_SET_FREQ: + sendACK(); + break; + + case MMDVM_FM_PARAMS1: + err = setFMParams1(m_buffer + 3U, m_len - 3U); + if (err == 0U) { + sendACK(); + } else { + DEBUG2("Received invalid FM params 1", err); + sendNAK(err); + } + break; + + case MMDVM_FM_PARAMS2: + err = setFMParams2(m_buffer + 3U, m_len - 3U); + if (err == 0U) { + sendACK(); + } else { + DEBUG2("Received invalid FM params 2", err); + sendNAK(err); + } + break; + + case MMDVM_FM_PARAMS3: + err = setFMParams3(m_buffer + 3U, m_len - 3U); + if (err == 0U) { + sendACK(); + } else { + DEBUG2("Received invalid FM params 3", err); + sendNAK(err); + } + break; + + case MMDVM_CAL_DATA: + if (m_modemState == STATE_DSTARCAL) + err = calDStarTX.write(m_buffer + 3U, m_len - 3U); + if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K) + err = calDMR.write(m_buffer + 3U, m_len - 3U); + if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K) + err = calFM.write(m_buffer + 3U, m_len - 3U); + if (m_modemState == STATE_P25CAL1K) + err = calP25.write(m_buffer + 3U, m_len - 3U); + if (m_modemState == STATE_NXDNCAL1K) + err = calNXDN.write(m_buffer + 3U, m_len - 3U); + if (m_modemState == STATE_POCSAGCAL) + err = calPOCSAG.write(m_buffer + 3U, m_len - 3U); + if (err == 0U) { + sendACK(); + } else { + DEBUG2("Received invalid calibration data", err); + sendNAK(err); + } + break; + + case MMDVM_SEND_CWID: + err = 5U; + if (m_modemState == STATE_IDLE) + err = cwIdTX.write(m_buffer + 3U, m_len - 3U); + if (err != 0U) { + DEBUG2("Invalid CW Id data", err); + sendNAK(err); + } + break; + + case MMDVM_DSTAR_HEADER: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeHeader(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star header", err); + sendNAK(err); + } + break; + + case MMDVM_DSTAR_DATA: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star data", err); + sendNAK(err); + } + break; + + case MMDVM_DSTAR_EOT: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeEOT(); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star EOT", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_DATA1: + if (m_dmrEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { + if (m_duplex) + err = dmrTX.writeData1(m_buffer + 3U, m_len - 3U); + } + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DMR); + } else { + DEBUG2("Received invalid DMR data", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_DATA2: + if (m_dmrEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { + if (m_duplex) + err = dmrTX.writeData2(m_buffer + 3U, m_len - 3U); + else + err = dmrDMOTX.writeData(m_buffer + 3U, m_len - 3U); + } + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DMR); + } else { + DEBUG2("Received invalid DMR data", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_START: + if (m_dmrEnable) { + err = 4U; + if (m_len == 4U) { + if (m_buffer[3U] == 0x01U && m_modemState == STATE_DMR) { + if (!m_tx) + dmrTX.setStart(true); + err = 0U; + } else if (m_buffer[3U] == 0x00U && m_modemState == STATE_DMR) { + if (m_tx) + dmrTX.setStart(false); + err = 0U; + } + } + } + if (err != 0U) { + DEBUG2("Received invalid DMR start", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_SHORTLC: + if (m_dmrEnable) + err = dmrTX.writeShortLC(m_buffer + 3U, m_len - 3U); + if (err != 0U) { + DEBUG2("Received invalid DMR Short LC", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_ABORT: + if (m_dmrEnable) + err = dmrTX.writeAbort(m_buffer + 3U, m_len - 3U); + if (err != 0U) { + DEBUG2("Received invalid DMR Abort", err); + sendNAK(err); + } + break; + + case MMDVM_YSF_DATA: + if (m_ysfEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF) + err = ysfTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_YSF); + } else { + DEBUG2("Received invalid System Fusion data", err); + sendNAK(err); + } + break; + + case MMDVM_P25_HDR: + if (m_p25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) + err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_P25); + } else { + DEBUG2("Received invalid P25 header", err); + sendNAK(err); + } + break; + + case MMDVM_P25_LDU: + if (m_p25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) + err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_P25); + } else { + DEBUG2("Received invalid P25 LDU", err); + sendNAK(err); + } + break; + + case MMDVM_NXDN_DATA: + if (m_nxdnEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN) + err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_NXDN); + } else { + DEBUG2("Received invalid NXDN data", err); + sendNAK(err); + } + break; + + case MMDVM_POCSAG_DATA: + if (m_pocsagEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG) + err = pocsagTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_POCSAG); + } else { + DEBUG2("Received invalid POCSAG data", err); + sendNAK(err); + } + break; + + case MMDVM_TRANSPARENT: + case MMDVM_QSO_INFO: + // Do nothing on the MMDVM. + break; + +#if defined(SERIAL_REPEATER) + case MMDVM_SERIAL: { + for (uint8_t i = 3U; i < m_len; i++) + m_repeat.put(m_buffer[i]); + } + break; +#endif + + default: + // Handle this, send a NAK back + sendNAK(1U); + break; + } + + m_ptr = 0U; + m_len = 0U; +} + void CSerialPort::writeDStarHeader(const uint8_t* header, uint8_t length) { if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE) @@ -1203,7 +1217,7 @@ void CSerialPort::writeNXDNLost() writeInt(1U, reply, 3); } -void CSerialPort::writeAX25Data(const uint8_t* data, uint8_t length) +void CSerialPort::writeAX25Data(const uint8_t* data, uint16_t length) { if (m_modemState != STATE_FM && m_modemState != STATE_IDLE) return; @@ -1211,19 +1225,28 @@ void CSerialPort::writeAX25Data(const uint8_t* data, uint8_t length) if (!m_ax25Enable) return; - uint8_t reply[300U]; + uint8_t reply[512U]; reply[0U] = MMDVM_FRAME_START; - reply[1U] = 0U; - reply[2U] = MMDVM_AX25_DATA; - uint8_t count = 3U; - for (uint8_t i = 0U; i < length; i++, count++) - reply[count] = data[i]; + if (length > 252U) { + reply[1U] = 0U; + reply[2U] = (length + 4U) - 255U; + reply[3U] = MMDVM_AX25_DATA; - reply[1U] = count; + for (uint8_t i = 0U; i < length; i++) + reply[i + 4U] = data[i]; - writeInt(1U, reply, count); + writeInt(1U, reply, length + 4U); + } else { + reply[1U] = length + 3U; + reply[2U] = MMDVM_AX25_DATA; + + for (uint8_t i = 0U; i < length; i++) + reply[i + 3U] = data[i]; + + writeInt(1U, reply, length + 3U); + } } void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) diff --git a/SerialPort.h b/SerialPort.h index e8b9d58..57b8f00 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -50,7 +50,7 @@ public: void writeNXDNData(const uint8_t* data, uint8_t length); void writeNXDNLost(); - void writeAX25Data(const uint8_t* data, uint8_t length); + void writeAX25Data(const uint8_t* data, uint16_t length); void writeCalData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length); @@ -62,9 +62,9 @@ public: void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4); private: - uint8_t m_buffer[256U]; - uint8_t m_ptr; - uint8_t m_len; + uint8_t m_buffer[512U]; + uint16_t m_ptr; + uint16_t m_len; bool m_debug; CSerialRB m_repeat; @@ -72,12 +72,13 @@ private: void sendNAK(uint8_t err); void getStatus(); void getVersion(); - uint8_t setConfig(const uint8_t* data, uint8_t length); - uint8_t setMode(const uint8_t* data, uint8_t length); + uint8_t setConfig(const uint8_t* data, uint16_t length); + uint8_t setMode(const uint8_t* data, uint16_t length); void setMode(MMDVM_STATE modemState); - 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 setFMParams1(const uint8_t* data, uint16_t length); + uint8_t setFMParams2(const uint8_t* data, uint16_t length); + uint8_t setFMParams3(const uint8_t* data, uint16_t length); + void processMessage(); // Hardware versions void beginInt(uint8_t n, int speed); diff --git a/YSFTX.cpp b/YSFTX.cpp index 090445a..9ac0607 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 @@ -116,7 +116,7 @@ void CYSFTX::process() } } -uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length) +uint8_t CYSFTX::writeData(const uint8_t* data, uint16_t length) { if (length != (YSF_FRAME_LENGTH_BYTES + 1U)) return 4U; diff --git a/YSFTX.h b/YSFTX.h index 647767c..4793221 100644 --- a/YSFTX.h +++ b/YSFTX.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,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 @@ -27,7 +27,7 @@ class CYSFTX { public: CYSFTX(); - uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeData(const uint8_t* data, uint16_t length); void process(); From 33d922b8c2a0153c8ef2eb72685e77057d738986 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 19 Jun 2020 13:27:45 +0100 Subject: [PATCH 110/139] Handle the incoming data offset correctly. --- SerialPort.cpp | 60 +++++++++++++++++++++++++++----------------------- SerialPort.h | 2 +- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index b1775b8..8918dff 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -616,15 +616,19 @@ void CSerialPort::process() // The full packet has been received, process it if (m_ptr == m_len) - processMessage(); + processMessage(m_buffer + 3U, m_len - 3U); } else { // Any other bytes are added to the buffer m_buffer[m_ptr] = c; m_ptr++; // The full packet has been received, process it - if (m_ptr == m_len) - processMessage(); + if (m_ptr == m_len) { + if (m_len > 255U) + processMessage(m_buffer + 4U, m_len - 4U); + else + processMessage(m_buffer + 3U, m_len - 3U); + } } } @@ -653,7 +657,7 @@ void CSerialPort::process() #endif } -void CSerialPort::processMessage() +void CSerialPort::processMessage(const uint8_t* buffer, uint16_t length) { uint8_t err = 2U; @@ -667,7 +671,7 @@ void CSerialPort::processMessage() break; case MMDVM_SET_CONFIG: - err = setConfig(m_buffer + 3U, m_len - 3U); + err = setConfig(buffer, length); if (err == 0U) sendACK(); else @@ -675,7 +679,7 @@ void CSerialPort::processMessage() break; case MMDVM_SET_MODE: - err = setMode(m_buffer + 3U, m_len - 3U); + err = setMode(buffer, length); if (err == 0U) sendACK(); else @@ -687,7 +691,7 @@ void CSerialPort::processMessage() break; case MMDVM_FM_PARAMS1: - err = setFMParams1(m_buffer + 3U, m_len - 3U); + err = setFMParams1(buffer, length); if (err == 0U) { sendACK(); } else { @@ -697,7 +701,7 @@ void CSerialPort::processMessage() break; case MMDVM_FM_PARAMS2: - err = setFMParams2(m_buffer + 3U, m_len - 3U); + err = setFMParams2(buffer, length); if (err == 0U) { sendACK(); } else { @@ -707,7 +711,7 @@ void CSerialPort::processMessage() break; case MMDVM_FM_PARAMS3: - err = setFMParams3(m_buffer + 3U, m_len - 3U); + err = setFMParams3(buffer, length); if (err == 0U) { sendACK(); } else { @@ -718,17 +722,17 @@ void CSerialPort::processMessage() case MMDVM_CAL_DATA: if (m_modemState == STATE_DSTARCAL) - err = calDStarTX.write(m_buffer + 3U, m_len - 3U); + err = calDStarTX.write(buffer, length); if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K) - err = calDMR.write(m_buffer + 3U, m_len - 3U); + err = calDMR.write(buffer, length); if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K) - err = calFM.write(m_buffer + 3U, m_len - 3U); + err = calFM.write(buffer, length); if (m_modemState == STATE_P25CAL1K) - err = calP25.write(m_buffer + 3U, m_len - 3U); + err = calP25.write(buffer, length); if (m_modemState == STATE_NXDNCAL1K) - err = calNXDN.write(m_buffer + 3U, m_len - 3U); + err = calNXDN.write(buffer, length); if (m_modemState == STATE_POCSAGCAL) - err = calPOCSAG.write(m_buffer + 3U, m_len - 3U); + err = calPOCSAG.write(buffer, length); if (err == 0U) { sendACK(); } else { @@ -740,7 +744,7 @@ void CSerialPort::processMessage() case MMDVM_SEND_CWID: err = 5U; if (m_modemState == STATE_IDLE) - err = cwIdTX.write(m_buffer + 3U, m_len - 3U); + err = cwIdTX.write(buffer, length); if (err != 0U) { DEBUG2("Invalid CW Id data", err); sendNAK(err); @@ -750,7 +754,7 @@ void CSerialPort::processMessage() case MMDVM_DSTAR_HEADER: if (m_dstarEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) - err = dstarTX.writeHeader(m_buffer + 3U, m_len - 3U); + err = dstarTX.writeHeader(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -764,7 +768,7 @@ void CSerialPort::processMessage() case MMDVM_DSTAR_DATA: if (m_dstarEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) - err = dstarTX.writeData(m_buffer + 3U, m_len - 3U); + err = dstarTX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -793,7 +797,7 @@ void CSerialPort::processMessage() if (m_dmrEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { if (m_duplex) - err = dmrTX.writeData1(m_buffer + 3U, m_len - 3U); + err = dmrTX.writeData1(buffer, length); } } if (err == 0U) { @@ -809,9 +813,9 @@ void CSerialPort::processMessage() if (m_dmrEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { if (m_duplex) - err = dmrTX.writeData2(m_buffer + 3U, m_len - 3U); + err = dmrTX.writeData2(buffer, length); else - err = dmrDMOTX.writeData(m_buffer + 3U, m_len - 3U); + err = dmrDMOTX.writeData(buffer, length); } } if (err == 0U) { @@ -846,7 +850,7 @@ void CSerialPort::processMessage() case MMDVM_DMR_SHORTLC: if (m_dmrEnable) - err = dmrTX.writeShortLC(m_buffer + 3U, m_len - 3U); + err = dmrTX.writeShortLC(buffer, length); if (err != 0U) { DEBUG2("Received invalid DMR Short LC", err); sendNAK(err); @@ -855,7 +859,7 @@ void CSerialPort::processMessage() case MMDVM_DMR_ABORT: if (m_dmrEnable) - err = dmrTX.writeAbort(m_buffer + 3U, m_len - 3U); + err = dmrTX.writeAbort(buffer, length); if (err != 0U) { DEBUG2("Received invalid DMR Abort", err); sendNAK(err); @@ -865,7 +869,7 @@ void CSerialPort::processMessage() case MMDVM_YSF_DATA: if (m_ysfEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF) - err = ysfTX.writeData(m_buffer + 3U, m_len - 3U); + err = ysfTX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -879,7 +883,7 @@ void CSerialPort::processMessage() case MMDVM_P25_HDR: if (m_p25Enable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) - err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + err = p25TX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -893,7 +897,7 @@ void CSerialPort::processMessage() case MMDVM_P25_LDU: if (m_p25Enable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) - err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + err = p25TX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -907,7 +911,7 @@ void CSerialPort::processMessage() case MMDVM_NXDN_DATA: if (m_nxdnEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN) - err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U); + err = nxdnTX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) @@ -921,7 +925,7 @@ void CSerialPort::processMessage() case MMDVM_POCSAG_DATA: if (m_pocsagEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG) - err = pocsagTX.writeData(m_buffer + 3U, m_len - 3U); + err = pocsagTX.writeData(buffer, length); } if (err == 0U) { if (m_modemState == STATE_IDLE) diff --git a/SerialPort.h b/SerialPort.h index 57b8f00..938c729 100644 --- a/SerialPort.h +++ b/SerialPort.h @@ -78,7 +78,7 @@ private: uint8_t setFMParams1(const uint8_t* data, uint16_t length); uint8_t setFMParams2(const uint8_t* data, uint16_t length); uint8_t setFMParams3(const uint8_t* data, uint16_t length); - void processMessage(); + void processMessage(const uint8_t* data, uint16_t length); // Hardware versions void beginInt(uint8_t n, int speed); From 0ea732780d35feaf50e980a6758ba9374fb73957 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 20 Jun 2020 21:03:11 +0100 Subject: [PATCH 111/139] 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) From f9fcdc52923a44ac8150d8259f0dd1bc0ab404bc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 19:16:02 +0100 Subject: [PATCH 112/139] Begin adding AX25 TX. --- AX25RX.h | 2 ++ AX25TX.h | 42 ++++++++++++++++++++++++++++++++++++++++++ Globals.h | 2 ++ IO.cpp | 7 ++++++- IO.h | 3 ++- MMDVM.cpp | 4 ++++ MMDVM.ino | 4 ++++ SerialPort.cpp | 37 +++++++++++++++++++++++++++++++++---- 8 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 AX25TX.h diff --git a/AX25RX.h b/AX25RX.h index 6ab6d1c..3416b81 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -29,6 +29,8 @@ public: void samples(q15_t* samples, uint8_t length); + void setParams(int8_t twist); + private: arm_fir_instance_q15 m_filter; q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare diff --git a/AX25TX.h b/AX25TX.h new file mode 100644 index 0000000..ffe31be --- /dev/null +++ b/AX25TX.h @@ -0,0 +1,42 @@ +/* + * 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(AX25TX_H) +#define AX25TX_H + +#include "Config.h" + +class CAX25TX { +public: + CAX25TX(); + + uint8_t writeData(const uint8_t* data, uint16_t length); + + void process(); + + void setParams(int8_t twist); + + void setTXDelay(uint8_t delay); + + uint8_t getSpace() const; + +private: +}; + +#endif + diff --git a/Globals.h b/Globals.h index 4d25617..045f628 100644 --- a/Globals.h +++ b/Globals.h @@ -98,6 +98,7 @@ enum MMDVM_STATE { #include "CalRSSI.h" #include "CWIdTX.h" #include "AX25RX.h" +#include "AX25TX.h" #include "Debug.h" #include "IO.h" #include "FM.h" @@ -159,6 +160,7 @@ extern CPOCSAGTX pocsagTX; extern CFM fm; extern CAX25RX ax25RX; +extern CAX25TX ax25TX; extern CCalDStarRX calDStarRX; extern CCalDStarTX calDStarTX; diff --git a/IO.cpp b/IO.cpp index 6962f08..27e54b0 100644 --- a/IO.cpp +++ b/IO.cpp @@ -81,6 +81,7 @@ m_p25TXLevel(128 * 128), m_nxdnTXLevel(128 * 128), m_pocsagTXLevel(128 * 128), m_fmTXLevel(128 * 128), +m_ax25TXLevel(128 * 128), m_rxDCOffset(DC_OFFSET), m_txDCOffset(DC_OFFSET), m_ledCount(0U), @@ -489,6 +490,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t case STATE_FM: txLevel = m_fmTXLevel; break; + case STATE_AX25: + txLevel = m_ax25TXLevel; + break; default: txLevel = m_cwIdTXLevel; break; @@ -541,7 +545,7 @@ void CIO::setMode() #endif } -void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset) +void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset) { m_pttInvert = pttInvert; @@ -554,6 +558,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx m_nxdnTXLevel = q15_t(nxdnTXLevel * 128); m_pocsagTXLevel = q15_t(pocsagTXLevel * 128); m_fmTXLevel = q15_t(fmTXLevel * 128); + m_ax25TXLevel = q15_t(ax25TXLevel * 128); m_rxDCOffset = DC_OFFSET + rxDCOffset; m_txDCOffset = DC_OFFSET + txDCOffset; diff --git a/IO.h b/IO.h index 07ed700..d32be95 100644 --- a/IO.h +++ b/IO.h @@ -42,7 +42,7 @@ public: void interrupt(); - void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset); + void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset); void getOverflow(bool& adcOverflow, bool& dacOverflow); @@ -87,6 +87,7 @@ private: q15_t m_nxdnTXLevel; q15_t m_pocsagTXLevel; q15_t m_fmTXLevel; + q15_t m_ax25TXLevel; uint16_t m_rxDCOffset; uint16_t m_txDCOffset; diff --git a/MMDVM.cpp b/MMDVM.cpp index 5b5bc4b..e80cacf 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -63,6 +63,7 @@ CPOCSAGTX pocsagTX; CFM fm; CAX25RX ax25RX; +CAX25TX ax25TX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; @@ -112,6 +113,9 @@ void loop() if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) pocsagTX.process(); + if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) + ax25TX.process(); + if (m_fmEnable && m_modemState == STATE_FM) fm.process(); diff --git a/MMDVM.ino b/MMDVM.ino index f1073dd..5785e15 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -60,6 +60,7 @@ CPOCSAGTX pocsagTX; CFM fm; CAX25RX ax25RX; +CAX25 ax25TX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; @@ -109,6 +110,9 @@ void loop() if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) pocsagTX.process(); + if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM)) + ax25TX.process(); + if (m_fmEnable && m_modemState == STATE_FM) fm.process(); diff --git a/SerialPort.cpp b/SerialPort.cpp index 8918dff..e8c09b1 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -105,7 +105,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200617 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200621 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -244,7 +244,12 @@ void CSerialPort::getStatus() else reply[12U] = 0U; - writeInt(1U, reply, 13); + if (m_ax25Enable) + reply[13U] = ax25TX.getSpace(); + else + reply[13U] = 0U; + + writeInt(1U, reply, 14); } void CSerialPort::getVersion() @@ -268,7 +273,7 @@ void CSerialPort::getVersion() uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) { - if (length < 21U) + if (length < 24U) return 4U; bool rxInvert = (data[0U] & 0x01U) == 0x01U; @@ -340,6 +345,16 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) uint8_t nxdnTXHang = data[20U]; + uint8_t ax25TXLevel = data[21U]; + + int8_t ax25RXTwist = int8_t(data[22U]) - 128; + if (ax25RXTwist < -4 || ax25RXTwist > 10) + return 4U; + + int8_t ax25TXTwist = int8_t(data[23U]) - 128; + if (ax25TXTwist < -4 || ax25TXTwist > 10) + return 4U; + setMode(modemState); m_dstarEnable = dstarEnable; @@ -358,6 +373,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) dmrDMOTX.setTXDelay(txDelay); nxdnTX.setTXDelay(txDelay); pocsagTX.setTXDelay(txDelay); + ax25TX.setTXDelay(txDelay); dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); @@ -368,8 +384,10 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) ysfTX.setParams(ysfLoDev, ysfTXHang); p25TX.setParams(p25TXHang); nxdnTX.setParams(nxdnTXHang); + ax25RX.setParams(ax25RXTwist); + ax25TX.setParams(ax25TXTwist); - io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, txDCOffset, rxDCOffset); + io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset); io.start(); @@ -936,6 +954,17 @@ void CSerialPort::processMessage(const uint8_t* buffer, uint16_t length) } break; + case MMDVM_AX25_DATA: + if (m_ax25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_FM) + err = ax25TX.writeData(buffer, length); + } + if (err != 0U) { + DEBUG2("Received invalid AX.25 data", err); + sendNAK(err); + } + break; + case MMDVM_TRANSPARENT: case MMDVM_QSO_INFO: // Do nothing on the MMDVM. From e21006236596ef5a009624df0058a33990ff0f2a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 21 Jun 2020 21:40:40 +0100 Subject: [PATCH 113/139] Add the twist processing to the AX25 RX. --- AX25Demodulator.cpp | 16 +-- AX25Demodulator.h | 8 +- AX25RX.cpp | 259 ++---------------------------------- AX25Twist.cpp | 311 ++++++++++++++++++++++++++++++++++++++++++++ AX25Twist.h | 39 ++++++ 5 files changed, 373 insertions(+), 260 deletions(-) create mode 100644 AX25Twist.cpp create mode 100644 AX25Twist.h diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 14f1415..7ffb99c 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -53,10 +53,9 @@ const uint32_t PLL_FILTER_LEN = 7U; float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; -CAX25Demodulator::CAX25Demodulator(q15_t* coeffs, uint16_t length) : +CAX25Demodulator::CAX25Demodulator(int8_t n) : m_frame(), -m_audioFilter(), -m_audioState(), +m_twist(n), m_lpfFilter(), m_lpfState(), m_delayLine(NULL), @@ -75,10 +74,6 @@ m_hdlcState(AX25_IDLE) { m_delayLine = new bool[DELAY_LEN]; - m_audioFilter.numTaps = length; - m_audioFilter.pState = m_audioState; - m_audioFilter.pCoeffs = coeffs; - m_lpfFilter.numTaps = LPF_FILTER_LEN; m_lpfFilter.pState = m_lpfState; m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS; @@ -93,7 +88,7 @@ bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame bool result = false; q15_t fa[RX_BLOCK_SIZE]; - ::arm_fir_fast_q15(&m_audioFilter, samples, fa, RX_BLOCK_SIZE); + m_twist.process(samples, fa, RX_BLOCK_SIZE); int16_t buffer[RX_BLOCK_SIZE]; for (uint8_t i = 0; i < length; i++) { @@ -263,3 +258,8 @@ bool CAX25Demodulator::HDLC(bool b) return false; } +void CAX25Demodulator::setTwist(int8_t n) +{ + m_twist.setTwist(n); +} + diff --git a/AX25Demodulator.h b/AX25Demodulator.h index 7e9063e..84a98d6 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -22,6 +22,7 @@ #include "Config.h" #include "AX25Frame.h" +#include "AX25Twist.h" enum AX25_STATE { AX25_IDLE, @@ -31,14 +32,15 @@ enum AX25_STATE { class CAX25Demodulator { public: - CAX25Demodulator(q15_t* coeffs, uint16_t length); + CAX25Demodulator(int8_t n); bool process(q15_t* samples, uint8_t length, CAX25Frame& frame); + void setTwist(int8_t n); + private: CAX25Frame m_frame; - arm_fir_instance_q15 m_audioFilter; - q15_t m_audioState[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare + CAX25Twist m_twist; arm_fir_instance_q15 m_lpfFilter; q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 20 - 1 plus some spare bool* m_delayLine; diff --git a/AX25RX.cpp b/AX25RX.cpp index 25b533b..7a6b166 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -20,252 +20,6 @@ #include "Globals.h" #include "AX25RX.h" -// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine. -q15_t dB12[] = { - 176, - -812, - -3916, - -7586, - 23536, - -7586, - -3916, - -812, - 176 -}; - -// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine. -q15_t dB11[] = { - 121, - -957, - -3959, - -7383, - 23871, - -7383, - -3959, - -957, - 121 -}; - -// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine. -q15_t dB10[] = { - 56, - -1110, - -3987, - -7141, - 24254, - -7141, - -3987, - -1110, - 56 -}; - -// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine. -q15_t dB9[] = { - -19, - -1268, - -3994, - -6856, - 24688, - -6856, - -3994, - -1268, - -19 -}; - -// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine. -q15_t dB8[] = { - -104, - -1424, - -3968, - -6516, - 25182, - -6516, - -3968, - -1424, - -104 -}; - -// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine. -q15_t dB7[] = { - -196, - -1565, - -3896, - -6114, - 25742, - -6114, - -3896, - -1565, - -196 -}; - -// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine. -q15_t dB6[] = { - -288, - -1676, - -3761, - -5642, - 26370, - -5642, - -3761, - -1676, - -288 -}; - -// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine. -q15_t dB5[] = { - -370, - -1735, - -3545, - -5088, - 27075, - -5088, - -3545, - -1735, - -370 -}; - -// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine. -q15_t dB4[] = { - -432, - -1715, - -3220, - -4427, - 27880, - -4427, - -3220, - -1715, - -432 -}; - -// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine. -q15_t dB3[] = { - -452, - -1582, - -2759, - -3646, - 28792, - -3646, - -2759, - -1582, - -452 -}; - -// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine. -q15_t dB2[] = { - -408, - -1295, - -2123, - -2710, - 29846, - -2710, - -2123, - -1295, - -408 -}; - -// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine. -q15_t dB1[] = { - -268, - -795, - -1244, - -1546, - 31116, - -1546, - -1244, - -795, - -268 -}; - -q15_t dB0[] = { - 0, - 0, - 0, - 0, - 32767, - 0, - 0, - 0, - 0, -}; - -// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine. -q15_t dB_1[] = { - -419, - -177, - 3316, - 8650, - 11278, - 8650, - 3316, - -177, - -419 -}; - -// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine. -q15_t dB_2[] = { - -90, - 1033, - 3975, - 7267, - 8711, - 7267, - 3975, - 1033, - -90 -}; - -// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine. -q15_t dB_3[] = { - 292, - 1680, - 3752, - 5615, - 6362, - 5615, - 3752, - 1680, - 292 -}; - -// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar. -q15_t dB_4[] = { - 917, - 3024, - 5131, - 6684, - 7255, - 6684, - 5131, - 3024, - 917 -}; - -// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar. -q15_t dB_5[] = { - 1620, - 3339, - 4925, - 6042, - 6444, - 6042, - 4925, - 3339, - 1620 -}; - -// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar. -q15_t dB_6[] = { - 2161, - 3472, - 4605, - 5373, - 5644, - 5373, - 4605, - 3472, - 2161 -}; - /* * Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass, * Hann window, starting and ending 0 value coefficients removed. @@ -306,9 +60,9 @@ q15_t FILTER_COEFFS[] = { CAX25RX::CAX25RX() : m_filter(), m_state(), -m_demod1(dB3, 9U), -m_demod2(dB6, 9U), -m_demod3(dB9, 9U), +m_demod1(3), +m_demod2(6), +m_demod3(9), m_lastFCS(0U) { m_filter.numTaps = FILTER_LEN; @@ -346,3 +100,10 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) } } +void CAX25RX::setParams(int8_t twist) +{ + m_demod1.setTwist(twist - 3); + m_demod2.setTwist(twist); + m_demod3.setTwist(twist + 3); +} + diff --git a/AX25Twist.cpp b/AX25Twist.cpp new file mode 100644 index 0000000..bf0c534 --- /dev/null +++ b/AX25Twist.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "AX25Twist.h" + +// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine. +q15_t dB12[] = { + 176, + -812, + -3916, + -7586, + 23536, + -7586, + -3916, + -812, + 176 +}; + +// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine. +q15_t dB11[] = { + 121, + -957, + -3959, + -7383, + 23871, + -7383, + -3959, + -957, + 121 +}; + +// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine. +q15_t dB10[] = { + 56, + -1110, + -3987, + -7141, + 24254, + -7141, + -3987, + -1110, + 56 +}; + +// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine. +q15_t dB9[] = { + -19, + -1268, + -3994, + -6856, + 24688, + -6856, + -3994, + -1268, + -19 +}; + +// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine. +q15_t dB8[] = { + -104, + -1424, + -3968, + -6516, + 25182, + -6516, + -3968, + -1424, + -104 +}; + +// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine. +q15_t dB7[] = { + -196, + -1565, + -3896, + -6114, + 25742, + -6114, + -3896, + -1565, + -196 +}; + +// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine. +q15_t dB6[] = { + -288, + -1676, + -3761, + -5642, + 26370, + -5642, + -3761, + -1676, + -288 +}; + +// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine. +q15_t dB5[] = { + -370, + -1735, + -3545, + -5088, + 27075, + -5088, + -3545, + -1735, + -370 +}; + +// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine. +q15_t dB4[] = { + -432, + -1715, + -3220, + -4427, + 27880, + -4427, + -3220, + -1715, + -432 +}; + +// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine. +q15_t dB3[] = { + -452, + -1582, + -2759, + -3646, + 28792, + -3646, + -2759, + -1582, + -452 +}; + +// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine. +q15_t dB2[] = { + -408, + -1295, + -2123, + -2710, + 29846, + -2710, + -2123, + -1295, + -408 +}; + +// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine. +q15_t dB1[] = { + -268, + -795, + -1244, + -1546, + 31116, + -1546, + -1244, + -795, + -268 +}; + +q15_t dB0[] = { + 0, + 0, + 0, + 0, + 32767, + 0, + 0, + 0, + 0, +}; + +// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine. +q15_t dB_1[] = { + -419, + -177, + 3316, + 8650, + 11278, + 8650, + 3316, + -177, + -419 +}; + +// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine. +q15_t dB_2[] = { + -90, + 1033, + 3975, + 7267, + 8711, + 7267, + 3975, + 1033, + -90 +}; + +// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine. +q15_t dB_3[] = { + 292, + 1680, + 3752, + 5615, + 6362, + 5615, + 3752, + 1680, + 292 +}; + +// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar. +q15_t dB_4[] = { + 917, + 3024, + 5131, + 6684, + 7255, + 6684, + 5131, + 3024, + 917 +}; + +// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar. +q15_t dB_5[] = { + 1620, + 3339, + 4925, + 6042, + 6444, + 6042, + 4925, + 3339, + 1620 +}; + +// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar. +q15_t dB_6[] = { + 2161, + 3472, + 4605, + 5373, + 5644, + 5373, + 4605, + 3472, + 2161 +}; + +q15_t* coeffs[] = { + dB12, + dB11, + dB10, + dB9, + dB8, + dB7, + dB6, + dB5, + dB4, + dB3, + dB2, + dB1, + dB0, + dB_1, + dB_2, + dB_3, + dB_4, + dB_5, + dB_6 +}; + +CAX25Twist::CAX25Twist(int8_t n) : +m_filter(), +m_state() +{ + setTwist(n); +} + +void CAX25Twist::process(q15_t* in, q15_t* out, uint8_t length) +{ + ::arm_fir_fast_q15(&m_filter, in, out, length); +} + +void CAX25Twist::setTwist(int8_t n) +{ + uint8_t twist = uint8_t(n + 6); + + m_filter.numTaps = 9; + m_filter.pState = m_state; + m_filter.pCoeffs = coeffs[twist]; +} + diff --git a/AX25Twist.h b/AX25Twist.h new file mode 100644 index 0000000..ea1c6de --- /dev/null +++ b/AX25Twist.h @@ -0,0 +1,39 @@ +/* + * 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(AX25Twist_H) +#define AX25Twist_H + +#include "Config.h" + + +class CAX25Twist { +public: + CAX25Twist(int8_t n); + + void process(q15_t* in, q15_t* out, uint8_t length); + + void setTwist(int8_t n); + +private: + arm_fir_instance_q15 m_filter; + q15_t m_state[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare +}; + +#endif + From 7ad70d04a44b727565eafd1e12ea88a6d1c61eca Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 23 Jun 2020 10:34:19 +0100 Subject: [PATCH 114/139] Add a dummy AX25 transmit function and make AX25 RX changes. --- AX25RX.cpp | 33 ++++++++++++++++++++++----------- AX25RX.h | 1 + AX25TX.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ AX25TX.h | 2 ++ 4 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 AX25TX.cpp diff --git a/AX25RX.cpp b/AX25RX.cpp index 7a6b166..637bde0 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -63,7 +63,8 @@ m_state(), m_demod1(3), m_demod2(6), m_demod3(9), -m_lastFCS(0U) +m_lastFCS(0U), +m_count(0U) { m_filter.numTaps = FILTER_LEN; m_filter.pState = m_state; @@ -75,28 +76,38 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) q15_t output[RX_BLOCK_SIZE]; ::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE); - m_lastFCS = 0U; + m_count++; + CAX25Frame frame; bool ret = m_demod1.process(output, length, frame); - if (ret && frame.m_fcs != m_lastFCS) { + if (ret) { + if (frame.m_fcs != m_lastFCS || m_count > 2U) { + m_lastFCS = frame.m_fcs; + m_count = 0U; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); + } DEBUG1("Decoder 1 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } ret = m_demod2.process(output, length, frame); - if (ret && frame.m_fcs != m_lastFCS) { + if (ret) { + if (frame.m_fcs != m_lastFCS || m_count > 2U) { + m_lastFCS = frame.m_fcs; + m_count = 0U; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); + } DEBUG1("Decoder 2 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } ret = m_demod3.process(output, length, frame); - if (ret && frame.m_fcs != m_lastFCS) { + if (ret) { + if (frame.m_fcs != m_lastFCS || m_count > 2U) { + m_lastFCS = frame.m_fcs; + m_count = 0U; + serial.writeAX25Data(frame.m_data, frame.m_length - 2U); + } DEBUG1("Decoder 3 reported"); - m_lastFCS = frame.m_fcs; - serial.writeAX25Data(frame.m_data, frame.m_length - 2U); } } diff --git a/AX25RX.h b/AX25RX.h index 3416b81..220d61d 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -38,6 +38,7 @@ private: CAX25Demodulator m_demod2; CAX25Demodulator m_demod3; uint16_t m_lastFCS; + uint32_t m_count; }; #endif diff --git a/AX25TX.cpp b/AX25TX.cpp new file mode 100644 index 0000000..6f9ed5e --- /dev/null +++ b/AX25TX.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "AX25TX.h" + + +CAX25TX::CAX25TX() +{ +} + +void CAX25TX::process() +{ +} + +uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) +{ + return 0U; +} + +void CAX25TX::setParams(int8_t twist) +{ +} + +void CAX25TX::setTXDelay(uint8_t delay) +{ +} + +uint8_t CAX25TX::getSpace() const +{ + return 0U; +} + diff --git a/AX25TX.h b/AX25TX.h index ffe31be..d89f77c 100644 --- a/AX25TX.h +++ b/AX25TX.h @@ -21,6 +21,8 @@ #include "Config.h" +#include "SerialRB.h" + class CAX25TX { public: CAX25TX(); From 3de10fe98b384863268b36f37a0153ced136ce47 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 11:14:02 +0100 Subject: [PATCH 115/139] First version of the AX25 TX functionality. --- AX25Defines.h | 36 ++++++++++++ AX25Demodulator.cpp | 9 +-- AX25Frame.cpp | 28 +++++++++ AX25Frame.h | 3 + AX25TX.cpp | 134 +++++++++++++++++++++++++++++++++++++++++++- AX25TX.h | 12 +++- 6 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 AX25Defines.h diff --git a/AX25Defines.h b/AX25Defines.h new file mode 100644 index 0000000..03424b2 --- /dev/null +++ b/AX25Defines.h @@ -0,0 +1,36 @@ +/* + * 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(AX25DEFINES_H) +#define AX25DEFINES_H + +const uint8_t AX25_RADIO_SYMBOL_LENGTH = 20U; // At 24 kHz sample rate + +const uint8_t AX25_FRAME_START = 0x7EU; +const uint8_t AX25_FRAME_END = 0x7EU; +const uint8_t AX25_FRAME_ABORT = 0xFEU; + +const uint8_t AX25_MAX_ONES = 5U; + +const uint16_t AX25_MIN_FRAME_LENGTH = 17U; // Callsign (7) + Callsign (7) + Control (1) + Checksum (2) + +const uint16_t AX25_MAX_FRAME_LENGTH = 294U; // Callsign (7) + Callsign (7) + 3 Digipeaters (21) + + // Control (1) + Data (256) + Checksum (2) + +#endif + diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 7ffb99c..b59dc6b 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -20,6 +20,7 @@ #include "Config.h" #include "Globals.h" #include "AX25Demodulator.h" +#include "AX25Defines.h" const float32_t SAMPLE_RATE = 24000.0F; const float32_t SYMBOL_RATE = 1200.0F; @@ -178,7 +179,7 @@ bool CAX25Demodulator::PLL(bool input) bool CAX25Demodulator::HDLC(bool b) { - if (m_hdlcOnes == 5U) { + if (m_hdlcOnes == AX25_MAX_ONES) { if (b) { // flag byte m_hdlcFlag = true; @@ -203,8 +204,8 @@ bool CAX25Demodulator::HDLC(bool b) bool result = false; switch (m_hdlcBuffer) { - case 0x7E: - if (m_frame.m_length >= 17U) { + case AX25_FRAME_END: + if (m_frame.m_length >= AX25_MIN_FRAME_LENGTH) { result = m_frame.checkCRC(); if (!result) m_frame.m_length = 0U; @@ -216,7 +217,7 @@ bool CAX25Demodulator::HDLC(bool b) m_hdlcBits = 0U; break; - case 0xFE: + case AX25_FRAME_ABORT: // Frame aborted m_frame.m_length = 0U; m_hdlcState = AX25_IDLE; diff --git a/AX25Frame.cpp b/AX25Frame.cpp index 905682e..d666f33 100644 --- a/AX25Frame.cpp +++ b/AX25Frame.cpp @@ -54,6 +54,15 @@ const uint16_t CCITT_TABLE[] = { 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 }; +CAX25Frame::CAX25Frame(const uint8_t* data, uint16_t length) : +m_data(), +m_length(0U), +m_fcs(0U) +{ + for (uint16_t i = 0U; i < length && i < (AX25_MAX_PACKET_LEN - 2U); i++) + m_data[m_length++] = data[i]; +} + CAX25Frame::CAX25Frame() : m_data(), m_length(0U), @@ -92,3 +101,22 @@ bool CAX25Frame::checkCRC() } } +void CAX25Frame::addCRC() +{ + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0xFFFFU; + for (uint16_t i = 0U; i < m_length; i++) + crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]]; + + crc16 = ~crc16; + + m_fcs = crc16; + + m_data[m_length++] = crc8[0U]; + m_data[m_length++] = crc8[1U]; +} + diff --git a/AX25Frame.h b/AX25Frame.h index eaf770c..7f79c28 100644 --- a/AX25Frame.h +++ b/AX25Frame.h @@ -25,12 +25,15 @@ const uint16_t AX25_MAX_PACKET_LEN = 300U; class CAX25Frame { public: + CAX25Frame(const uint8_t* data, uint16_t length); CAX25Frame(); bool append(uint16_t c); bool checkCRC(); + void addCRC(); + uint8_t m_data[AX25_MAX_PACKET_LEN]; uint16_t m_length; uint16_t m_fcs; diff --git a/AX25TX.cpp b/AX25TX.cpp index 6f9ed5e..8658fb4 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -20,30 +20,160 @@ #include "Globals.h" #include "AX25TX.h" +#include "AX25Defines.h" +#include "AX25Frame.h" -CAX25TX::CAX25TX() + +const uint8_t START_FLAG[] = { AX25_FRAME_START }; +const uint8_t END_FLAG[] = { AX25_FRAME_END }; + +const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7]) + +const uint8_t BIT_MASK_TABLE2[] = { 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U }; + +#define WRITE_BIT2(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE2[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE2[(i)&7]) +#define READ_BIT2(p,i) (p[(i)>>3] & BIT_MASK_TABLE2[(i)&7]) + +const uint16_t AUDIO_TABLE_LEN = 120U; + +const q15_t AUDIO_TABLE_DATA[] = { + 0, 214, 428, 641, 851, 1060, 1265, 1468, 1666, 1859, 2048, 2230, 2407, 2577, 2740, 2896, 3043, 3182, 3313, 3434, 3546, 3649, + 3741, 3823, 3895, 3955, 4006, 4045, 4073, 4089, 4095, 4089, 4073, 4045, 4006, 3955, 3895, 3823, 3741, 3649, 3546, 3434, 3313, + 3182, 3043, 2896, 2740, 2577, 2407, 2230, 2048, 1859, 1666, 1468, 1265, 1060, 851, 641, 428, 214, 0, -214, -428, -641, -851, + -1060, -1265, -1468, -1666, -1859, -2047, -2230, -2407, -2577, -2740, -2896, -3043, -3182, -3313, -3434, -3546, -3649, -3741, + -3823, -3895, -3955, -4006, -4045, -4073, -4089, -4095, -4089, -4073, -4045, -4006, -3955, -3895, -3823, -3741, -3649, -3546, + -3434, -3313, -3182, -3043, -2896, -2740, -2577, -2407, -2230, -2047, -1859, -1666, -1468, -1265, -1060, -851, -641, -428, -214 +}; + +CAX25TX::CAX25TX() : +m_twist(-6), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(120U), +m_tablePtr(0U), +m_nrzi(false) { } void CAX25TX::process() { + if (m_poLen == 0U) + return; + + uint16_t space = io.getSpace(); + + while (space > AX25_RADIO_SYMBOL_LENGTH) { + bool b = READ_BIT1(m_poBuffer, m_poPtr) != 0U; + m_poPtr++; + + writeBit(b); + + space -= AX25_RADIO_SYMBOL_LENGTH; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + return; + } + } } uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) { + CAX25Frame frame(data, length); + frame.addCRC(); + + m_poLen = 0U; + m_poPtr = 0U; + m_nrzi = false; + m_tablePtr = 0U; + + // Add TX delay (already NRZI) + for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) + WRITE_BIT1(m_poBuffer, m_poLen, false); + + // Add the Start Flag + for (uint16_t i = 0U; i < 8U; i++, m_poLen++) { + bool b1 = READ_BIT1(START_FLAG, i) != 0U; + bool b2 = NRZI(b1); + WRITE_BIT1(m_poBuffer, m_poLen, b2); + } + + uint8_t ones = 0U; + for (uint16_t i = 0U; i < (frame.m_length * 8U); i++) { + bool b1 = READ_BIT2(START_FLAG, i) != 0U; + bool b2 = NRZI(b1); + WRITE_BIT1(m_poBuffer, m_poLen, b2); + m_poLen++; + + if (b1) { + ones++; + if (ones == AX25_MAX_ONES) { + bool b = NRZI(false); + WRITE_BIT1(m_poBuffer, m_poLen, b); + m_poLen++; + ones = 0U; + } + } else { + ones = 0U; + } + } + + // Add the End Flag + for (uint16_t i = 0U; i < 8U; i++, m_poLen++) { + bool b1 = READ_BIT1(END_FLAG, i) != 0U; + bool b2 = NRZI(b1); + WRITE_BIT1(m_poBuffer, m_poLen, b2); + } + return 0U; } +void CAX25TX::writeBit(bool b) +{ + q15_t in[AX25_RADIO_SYMBOL_LENGTH]; + for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) { + in[i] = AUDIO_TABLE_DATA[m_tablePtr]; + if (b) + m_tablePtr += 6U; + else + m_tablePtr += 11U; + + if (m_tablePtr >= AUDIO_TABLE_LEN) + m_tablePtr -= AUDIO_TABLE_LEN; + } + + q15_t out[AX25_RADIO_SYMBOL_LENGTH]; + m_twist.process(in, out, AX25_RADIO_SYMBOL_LENGTH); + + io.write(STATE_AX25, out, AX25_RADIO_SYMBOL_LENGTH); +} + void CAX25TX::setParams(int8_t twist) { + m_twist.setTwist(twist); } void CAX25TX::setTXDelay(uint8_t delay) { + m_txDelay = delay * 12U; } uint8_t CAX25TX::getSpace() const { - return 0U; + return m_poLen == 0U ? 255U : 0U; +} + +bool CAX25TX::NRZI(bool b) +{ + bool result = (b == m_nrzi); + + m_nrzi = b; + + return result; } diff --git a/AX25TX.h b/AX25TX.h index d89f77c..e77c500 100644 --- a/AX25TX.h +++ b/AX25TX.h @@ -21,7 +21,7 @@ #include "Config.h" -#include "SerialRB.h" +#include "AX25Twist.h" class CAX25TX { public: @@ -38,6 +38,16 @@ public: uint8_t getSpace() const; private: + CAX25Twist m_twist; + uint8_t m_poBuffer[560U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + uint16_t m_tablePtr; + bool m_nrzi; + + void writeBit(bool b); + bool NRZI(bool b); }; #endif From 835ef46aef20c068d53370c0faffaa0c275d3a1c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 11:16:02 +0100 Subject: [PATCH 116/139] Bump the version date. --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index e8c09b1..98f77db 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -105,7 +105,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200621 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200624 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From a7ac55795d3535f3fc6c58970c650bb02a8a5655 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 12:46:27 +0100 Subject: [PATCH 117/139] Fix obvious AX25 TX data bug. --- AX25TX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index 8658fb4..5652bd8 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -105,7 +105,7 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) uint8_t ones = 0U; for (uint16_t i = 0U; i < (frame.m_length * 8U); i++) { - bool b1 = READ_BIT2(START_FLAG, i) != 0U; + bool b1 = READ_BIT2(frame.m_data, i) != 0U; bool b2 = NRZI(b1); WRITE_BIT1(m_poBuffer, m_poLen, b2); m_poLen++; @@ -113,6 +113,7 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) if (b1) { ones++; if (ones == AX25_MAX_ONES) { + // Bit stuffing bool b = NRZI(false); WRITE_BIT1(m_poBuffer, m_poLen, b); m_poLen++; From 2da28ede64d35d8f82d3c9a3f74f134d650bf502 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 24 Jun 2020 13:14:10 +0100 Subject: [PATCH 118/139] Increase the maximum AX25 frame size. --- AX25Defines.h | 4 ++-- AX25TX.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AX25Defines.h b/AX25Defines.h index 03424b2..7087847 100644 --- a/AX25Defines.h +++ b/AX25Defines.h @@ -29,8 +29,8 @@ const uint8_t AX25_MAX_ONES = 5U; const uint16_t AX25_MIN_FRAME_LENGTH = 17U; // Callsign (7) + Callsign (7) + Control (1) + Checksum (2) -const uint16_t AX25_MAX_FRAME_LENGTH = 294U; // Callsign (7) + Callsign (7) + 3 Digipeaters (21) + - // Control (1) + Data (256) + Checksum (2) +const uint16_t AX25_MAX_FRAME_LENGTH = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) + + // Control (1) + PID (1) + Data (256) + Checksum (2) #endif diff --git a/AX25TX.h b/AX25TX.h index e77c500..628e549 100644 --- a/AX25TX.h +++ b/AX25TX.h @@ -39,7 +39,7 @@ public: private: CAX25Twist m_twist; - uint8_t m_poBuffer[560U]; + uint8_t m_poBuffer[600U]; uint16_t m_poLen; uint16_t m_poPtr; uint16_t m_txDelay; From a29cb23a75d1c14cef7a6fda3693593b0d763a6f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 27 Jun 2020 22:55:16 +0100 Subject: [PATCH 119/139] Remove TX Twist. --- AX25TX.cpp | 11 +++-------- AX25TX.h | 2 -- SerialPort.cpp | 9 +++------ 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index 5652bd8..152e1b5 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -53,7 +53,7 @@ m_twist(-6), m_poBuffer(), m_poLen(0U), m_poPtr(0U), -m_txDelay(120U), +m_txDelay(360U), m_tablePtr(0U), m_nrzi(false) { @@ -140,9 +140,9 @@ void CAX25TX::writeBit(bool b) for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) { in[i] = AUDIO_TABLE_DATA[m_tablePtr]; if (b) - m_tablePtr += 6U; - else m_tablePtr += 11U; + else + m_tablePtr += 6U; if (m_tablePtr >= AUDIO_TABLE_LEN) m_tablePtr -= AUDIO_TABLE_LEN; @@ -154,11 +154,6 @@ void CAX25TX::writeBit(bool b) io.write(STATE_AX25, out, AX25_RADIO_SYMBOL_LENGTH); } -void CAX25TX::setParams(int8_t twist) -{ - m_twist.setTwist(twist); -} - void CAX25TX::setTXDelay(uint8_t delay) { m_txDelay = delay * 12U; diff --git a/AX25TX.h b/AX25TX.h index 628e549..2c8eb8b 100644 --- a/AX25TX.h +++ b/AX25TX.h @@ -31,8 +31,6 @@ public: void process(); - void setParams(int8_t twist); - void setTXDelay(uint8_t delay); uint8_t getSpace() const; diff --git a/SerialPort.cpp b/SerialPort.cpp index 7b64a47..2e2d3dc 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200625 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200627 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -360,9 +360,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) if (ax25RXTwist < -4 || ax25RXTwist > 10) return 4U; - int8_t ax25TXTwist = int8_t(data[23U]) - 128; - if (ax25TXTwist < -4 || ax25TXTwist > 10) - return 4U; + uint8_t ax25TXDelay = data[23U]; setMode(modemState); @@ -382,7 +380,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) dmrDMOTX.setTXDelay(txDelay); nxdnTX.setTXDelay(txDelay); pocsagTX.setTXDelay(txDelay); - ax25TX.setTXDelay(txDelay); + ax25TX.setTXDelay(ax25TXDelay); dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); @@ -394,7 +392,6 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) p25TX.setParams(p25TXHang); nxdnTX.setParams(nxdnTXHang); ax25RX.setParams(ax25RXTwist); - ax25TX.setParams(ax25TXTwist); io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset); From ea0c1953cc3342ccd8cd575e4bc88d8214e50b5d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 28 Jun 2020 11:22:10 +0200 Subject: [PATCH 120/139] correct preamble and NRZI --- AX25TX.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index 152e1b5..2565dff 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -93,8 +93,10 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) m_tablePtr = 0U; // Add TX delay (already NRZI) - for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) - WRITE_BIT1(m_poBuffer, m_poLen, false); + for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) { + bool preamble = NRZI(false); + WRITE_BIT1(m_poBuffer, m_poLen, preamble); + } // Add the Start Flag for (uint16_t i = 0U; i < 8U; i++, m_poLen++) { @@ -115,7 +117,7 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) if (ones == AX25_MAX_ONES) { // Bit stuffing bool b = NRZI(false); - WRITE_BIT1(m_poBuffer, m_poLen, b); + WRITE_BIT1(m_poBuffer, m_poLen, false); m_poLen++; ones = 0U; } @@ -166,10 +168,14 @@ uint8_t CAX25TX::getSpace() const bool CAX25TX::NRZI(bool b) { - bool result = (b == m_nrzi); + if(!b) + m_nrzi ^= 1; - m_nrzi = b; + return m_nrzi; + // bool result = (b == m_nrzi); - return result; + // m_nrzi = b; + + // return result; } From a73376671c47a8f38c0a5066b23c8fe505a897f7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 28 Jun 2020 15:27:58 +0100 Subject: [PATCH 121/139] Fix preamble and NRZI. --- AX25TX.cpp | 13 ++++--------- SerialPort.cpp | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index 2565dff..da4a002 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -92,7 +92,7 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) m_nrzi = false; m_tablePtr = 0U; - // Add TX delay (already NRZI) + // Add TX delay for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) { bool preamble = NRZI(false); WRITE_BIT1(m_poBuffer, m_poLen, preamble); @@ -117,7 +117,7 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) if (ones == AX25_MAX_ONES) { // Bit stuffing bool b = NRZI(false); - WRITE_BIT1(m_poBuffer, m_poLen, false); + WRITE_BIT1(m_poBuffer, m_poLen, b); m_poLen++; ones = 0U; } @@ -168,14 +168,9 @@ uint8_t CAX25TX::getSpace() const bool CAX25TX::NRZI(bool b) { - if(!b) - m_nrzi ^= 1; + if (!b) + m_nrzi = !m_nrzi; return m_nrzi; - // bool result = (b == m_nrzi); - - // m_nrzi = b; - - // return result; } diff --git a/SerialPort.cpp b/SerialPort.cpp index 2e2d3dc..7a81dc9 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200627 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200628 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From 43f84ae9689346c33f029ef454062c94dbe297f1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jun 2020 15:59:46 +0100 Subject: [PATCH 122/139] Simplify the pre-emphasis code for AX.25. --- AX25TX.cpp | 20 +++++++++++--------- AX25TX.h | 3 --- SerialPort.cpp | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index da4a002..3296288 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -49,7 +49,6 @@ const q15_t AUDIO_TABLE_DATA[] = { }; CAX25TX::CAX25TX() : -m_twist(-6), m_poBuffer(), m_poLen(0U), m_poPtr(0U), @@ -138,22 +137,25 @@ uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length) void CAX25TX::writeBit(bool b) { - q15_t in[AX25_RADIO_SYMBOL_LENGTH]; + q15_t buffer[AX25_RADIO_SYMBOL_LENGTH]; for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) { - in[i] = AUDIO_TABLE_DATA[m_tablePtr]; - if (b) + q15_t value = AUDIO_TABLE_DATA[m_tablePtr]; + + if (b) { m_tablePtr += 11U; - else + } else { + // De-emphasise the lower frequency by 6dB + value >>= 2; m_tablePtr += 6U; + } + + buffer[i] = value; if (m_tablePtr >= AUDIO_TABLE_LEN) m_tablePtr -= AUDIO_TABLE_LEN; } - q15_t out[AX25_RADIO_SYMBOL_LENGTH]; - m_twist.process(in, out, AX25_RADIO_SYMBOL_LENGTH); - - io.write(STATE_AX25, out, AX25_RADIO_SYMBOL_LENGTH); + io.write(STATE_AX25, buffer, AX25_RADIO_SYMBOL_LENGTH); } void CAX25TX::setTXDelay(uint8_t delay) diff --git a/AX25TX.h b/AX25TX.h index 2c8eb8b..0a41757 100644 --- a/AX25TX.h +++ b/AX25TX.h @@ -21,8 +21,6 @@ #include "Config.h" -#include "AX25Twist.h" - class CAX25TX { public: CAX25TX(); @@ -36,7 +34,6 @@ public: uint8_t getSpace() const; private: - CAX25Twist m_twist; uint8_t m_poBuffer[600U]; uint16_t m_poLen; uint16_t m_poPtr; diff --git a/SerialPort.cpp b/SerialPort.cpp index 7a81dc9..390338a 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200628 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200629 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From 52a351d0f144a78ee4cdbff60adb24c30a0a963f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jun 2020 16:11:56 +0100 Subject: [PATCH 123/139] Slight tweak to the mark and space. --- AX25TX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AX25TX.cpp b/AX25TX.cpp index 3296288..fb3bd26 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -142,11 +142,11 @@ void CAX25TX::writeBit(bool b) q15_t value = AUDIO_TABLE_DATA[m_tablePtr]; if (b) { - m_tablePtr += 11U; - } else { // De-emphasise the lower frequency by 6dB value >>= 2; m_tablePtr += 6U; + } else { + m_tablePtr += 11U; } buffer[i] = value; From 14d50980181892efeccf0654fcd60ccb46aeb04f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jun 2020 12:44:02 +0100 Subject: [PATCH 124/139] Rename FMDownsampler to FMDownSampler. --- FM.cpp | 12 ++++++------ FM.h | 4 ++-- FMDownsampler.cpp => FMDownSampler.cpp | 16 ++++++++-------- FMDownsampler.h => FMDownSampler.h | 9 +++++++-- SerialPort.cpp | 2 +- 5 files changed, 24 insertions(+), 19 deletions(-) rename FMDownsampler.cpp => FMDownSampler.cpp (84%) rename FMDownsampler.h => FMDownSampler.h (95%) diff --git a/FM.cpp b/FM.cpp index 01fa209..980b0fc 100644 --- a/FM.cpp +++ b/FM.cpp @@ -54,7 +54,7 @@ m_useCOS(true), m_cosInvert(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), -m_downsampler(400U),// 100 ms of audio +m_downSampler(400U),// 100 ms of audio m_extEnabled(false), m_rxLevel(1), m_inputRFRB(2401U), // 100ms of audio + 1 sample @@ -120,7 +120,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) 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); + m_downSampler.addSample(currentSample); currentSample *= currentBoost; } else { @@ -177,7 +177,7 @@ void CFM::process() } if (m_extEnabled) { - uint16_t length = m_downsampler.getData(); + uint16_t length = m_downSampler.getData(); if (length >= FM_SERIAL_BLOCK_SIZE) { if (length > FM_SERIAL_BLOCK_SIZE) @@ -186,7 +186,7 @@ void CFM::process() TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE]; for (uint16_t j = 0U; j < length; j++) - m_downsampler.getPackedData(serialSamples[j]); + m_downSampler.getPackedData(serialSamples[j]); serial.writeFMData((uint8_t*)serialSamples, length * sizeof(TSamplePairPack)); } @@ -214,7 +214,7 @@ void CFM::reset() m_outputRFRB.reset(); m_inputExtRB.reset(); - m_downsampler.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) @@ -325,7 +325,7 @@ void CFM::stateMachine(bool validRFSignal, bool validExtSignal) if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) { m_outputRFRB.reset(); - m_downsampler.reset(); + m_downSampler.reset(); } } diff --git a/FM.h b/FM.h index 6b691c9..a6a37a8 100644 --- a/FM.h +++ b/FM.h @@ -29,7 +29,7 @@ #include "FMTimer.h" #include "RingBuffer.h" #include "FMDirectForm1.h" -#include "FMDownsampler.h" +#include "FMDownSampler.h" #include "FMUpSampler.h" enum FM_STATE { @@ -95,7 +95,7 @@ private: bool m_cosInvert; q15_t m_rfAudioBoost; q15_t m_extAudioBoost; - CFMDownsampler m_downsampler; + CFMDownSampler m_downSampler; bool m_extEnabled; q15_t m_rxLevel; CRingBuffer m_inputRFRB; diff --git a/FMDownsampler.cpp b/FMDownSampler.cpp similarity index 84% rename from FMDownsampler.cpp rename to FMDownSampler.cpp index b5303f6..8ed95bc 100644 --- a/FMDownsampler.cpp +++ b/FMDownSampler.cpp @@ -18,9 +18,9 @@ */ #include "Config.h" -#include "FMDownsampler.h" +#include "FMDownSampler.h" -CFMDownsampler::CFMDownsampler(uint16_t length) : +CFMDownSampler::CFMDownSampler(uint16_t length) : m_ringBuffer(length), m_samplePack(0U), m_samplePackPointer(NULL), @@ -29,7 +29,7 @@ m_sampleIndex(0U) m_samplePackPointer = (uint8_t*)&m_samplePack; } -void CFMDownsampler::addSample(q15_t sample) +void CFMDownSampler::addSample(q15_t sample) { uint32_t usample = uint32_t(int32_t(sample) + 2048); //only take one of three samples @@ -54,21 +54,21 @@ void CFMDownsampler::addSample(q15_t sample) } m_sampleIndex++; - if(m_sampleIndex >= 6U)//did we pack two samples ? + if (m_sampleIndex >= 6U)//did we pack two samples ? m_sampleIndex = 0U; } -bool CFMDownsampler::getPackedData(TSamplePairPack& data) +bool CFMDownSampler::getPackedData(TSamplePairPack& data) { return m_ringBuffer.get(data); } -uint16_t CFMDownsampler::getData() +uint16_t CFMDownSampler::getData() { return m_ringBuffer.getData(); } -void CFMDownsampler::reset() +void CFMDownSampler::reset() { m_sampleIndex = 0U; -} \ No newline at end of file +} diff --git a/FMDownsampler.h b/FMDownSampler.h similarity index 95% rename from FMDownsampler.h rename to FMDownSampler.h index ab91bd0..9f26acf 100644 --- a/FMDownsampler.h +++ b/FMDownSampler.h @@ -24,12 +24,16 @@ #include "RingBuffer.h" #include "FMSamplePairPack.h" -class CFMDownsampler { +class CFMDownSampler { public: - CFMDownsampler(uint16_t length); + CFMDownSampler(uint16_t length); + void addSample(q15_t sample); + bool getPackedData(TSamplePairPack& data); + uint16_t getData(); + void reset(); private: @@ -40,3 +44,4 @@ private: }; #endif + diff --git a/SerialPort.cpp b/SerialPort.cpp index 390338a..2a3d209 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200629 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200630 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From 8d10555dc97d186b220e767668e80c49406a51f0 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jun 2020 15:35:58 +0100 Subject: [PATCH 125/139] Reduce the low pass filter a little. --- AX25Demodulator.cpp | 18 +++++++----------- AX25Demodulator.h | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index b59dc6b..98f235c 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -30,19 +30,15 @@ const uint16_t DELAY_LEN = 11U; const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE; const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; -const uint32_t LPF_FILTER_LEN = 96U; +const uint32_t LPF_FILTER_LEN = 48U; q15_t LPF_FILTER_COEFFS[] = { - 0, 0, 0, 1, 2, 5, 8, 12, 18, 23, - 29, 33, 36, 36, 33, 25, 13, -5, -28, -57, - -89, -123, -159, -194, -225, -249, -264, -267, -254, -224, - -175, -104, -12, 102, 236, 389, 557, 738, 926, 1117, - 1306, 1486, 1654, 1802, 1927, 2025, 2092, 2126, 2126, 2092, - 2025, 1927, 1802, 1654, 1486, 1306, 1117, 926, 738, 557, - 389, 236, 102, -12, -104, -175, -224, -254, -267, -264, - -249, -225, -194, -159, -123, -89, -57, -28, -5, 13, - 25, 33, 36, 36, 33, 29, 23, 18, 12, 8, - 5, 2, 1, 0, 0, 0 + -2, -8, -17, -28, -40, -47, -47, -34, + -5, 46, 122, 224, 354, 510, 689, 885, + 1092, 1302, 1506, 1693, 1856, 1987, 2077, 2124, + 2124, 2077, 1987, 1856, 1693, 1506, 1302, 1092, + 885, 689, 510, 354, 224, 122, 46, -5, + -34, -47, -47, -40, -28, -17, -8, -2 }; // 64 Hz loop filter. diff --git a/AX25Demodulator.h b/AX25Demodulator.h index 84a98d6..b6b87a4 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -42,7 +42,7 @@ private: CAX25Frame m_frame; CAX25Twist m_twist; arm_fir_instance_q15 m_lpfFilter; - q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 20 - 1 plus some spare + q15_t m_lpfState[70U]; // NoTaps + BlockSize - 1, 48 + 20 - 1 plus some spare bool* m_delayLine; uint16_t m_delayPos; bool m_nrziState; From 2c6e2c2a1121fe358ccf72699c01efcc88a30fd8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jun 2020 17:09:09 +0100 Subject: [PATCH 126/139] Remove unneeded zeroes from the band pass FIR filter. --- AX25RX.cpp | 31 ++++++++++++++++--------------- AX25RX.h | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/AX25RX.cpp b/AX25RX.cpp index 637bde0..2e2592b 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -39,22 +39,23 @@ * window='hann') * 32768, * dtype=int)[10:-10] */ -const uint32_t FILTER_LEN = 132; + +const uint32_t FILTER_LEN = 130U; + q15_t FILTER_COEFFS[] = { - 0, 5, 12, 18, 21, 19, 11, -2, -15, -25, - -27, -21, -11, -3, -5, -19, -43, -69, -83, -73, - -35, 27, 98, 155, 180, 163, 109, 39, -20, -45, - -26, 23, 74, 89, 39, -81, -247, -407, -501, -480, - -334, -92, 175, 388, 479, 429, 275, 99, 5, 68, - 298, 626, 913, 994, 740, 115, -791, -1770, -2544, -2847, - -2509, -1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76, - -1527, -2509, -2847, -2544, -1770, -791, 115, 740, 994, 913, - 626, 298, 68, 5, 99, 275, 429, 479, 388, 175, - -92, -334, -480, -501, -407, -247, -81, 39, 89, 74, - 23, -26, -45, -20, 39, 109, 163, 180, 155, 98, - 27, -35, -73, -83, -69, -43, -19, -5, -3, -11, - -21, -27, -25, -15, -2, 11, 19, 21, 18, 12, - 5, 0 + 5, 12, 18, 21, 19, 11, -2, -15, -25, -27, + -21, -11, -3, -5, -19, -43, -69, -83, -73, -35, + 27, 98, 155, 180, 163, 109, 39, -20, -45, -26, + 23, 74, 89, 39, -81, -247, -407, -501, -480, -334, + -92, 175, 388, 479, 429, 275, 99, 5, 68, 298, + 626, 913, 994, 740, 115, -791, -1770, -2544, -2847, -2509, + -1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76, -1527, + -2509, -2847, -2544, -1770, -791, 115, 740, 994, 913, 626, + 298, 68, 5, 99, 275, 429, 479, 388, 175, -92, + -334, -480, -501, -407, -247, -81, 39, 89, 74, 23, + -26, -45, -20, 39, 109, 163, 180, 155, 98, 27, + -35, -73, -83, -69, -43, -19, -5, -3, -11, -21, + -27, -25, -15, -2, 11, 19, 21, 18, 12, 5 }; CAX25RX::CAX25RX() : diff --git a/AX25RX.h b/AX25RX.h index 220d61d..d6e55c3 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -33,7 +33,7 @@ public: private: arm_fir_instance_q15 m_filter; - q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare + q15_t m_state[160U]; // NoTaps + BlockSize - 1, 130 + 20 - 1 plus some spare CAX25Demodulator m_demod1; CAX25Demodulator m_demod2; CAX25Demodulator m_demod3; From 29c8cf941451b34add208e1261f3c0c1ce0c5e8a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 1 Jul 2020 12:33:08 +0100 Subject: [PATCH 127/139] Add AX.25 Slot Time and P-Persist processing for simplex work. --- AX25Demodulator.cpp | 54 ++++++++++++++++++++++++++++++++ AX25Demodulator.h | 6 ++++ AX25RX.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++-- AX25RX.h | 15 ++++++++- AX25TX.cpp | 8 +++++ SerialPort.cpp | 10 ++++-- 6 files changed, 163 insertions(+), 6 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index 98f235c..df3e13c 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -41,6 +41,18 @@ q15_t LPF_FILTER_COEFFS[] = { -34, -47, -47, -40, -28, -17, -8, -2 }; +// Lock low-pass filter taps (80Hz Bessel) +// scipy.signal: +// b, a = bessel(4, [80.0/(1200/2)], 'lowpass') +// +const uint8_t PLL_IIR_SIZE = 5U; + +const float32_t PLL_LOCK_B[] = { + 1.077063e-03,4.308253e-03,6.462379e-03,4.308253e-03,1.077063e-03}; + +const float32_t PLL_LOCK_A[] = { + 1.000000e+00,-2.774567e+00,2.962960e+00,-1.437990e+00,2.668296e-01}; + // 64 Hz loop filter. // scipy.signal: // loop_coeffs = firwin(9, [64.0/(1200/2)], width = None, @@ -63,6 +75,9 @@ m_pllState(), m_pllLast(false), m_pllBits(1U), m_pllCount(0.0F), +m_pllJitter(0.0F), +m_pllDCD(false), +m_iirHistory(), m_hdlcOnes(0U), m_hdlcFlag(false), m_hdlcBuffer(0U), @@ -78,6 +93,9 @@ m_hdlcState(AX25_IDLE) m_pllFilter.numTaps = PLL_FILTER_LEN; m_pllFilter.pState = m_pllState; m_pllFilter.pCoeffs = PLL_FILTER_COEFFS; + + for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++) + m_iirHistory[i] = 0.0F; } bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame) @@ -154,10 +172,20 @@ bool CAX25Demodulator::PLL(bool input) if (m_pllCount > PLL_LIMIT) m_pllCount -= SAMPLES_PER_SYMBOL; + float32_t adjust = m_pllBits > 16U ? 5.0F : 0.0F; float32_t offset = m_pllCount / float32_t(m_pllBits); float32_t jitter; ::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U); + if (!m_duplex) { + float32_t absOffset = adjust; + if (offset < 0.0F) + absOffset -= offset; + else + absOffset += offset; + m_pllJitter = iir(absOffset); + } + m_pllCount -= jitter / 2.0F; m_pllBits = 1U; } else { @@ -260,3 +288,29 @@ void CAX25Demodulator::setTwist(int8_t n) m_twist.setTwist(n); } +bool CAX25Demodulator::isDCD() +{ + if (m_pllJitter <= (SAMPLES_PER_SYMBOL * 0.03F)) + m_pllDCD = true; + else if (m_pllJitter >= (SAMPLES_PER_SYMBOL * 0.15F)) + m_pllDCD = false; + + return m_pllDCD; +} + +float32_t CAX25Demodulator::iir(float32_t input) +{ + for (int8_t i = int8_t(PLL_IIR_SIZE) - 1; i != 0; i--) + m_iirHistory[i] = m_iirHistory[i - 1]; + + m_iirHistory[0] = input; + for (uint8_t i = 1U; i < PLL_IIR_SIZE; i++) + m_iirHistory[0] -= PLL_LOCK_A[i] * m_iirHistory[i]; + + float32_t result = 0.0F; + for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++) + result += PLL_LOCK_B[i] * m_iirHistory[i]; + + return result; +} + diff --git a/AX25Demodulator.h b/AX25Demodulator.h index b6b87a4..d1baff8 100644 --- a/AX25Demodulator.h +++ b/AX25Demodulator.h @@ -38,6 +38,8 @@ public: void setTwist(int8_t n); + bool isDCD(); + private: CAX25Frame m_frame; CAX25Twist m_twist; @@ -51,6 +53,9 @@ private: bool m_pllLast; uint8_t m_pllBits; float32_t m_pllCount; + float32_t m_pllJitter; + bool m_pllDCD; + float32_t m_iirHistory[5U]; uint16_t m_hdlcOnes; bool m_hdlcFlag; uint16_t m_hdlcBuffer; @@ -61,6 +66,7 @@ private: bool NRZI(bool b); bool PLL(bool b); bool HDLC(bool b); + float32_t iir(float32_t input); }; #endif diff --git a/AX25RX.cpp b/AX25RX.cpp index 2e2592b..4836701 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -65,11 +65,21 @@ m_demod1(3), m_demod2(6), m_demod3(9), m_lastFCS(0U), -m_count(0U) +m_count(0U), +m_slotTime(30U), +m_slotCount(0U), +m_pPersist(128U), +m_canTX(false), +m_x(1U), +m_a(0xB7U), +m_b(0x73U), +m_c(0xF6U) { m_filter.numTaps = FILTER_LEN; m_filter.pState = m_state; m_filter.pCoeffs = FILTER_COEFFS; + + initRand(); } void CAX25RX::samples(q15_t* samples, uint8_t length) @@ -110,12 +120,74 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) } DEBUG1("Decoder 3 reported"); } + + if (!m_duplex) { + m_slotCount += RX_BLOCK_SIZE; + if (m_slotCount >= m_slotTime) { + m_slotCount = 0U; + + bool dcd1 = m_demod1.isDCD(); + bool dcd2 = m_demod2.isDCD(); + bool dcd3 = m_demod3.isDCD(); + + if (dcd1 || dcd2 || dcd3) + m_canTX = false; + else + m_canTX = m_pPersist >= rand(); + } + } } -void CAX25RX::setParams(int8_t twist) +bool CAX25RX::canTX() const +{ + return m_canTX; +} + +void CAX25RX::setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist) { m_demod1.setTwist(twist - 3); m_demod2.setTwist(twist); m_demod3.setTwist(twist + 3); + + m_slotTime = slotTime * 240U; // Slot time in samples + m_pPersist = pPersist; } +// Taken from https://www.electro-tech-online.com/threads/ultra-fast-pseudorandom-number-generator-for-8-bit.124249/ +//X ABC Algorithm Random Number Generator for 8-Bit Devices: +//This is a small PRNG, experimentally verified to have at least a 50 million byte period +//by generating 50 million bytes and observing that there were no overapping sequences and repeats. +//This generator passes serial correlation, entropy , Monte Carlo Pi value, arithmetic mean, +//And many other statistical tests. This generator may have a period of up to 2^32, but this has +//not been verified. +// +// By XORing 3 bytes into the a,b, and c registers, you can add in entropy from +//an external source easily. +// +//This generator is free to use, but is not suitable for cryptography due to its short period(by //cryptographic standards) and simple construction. No attempt was made to make this generator +// suitable for cryptographic use. +// +//Due to the use of a constant counter, the generator should be resistant to latching up. +//A significant performance gain is had in that the x variable is only ever incremented. +// +//Only 4 bytes of ram are needed for the internal state, and generating a byte requires 3 XORs , //2 ADDs, one bit shift right , and one increment. Difficult or slow operations like multiply, etc +//were avoided for maximum speed on ultra low power devices. + + +void CAX25RX::initRand() //Can also be used to seed the rng with more entropy during use. +{ + m_a = (m_a ^ m_c ^ m_x); + m_b = (m_b + m_a); + m_c = (m_c + (m_b >> 1) ^ m_a); +} + +uint8_t CAX25RX::rand() +{ + m_x++; //x is incremented every round and is not affected by any other variable + + m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR + m_b = (m_b + m_a); //And the use of very few instructions + m_c = (m_c + (m_b >> 1) ^ m_a); //the right shift is to ensure that high-order bits from b can affect + + return uint8_t(m_c); //low order bits of other variables +} diff --git a/AX25RX.h b/AX25RX.h index d6e55c3..49186d2 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -29,7 +29,9 @@ public: void samples(q15_t* samples, uint8_t length); - void setParams(int8_t twist); + void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist); + + bool canTX() const; private: arm_fir_instance_q15 m_filter; @@ -39,6 +41,17 @@ private: CAX25Demodulator m_demod3; uint16_t m_lastFCS; uint32_t m_count; + uint32_t m_slotTime; + uint32_t m_slotCount; + uint8_t m_pPersist; + bool m_canTX; + uint8_t m_x; + uint8_t m_a; + uint8_t m_b; + uint8_t m_c; + + void initRand(); + uint8_t rand(); }; #endif diff --git a/AX25TX.cpp b/AX25TX.cpp index fb3bd26..a5b6c95 100644 --- a/AX25TX.cpp +++ b/AX25TX.cpp @@ -63,6 +63,14 @@ void CAX25TX::process() if (m_poLen == 0U) return; + if (!m_duplex) { + if (m_poPtr == 0U) { + bool tx = ax25RX.canTX(); + if (!tx) + return; + } + } + uint16_t space = io.getSpace(); while (space > AX25_RADIO_SYMBOL_LENGTH) { diff --git a/SerialPort.cpp b/SerialPort.cpp index 2a3d209..e8d7812 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200630 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200701 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -282,7 +282,7 @@ void CSerialPort::getVersion() uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) { - if (length < 24U) + if (length < 26U) return 4U; bool rxInvert = (data[0U] & 0x01U) == 0x01U; @@ -362,6 +362,10 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) uint8_t ax25TXDelay = data[23U]; + uint8_t ax25SlotTime = data[24U]; + + uint8_t ax25PPersist = data[25U]; + setMode(modemState); m_dstarEnable = dstarEnable; @@ -391,7 +395,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) ysfTX.setParams(ysfLoDev, ysfTXHang); p25TX.setParams(p25TXHang); nxdnTX.setParams(nxdnTXHang); - ax25RX.setParams(ax25RXTwist); + ax25RX.setParams(ax25RXTwist, ax25SlotTime, ax25PPersist); io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset); From c99f50575d100fc835f407f587fa3830370d63f9 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 1 Jul 2020 13:02:14 +0100 Subject: [PATCH 128/139] Add a simpe simplex FM controller state machine. --- FM.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++-------------- FM.h | 31 ++++++----- 2 files changed, 142 insertions(+), 52 deletions(-) diff --git a/FM.cpp b/FM.cpp index 980b0fc..907ad5e 100644 --- a/FM.cpp +++ b/FM.cpp @@ -117,14 +117,24 @@ 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); + if (m_duplex) { + 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; + currentSample *= currentBoost; + } else { + currentSample = 0; + } } else { - currentSample = 0; + if (m_state == FS_RELAYING_EXT) { + currentSample *= currentBoost; + } else { + if (m_extEnabled && m_state == FS_RELAYING_RF) + m_downSampler.addSample(currentSample); + return; + } } if (!m_callsign.isRunning() && !m_extAck.isRunning()) @@ -281,43 +291,73 @@ uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t } void CFM::stateMachine(bool validRFSignal, bool validExtSignal) +{ + if (m_duplex) + duplexStateMachine(validRFSignal, validExtSignal); + else + simplexStateMachine(validRFSignal, validExtSignal); +} + +void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal) { switch (m_state) { case FS_LISTENING: - listeningState(validRFSignal, validExtSignal); - break; - case FS_KERCHUNK_RF: - kerchunkRFState(validRFSignal); + listeningStateSimplex(validRFSignal, validExtSignal); break; case FS_RELAYING_RF: - relayingRFState(validRFSignal); - break; - case FS_RELAYING_WAIT_RF: - relayingRFWaitState(validRFSignal); - break; - case FS_TIMEOUT_RF: - timeoutRFState(validRFSignal); - break; - case FS_TIMEOUT_WAIT_RF: - timeoutRFWaitState(validRFSignal); - break; - case FS_KERCHUNK_EXT: - kerchunkExtState(validExtSignal); + relayingRFStateSimplex(validRFSignal); break; case FS_RELAYING_EXT: - relayingExtState(validExtSignal); + relayingExtStateSimplex(validExtSignal); + break; + default: + break; + } + + if (m_state == FS_LISTENING) { + m_outputRFRB.reset(); + m_downSampler.reset(); + } +} + +void CFM::duplexStateMachine(bool validRFSignal, bool validExtSignal) +{ + switch (m_state) { + case FS_LISTENING: + listeningStateDuplex(validRFSignal, validExtSignal); + break; + case FS_KERCHUNK_RF: + kerchunkRFStateDuplex(validRFSignal); + break; + case FS_RELAYING_RF: + relayingRFStateDuplex(validRFSignal); + break; + case FS_RELAYING_WAIT_RF: + relayingRFWaitStateDuplex(validRFSignal); + break; + case FS_TIMEOUT_RF: + timeoutRFStateDuplex(validRFSignal); + break; + case FS_TIMEOUT_WAIT_RF: + timeoutRFWaitStateDuplex(validRFSignal); + break; + case FS_KERCHUNK_EXT: + kerchunkExtStateDuplex(validExtSignal); + break; + case FS_RELAYING_EXT: + relayingExtStateDuplex(validExtSignal); break; case FS_RELAYING_WAIT_EXT: - relayingExtWaitState(validExtSignal); + relayingExtWaitStateDuplex(validExtSignal); break; case FS_TIMEOUT_EXT: - timeoutExtState(validExtSignal); + timeoutExtStateDuplex(validExtSignal); break; case FS_TIMEOUT_WAIT_EXT: - timeoutExtWaitState(validExtSignal); + timeoutExtWaitStateDuplex(validExtSignal); break; case FS_HANG: - hangState(validRFSignal, validExtSignal); + hangStateDuplex(validRFSignal, validExtSignal); break; default: break; @@ -346,7 +386,7 @@ void CFM::clock(uint8_t length) } } -void CFM::listeningState(bool validRFSignal, bool validExtSignal) +void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal) { if (validRFSignal) { if (m_kerchunkTimer.getTimeout() > 0U) { @@ -402,7 +442,27 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal) } } -void CFM::kerchunkRFState(bool validSignal) +void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal) +{ + if (validRFSignal) { + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; + + io.setDecode(true); + io.setADCDetection(true); + + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } else if (validExtSignal) { + DEBUG1("State to RELAYING_EXT"); + m_state = FS_RELAYING_EXT; + + m_statusTimer.start(); + serial.writeFMStatus(m_state); + } +} + +void CFM::kerchunkRFStateDuplex(bool validSignal) { if (validSignal) { if (m_kerchunkTimer.hasExpired()) { @@ -444,7 +504,7 @@ void CFM::kerchunkRFState(bool validSignal) } } -void CFM::relayingRFState(bool validSignal) +void CFM::relayingRFStateDuplex(bool validSignal) { if (validSignal) { if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { @@ -475,7 +535,22 @@ void CFM::relayingRFState(bool validSignal) } } -void CFM::relayingRFWaitState(bool validSignal) +void CFM::relayingRFStateSimplex(bool validSignal) +{ + if (!validSignal) { + io.setDecode(false); + io.setADCDetection(false); + + DEBUG1("State to LISTENING"); + m_state = FS_LISTENING; + m_ackDelayTimer.start(); + + if (m_extEnabled) + serial.writeFMEOT(); + } +} + +void CFM::relayingRFWaitStateDuplex(bool validSignal) { if (validSignal) { io.setDecode(true); @@ -513,7 +588,7 @@ void CFM::relayingRFWaitState(bool validSignal) } } -void CFM::kerchunkExtState(bool validSignal) +void CFM::kerchunkExtStateDuplex(bool validSignal) { if (validSignal) { if (m_kerchunkTimer.hasExpired()) { @@ -546,7 +621,7 @@ void CFM::kerchunkExtState(bool validSignal) } } -void CFM::relayingExtState(bool validSignal) +void CFM::relayingExtStateDuplex(bool validSignal) { if (validSignal) { if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { @@ -568,7 +643,15 @@ void CFM::relayingExtState(bool validSignal) } } -void CFM::relayingExtWaitState(bool validSignal) +void CFM::relayingExtStateSimplex(bool validSignal) +{ + if (!validSignal) { + DEBUG1("State to LISTENING"); + m_state = FS_LISTENING; + } +} + +void CFM::relayingExtWaitStateDuplex(bool validSignal) { if (validSignal) { DEBUG1("State to RELAYING_EXT"); @@ -603,7 +686,7 @@ void CFM::relayingExtWaitState(bool validSignal) } } -void CFM::hangState(bool validRFSignal, bool validExtSignal) +void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal) { if (validRFSignal) { io.setDecode(true); @@ -643,7 +726,7 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal) } } -void CFM::timeoutRFState(bool validSignal) +void CFM::timeoutRFStateDuplex(bool validSignal) { if (!validSignal) { io.setDecode(false); @@ -664,7 +747,7 @@ void CFM::timeoutRFState(bool validSignal) } } -void CFM::timeoutRFWaitState(bool validSignal) +void CFM::timeoutRFWaitStateDuplex(bool validSignal) { if (validSignal) { io.setDecode(true); @@ -693,7 +776,7 @@ void CFM::timeoutRFWaitState(bool validSignal) } } -void CFM::timeoutExtState(bool validSignal) +void CFM::timeoutExtStateDuplex(bool validSignal) { if (!validSignal) { DEBUG1("State to TIMEOUT_WAIT_EXT"); @@ -707,7 +790,7 @@ void CFM::timeoutExtState(bool validSignal) } } -void CFM::timeoutExtWaitState(bool validSignal) +void CFM::timeoutExtWaitStateDuplex(bool validSignal) { if (validSignal) { DEBUG1("State to TIMEOUT_EXT"); diff --git a/FM.h b/FM.h index a6a37a8..58ca5a9 100644 --- a/FM.h +++ b/FM.h @@ -103,18 +103,25 @@ private: CFMUpSampler m_inputExtRB; 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 duplexStateMachine(bool validRFSignal, bool validExtSignal); + void listeningStateDuplex(bool validRFSignal, bool validExtSignal); + void kerchunkRFStateDuplex(bool validSignal); + void relayingRFStateDuplex(bool validSignal); + void relayingRFWaitStateDuplex(bool validSignal); + void timeoutRFStateDuplex(bool validSignal); + void timeoutRFWaitStateDuplex(bool validSignal); + void kerchunkExtStateDuplex(bool validSignal); + void relayingExtStateDuplex(bool validSignal); + void relayingExtWaitStateDuplex(bool validSignal); + void timeoutExtStateDuplex(bool validSignal); + void timeoutExtWaitStateDuplex(bool validSignal); + void hangStateDuplex(bool validRFSignal, bool validExtSignal); + + void simplexStateMachine(bool validRFSignal, bool validExtSignal); + void listeningStateSimplex(bool validRFSignal, bool validExtSignal); + void relayingRFStateSimplex(bool validSignal); + void relayingExtStateSimplex(bool validSignal); void clock(uint8_t length); From d5f2d1c382ed700220cb1e964c9d7e6b335f6e79 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 4 Jul 2020 12:15:33 +0200 Subject: [PATCH 129/139] Fix wrong frame type --- SerialPort.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPort.cpp b/SerialPort.cpp index e8d7812..70df849 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -1327,7 +1327,7 @@ void CSerialPort::writeFMData(const uint8_t* data, uint16_t length) writeInt(1U, reply, length + 4U); } else { reply[1U] = length + 3U; - reply[2U] = MMDVM_AX25_DATA; + reply[2U] = MMDVM_FM_DATA; for (uint8_t i = 0U; i < length; i++) reply[i + 3U] = data[i]; From f1d6a8b36ea036a86382c7d996d9c9831d04a979 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Jul 2020 10:03:48 +0100 Subject: [PATCH 130/139] Add DCD LED control. --- AX25Demodulator.cpp | 14 ++++++-------- AX25RX.cpp | 34 +++++++++++++++++++++++----------- AX25RX.h | 1 + 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index df3e13c..276a8e6 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -177,14 +177,12 @@ bool CAX25Demodulator::PLL(bool input) float32_t jitter; ::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U); - if (!m_duplex) { - float32_t absOffset = adjust; - if (offset < 0.0F) - absOffset -= offset; - else - absOffset += offset; - m_pllJitter = iir(absOffset); - } + float32_t absOffset = adjust; + if (offset < 0.0F) + absOffset -= offset; + else + absOffset += offset; + m_pllJitter = iir(absOffset); m_pllCount -= jitter / 2.0F; m_pllBits = 1U; diff --git a/AX25RX.cpp b/AX25RX.cpp index 4836701..093316b 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -69,6 +69,7 @@ m_count(0U), m_slotTime(30U), m_slotCount(0U), m_pPersist(128U), +m_dcd(false), m_canTX(false), m_x(1U), m_a(0xB7U), @@ -121,19 +122,30 @@ void CAX25RX::samples(q15_t* samples, uint8_t length) DEBUG1("Decoder 3 reported"); } - if (!m_duplex) { - m_slotCount += RX_BLOCK_SIZE; - if (m_slotCount >= m_slotTime) { - m_slotCount = 0U; + m_slotCount += RX_BLOCK_SIZE; + if (m_slotCount >= m_slotTime) { + m_slotCount = 0U; - bool dcd1 = m_demod1.isDCD(); - bool dcd2 = m_demod2.isDCD(); - bool dcd3 = m_demod3.isDCD(); + bool dcd1 = m_demod1.isDCD(); + bool dcd2 = m_demod2.isDCD(); + bool dcd3 = m_demod3.isDCD(); - if (dcd1 || dcd2 || dcd3) - m_canTX = false; - else - m_canTX = m_pPersist >= rand(); + if (dcd1 || dcd2 || dcd3) { + if (!m_dcd) { + io.setDecode(true); + io.setADCDetection(true); + m_dcd = true; + } + + m_canTX = false; + } else { + if (m_dcd) { + io.setDecode(false); + io.setADCDetection(false); + m_dcd = false; + } + + m_canTX = m_pPersist >= rand(); } } } diff --git a/AX25RX.h b/AX25RX.h index 49186d2..cbafe91 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -44,6 +44,7 @@ private: uint32_t m_slotTime; uint32_t m_slotCount; uint8_t m_pPersist; + bool m_dcd; bool m_canTX; uint8_t m_x; uint8_t m_a; From aab8f5469f6e6e8555ac3a91d07804b8a3803232 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Jul 2020 10:56:35 +0100 Subject: [PATCH 131/139] Add timeouts to the FM simplex state machine. --- FM.cpp | 149 +++++++++++++++++++++++++++++++++++++++++++++++-- FM.h | 6 ++ SerialPort.cpp | 2 +- 3 files changed, 150 insertions(+), 7 deletions(-) diff --git a/FM.cpp b/FM.cpp index 907ad5e..5bed1f1 100644 --- a/FM.cpp +++ b/FM.cpp @@ -307,9 +307,27 @@ void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal) case FS_RELAYING_RF: relayingRFStateSimplex(validRFSignal); break; + case FS_RELAYING_WAIT_RF: + relayingRFWaitStateSimplex(validRFSignal); + break; + case FS_TIMEOUT_RF: + timeoutRFStateSimplex(validRFSignal); + break; + case FS_TIMEOUT_WAIT_RF: + timeoutRFStateSimplex(validRFSignal); + break; case FS_RELAYING_EXT: relayingExtStateSimplex(validExtSignal); break; + case FS_RELAYING_WAIT_EXT: + relayingExtWaitStateSimplex(validExtSignal); + break; + case FS_TIMEOUT_EXT: + timeoutExtStateSimplex(validExtSignal); + break; + case FS_TIMEOUT_WAIT_EXT: + timeoutExtWaitStateSimplex(validExtSignal); + break; default: break; } @@ -451,12 +469,18 @@ void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal) io.setDecode(true); io.setADCDetection(true); + m_timeoutTimer.start(); + m_statusTimer.start(); serial.writeFMStatus(m_state); } else if (validExtSignal) { DEBUG1("State to RELAYING_EXT"); m_state = FS_RELAYING_EXT; + insertSilence(50U); + + m_timeoutTimer.start(); + m_statusTimer.start(); serial.writeFMStatus(m_state); } @@ -537,12 +561,22 @@ void CFM::relayingRFStateDuplex(bool validSignal) void CFM::relayingRFStateSimplex(bool validSignal) { - if (!validSignal) { + if (validSignal) { + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { + DEBUG1("State to TIMEOUT_RF"); + m_state = FS_TIMEOUT_RF; + + m_timeoutTimer.stop(); + + if (m_extEnabled) + serial.writeFMEOT(); + } + } else { io.setDecode(false); io.setADCDetection(false); - DEBUG1("State to LISTENING"); - m_state = FS_LISTENING; + DEBUG1("State to RELAYING_WAIT_RF"); + m_state = FS_RELAYING_WAIT_RF; m_ackDelayTimer.start(); if (m_extEnabled) @@ -588,6 +622,26 @@ void CFM::relayingRFWaitStateDuplex(bool validSignal) } } +void CFM::relayingRFWaitStateSimplex(bool validSignal) +{ + if (validSignal) { + io.setDecode(true); + io.setADCDetection(true); + + DEBUG1("State to RELAYING_RF"); + m_state = FS_RELAYING_RF; + m_ackDelayTimer.stop(); + } else { + if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { + DEBUG1("State to LISTENING"); + m_state = FS_LISTENING; + + m_ackDelayTimer.stop(); + m_timeoutTimer.stop(); + } + } +} + void CFM::kerchunkExtStateDuplex(bool validSignal) { if (validSignal) { @@ -645,9 +699,17 @@ void CFM::relayingExtStateDuplex(bool validSignal) void CFM::relayingExtStateSimplex(bool validSignal) { - if (!validSignal) { - DEBUG1("State to LISTENING"); - m_state = FS_LISTENING; + if (validSignal) { + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { + DEBUG1("State to TIMEOUT_EXT"); + m_state = FS_TIMEOUT_EXT; + + m_timeoutTimer.stop(); + } + } else { + DEBUG1("State to RELAYING_WAIT_EXT"); + m_state = FS_RELAYING_WAIT_EXT; + m_ackDelayTimer.start(); } } @@ -686,6 +748,23 @@ void CFM::relayingExtWaitStateDuplex(bool validSignal) } } +void CFM::relayingExtWaitStateSimplex(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 LISTENING"); + m_state = FS_LISTENING; + + m_ackDelayTimer.stop(); + m_timeoutTimer.stop(); + } + } +} + void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal) { if (validRFSignal) { @@ -747,6 +826,19 @@ void CFM::timeoutRFStateDuplex(bool validSignal) } } +void CFM::timeoutRFStateSimplex(bool validSignal) +{ + if (!validSignal) { + io.setDecode(false); + io.setADCDetection(false); + + DEBUG1("State to TIMEOUT_WAIT_RF"); + m_state = FS_TIMEOUT_WAIT_RF; + + m_ackDelayTimer.start(); + } +} + void CFM::timeoutRFWaitStateDuplex(bool validSignal) { if (validSignal) { @@ -776,6 +868,25 @@ void CFM::timeoutRFWaitStateDuplex(bool validSignal) } } +void CFM::timeoutRFWaitStateSimplex(bool validSignal) +{ + if (validSignal) { + io.setDecode(true); + io.setADCDetection(true); + + DEBUG1("State to TIMEOUT_RF"); + m_state = FS_TIMEOUT_RF; + m_ackDelayTimer.stop(); + } else { + if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { + DEBUG1("State to LISTENING"); + m_state = FS_LISTENING; + m_ackDelayTimer.stop(); + m_timeoutTimer.stop(); + } + } +} + void CFM::timeoutExtStateDuplex(bool validSignal) { if (!validSignal) { @@ -790,6 +901,15 @@ void CFM::timeoutExtStateDuplex(bool validSignal) } } +void CFM::timeoutExtStateSimplex(bool validSignal) +{ + if (!validSignal) { + DEBUG1("State to TIMEOUT_WAIT_EXT"); + m_state = FS_TIMEOUT_WAIT_EXT; + m_ackDelayTimer.start(); + } +} + void CFM::timeoutExtWaitStateDuplex(bool validSignal) { if (validSignal) { @@ -815,6 +935,23 @@ void CFM::timeoutExtWaitStateDuplex(bool validSignal) m_callsignTimer.start(); } } + +void CFM::timeoutExtWaitStateSimplex(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 LISTENING"); + m_state = FS_LISTENING; + m_ackDelayTimer.stop(); + m_timeoutTimer.stop(); + } + } +} + void CFM::sendCallsign() { if (m_holdoffTimer.isRunning()) { diff --git a/FM.h b/FM.h index 58ca5a9..8dcaa4a 100644 --- a/FM.h +++ b/FM.h @@ -121,7 +121,13 @@ private: void simplexStateMachine(bool validRFSignal, bool validExtSignal); void listeningStateSimplex(bool validRFSignal, bool validExtSignal); void relayingRFStateSimplex(bool validSignal); + void relayingRFWaitStateSimplex(bool validSignal); + void timeoutRFStateSimplex(bool validSignal); + void timeoutRFWaitStateSimplex(bool validSignal); void relayingExtStateSimplex(bool validSignal); + void relayingExtWaitStateSimplex(bool validSignal); + void timeoutExtStateSimplex(bool validSignal); + void timeoutExtWaitStateSimplex(bool validSignal); void clock(uint8_t length); diff --git a/SerialPort.cpp b/SerialPort.cpp index 70df849..9e657e4 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200701 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200706 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From ad77fd60fd8b59a94cbb2be612af2c41c9415a1a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 7 Jul 2020 17:57:31 +0100 Subject: [PATCH 132/139] Remove KerchunkTX. --- FM.cpp | 31 +++---------------------------- FM.h | 3 +-- SerialPort.cpp | 5 ++--- 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/FM.cpp b/FM.cpp index 5bed1f1..655c467 100644 --- a/FM.cpp +++ b/FM.cpp @@ -41,7 +41,6 @@ m_callsignTimer(), m_timeoutTimer(), m_holdoffTimer(), m_kerchunkTimer(), -m_kerchunkTX(true), m_ackMinTimer(), m_ackDelayTimer(), m_hangTimer(), @@ -255,7 +254,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, bool kerchunkTX, 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, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel) { m_useCOS = useCOS; m_cosInvert = cosInvert; @@ -265,7 +264,6 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque m_timeoutTimer.setTimeout(timeout, 0U); m_kerchunkTimer.setTimeout(kerchunkTime, 0U); - m_kerchunkTX = kerchunkTX; m_hangTimer.setTimeout(hangTime, 0U); @@ -420,7 +418,7 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal) sendCallsign(); } - if (m_state == FS_RELAYING_RF || (m_state == FS_KERCHUNK_RF && m_kerchunkTX)) { + if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF) { insertSilence(50U); beginRelaying(); @@ -447,7 +445,7 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal) sendCallsign(); } - if (m_state == FS_RELAYING_EXT || (m_state == FS_KERCHUNK_EXT && m_kerchunkTX)) { + if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) { insertSilence(50U); beginRelaying(); @@ -493,19 +491,6 @@ void CFM::kerchunkRFStateDuplex(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(); @@ -649,16 +634,6 @@ void CFM::kerchunkExtStateDuplex(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 8dcaa4a..12c7d67 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, bool kerchunkTX, 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, 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,7 +82,6 @@ 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 9e657e4..04487b0 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200706 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200707 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -467,13 +467,12 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_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, kerchunkTX, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); + return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel); } uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint16_t length) From d8f138066ea28ac33e4a9a405a67f7c8f607fe4c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 28 Jul 2020 13:55:50 +0100 Subject: [PATCH 133/139] Add an experimental noise squelch. --- FM.cpp | 17 +++++-- FM.h | 5 +- FMNoiseSquelch.cpp | 112 +++++++++++++++++++++++++++++++++++++++++++++ FMNoiseSquelch.h | 52 +++++++++++++++++++++ SerialPort.cpp | 10 ++-- 5 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 FMNoiseSquelch.cpp create mode 100644 FMNoiseSquelch.h diff --git a/FM.cpp b/FM.cpp index 09b0e9a..52aa742 100644 --- a/FM.cpp +++ b/FM.cpp @@ -39,6 +39,7 @@ m_rfAck(), m_extAck(), m_ctcssRX(), m_ctcssTX(), +m_squelch(), m_timeoutTone(), m_state(FS_LISTENING), m_callsignAtStart(false), @@ -60,6 +61,7 @@ m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460), m_blanking(), m_accessMode(1U), m_cosInvert(false), +m_noiseSquelch(false), m_rfAudioBoost(1U), m_extAudioBoost(1U), m_downSampler(400U),// 100 ms of audio @@ -87,6 +89,11 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) // ARMv7-M has hardware integer division q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel); + if (m_noiseSquelch) { + uint8_t squelchState = m_squelch.process(currentRFSample); + cos = NSQ_VALID(squelchState); + } + q15_t currentExtSample; bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow inputExt = inputExt && m_extEnabled; @@ -281,6 +288,7 @@ void CFM::reset() m_inputExtRB.reset(); m_downSampler.reset(); + m_squelch.reset(); m_needReverse = false; } @@ -313,10 +321,11 @@ 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, uint8_t accessMode, 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, uint8_t hangTime, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel) { - m_accessMode = accessMode; - m_cosInvert = cosInvert; + m_accessMode = accessMode; + m_cosInvert = cosInvert; + m_noiseSquelch = noiseSquelch; m_rfAudioBoost = q15_t(rfAudioBoost); @@ -331,6 +340,8 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque m_rxLevel = rxLevel; //q15_t(255)/q15_t(rxLevel >> 1); + m_squelch.setParams(squelchHighThreshold, squelchLowThreshold); + uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold); if (ret != 0U) return ret; diff --git a/FM.h b/FM.h index 2b269a7..2ead4a3 100644 --- a/FM.h +++ b/FM.h @@ -31,6 +31,7 @@ #include "FMDirectForm1.h" #include "FMDownSampler.h" #include "FMUpSampler.h" +#include "FMNoiseSquelch.h" enum FM_STATE { FS_LISTENING, @@ -60,7 +61,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, uint8_t accessMode, 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, uint8_t hangTime, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, 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; @@ -73,6 +74,7 @@ private: CFMKeyer m_extAck; CFMCTCSSRX m_ctcssRX; CFMCTCSSTX m_ctcssTX; + CFMNoiseSquelch m_squelch; CFMTimeout m_timeoutTone; FM_STATE m_state; bool m_callsignAtStart; @@ -94,6 +96,7 @@ private: CFMBlanking m_blanking; uint8_t m_accessMode; bool m_cosInvert; + bool m_noiseSquelch; q15_t m_rfAudioBoost; q15_t m_extAudioBoost; CFMDownSampler m_downSampler; diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp new file mode 100644 index 0000000..1f65fea --- /dev/null +++ b/FMNoiseSquelch.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "FMNoiseSquelch.h" + +// 4500Hz centre frequency +const q31_t COEFF_DIV_TWO = 821806413; + +// 400Hz bandwidth +const uint16_t N = 24000U / 400U; + +CFMNoiseSquelch::CFMNoiseSquelch() : +m_highThreshold(0), +m_lowThreshold(0), +m_count(0U), +m_q0(0), +m_q1(0), +m_result(NS_NONE) +{ +} + +void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold) +{ + m_highThreshold = q31_t(highThreshold); + m_lowThreshold = q31_t(lowThreshold); +} + +uint8_t CFMNoiseSquelch::process(q15_t sample) +{ + //get more dynamic into the decoder by multiplying the sample by 1.5 + q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1); + + m_result &= ~NS_READY; + + q31_t q2 = m_q1; + m_q1 = m_q0; + + // Q31 multiplication, t3 = m_coeffDivTwo * 2 * m_q1 + q63_t t1 = COEFF_DIV_TWO * m_q1; + q31_t t2 = __SSAT((t1 >> 31), 31); + q31_t t3 = t2 * 2; + + // m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample + m_q0 = t3 - q2 + sample31; + + m_count++; + if (m_count == N) { + // Q31 multiplication, t2 = m_q0 * m_q0 + q63_t t1 = q63_t(m_q0) * q63_t(m_q0); + q31_t t2 = __SSAT((t1 >> 31), 31); + + // Q31 multiplication, t4 = m_q0 * m_q0 + q63_t t3 = q63_t(m_q1) * q63_t(m_q1); + q31_t t4 = __SSAT((t3 >> 31), 31); + + // Q31 multiplication, t9 = m_q0 * m_q1 * m_coeffDivTwo * 2 + q63_t t5 = q63_t(m_q0) * q63_t(m_q1); + q31_t t6 = __SSAT((t5 >> 31), 31); + q63_t t7 = t6 * COEFF_DIV_TWO; + q31_t t8 = __SSAT((t7 >> 31), 31); + q31_t t9 = t8 * 2; + + // value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2 + q31_t value = t2 + t4 - t9; + + bool previousNSQValid = NSQ_VALID(m_result); + + q31_t threshold = m_highThreshold; + if (previousNSQValid) + threshold = m_lowThreshold; + + m_result |= NS_READY; + if (value >= threshold) + m_result |= NS_VALID; + else + m_result &= ~NS_VALID; + + if (previousNSQValid != NSQ_VALID(m_result)) + DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, NSQ_VALID(m_result)); + + m_count = 0U; + m_q0 = 0; + m_q1 = 0; + } + + return m_result; +} + +void CFMNoiseSquelch::reset() +{ + m_q0 = 0; + m_q1 = 0; + m_result = NS_NONE; + m_count = 0U; +} diff --git a/FMNoiseSquelch.h b/FMNoiseSquelch.h new file mode 100644 index 0000000..a17f7a2 --- /dev/null +++ b/FMNoiseSquelch.h @@ -0,0 +1,52 @@ +/* + * 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(FMNOISESQUELCH_H) +#define FMNOISESQUELCH_H + +#include "Config.h" + +const uint8_t NS_NONE = 0U; +const uint8_t NS_READY = 1U; +const uint8_t NS_VALID = 2U; + +#define NSQ_READY(a) ((a & NS_READY) != 0) +#define NSQ_NOT_READY(a) ((a & NS_READY) == 0) +#define NSQ_VALID(a) ((a & NS_VALID) != 0) +#define NSQ_NOT_VALID(a) ((a & NS_VALID) == 0) + +class CFMNoiseSquelch { +public: + CFMNoiseSquelch(); + + void setParams(uint8_t highThreshold, uint8_t lowThreshold); + + uint8_t process(q15_t sample); + + void reset(); + +private: + q31_t m_highThreshold; + q31_t m_lowThreshold; + uint16_t m_count; + q31_t m_q0; + q31_t m_q1; + uint8_t m_result; +}; + +#endif diff --git a/SerialPort.cpp b/SerialPort.cpp index b6a7cef..c61d883 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200714 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200728 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" @@ -452,7 +452,7 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint16_t length) uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length) { - if (length < 12U) + if (length < 14U) return 4U; uint16_t timeout = data[0U] * 5U; @@ -467,13 +467,17 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length) uint8_t hangTime = data[7U]; uint8_t accessMode = data[8U] & 0x7FU; + bool noiseSquelch = (data[8U] & 0x40U) == 0x40U; bool cosInvert = (data[8U] & 0x80U) == 0x80U; 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, accessMode, cosInvert, rfAudioBoost, maxDev, rxLevel); + uint8_t squelchHighThreshold = data[12U]; + uint8_t squelchLowThreshold = data[13U]; + + return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, noiseSquelch, squelchHighThreshold, squelchLowThreshold, rfAudioBoost, maxDev, rxLevel); } uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint16_t length) From b5ba38449549b9610c38364142ab7142ce5450e8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 28 Jul 2020 14:24:51 +0100 Subject: [PATCH 134/139] Fix a couple of minor bugs. --- FMNoiseSquelch.cpp | 2 +- SerialPort.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp index 1f65fea..06bbccb 100644 --- a/FMNoiseSquelch.cpp +++ b/FMNoiseSquelch.cpp @@ -87,7 +87,7 @@ uint8_t CFMNoiseSquelch::process(q15_t sample) threshold = m_lowThreshold; m_result |= NS_READY; - if (value >= threshold) + if (value < threshold) m_result |= NS_VALID; else m_result &= ~NS_VALID; diff --git a/SerialPort.cpp b/SerialPort.cpp index c61d883..0b9111c 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -466,7 +466,7 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length) uint8_t kerchunkTime = data[6U]; uint8_t hangTime = data[7U]; - uint8_t accessMode = data[8U] & 0x7FU; + uint8_t accessMode = data[8U] & 0x0FU; bool noiseSquelch = (data[8U] & 0x40U) == 0x40U; bool cosInvert = (data[8U] & 0x80U) == 0x80U; From 2a001f491d8cab387c3b78be1666acd14c1b250c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 31 Jul 2020 09:20:55 +0100 Subject: [PATCH 135/139] Simplify the CTCSS and Noise Squelch decoders and logic. --- FM.cpp | 69 +++++++++++++++++++++------------------------- FMCTCSSRX.cpp | 26 +++++++---------- FMCTCSSRX.h | 13 ++------- FMNoiseSquelch.cpp | 30 ++++++++------------ FMNoiseSquelch.h | 13 ++------- SerialPort.cpp | 2 +- 6 files changed, 58 insertions(+), 95 deletions(-) diff --git a/FM.cpp b/FM.cpp index 52aa742..787206b 100644 --- a/FM.cpp +++ b/FM.cpp @@ -89,10 +89,8 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) // ARMv7-M has hardware integer division q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel); - if (m_noiseSquelch) { - uint8_t squelchState = m_squelch.process(currentRFSample); - cos = NSQ_VALID(squelchState); - } + if (m_noiseSquelch) + cos = m_squelch.process(currentRFSample); q15_t currentExtSample; bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow @@ -107,55 +105,50 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length) break; case 1U: { - uint8_t ctcssState = m_ctcssRX.process(currentRFSample); + bool ctcss = 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 (!inputExt && CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) { - // Not enough samples to determine if you have CTCSS, just carry on + if (!inputExt && !ctcss && m_modemState != STATE_FM) { + // No CTCSS detected, just carry on 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 - bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS, inputExt); - if (m_state == FS_LISTENING) - continue; - } else { - bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS, inputExt); - } - } - break; - - case 2U: { - uint8_t ctcssState = m_ctcssRX.process(currentRFSample); - 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 ((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) && m_modemState != STATE_FM) { + // We had CTCSS or external input + stateMachine(ctcss, inputExt); if (m_state == FS_LISTENING) continue; } else { - bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos, inputExt); + stateMachine(ctcss, inputExt); + } + } + break; + + case 2U: { + bool ctcss = m_ctcssRX.process(currentRFSample); + if (!inputExt && !ctcss && m_modemState != STATE_FM) { + // No CTCSS detected, just carry on + continue; + } else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) { + // We had CTCSS or external input + stateMachine(ctcss && cos, inputExt); + if (m_state == FS_LISTENING) + continue; + } else { + stateMachine(ctcss && cos, inputExt); } } break; default: { - uint8_t ctcssState = m_ctcssRX.process(currentRFSample); - if (!inputExt && CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) { - // Not enough samples to determine if you have CTCSS, just carry on + bool ctcss = m_ctcssRX.process(currentRFSample); + if (!inputExt && !ctcss && m_modemState != STATE_FM) { + // No CTCSS detected, just carry on 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 - bool validCTCSS = CTCSS_VALID(ctcssState); - stateMachine(validCTCSS && cos, inputExt); + } else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) { + // We had CTCSS or external input + stateMachine(ctcss && cos, inputExt); if (m_state == FS_LISTENING) continue; } else { diff --git a/FMCTCSSRX.cpp b/FMCTCSSRX.cpp index e88ff98..b2ecb43 100644 --- a/FMCTCSSRX.cpp +++ b/FMCTCSSRX.cpp @@ -87,7 +87,7 @@ m_lowThreshold(0), m_count(0U), m_q0(0), m_q1(0), -m_result(CTS_NONE) +m_state(false) { } @@ -111,13 +111,11 @@ uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t highThreshold, uint8_t return 0U; } -uint8_t CFMCTCSSRX::process(q15_t sample) +bool CFMCTCSSRX::process(q15_t sample) { //get more dynamic into the decoder by multiplying the sample by 1.5 q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1); - m_result &= ~CTS_READY; - q31_t q2 = m_q1; m_q1 = m_q0; @@ -149,33 +147,29 @@ uint8_t CFMCTCSSRX::process(q15_t sample) // value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2 q31_t value = t2 + t4 - t9; - bool previousCTCSSValid = CTCSS_VALID(m_result); + bool previousState = m_state; q31_t threshold = m_highThreshold; - if (previousCTCSSValid) + if (previousState) threshold = m_lowThreshold; - m_result |= CTS_READY; - if (value >= threshold) - m_result |= CTS_VALID; - else - m_result &= ~CTS_VALID; + m_state = value >= threshold; - if (previousCTCSSValid != CTCSS_VALID(m_result)) - DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, CTCSS_VALID(m_result)); + if (previousState != m_state) + DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, m_state); m_count = 0U; m_q0 = 0; m_q1 = 0; } - return m_result; + return m_state; } void CFMCTCSSRX::reset() { m_q0 = 0; m_q1 = 0; - m_result = CTS_NONE; - m_count = 0U; + m_state = false; + m_count = 0U; } diff --git a/FMCTCSSRX.h b/FMCTCSSRX.h index eed82de..0980c4c 100644 --- a/FMCTCSSRX.h +++ b/FMCTCSSRX.h @@ -21,22 +21,13 @@ #include "Config.h" -const uint8_t CTS_NONE = 0U; -const uint8_t CTS_READY = 1U; -const uint8_t CTS_VALID = 2U; - -#define CTCSS_READY(a) ((a & CTS_READY) != 0) -#define CTCSS_NOT_READY(a) ((a & CTS_READY) == 0) -#define CTCSS_VALID(a) ((a & CTS_VALID) != 0) -#define CTCSS_NOT_VALID(a) ((a & CTS_VALID) == 0) - class CFMCTCSSRX { public: CFMCTCSSRX(); uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold); - uint8_t process(q15_t sample); + bool process(q15_t sample); void reset(); @@ -47,7 +38,7 @@ private: uint16_t m_count; q31_t m_q0; q31_t m_q1; - uint8_t m_result; + bool m_state; }; #endif diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp index 06bbccb..3f94cfd 100644 --- a/FMNoiseSquelch.cpp +++ b/FMNoiseSquelch.cpp @@ -32,23 +32,21 @@ m_lowThreshold(0), m_count(0U), m_q0(0), m_q1(0), -m_result(NS_NONE) +m_state(false) { } void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold) { - m_highThreshold = q31_t(highThreshold); - m_lowThreshold = q31_t(lowThreshold); + m_highThreshold = q31_t(highThreshold) * 20; + m_lowThreshold = q31_t(lowThreshold) * 20; } -uint8_t CFMNoiseSquelch::process(q15_t sample) +bool CFMNoiseSquelch::process(q15_t sample) { //get more dynamic into the decoder by multiplying the sample by 1.5 q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1); - m_result &= ~NS_READY; - q31_t q2 = m_q1; m_q1 = m_q0; @@ -80,33 +78,29 @@ uint8_t CFMNoiseSquelch::process(q15_t sample) // value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2 q31_t value = t2 + t4 - t9; - bool previousNSQValid = NSQ_VALID(m_result); + bool previousState = m_state; q31_t threshold = m_highThreshold; - if (previousNSQValid) + if (previousState) threshold = m_lowThreshold; - m_result |= NS_READY; - if (value < threshold) - m_result |= NS_VALID; - else - m_result &= ~NS_VALID; + m_state = value < threshold; - if (previousNSQValid != NSQ_VALID(m_result)) - DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, NSQ_VALID(m_result)); + if (previousState != m_state) + DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, m_state); m_count = 0U; m_q0 = 0; m_q1 = 0; } - return m_result; + return m_state; } void CFMNoiseSquelch::reset() { m_q0 = 0; m_q1 = 0; - m_result = NS_NONE; - m_count = 0U; + m_state = false; + m_count = 0U; } diff --git a/FMNoiseSquelch.h b/FMNoiseSquelch.h index a17f7a2..57ee5eb 100644 --- a/FMNoiseSquelch.h +++ b/FMNoiseSquelch.h @@ -21,22 +21,13 @@ #include "Config.h" -const uint8_t NS_NONE = 0U; -const uint8_t NS_READY = 1U; -const uint8_t NS_VALID = 2U; - -#define NSQ_READY(a) ((a & NS_READY) != 0) -#define NSQ_NOT_READY(a) ((a & NS_READY) == 0) -#define NSQ_VALID(a) ((a & NS_VALID) != 0) -#define NSQ_NOT_VALID(a) ((a & NS_VALID) == 0) - class CFMNoiseSquelch { public: CFMNoiseSquelch(); void setParams(uint8_t highThreshold, uint8_t lowThreshold); - uint8_t process(q15_t sample); + bool process(q15_t sample); void reset(); @@ -46,7 +37,7 @@ private: uint16_t m_count; q31_t m_q0; q31_t m_q1; - uint8_t m_result; + bool m_state; }; #endif diff --git a/SerialPort.cpp b/SerialPort.cpp index 0b9111c..1314f56 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U; #define HW_TYPE "MMDVM" #endif -#define DESCRIPTION "20200728 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" +#define DESCRIPTION "20200731 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #if defined(GITVERSION) #define concat(h, a, b, c) h " " a " " b " GitID #" c "" From 252d54a484b65116ef4da15edc4a23340ad4a814 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Aug 2020 21:11:32 +0200 Subject: [PATCH 136/139] Add some delay to squelch --- FMNoiseSquelch.cpp | 36 ++++++++++++++++++++++++++++++------ FMNoiseSquelch.h | 2 ++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp index 3f94cfd..fe018fd 100644 --- a/FMNoiseSquelch.cpp +++ b/FMNoiseSquelch.cpp @@ -26,26 +26,31 @@ const q31_t COEFF_DIV_TWO = 821806413; // 400Hz bandwidth const uint16_t N = 24000U / 400U; +//const q63_t ALPHA = 1073741824; //0.5 as q31 but stored in a q64 to avoid overflow +const q63_t ALPHA = 536870912; //0.25 as q31 but stored in a q64 to avoid overflow + CFMNoiseSquelch::CFMNoiseSquelch() : m_highThreshold(0), m_lowThreshold(0), m_count(0U), m_q0(0), m_q1(0), -m_state(false) +m_state(false), +m_validCount(0U) { + } void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold) { - m_highThreshold = q31_t(highThreshold) * 20; - m_lowThreshold = q31_t(lowThreshold) * 20; + m_highThreshold = q31_t(highThreshold); + m_lowThreshold = q31_t(lowThreshold); } bool CFMNoiseSquelch::process(q15_t sample) { //get more dynamic into the decoder by multiplying the sample by 1.5 - q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1); + q31_t sample31 = q31_t(sample) << 6; //+ (q31_t(sample) >> 1); q31_t q2 = m_q1; m_q1 = m_q0; @@ -84,10 +89,29 @@ bool CFMNoiseSquelch::process(q15_t sample) if (previousState) threshold = m_lowThreshold; - m_state = value < threshold; + if (!m_state) { + if (value < threshold) + m_validCount++; + else + m_validCount = 0U; + } - if (previousState != m_state) + if (m_state) { + if (value >= threshold) + m_invalidCount++; + else + m_invalidCount = 0U; + } + + m_state = m_validCount >= 10U && m_invalidCount < 10U; + + if(previousState && !m_state) + m_invalidCount = 0U; + + if (previousState != m_state) { DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, m_state); + DEBUG3("Valid Count / Invalid Count", m_validCount, m_invalidCount); + } m_count = 0U; m_q0 = 0; diff --git a/FMNoiseSquelch.h b/FMNoiseSquelch.h index 57ee5eb..c4f5a62 100644 --- a/FMNoiseSquelch.h +++ b/FMNoiseSquelch.h @@ -38,6 +38,8 @@ private: q31_t m_q0; q31_t m_q1; bool m_state; + uint8_t m_validCount; + uint8_t m_invalidCount; }; #endif From b2111553c690bcfd058951c9aabe5799fca91195 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Aug 2020 21:15:03 +0200 Subject: [PATCH 137/139] Correct comment --- FMNoiseSquelch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp index fe018fd..604efe3 100644 --- a/FMNoiseSquelch.cpp +++ b/FMNoiseSquelch.cpp @@ -49,7 +49,7 @@ void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold) bool CFMNoiseSquelch::process(q15_t sample) { - //get more dynamic into the decoder by multiplying the sample by 1.5 + //get more dynamic into the decoder by multiplying the sample by 64 q31_t sample31 = q31_t(sample) << 6; //+ (q31_t(sample) >> 1); q31_t q2 = m_q1; From 625ec93af8e9fd23f83d60c8f773f2d0fa4f5d87 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Aug 2020 21:17:05 +0200 Subject: [PATCH 138/139] Remove unused variable --- FMNoiseSquelch.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/FMNoiseSquelch.cpp b/FMNoiseSquelch.cpp index 604efe3..6becf99 100644 --- a/FMNoiseSquelch.cpp +++ b/FMNoiseSquelch.cpp @@ -26,9 +26,6 @@ const q31_t COEFF_DIV_TWO = 821806413; // 400Hz bandwidth const uint16_t N = 24000U / 400U; -//const q63_t ALPHA = 1073741824; //0.5 as q31 but stored in a q64 to avoid overflow -const q63_t ALPHA = 536870912; //0.25 as q31 but stored in a q64 to avoid overflow - CFMNoiseSquelch::CFMNoiseSquelch() : m_highThreshold(0), m_lowThreshold(0), From b6093406adc7038a34c184031aed3da91e94b4cb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 11 Aug 2020 16:39:19 +0100 Subject: [PATCH 139/139] Fix missing AX25 class definition. --- MMDVM.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MMDVM.ino b/MMDVM.ino index 5785e15..255a876 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -60,7 +60,7 @@ CPOCSAGTX pocsagTX; CFM fm; CAX25RX ax25RX; -CAX25 ax25TX; +CAX25TX ax25TX; CCalDStarRX calDStarRX; CCalDStarTX calDStarTX;