mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-16 16:54:12 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b971c5bc38 | ||
|
|
598d32287d | ||
|
|
53d8cfa360 | ||
|
|
7fabddd7f1 | ||
|
|
2cf2ce4dfa | ||
|
|
5f29808b80 | ||
|
|
063b21f999 | ||
|
|
89b8641955 | ||
|
|
6397c720e8 | ||
|
|
50c1e5aa3f | ||
|
|
970d02773f | ||
|
|
ff375abb0e | ||
|
|
7169836621 | ||
|
|
8e52bdcc5c | ||
|
|
66feb9d50b | ||
|
|
435544f7a1 | ||
|
|
75e32e1b71 | ||
|
|
c54c13c146 | ||
|
|
4cba5931f4 | ||
|
|
d0062a55f8 | ||
|
|
66ea3ad0d1 | ||
|
|
85acdc7121 | ||
|
|
a2518e99f2 | ||
|
|
3bb7cde322 | ||
|
|
fa29a27695 | ||
|
|
e30eb3adaf | ||
|
|
9b0fed975c | ||
|
|
5ca9313db8 | ||
|
|
feff1ee2c7 | ||
|
|
77e0deee76 |
@@ -41,7 +41,7 @@ CCalFM::CCalFM() :
|
|||||||
m_frequency(0),
|
m_frequency(0),
|
||||||
m_length(0),
|
m_length(0),
|
||||||
m_tone(NULL),
|
m_tone(NULL),
|
||||||
m_level(128*32),
|
m_level(128 * 12),
|
||||||
m_transmit(false),
|
m_transmit(false),
|
||||||
m_audioSeq(0),
|
m_audioSeq(0),
|
||||||
m_lastState(STATE_IDLE)
|
m_lastState(STATE_IDLE)
|
||||||
@@ -56,25 +56,25 @@ void CCalFM::process()
|
|||||||
{
|
{
|
||||||
switch (m_modemState) {
|
switch (m_modemState) {
|
||||||
case STATE_FMCAL10K:
|
case STATE_FMCAL10K:
|
||||||
m_frequency=956U;
|
m_frequency = 956U;
|
||||||
break;
|
break;
|
||||||
case STATE_FMCAL12K:
|
case STATE_FMCAL12K:
|
||||||
m_frequency=1039U;
|
m_frequency = 1039U;
|
||||||
break;
|
break;
|
||||||
case STATE_FMCAL15K:
|
case STATE_FMCAL15K:
|
||||||
m_frequency=1247U;
|
m_frequency = 1247U;
|
||||||
break;
|
break;
|
||||||
case STATE_FMCAL20K:
|
case STATE_FMCAL20K:
|
||||||
m_frequency=1633U;
|
m_frequency = 1633U;
|
||||||
break;
|
break;
|
||||||
case STATE_FMCAL25K:
|
case STATE_FMCAL25K:
|
||||||
m_frequency=2079U;
|
m_frequency = 2079U;
|
||||||
break;
|
break;
|
||||||
case STATE_FMCAL30K:
|
case STATE_FMCAL30K:
|
||||||
m_frequency=2495U;
|
m_frequency = 2495U;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
m_frequency=0;
|
m_frequency = 0U;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,23 +34,26 @@ m_callsignTimer(),
|
|||||||
m_timeoutTimer(),
|
m_timeoutTimer(),
|
||||||
m_holdoffTimer(),
|
m_holdoffTimer(),
|
||||||
m_kerchunkTimer(),
|
m_kerchunkTimer(),
|
||||||
|
m_kerchunkTX(true),
|
||||||
m_ackMinTimer(),
|
m_ackMinTimer(),
|
||||||
m_ackDelayTimer(),
|
m_ackDelayTimer(),
|
||||||
m_hangTimer(),
|
m_hangTimer(),
|
||||||
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_preemphasis(32768, 13967, 0, 32768, -18801, 0),//75µS 24kHz sampling rate
|
|
||||||
m_deemphasis (32768, -18801, 0, 32768, 13967, 0),//75µS 24kHz sampling rate
|
|
||||||
m_blanking(),
|
m_blanking(),
|
||||||
m_useCOS(true),
|
m_useCOS(true),
|
||||||
m_cosInvert(false),
|
m_cosInvert(false),
|
||||||
m_rfAudioBoost(1U),
|
m_rfAudioBoost(1U),
|
||||||
m_downsampler(128)//Size might need adjustement
|
m_downsampler(128U),//Size might need adjustement
|
||||||
|
m_rxLevel(1),
|
||||||
|
m_inputRB(4800U), // 200ms of audio
|
||||||
|
m_outputRB(2400U) // 100ms of audio
|
||||||
{
|
{
|
||||||
|
insertDelay(100U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_useCOS) {
|
if (m_useCOS) {
|
||||||
if (m_cosInvert)
|
if (m_cosInvert)
|
||||||
@@ -63,10 +66,17 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
|
|
||||||
uint8_t i = 0U;
|
uint8_t i = 0U;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
q15_t currentSample = samples[i];//save to a local variable to avoid indirection on every access
|
// ARMv7-M has hardware integer division
|
||||||
|
q15_t currentSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
||||||
|
|
||||||
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
||||||
|
|
||||||
|
if (!m_useCOS) {
|
||||||
|
// Delay the audio by 100ms to better match the CTCSS detector output
|
||||||
|
m_inputRB.put(currentSample);
|
||||||
|
m_inputRB.get(currentSample);
|
||||||
|
}
|
||||||
|
|
||||||
if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
|
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;
|
continue;
|
||||||
@@ -90,8 +100,7 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only let audio through when relaying audio
|
// Only let audio through when relaying audio
|
||||||
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
||||||
// currentSample = m_deemphasis.filter(currentSample);
|
|
||||||
// m_downsampler.addSample(currentSample);
|
// m_downsampler.addSample(currentSample);
|
||||||
currentSample = m_blanking.process(currentSample);
|
currentSample = m_blanking.process(currentSample);
|
||||||
currentSample *= m_rfAudioBoost;
|
currentSample *= m_rfAudioBoost;
|
||||||
@@ -114,19 +123,18 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
|
|
||||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||||
|
|
||||||
// currentSample = m_preemphasis.filter(currentSample);
|
|
||||||
|
|
||||||
currentSample += m_ctcssTX.getAudio();
|
currentSample += m_ctcssTX.getAudio();
|
||||||
|
|
||||||
samples[i] = currentSample;
|
if (m_modemState == STATE_FM)
|
||||||
|
m_outputRB.put(currentSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_modemState == STATE_FM)
|
|
||||||
io.write(STATE_FM, samples, i);//only write the actual number of processed samples to IO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::process()
|
void CFM::process()
|
||||||
{
|
{
|
||||||
|
q15_t sample;
|
||||||
|
while (io.getSpace() >= 3U && m_outputRB.get(sample))
|
||||||
|
io.write(STATE_FM, &sample, 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::reset()
|
void CFM::reset()
|
||||||
@@ -144,6 +152,8 @@ void CFM::reset()
|
|||||||
m_rfAck.stop();
|
m_rfAck.stop();
|
||||||
m_callsign.stop();
|
m_callsign.stop();
|
||||||
m_timeoutTone.stop();
|
m_timeoutTone.stop();
|
||||||
|
|
||||||
|
m_outputRB.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFM::setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
|
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)
|
||||||
@@ -174,7 +184,7 @@ 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 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 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_useCOS = useCOS;
|
||||||
m_cosInvert = cosInvert;
|
m_cosInvert = cosInvert;
|
||||||
@@ -182,13 +192,18 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque
|
|||||||
m_rfAudioBoost = q15_t(rfAudioBoost);
|
m_rfAudioBoost = q15_t(rfAudioBoost);
|
||||||
|
|
||||||
m_timeoutTimer.setTimeout(timeout, 0U);
|
m_timeoutTimer.setTimeout(timeout, 0U);
|
||||||
|
|
||||||
m_kerchunkTimer.setTimeout(kerchunkTime, 0U);
|
m_kerchunkTimer.setTimeout(kerchunkTime, 0U);
|
||||||
|
m_kerchunkTX = kerchunkTX;
|
||||||
|
|
||||||
m_hangTimer.setTimeout(hangTime, 0U);
|
m_hangTimer.setTimeout(hangTime, 0U);
|
||||||
|
|
||||||
m_timeoutTone.setParams(timeoutLevel);
|
m_timeoutTone.setParams(timeoutLevel);
|
||||||
m_blanking.setParams(maxDev, timeoutLevel);
|
m_blanking.setParams(maxDev, timeoutLevel);
|
||||||
|
|
||||||
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssThreshold, rxLevel);
|
m_rxLevel = rxLevel; //q15_t(255)/q15_t(rxLevel >> 1);
|
||||||
|
|
||||||
|
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold);
|
||||||
if (ret != 0U)
|
if (ret != 0U)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -224,7 +239,7 @@ void CFM::stateMachine(bool validSignal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == FS_LISTENING && m_modemState == STATE_FM) {
|
if (m_state == FS_LISTENING && m_modemState == STATE_FM) {
|
||||||
if (!m_callsign.isRunning() && !m_rfAck.isRunning()) {
|
if (!m_callsign.isWanted() && !m_rfAck.isWanted()) {
|
||||||
DEBUG1("Change to STATE_IDLE");
|
DEBUG1("Change to STATE_IDLE");
|
||||||
m_modemState = STATE_IDLE;
|
m_modemState = STATE_IDLE;
|
||||||
m_callsignTimer.stop();
|
m_callsignTimer.stop();
|
||||||
@@ -264,12 +279,19 @@ void CFM::listeningState(bool validSignal)
|
|||||||
sendCallsign();
|
sendCallsign();
|
||||||
}
|
}
|
||||||
|
|
||||||
beginRelaying();
|
if (m_state == FS_RELAYING || (m_state == FS_KERCHUNK && m_kerchunkTX)) {
|
||||||
|
insertSilence(50U);
|
||||||
|
|
||||||
m_callsignTimer.start();
|
beginRelaying();
|
||||||
|
|
||||||
DEBUG1("Change to STATE_FM");
|
m_callsignTimer.start();
|
||||||
m_modemState = STATE_FM;
|
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
DEBUG1("Change to STATE_FM");
|
||||||
|
m_modemState = STATE_FM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,8 +306,24 @@ void CFM::kerchunkState(bool validSignal)
|
|||||||
sendCallsign();
|
sendCallsign();
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
}
|
}
|
||||||
|
if (!m_kerchunkTX) {
|
||||||
|
insertSilence(50U);
|
||||||
|
|
||||||
|
beginRelaying();
|
||||||
|
|
||||||
|
m_callsignTimer.start();
|
||||||
|
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
DEBUG1("Change to STATE_FM");
|
||||||
|
m_modemState = STATE_FM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to LISTENING");
|
DEBUG1("State to LISTENING");
|
||||||
m_state = FS_LISTENING;
|
m_state = FS_LISTENING;
|
||||||
m_kerchunkTimer.stop();
|
m_kerchunkTimer.stop();
|
||||||
@@ -306,6 +344,9 @@ void CFM::relayingState(bool validSignal)
|
|||||||
m_timeoutTone.start();
|
m_timeoutTone.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING_WAIT");
|
DEBUG1("State to RELAYING_WAIT");
|
||||||
m_state = FS_RELAYING_WAIT;
|
m_state = FS_RELAYING_WAIT;
|
||||||
m_ackDelayTimer.start();
|
m_ackDelayTimer.start();
|
||||||
@@ -320,6 +361,9 @@ void CFM::relayingState(bool validSignal)
|
|||||||
void CFM::relayingWaitState(bool validSignal)
|
void CFM::relayingWaitState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING");
|
DEBUG1("State to RELAYING");
|
||||||
m_state = FS_RELAYING;
|
m_state = FS_RELAYING;
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
@@ -355,6 +399,9 @@ void CFM::relayingWaitState(bool validSignal)
|
|||||||
void CFM::hangState(bool validSignal)
|
void CFM::hangState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING");
|
DEBUG1("State to RELAYING");
|
||||||
m_state = FS_RELAYING;
|
m_state = FS_RELAYING;
|
||||||
DEBUG1("Stop ack");
|
DEBUG1("Stop ack");
|
||||||
@@ -382,6 +429,9 @@ void CFM::hangState(bool validSignal)
|
|||||||
void CFM::timeoutState(bool validSignal)
|
void CFM::timeoutState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (!validSignal) {
|
if (!validSignal) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to TIMEOUT_WAIT");
|
DEBUG1("State to TIMEOUT_WAIT");
|
||||||
m_state = FS_TIMEOUT_WAIT;
|
m_state = FS_TIMEOUT_WAIT;
|
||||||
m_ackDelayTimer.start();
|
m_ackDelayTimer.start();
|
||||||
@@ -396,6 +446,9 @@ void CFM::timeoutState(bool validSignal)
|
|||||||
void CFM::timeoutWaitState(bool validSignal)
|
void CFM::timeoutWaitState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to TIMEOUT");
|
DEBUG1("State to TIMEOUT");
|
||||||
m_state = FS_TIMEOUT;
|
m_state = FS_TIMEOUT;
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
@@ -438,3 +491,19 @@ void CFM::beginRelaying()
|
|||||||
m_timeoutTimer.start();
|
m_timeoutTimer.start();
|
||||||
m_ackMinTimer.start();
|
m_ackMinTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFM::insertDelay(uint16_t ms)
|
||||||
|
{
|
||||||
|
uint32_t nSamples = ms * 24U;
|
||||||
|
|
||||||
|
for (uint32_t i = 0U; i < nSamples; i++)
|
||||||
|
m_inputRB.put(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::insertSilence(uint16_t ms)
|
||||||
|
{
|
||||||
|
uint32_t nSamples = ms * 24U;
|
||||||
|
|
||||||
|
for (uint32_t i = 0U; i < nSamples; i++)
|
||||||
|
m_outputRB.put(0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "FMTimeout.h"
|
#include "FMTimeout.h"
|
||||||
#include "FMKeyer.h"
|
#include "FMKeyer.h"
|
||||||
#include "FMTimer.h"
|
#include "FMTimer.h"
|
||||||
|
#include "FMRB.h"
|
||||||
#include "FMDirectForm1.h"
|
#include "FMDirectForm1.h"
|
||||||
#include "FMDownsampler.h"
|
#include "FMDownsampler.h"
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class CFM {
|
|||||||
public:
|
public:
|
||||||
CFM();
|
CFM();
|
||||||
|
|
||||||
void samples(bool cos, q15_t* samples, uint8_t length);
|
void samples(bool cos, const q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -55,7 +56,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 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 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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CFMKeyer m_callsign;
|
CFMKeyer m_callsign;
|
||||||
@@ -71,19 +72,21 @@ private:
|
|||||||
CFMTimer m_timeoutTimer;
|
CFMTimer m_timeoutTimer;
|
||||||
CFMTimer m_holdoffTimer;
|
CFMTimer m_holdoffTimer;
|
||||||
CFMTimer m_kerchunkTimer;
|
CFMTimer m_kerchunkTimer;
|
||||||
|
bool m_kerchunkTX;
|
||||||
CFMTimer m_ackMinTimer;
|
CFMTimer m_ackMinTimer;
|
||||||
CFMTimer m_ackDelayTimer;
|
CFMTimer m_ackDelayTimer;
|
||||||
CFMTimer m_hangTimer;
|
CFMTimer m_hangTimer;
|
||||||
CFMDirectFormI m_filterStage1;
|
CFMDirectFormI m_filterStage1;
|
||||||
CFMDirectFormI m_filterStage2;
|
CFMDirectFormI m_filterStage2;
|
||||||
CFMDirectFormI m_filterStage3;
|
CFMDirectFormI m_filterStage3;
|
||||||
CFMDirectFormI m_preemphasis;
|
|
||||||
CFMDirectFormI m_deemphasis;
|
|
||||||
CFMBlanking m_blanking;
|
CFMBlanking m_blanking;
|
||||||
bool m_useCOS;
|
bool m_useCOS;
|
||||||
bool m_cosInvert;
|
bool m_cosInvert;
|
||||||
q15_t m_rfAudioBoost;
|
q15_t m_rfAudioBoost;
|
||||||
CFMDownsampler m_downsampler;
|
CFMDownsampler m_downsampler;
|
||||||
|
q15_t m_rxLevel;
|
||||||
|
CFMRB m_inputRB;
|
||||||
|
CFMRB m_outputRB;
|
||||||
|
|
||||||
void stateMachine(bool validSignal);
|
void stateMachine(bool validSignal);
|
||||||
void listeningState(bool validSignal);
|
void listeningState(bool validSignal);
|
||||||
@@ -98,6 +101,9 @@ private:
|
|||||||
|
|
||||||
void sendCallsign();
|
void sendCallsign();
|
||||||
void beginRelaying();
|
void beginRelaying();
|
||||||
|
|
||||||
|
void insertDelay(uint16_t ms);
|
||||||
|
void insertSilence(uint16_t ms);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+15
-23
@@ -82,19 +82,17 @@ const uint16_t N = 24000U / 4U;
|
|||||||
|
|
||||||
CFMCTCSSRX::CFMCTCSSRX() :
|
CFMCTCSSRX::CFMCTCSSRX() :
|
||||||
m_coeffDivTwo(0),
|
m_coeffDivTwo(0),
|
||||||
m_threshold(0),
|
m_highThreshold(0),
|
||||||
|
m_lowThreshold(0),
|
||||||
m_count(0U),
|
m_count(0U),
|
||||||
m_q0(0),
|
m_q0(0),
|
||||||
m_q1(0),
|
m_q1(0),
|
||||||
m_result(CTS_NONE),
|
m_result(CTS_NONE)
|
||||||
m_rxLevelInverse(1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t threshold, uint8_t level)
|
uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold)
|
||||||
{
|
{
|
||||||
m_rxLevelInverse = q15Division(65535, q15_t(level * 128));
|
|
||||||
|
|
||||||
m_coeffDivTwo = 0;
|
m_coeffDivTwo = 0;
|
||||||
|
|
||||||
for (uint8_t i = 0U; i < CTCSS_TABLE_DATA_LEN; i++) {
|
for (uint8_t i = 0U; i < CTCSS_TABLE_DATA_LEN; i++) {
|
||||||
@@ -107,14 +105,16 @@ uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t threshold, uint8_t leve
|
|||||||
if (m_coeffDivTwo == 0)
|
if (m_coeffDivTwo == 0)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|
||||||
m_threshold = q31_t(threshold);
|
m_highThreshold = q31_t(highThreshold);
|
||||||
|
m_lowThreshold = q31_t(lowThreshold);
|
||||||
|
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFMCTCSSRX::process(q15_t sample)
|
uint8_t CFMCTCSSRX::process(q15_t sample)
|
||||||
{
|
{
|
||||||
q31_t sample31 = q31_t(sample) * m_rxLevelInverse;
|
//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;
|
m_result &= ~CTS_READY;
|
||||||
|
|
||||||
@@ -150,14 +150,19 @@ uint8_t CFMCTCSSRX::process(q15_t sample)
|
|||||||
q31_t value = t2 + t4 - t9;
|
q31_t value = t2 + t4 - t9;
|
||||||
|
|
||||||
bool previousCTCSSValid = CTCSS_VALID(m_result);
|
bool previousCTCSSValid = CTCSS_VALID(m_result);
|
||||||
|
|
||||||
|
q31_t threshold = m_highThreshold;
|
||||||
|
if (previousCTCSSValid)
|
||||||
|
threshold = m_lowThreshold;
|
||||||
|
|
||||||
m_result |= CTS_READY;
|
m_result |= CTS_READY;
|
||||||
if (value >= m_threshold)
|
if (value >= threshold)
|
||||||
m_result |= CTS_VALID;
|
m_result |= CTS_VALID;
|
||||||
else
|
else
|
||||||
m_result &= ~CTS_VALID;
|
m_result &= ~CTS_VALID;
|
||||||
|
|
||||||
if (previousCTCSSValid != CTCSS_VALID(m_result))
|
if (previousCTCSSValid != CTCSS_VALID(m_result))
|
||||||
DEBUG4("CTCSS Value / Threshold / Valid", value, m_threshold, CTCSS_VALID(m_result));
|
DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, CTCSS_VALID(m_result));
|
||||||
|
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
m_q0 = 0;
|
m_q0 = 0;
|
||||||
@@ -174,16 +179,3 @@ void CFMCTCSSRX::reset()
|
|||||||
m_result = CTS_NONE;
|
m_result = CTS_NONE;
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Taken from https://en.wikipedia.org/wiki/Q_(number_format)#Division
|
|
||||||
q15_t CFMCTCSSRX::q15Division(q15_t a, q15_t divisor)
|
|
||||||
{
|
|
||||||
q31_t a31 = q31_t(a) << 16;
|
|
||||||
|
|
||||||
if (((a >> 31) & 1) == ((divisor >> 15) & 1))
|
|
||||||
a31 += divisor >> 1;
|
|
||||||
else
|
|
||||||
a31 -= divisor >> 1;
|
|
||||||
|
|
||||||
return a31 / divisor;
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-5
@@ -34,7 +34,7 @@ class CFMCTCSSRX {
|
|||||||
public:
|
public:
|
||||||
CFMCTCSSRX();
|
CFMCTCSSRX();
|
||||||
|
|
||||||
uint8_t setParams(uint8_t frequency, uint8_t threshold, uint8_t level);
|
uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold);
|
||||||
|
|
||||||
uint8_t process(q15_t sample);
|
uint8_t process(q15_t sample);
|
||||||
|
|
||||||
@@ -42,14 +42,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
q63_t m_coeffDivTwo;
|
q63_t m_coeffDivTwo;
|
||||||
q31_t m_threshold;
|
q31_t m_highThreshold;
|
||||||
|
q31_t m_lowThreshold;
|
||||||
uint16_t m_count;
|
uint16_t m_count;
|
||||||
q31_t m_q0;
|
q31_t m_q0;
|
||||||
q31_t m_q1;
|
q31_t m_q1;
|
||||||
uint8_t m_result;
|
uint8_t m_result;
|
||||||
q15_t m_rxLevelInverse;
|
|
||||||
|
|
||||||
q15_t q15Division(q15_t a, q15_t divisor);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -16,8 +16,8 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(FMRB_H)
|
#if !defined(FMDOWNSAMPLERB_H)
|
||||||
#define FMRB_H
|
#define FMDOWNSAMPLERB_H
|
||||||
|
|
||||||
#if defined(STM32F4XX)
|
#if defined(STM32F4XX)
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
|
|||||||
+1
-1
@@ -40,4 +40,4 @@ private:
|
|||||||
uint8_t m_downSampleIndex;
|
uint8_t m_downSampleIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -205,6 +205,11 @@ void CFMKeyer::stop()
|
|||||||
m_audioPos = 0U;
|
m_audioPos = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CFMKeyer::isWanted() const
|
||||||
|
{
|
||||||
|
return m_wanted;
|
||||||
|
}
|
||||||
|
|
||||||
bool CFMKeyer::isRunning() const
|
bool CFMKeyer::isRunning() const
|
||||||
{
|
{
|
||||||
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ public:
|
|||||||
|
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
|
|
||||||
|
bool isWanted() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_wanted;
|
bool m_wanted;
|
||||||
uint8_t m_poBuffer[1000U];
|
uint8_t m_poBuffer[1000U];
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
TX fifo control - Copyright (C) KI6ZUM 2015
|
||||||
|
Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FMRB.h"
|
||||||
|
|
||||||
|
CFMRB::CFMRB(uint16_t length) :
|
||||||
|
m_length(length),
|
||||||
|
m_head(0U),
|
||||||
|
m_tail(0U),
|
||||||
|
m_full(false),
|
||||||
|
m_overflow(false)
|
||||||
|
{
|
||||||
|
m_samples = new q15_t[length];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CFMRB::getSpace() const
|
||||||
|
{
|
||||||
|
uint16_t n = 0U;
|
||||||
|
|
||||||
|
if (m_tail == m_head)
|
||||||
|
n = m_full ? 0U : m_length;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
n = m_length - m_head + m_tail;
|
||||||
|
else
|
||||||
|
n = m_tail - m_head;
|
||||||
|
|
||||||
|
if (n > m_length)
|
||||||
|
n = 0U;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CFMRB::getData() const
|
||||||
|
{
|
||||||
|
if (m_tail == m_head)
|
||||||
|
return m_full ? m_length : 0U;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
return m_head - m_tail;
|
||||||
|
else
|
||||||
|
return m_length - m_tail + m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMRB::put(q15_t sample)
|
||||||
|
{
|
||||||
|
if (m_full) {
|
||||||
|
m_overflow = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_samples[m_head] = sample;
|
||||||
|
|
||||||
|
m_head++;
|
||||||
|
if (m_head >= m_length)
|
||||||
|
m_head = 0U;
|
||||||
|
|
||||||
|
if (m_head == m_tail)
|
||||||
|
m_full = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMRB::get(q15_t& sample)
|
||||||
|
{
|
||||||
|
if (m_head == m_tail && !m_full)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sample = m_samples[m_tail];
|
||||||
|
|
||||||
|
m_full = false;
|
||||||
|
|
||||||
|
m_tail++;
|
||||||
|
if (m_tail >= m_length)
|
||||||
|
m_tail = 0U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMRB::hasOverflowed()
|
||||||
|
{
|
||||||
|
bool overflow = m_overflow;
|
||||||
|
|
||||||
|
m_overflow = false;
|
||||||
|
|
||||||
|
return overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMRB::reset()
|
||||||
|
{
|
||||||
|
m_head = 0U;
|
||||||
|
m_tail = 0U;
|
||||||
|
m_full = false;
|
||||||
|
m_overflow = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
Serial fifo control - Copyright (C) KI6ZUM 2015
|
||||||
|
Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; if not, write to the
|
||||||
|
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMRB_H)
|
||||||
|
#define FMRB_H
|
||||||
|
|
||||||
|
#if defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#elif defined(STM32F7XX)
|
||||||
|
#include "stm32f7xx.h"
|
||||||
|
#elif defined(STM32F105xC)
|
||||||
|
#include "stm32f1xx.h"
|
||||||
|
#include <cstddef>
|
||||||
|
#else
|
||||||
|
#include <Arduino.h>
|
||||||
|
#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 <arm_math.h>
|
||||||
|
|
||||||
|
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
|
||||||
+13
-45
@@ -41,7 +41,6 @@ YSF PB8 output
|
|||||||
P25 PB9 output
|
P25 PB9 output
|
||||||
NXDN PB10 output
|
NXDN PB10 output
|
||||||
POCSAG PB11 output
|
POCSAG PB11 output
|
||||||
FM PB12 output
|
|
||||||
|
|
||||||
RX PB0 analog input (ADC1_8)
|
RX PB0 analog input (ADC1_8)
|
||||||
RSSI PB1 analog input (ADC2_9)
|
RSSI PB1 analog input (ADC2_9)
|
||||||
@@ -85,9 +84,6 @@ USART1_RXD PA10 input (AF)
|
|||||||
#define PIN_POCSAG 11
|
#define PIN_POCSAG 11
|
||||||
#define PORT_POCSAG GPIOB
|
#define PORT_POCSAG GPIOB
|
||||||
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
|
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
|
||||||
#define PIN_FM 14
|
|
||||||
#define PORT_FM GPIOB
|
|
||||||
#define BB_FM *((bitband_t)BITBAND_PERIPH(&PORT_FM->ODR, PIN_FM))
|
|
||||||
|
|
||||||
#define PIN_RX 0
|
#define PIN_RX 0
|
||||||
#define PIN_RX_ADC_CH 8
|
#define PIN_RX_ADC_CH 8
|
||||||
@@ -158,35 +154,16 @@ void GPIOConfigPin(GPIO_TypeDef *port_ptr, uint32_t pin, uint32_t mode_cnf_value
|
|||||||
#if defined(STM32F1_POG)
|
#if defined(STM32F1_POG)
|
||||||
void FancyLEDEffect()
|
void FancyLEDEffect()
|
||||||
{
|
{
|
||||||
int ledCount = 10;
|
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
|
||||||
|
|
||||||
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25,
|
for(int i=0; i<7; i++){
|
||||||
#if defined(USE_ALTERNATE_NXDN_LEDS)
|
*foo[i] = 0x01;
|
||||||
NULL,
|
|
||||||
#else
|
|
||||||
&BB_NXDN,
|
|
||||||
#endif
|
|
||||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
|
||||||
NULL,
|
|
||||||
#else
|
|
||||||
&BB_POCSAG,
|
|
||||||
#endif
|
|
||||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
|
||||||
NULL};
|
|
||||||
#else
|
|
||||||
&BB_FM};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(int i=0; i<ledCount; i++){
|
|
||||||
if(foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||||
delay(SystemCoreClock/1000*100);
|
delay(SystemCoreClock/1000*100);
|
||||||
for(int i=0; i<ledCount; i++){
|
for(int i=0; i<7; i++){
|
||||||
if(foo[i] != NULL)
|
*foo[i] = 0x00;
|
||||||
*foo[i] = 0x00;
|
|
||||||
}
|
}
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
delay(SystemCoreClock/1000*20);
|
delay(SystemCoreClock/1000*20);
|
||||||
@@ -195,22 +172,18 @@ void FancyLEDEffect()
|
|||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
|
|
||||||
*foo[0] = 0x01;
|
*foo[0] = 0x01;
|
||||||
for(int i=1; i<ledCount; i++){
|
for(int i=1; i<7; i++){
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
if (foo[i-1] != NULL)
|
*foo[i-1] = 0x00;
|
||||||
*foo[i-1] = 0x00;
|
*foo[i] = 0x01;
|
||||||
if (foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
for(int i=ledCount - 2; i>=0; i--) {
|
for(int i=5; i>=0; i--){
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
if (foo[i+1] != NULL)
|
*foo[i+1] = 0x00;
|
||||||
*foo[i+1] = 0x00;
|
*foo[i] = 0x01;
|
||||||
if (foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
*foo[0] = 0x00;
|
*foo[5+1-6] = 0x00;
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
@@ -255,9 +228,6 @@ static inline void GPIOInit()
|
|||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
||||||
#endif
|
#endif
|
||||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
|
||||||
GPIOConfigPin(PORT_FM, PIN_FM, GPIO_CRL_MODE0_1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
@@ -495,8 +465,6 @@ void CIO::setFMInt(bool on)
|
|||||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||||
BB_DSTAR = !!on;
|
BB_DSTAR = !!on;
|
||||||
BB_YSF = !!on;
|
BB_YSF = !!on;
|
||||||
#else
|
|
||||||
BB_FM = !!on;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ LDFLAGS_F722 =-T stm32f722_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_
|
|||||||
# Common flags
|
# Common flags
|
||||||
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
LDFLAGS=-Os --specs=nano.specs
|
LDFLAGS=-Os --specs=nano.specs -Wl,-Map=bin/mmdvm.map
|
||||||
|
|
||||||
# Build Rules
|
# Build Rules
|
||||||
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
|
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
|
||||||
|
|||||||
+3
-6
@@ -54,7 +54,7 @@ m_poBuffer(),
|
|||||||
m_poLen(0U),
|
m_poLen(0U),
|
||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(240U), // 200ms
|
m_txDelay(240U), // 200ms
|
||||||
m_txHang(6000U), // 5s
|
m_txHang(3000U), // 5s
|
||||||
m_txCount(0U)
|
m_txCount(0U)
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||||
@@ -72,10 +72,7 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CNXDNTX::process()
|
void CNXDNTX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
||||||
@@ -200,5 +197,5 @@ uint8_t CNXDNTX::getSpace() const
|
|||||||
|
|
||||||
void CNXDNTX::setParams(uint8_t txHang)
|
void CNXDNTX::setParams(uint8_t txHang)
|
||||||
{
|
{
|
||||||
m_txHang = txHang * 1200U;
|
m_txHang = txHang * 600U;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CP25TX::process()
|
void CP25TX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, and POCSAG modes.
|
This is the source code of the MMDVM firmware that supports D-Star, DMR,
|
||||||
|
System Fusion, P25, NXDN, POCSAG, and FM modes.
|
||||||
|
|
||||||
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3 or M4 processor with a clock speed greater than 70 MHz, and access to at least one analogue to digital converter and one digital to analogue converter.
|
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx
|
||||||
|
processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in
|
||||||
|
common is the use of an ARM Cortex-M3, M4, or M7 processors with a clock speed
|
||||||
|
greater than 70 MHz, and access to at least one analogue to digital converter
|
||||||
|
and one digital to analogue converter.
|
||||||
|
|
||||||
In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is being supplied via the Coocox IDE with ARM GCC. The Teensy support uses Teensyduino.
|
In order to build this software for the Arduino Due, you will need to edit a
|
||||||
|
file within the Arduino GUI and that is detailed in the BUILD.txt file. The
|
||||||
|
STM32 support is being supplied via the ARM GCC compiler. The Teensy support
|
||||||
|
uses Teensyduino.
|
||||||
|
|
||||||
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
|
This software is licenced under the GPL v2 and is intended for amateur and
|
||||||
|
educational use only. Use of this software for commercial purposes is strictly
|
||||||
|
forbidden.
|
||||||
|
|||||||
+15
-13
@@ -103,7 +103,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
|
|||||||
#define HW_TYPE "MMDVM"
|
#define HW_TYPE "MMDVM"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DESCRIPTION "20200506 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)"
|
#define DESCRIPTION "20200620 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)"
|
||||||
|
|
||||||
#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 ""
|
||||||
@@ -417,27 +417,29 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length)
|
|||||||
|
|
||||||
uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
||||||
{
|
{
|
||||||
if (length < 11U)
|
if (length < 12U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|
||||||
uint16_t timeout = data[0U] * 5U;
|
uint16_t timeout = data[0U] * 5U;
|
||||||
uint8_t timeoutLevel = data[1U];
|
uint8_t timeoutLevel = data[1U];
|
||||||
|
|
||||||
uint8_t ctcssFrequency = data[2U];
|
uint8_t ctcssFrequency = data[2U];
|
||||||
uint8_t ctcssThreshold = data[3U];
|
uint8_t ctcssHighThreshold = data[3U];
|
||||||
uint8_t ctcssLevel = data[4U];
|
uint8_t ctcssLowThreshold = data[4U];
|
||||||
|
uint8_t ctcssLevel = data[5U];
|
||||||
|
|
||||||
uint8_t kerchunkTime = data[5U];
|
uint8_t kerchunkTime = data[6U];
|
||||||
uint8_t hangTime = data[6U];
|
uint8_t hangTime = data[7U];
|
||||||
|
|
||||||
bool useCOS = (data[7U] & 0x01U) == 0x01U;
|
bool useCOS = (data[8U] & 0x01U) == 0x01U;
|
||||||
bool cosInvert = (data[7U] & 0x02U) == 0x02U;
|
bool cosInvert = (data[8U] & 0x02U) == 0x02U;
|
||||||
|
bool kerchunkTX = (data[8U] & 0x04U) == 0x04U;
|
||||||
|
|
||||||
uint8_t rfAudioBoost = data[8U];
|
uint8_t rfAudioBoost = data[9U];
|
||||||
uint8_t maxDev = data[9U];
|
uint8_t maxDev = data[10U];
|
||||||
uint8_t rxLevel = data[10U];
|
uint8_t rxLevel = data[11U];
|
||||||
|
|
||||||
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssThreshold, 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::setMode(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||||
|
|||||||
+1
-1
@@ -906,7 +906,7 @@ int CSerialPort::availableForWriteInt(uint8_t n)
|
|||||||
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
|
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
|
||||||
return AvailForWriteUSART1();
|
return AvailForWriteUSART1();
|
||||||
#elif defined(DRCC_DVM)
|
#elif defined(DRCC_DVM)
|
||||||
AvailForWriteUSART2();
|
return AvailForWriteUSART2();
|
||||||
#else
|
#else
|
||||||
return AvailForWriteUART5();
|
return AvailForWriteUART5();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -66,9 +66,6 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CYSFTX::process()
|
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 we have YSF data to transmit, do so.
|
||||||
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
@@ -191,4 +188,3 @@ void CYSFTX::setParams(bool on, uint8_t txHang)
|
|||||||
m_loDev = on;
|
m_loDev = on;
|
||||||
m_txHang = txHang * 1200U;
|
m_txHang = txHang * 1200U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-29
@@ -22,36 +22,40 @@
|
|||||||
/*
|
/*
|
||||||
Pin definitions for DRCC_DVM BG7NQF board rev1
|
Pin definitions for DRCC_DVM BG7NQF board rev1
|
||||||
|
|
||||||
PTT PB12 output
|
TX/PTT_LED PB12 output
|
||||||
LED_PTT PB4 output
|
RX/COS_LED PB5 output
|
||||||
LED_COS PB5 output
|
STATUS_LED PB10 output
|
||||||
LED_SRV PB10 output
|
|
||||||
COS PB13 input
|
|
||||||
|
|
||||||
DSTAR N/A
|
COS_IN PB13 input
|
||||||
DMR N/A
|
|
||||||
YSF N/A
|
|
||||||
P25 N/A
|
|
||||||
NXDN N/A
|
|
||||||
POCSAG N/A
|
|
||||||
|
|
||||||
MDSTAR PB14 output
|
DSTAR N/A
|
||||||
MDMR PB8 output
|
DMR N/A
|
||||||
MYSF PB9 output
|
YSF N/A
|
||||||
MP25 PB15 output
|
P25 N/A
|
||||||
MNXDN N/A
|
NXDN N/A
|
||||||
MPOCSAG N/A
|
POCSAG N/A
|
||||||
|
|
||||||
RX PB0 analog input
|
MDMR/BIT0 PB8 output
|
||||||
RSSI PB1 analog input
|
MYSF/BIT1 PB9 output
|
||||||
TX PA4 analog output
|
MDSTAR/BIT2 PB14 output
|
||||||
|
MP25/BIT3 PB15 output Generic Mode Pins
|
||||||
|
MNXDN N/A
|
||||||
|
MPOCSAG N/A
|
||||||
|
|
||||||
EXT_CLK PA15 input
|
RX PA0 analog input
|
||||||
|
RSSI PA1 analog input
|
||||||
|
TX PA4 analog output
|
||||||
|
|
||||||
UART1_TX PA9 output
|
EXT_CLK PA15 input
|
||||||
UART1_RX PA10 output
|
|
||||||
UART2_TX PA2 output
|
UART1_TX PA9 output
|
||||||
UART2_RX PA3 output
|
UART1_RX PA10 output Host Data Communication
|
||||||
|
|
||||||
|
UART2_TX PA2 output
|
||||||
|
UART2_RX PA3 output Nextion Data Communication
|
||||||
|
|
||||||
|
I2C1_SCL PB6 output
|
||||||
|
I2C1_SDA PB7 output OLED Data Communication as master
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -124,13 +128,13 @@ UART2_RX PA3 output
|
|||||||
|
|
||||||
#define PIN_RX GPIO_Pin_0
|
#define PIN_RX GPIO_Pin_0
|
||||||
#define PIN_RX_CH ADC_Channel_0
|
#define PIN_RX_CH ADC_Channel_0
|
||||||
#define PORT_RX GPIOB
|
#define PORT_RX GPIOA
|
||||||
#define RCC_Per_RX RCC_AHB1Periph_GPIOB
|
#define RCC_Per_RX RCC_AHB1Periph_GPIOA
|
||||||
|
|
||||||
#define PIN_RSSI GPIO_Pin_1
|
#define PIN_RSSI GPIO_Pin_1
|
||||||
#define PIN_RSSI_CH ADC_Channel_1
|
#define PIN_RSSI_CH ADC_Channel_1
|
||||||
#define PORT_RSSI GPIOB
|
#define PORT_RSSI GPIOA
|
||||||
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOB
|
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOA
|
||||||
|
|
||||||
#define PIN_TX GPIO_Pin_4
|
#define PIN_TX GPIO_Pin_4
|
||||||
#define PIN_TX_CH DAC_Channel_1
|
#define PIN_TX_CH DAC_Channel_1
|
||||||
|
|||||||
Reference in New Issue
Block a user