Merge branch 'AX25' into AX25_FM

This commit is contained in:
Jonathan Naylor 2020-07-15 10:42:43 +01:00
commit 9ff59570c7
8 changed files with 151 additions and 65 deletions

View File

@ -93,3 +93,4 @@
#define USE_ALTERNATE_FM_LEDS #define USE_ALTERNATE_FM_LEDS
#endif #endif

143
FM.cpp
View File

@ -20,12 +20,19 @@
#include "Globals.h" #include "Globals.h"
#include "FM.h" #include "FM.h"
const uint16_t FM_TX_BLOCK_SIZE = 100U; const uint16_t FM_TX_BLOCK_SIZE = 100U;
const uint16_t FM_SERIAL_BLOCK_SIZE = 84U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes. 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 //three times this value shall never exceed 252
const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U; const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U;
/*
* Access Mode values are:
* 0 - Carrier access with COS
* 1 - CTCSS only access without COS
* 2 - CTCSS only access with COS
* 3 - CTCSS only access with COS to start, then carrier access with COS
*/
CFM::CFM() : CFM::CFM() :
m_callsign(), m_callsign(),
m_rfAck(), m_rfAck(),
@ -45,11 +52,13 @@ m_ackMinTimer(),
m_ackDelayTimer(), m_ackDelayTimer(),
m_hangTimer(), m_hangTimer(),
m_statusTimer(), m_statusTimer(),
m_reverseTimer(),
m_needReverse(false),
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz 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_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460), m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
m_blanking(), m_blanking(),
m_useCOS(true), m_accessMode(1U),
m_cosInvert(false), m_cosInvert(false),
m_rfAudioBoost(1U), m_rfAudioBoost(1U),
m_extAudioBoost(1U), m_extAudioBoost(1U),
@ -61,18 +70,15 @@ m_outputRFRB(2400U), // 100ms of audio
m_inputExtRB() m_inputExtRB()
{ {
m_statusTimer.setTimeout(1U, 0U); m_statusTimer.setTimeout(1U, 0U);
m_reverseTimer.setTimeout(0U, 150U);
insertDelay(100U); insertDelay(100U);
} }
void CFM::samples(bool cos, q15_t* samples, uint8_t length) void CFM::samples(bool cos, q15_t* samples, uint8_t length)
{ {
if (m_useCOS) {
if (m_cosInvert) if (m_cosInvert)
cos = !cos; cos = !cos;
} else {
cos = true;
}
clock(length); clock(length);
@ -80,33 +86,83 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
for (; i < length; i++) { for (; i < length; i++) {
// ARMv7-M has hardware integer division // ARMv7-M has hardware integer division
q15_t currentRFSample = 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);
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; q15_t currentExtSample;
bool inputExt = m_inputExtRB.getSample(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; inputExt = inputExt && m_extEnabled;
if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) { switch (m_accessMode) {
//Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue case 0U:
if (!inputExt && !cos && m_modemState != STATE_FM)
continue;
else
stateMachine(cos, inputExt);
break;
case 1U: {
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 (!inputExt && CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
// Not enough samples to determine if you have CTCSS, just carry on
continue; continue;
} else if ((inputExt || 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 // 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); bool validCTCSS = CTCSS_VALID(ctcssState);
stateMachine(validCTCSS && cos, inputExt); stateMachine(validCTCSS && cos, inputExt);
if (m_modemState != STATE_FM) if (m_state == FS_LISTENING)
continue; continue;
} else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) { } else {
//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); bool validCTCSS = CTCSS_VALID(ctcssState);
stateMachine(validCTCSS && cos, inputExt); stateMachine(validCTCSS && 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
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);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(cos, inputExt);
}
}
break;
}
if (m_modemState != STATE_FM)
continue;
if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted() && !m_reverseTimer.isRunning())
continue;
q15_t currentSample = currentRFSample; q15_t currentSample = currentRFSample;
q15_t currentBoost = m_rfAudioBoost; q15_t currentBoost = m_rfAudioBoost;
@ -127,12 +183,12 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
currentSample = 0; currentSample = 0;
} }
} else { } else {
if (m_state == FS_RELAYING_EXT) { if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
currentSample *= currentBoost; currentSample *= currentBoost;
} else { } else {
if (m_extEnabled && m_state == FS_RELAYING_RF) if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
m_downSampler.addSample(currentSample); m_downSampler.addSample(currentSample);
return; continue;
} }
} }
@ -154,7 +210,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning()) if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning())
currentSample += m_timeoutTone.getAudio(); currentSample += m_timeoutTone.getAudio();
currentSample += m_ctcssTX.getAudio(); currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
m_outputRFRB.put(currentSample); m_outputRFRB.put(currentSample);
} }
@ -213,6 +269,7 @@ void CFM::reset()
m_ackDelayTimer.stop(); m_ackDelayTimer.stop();
m_hangTimer.stop(); m_hangTimer.stop();
m_statusTimer.stop(); m_statusTimer.stop();
m_reverseTimer.stop();
m_ctcssRX.reset(); m_ctcssRX.reset();
m_rfAck.stop(); m_rfAck.stop();
@ -224,6 +281,8 @@ void CFM::reset()
m_inputExtRB.reset(); m_inputExtRB.reset();
m_downSampler.reset(); m_downSampler.reset();
m_needReverse = false;
} }
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) 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)
@ -254,9 +313,9 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_
return m_rfAck.setParams(rfAck, speed, frequency, level, level); 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, uint8_t hangTime, uint8_t accessMode, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
{ {
m_useCOS = useCOS; m_accessMode = accessMode;
m_cosInvert = cosInvert; m_cosInvert = cosInvert;
m_rfAudioBoost = q15_t(rfAudioBoost); m_rfAudioBoost = q15_t(rfAudioBoost);
@ -331,8 +390,13 @@ void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal)
} }
if (m_state == FS_LISTENING) { if (m_state == FS_LISTENING) {
m_outputRFRB.reset(); if (!m_reverseTimer.isRunning() && m_needReverse)
m_downSampler.reset(); m_reverseTimer.start();
if (m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
m_reverseTimer.stop();
m_needReverse = false;
}
} }
} }
@ -380,8 +444,13 @@ void CFM::duplexStateMachine(bool validRFSignal, bool validExtSignal)
} }
if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) { if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) {
m_outputRFRB.reset(); if (!m_reverseTimer.isRunning() && m_needReverse)
m_downSampler.reset(); m_reverseTimer.start();
if (m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
m_reverseTimer.stop();
m_needReverse = false;
}
} }
} }
@ -395,6 +464,7 @@ void CFM::clock(uint8_t length)
m_ackDelayTimer.clock(length); m_ackDelayTimer.clock(length);
m_hangTimer.clock(length); m_hangTimer.clock(length);
m_statusTimer.clock(length); m_statusTimer.clock(length);
m_reverseTimer.clock(length);
if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) { if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) {
serial.writeFMStatus(m_state); serial.writeFMStatus(m_state);
@ -424,6 +494,7 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
beginRelaying(); beginRelaying();
m_callsignTimer.start(); m_callsignTimer.start();
m_reverseTimer.stop();
io.setDecode(true); io.setDecode(true);
io.setADCDetection(true); io.setADCDetection(true);
@ -451,6 +522,7 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
beginRelaying(); beginRelaying();
m_callsignTimer.start(); m_callsignTimer.start();
m_reverseTimer.stop();
m_statusTimer.start(); m_statusTimer.start();
serial.writeFMStatus(m_state); serial.writeFMStatus(m_state);
@ -468,6 +540,7 @@ void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal)
io.setADCDetection(true); io.setADCDetection(true);
m_timeoutTimer.start(); m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start(); m_statusTimer.start();
serial.writeFMStatus(m_state); serial.writeFMStatus(m_state);
@ -478,6 +551,7 @@ void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal)
insertSilence(50U); insertSilence(50U);
m_timeoutTimer.start(); m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start(); m_statusTimer.start();
serial.writeFMStatus(m_state); serial.writeFMStatus(m_state);
@ -507,7 +581,7 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
m_ackMinTimer.stop(); m_ackMinTimer.stop();
m_callsignTimer.stop(); m_callsignTimer.stop();
m_statusTimer.stop(); m_statusTimer.stop();
m_needReverse = true;
if (m_extEnabled) if (m_extEnabled)
serial.writeFMEOT(); serial.writeFMEOT();
} }
@ -620,7 +694,6 @@ void CFM::relayingRFWaitStateSimplex(bool validSignal)
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING"); DEBUG1("State to LISTENING");
m_state = FS_LISTENING; m_state = FS_LISTENING;
m_ackDelayTimer.stop(); m_ackDelayTimer.stop();
m_timeoutTimer.stop(); m_timeoutTimer.stop();
} }
@ -647,6 +720,7 @@ void CFM::kerchunkExtStateDuplex(bool validSignal)
m_ackMinTimer.stop(); m_ackMinTimer.stop();
m_callsignTimer.stop(); m_callsignTimer.stop();
m_statusTimer.stop(); m_statusTimer.stop();
m_needReverse = true;
} }
} }
@ -733,9 +807,9 @@ void CFM::relayingExtWaitStateSimplex(bool validSignal)
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) { if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING"); DEBUG1("State to LISTENING");
m_state = FS_LISTENING; m_state = FS_LISTENING;
m_ackDelayTimer.stop(); m_ackDelayTimer.stop();
m_timeoutTimer.stop(); m_timeoutTimer.stop();
m_needReverse = true;
} }
} }
} }
@ -770,7 +844,7 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
sendCallsign(); sendCallsign();
m_callsignTimer.stop(); m_callsignTimer.stop();
m_needReverse = true;
} }
} }
@ -923,6 +997,7 @@ void CFM::timeoutExtWaitStateSimplex(bool validSignal)
m_state = FS_LISTENING; m_state = FS_LISTENING;
m_ackDelayTimer.stop(); m_ackDelayTimer.stop();
m_timeoutTimer.stop(); m_timeoutTimer.stop();
m_needReverse = true;
} }
} }
} }

6
FM.h
View File

@ -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 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 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, uint8_t hangTime, uint8_t accessMode, 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 setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
uint8_t getSpace() const; uint8_t getSpace() const;
@ -86,11 +86,13 @@ private:
CFMTimer m_ackDelayTimer; CFMTimer m_ackDelayTimer;
CFMTimer m_hangTimer; CFMTimer m_hangTimer;
CFMTimer m_statusTimer; CFMTimer m_statusTimer;
CFMTimer m_reverseTimer;
bool m_needReverse;
CFMDirectFormI m_filterStage1; CFMDirectFormI m_filterStage1;
CFMDirectFormI m_filterStage2; CFMDirectFormI m_filterStage2;
CFMDirectFormI m_filterStage3; CFMDirectFormI m_filterStage3;
CFMBlanking m_blanking; CFMBlanking m_blanking;
bool m_useCOS; uint8_t m_accessMode;
bool m_cosInvert; bool m_cosInvert;
q15_t m_rfAudioBoost; q15_t m_rfAudioBoost;
q15_t m_extAudioBoost; q15_t m_extAudioBoost;

View File

@ -115,11 +115,14 @@ uint8_t CFMCTCSSTX::setParams(uint8_t frequency, uint8_t level)
return 0U; return 0U;
} }
q15_t CFMCTCSSTX::getAudio() q15_t CFMCTCSSTX::getAudio(bool reverse)
{ {
q15_t sample = m_values[m_n++]; q15_t sample = m_values[m_n++];
if(m_n >= m_length) if (m_n >= m_length)
m_n = 0U; m_n = 0U;
if (reverse)
return -sample;
else
return sample; return sample;
} }

View File

@ -27,7 +27,7 @@ public:
uint8_t setParams(uint8_t frequency, uint8_t level); uint8_t setParams(uint8_t frequency, uint8_t level);
q15_t getAudio(); q15_t getAudio(bool reverse);
private: private:
q15_t* m_values; q15_t* m_values;

8
IO.cpp
View File

@ -84,6 +84,7 @@ m_fmTXLevel(128 * 128),
m_ax25TXLevel(128 * 128), m_ax25TXLevel(128 * 128),
m_rxDCOffset(DC_OFFSET), m_rxDCOffset(DC_OFFSET),
m_txDCOffset(DC_OFFSET), m_txDCOffset(DC_OFFSET),
m_useCOSAsLockout(false),
m_ledCount(0U), m_ledCount(0U),
m_ledValue(true), m_ledValue(true),
m_detect(false), m_detect(false),
@ -257,9 +258,8 @@ void CIO::process()
return; return;
} }
#if defined(USE_COS_AS_LOCKOUT) if (m_useCOSAsLockout)
m_lockout = getCOSInt(); m_lockout = getCOSInt();
#endif
// Switch off the transmitter if needed // Switch off the transmitter if needed
if (m_txBuffer.getData() == 0U && m_tx) { if (m_txBuffer.getData() == 0U && m_tx) {
@ -548,7 +548,7 @@ void CIO::setMode()
#endif #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, uint8_t ax25TXLevel, 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, bool useCOSAsLockout)
{ {
m_pttInvert = pttInvert; m_pttInvert = pttInvert;
@ -566,6 +566,8 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_rxDCOffset = DC_OFFSET + rxDCOffset; m_rxDCOffset = DC_OFFSET + rxDCOffset;
m_txDCOffset = DC_OFFSET + txDCOffset; m_txDCOffset = DC_OFFSET + txDCOffset;
m_useCOSAsLockout = useCOSAsLockout;
if (rxInvert) if (rxInvert)
m_rxLevel = -m_rxLevel; m_rxLevel = -m_rxLevel;

4
IO.h
View File

@ -46,7 +46,7 @@ public:
void interrupt(); 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, uint8_t ax25TXLevel, 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, bool useCOSAsLockout);
void getOverflow(bool& adcOverflow, bool& dacOverflow); void getOverflow(bool& adcOverflow, bool& dacOverflow);
@ -96,6 +96,8 @@ private:
uint16_t m_rxDCOffset; uint16_t m_rxDCOffset;
uint16_t m_txDCOffset; uint16_t m_txDCOffset;
bool m_useCOSAsLockout;
uint32_t m_ledCount; uint32_t m_ledCount;
bool m_ledValue; bool m_ledValue;

View File

@ -109,7 +109,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
#define HW_TYPE "MMDVM" #define HW_TYPE "MMDVM"
#endif #endif
#define DESCRIPTION "20200712 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)" #define DESCRIPTION "20200714 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)"
#if defined(GITVERSION) #if defined(GITVERSION)
#define concat(h, a, b, c) h " " a " " b " GitID #" c "" #define concat(h, a, b, c) h " " a " " b " GitID #" c ""
@ -289,6 +289,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
bool txInvert = (data[0U] & 0x02U) == 0x02U; bool txInvert = (data[0U] & 0x02U) == 0x02U;
bool pttInvert = (data[0U] & 0x04U) == 0x04U; bool pttInvert = (data[0U] & 0x04U) == 0x04U;
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U; bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
bool useCOSAsLockout = (data[0U] & 0x20U) == 0x20U;
bool simplex = (data[0U] & 0x80U) == 0x80U; bool simplex = (data[0U] & 0x80U) == 0x80U;
m_debug = (data[0U] & 0x10U) == 0x10U; m_debug = (data[0U] & 0x10U) == 0x10U;
@ -397,7 +398,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
nxdnTX.setParams(nxdnTXHang); nxdnTX.setParams(nxdnTXHang);
ax25RX.setParams(ax25RXTwist, ax25SlotTime, ax25PPersist); ax25RX.setParams(ax25RXTwist, ax25SlotTime, ax25PPersist);
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset); io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset, useCOSAsLockout);
io.start(); io.start();
@ -465,14 +466,14 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length)
uint8_t kerchunkTime = data[6U]; uint8_t kerchunkTime = data[6U];
uint8_t hangTime = data[7U]; uint8_t hangTime = data[7U];
bool useCOS = (data[8U] & 0x01U) == 0x01U; uint8_t accessMode = data[8U] & 0x7FU;
bool cosInvert = (data[8U] & 0x02U) == 0x02U; bool cosInvert = (data[8U] & 0x80U) == 0x80U;
uint8_t rfAudioBoost = data[9U]; uint8_t rfAudioBoost = data[9U];
uint8_t maxDev = data[10U]; uint8_t maxDev = data[10U];
uint8_t rxLevel = data[11U]; 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, hangTime, accessMode, cosInvert, rfAudioBoost, maxDev, rxLevel);
} }
uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint16_t length) uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint16_t length)