mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-15 08:14:12 +02:00
Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60f87072ba | ||
|
|
f2d2033733 | ||
|
|
0334b5a791 | ||
|
|
a62fd814ae | ||
|
|
2509ab5ba1 | ||
|
|
fda1e3dcf4 | ||
|
|
632ddda68b | ||
|
|
fb85505433 | ||
|
|
823b91c97d | ||
|
|
a60ecb3e57 | ||
|
|
a2978d9e91 | ||
|
|
e304f5cce2 | ||
|
|
99a7df7c13 | ||
|
|
6dfe1a9271 | ||
|
|
1ac0628c1c | ||
|
|
dc41fd83d2 | ||
|
|
20013e3adc | ||
|
|
ccdbe126e0 | ||
|
|
f8d8f85841 | ||
|
|
598d32287d | ||
|
|
53d8cfa360 | ||
|
|
7fabddd7f1 |
@@ -35,9 +35,6 @@
|
||||
// For 19.2 MHz
|
||||
// #define EXTERNAL_OSC 19200000
|
||||
|
||||
// Allow the use of the COS line to lockout the modem
|
||||
// #define USE_COS_AS_LOCKOUT
|
||||
|
||||
// Use pins to output the current mode via LEDs
|
||||
// #define MODE_LEDS
|
||||
|
||||
@@ -81,6 +78,9 @@
|
||||
// Use the YSF and P25 LEDs for NXDN
|
||||
// #define USE_ALTERNATE_NXDN_LEDS
|
||||
|
||||
// Use the D-Star and P25 LEDs for M17
|
||||
// #define USE_ALTERNATE_M17_LEDS
|
||||
|
||||
// Use the D-Star and DMR LEDs for POCSAG
|
||||
// #define USE_ALTERNATE_POCSAG_LEDS
|
||||
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
#include "Globals.h"
|
||||
#include "FM.h"
|
||||
|
||||
/*
|
||||
* 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() :
|
||||
m_callsign(),
|
||||
m_rfAck(),
|
||||
@@ -37,11 +45,12 @@ m_kerchunkTimer(),
|
||||
m_ackMinTimer(),
|
||||
m_ackDelayTimer(),
|
||||
m_hangTimer(),
|
||||
m_reverseTimer(),
|
||||
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),
|
||||
m_blanking(),
|
||||
m_useCOS(true),
|
||||
m_accessMode(1U),
|
||||
m_cosInvert(false),
|
||||
m_rfAudioBoost(1U),
|
||||
m_downsampler(128U),//Size might need adjustement
|
||||
@@ -49,17 +58,15 @@ m_rxLevel(1),
|
||||
m_inputRB(4800U), // 200ms of audio
|
||||
m_outputRB(2400U) // 100ms of audio
|
||||
{
|
||||
m_reverseTimer.setTimeout(0U, 150U);
|
||||
|
||||
insertDelay(100U);
|
||||
}
|
||||
|
||||
void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
||||
{
|
||||
if (m_useCOS) {
|
||||
if (m_cosInvert)
|
||||
cos = !cos;
|
||||
} else {
|
||||
cos = true;
|
||||
}
|
||||
if (m_cosInvert)
|
||||
cos = !cos;
|
||||
|
||||
clock(length);
|
||||
|
||||
@@ -68,36 +75,56 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
||||
// 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);
|
||||
switch (m_accessMode) {
|
||||
case 0U:
|
||||
stateMachine(cos);
|
||||
break;
|
||||
|
||||
if (!m_useCOS) {
|
||||
// Delay the audio by 100ms to better match the CTCSS detector output
|
||||
m_inputRB.put(currentSample);
|
||||
m_inputRB.get(currentSample);
|
||||
}
|
||||
case 1U: {
|
||||
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
|
||||
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
|
||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||
stateMachine(validCTCSS && cos);
|
||||
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);
|
||||
if (m_modemState != STATE_FM)
|
||||
// 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) {
|
||||
// Not enough samples to determine if you have CTCSS, just carry on
|
||||
} else {
|
||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||
stateMachine(validCTCSS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2U: {
|
||||
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
|
||||
} else {
|
||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||
stateMachine(validCTCSS && cos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
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
|
||||
} 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);
|
||||
} else {
|
||||
stateMachine(cos);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if (m_modemState != STATE_FM)
|
||||
continue;
|
||||
|
||||
// Only let audio through when relaying audio
|
||||
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
||||
// m_downsampler.addSample(currentSample);
|
||||
@@ -117,15 +144,14 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
||||
currentSample += m_callsign.getLowAudio();
|
||||
}
|
||||
|
||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||
|
||||
if (!m_callsign.isRunning() && !m_rfAck.isRunning())
|
||||
currentSample += m_timeoutTone.getAudio();
|
||||
|
||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
|
||||
|
||||
currentSample += m_ctcssTX.getAudio();
|
||||
|
||||
if (m_modemState == STATE_FM)
|
||||
m_outputRB.put(currentSample);
|
||||
m_outputRB.put(currentSample);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +172,7 @@ void CFM::reset()
|
||||
m_ackMinTimer.stop();
|
||||
m_ackDelayTimer.stop();
|
||||
m_hangTimer.stop();
|
||||
m_reverseTimer.stop();
|
||||
|
||||
m_ctcssRX.reset();
|
||||
m_rfAck.stop();
|
||||
@@ -183,10 +210,10 @@ 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, uint8_t hangTime, uint8_t accessMode, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
|
||||
{
|
||||
m_useCOS = useCOS;
|
||||
m_cosInvert = cosInvert;
|
||||
m_accessMode = accessMode;
|
||||
m_cosInvert = cosInvert;
|
||||
|
||||
m_rfAudioBoost = q15_t(rfAudioBoost);
|
||||
|
||||
@@ -235,7 +262,10 @@ void CFM::stateMachine(bool validSignal)
|
||||
}
|
||||
|
||||
if (m_state == FS_LISTENING && m_modemState == STATE_FM) {
|
||||
if (!m_callsign.isWanted() && !m_rfAck.isWanted()) {
|
||||
if (!m_callsign.isWanted() && !m_rfAck.isWanted() && !m_reverseTimer.isRunning())
|
||||
m_reverseTimer.start();
|
||||
|
||||
if (!m_callsign.isWanted() && !m_rfAck.isWanted() && m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
|
||||
DEBUG1("Change to STATE_IDLE");
|
||||
m_modemState = STATE_IDLE;
|
||||
m_callsignTimer.stop();
|
||||
@@ -244,6 +274,7 @@ void CFM::stateMachine(bool validSignal)
|
||||
m_ackMinTimer.stop();
|
||||
m_ackDelayTimer.stop();
|
||||
m_hangTimer.stop();
|
||||
m_reverseTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,6 +288,7 @@ void CFM::clock(uint8_t length)
|
||||
m_ackMinTimer.clock(length);
|
||||
m_ackDelayTimer.clock(length);
|
||||
m_hangTimer.clock(length);
|
||||
m_reverseTimer.clock(length);
|
||||
}
|
||||
|
||||
void CFM::listeningState(bool validSignal)
|
||||
@@ -280,6 +312,7 @@ void CFM::listeningState(bool validSignal)
|
||||
beginRelaying();
|
||||
|
||||
m_callsignTimer.start();
|
||||
m_reverseTimer.stop();
|
||||
|
||||
io.setDecode(true);
|
||||
io.setADCDetection(true);
|
||||
|
||||
@@ -56,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 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);
|
||||
|
||||
private:
|
||||
CFMKeyer m_callsign;
|
||||
@@ -75,11 +75,12 @@ private:
|
||||
CFMTimer m_ackMinTimer;
|
||||
CFMTimer m_ackDelayTimer;
|
||||
CFMTimer m_hangTimer;
|
||||
CFMTimer m_reverseTimer;
|
||||
CFMDirectFormI m_filterStage1;
|
||||
CFMDirectFormI m_filterStage2;
|
||||
CFMDirectFormI m_filterStage3;
|
||||
CFMBlanking m_blanking;
|
||||
bool m_useCOS;
|
||||
uint8_t m_accessMode;
|
||||
bool m_cosInvert;
|
||||
q15_t m_rfAudioBoost;
|
||||
CFMDownsampler m_downsampler;
|
||||
|
||||
+6
-3
@@ -115,11 +115,14 @@ uint8_t CFMCTCSSTX::setParams(uint8_t frequency, uint8_t level)
|
||||
return 0U;
|
||||
}
|
||||
|
||||
q15_t CFMCTCSSTX::getAudio()
|
||||
q15_t CFMCTCSSTX::getAudio(bool reverse)
|
||||
{
|
||||
q15_t sample = m_values[m_n++];
|
||||
if(m_n >= m_length)
|
||||
if (m_n >= m_length)
|
||||
m_n = 0U;
|
||||
|
||||
return sample;
|
||||
if (reverse)
|
||||
return -sample;
|
||||
else
|
||||
return sample;
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ public:
|
||||
|
||||
uint8_t setParams(uint8_t frequency, uint8_t level);
|
||||
|
||||
q15_t getAudio();
|
||||
q15_t getAudio(bool reverse);
|
||||
|
||||
private:
|
||||
q15_t* m_values;
|
||||
|
||||
+5
-7
@@ -36,24 +36,22 @@ m_n(0U)
|
||||
|
||||
void CFMTimeout::setParams(uint8_t level)
|
||||
{
|
||||
m_level = q15_t(level * 128);
|
||||
m_level = q15_t(level * 5);
|
||||
}
|
||||
|
||||
q15_t CFMTimeout::getAudio()
|
||||
{
|
||||
q15_t sample = 0U;
|
||||
q15_t sample = 0;
|
||||
if (!m_running)
|
||||
return sample;
|
||||
|
||||
if (m_pos > 12000U) {
|
||||
q31_t sample = BUSY_AUDIO[m_n] * m_level;
|
||||
sample = q15_t(__SSAT((sample >> 15), 16));
|
||||
if (m_pos >= 12000U) {
|
||||
q31_t sample31 = BUSY_AUDIO[m_n] * m_level;
|
||||
sample = q15_t(__SSAT((sample31 >> 15), 16));
|
||||
|
||||
m_n++;
|
||||
if (m_n >= BUSY_AUDIO_LEN)
|
||||
m_n = 0U;
|
||||
} else {
|
||||
sample = 0U;
|
||||
}
|
||||
|
||||
m_pos++;
|
||||
|
||||
@@ -50,6 +50,7 @@ enum MMDVM_STATE {
|
||||
STATE_P25 = 4,
|
||||
STATE_NXDN = 5,
|
||||
STATE_POCSAG = 6,
|
||||
STATE_M17 = 7,
|
||||
STATE_FM = 10,
|
||||
|
||||
// Dummy states start at 90
|
||||
@@ -84,6 +85,8 @@ enum MMDVM_STATE {
|
||||
#include "YSFTX.h"
|
||||
#include "P25RX.h"
|
||||
#include "P25TX.h"
|
||||
#include "M17RX.h"
|
||||
#include "M17TX.h"
|
||||
#include "NXDNRX.h"
|
||||
#include "NXDNTX.h"
|
||||
#include "POCSAGTX.h"
|
||||
@@ -123,6 +126,7 @@ extern bool m_ysfEnable;
|
||||
extern bool m_p25Enable;
|
||||
extern bool m_nxdnEnable;
|
||||
extern bool m_pocsagEnable;
|
||||
extern bool m_m17Enable;
|
||||
extern bool m_fmEnable;
|
||||
|
||||
extern bool m_duplex;
|
||||
@@ -154,6 +158,9 @@ extern CNXDNTX nxdnTX;
|
||||
|
||||
extern CPOCSAGTX pocsagTX;
|
||||
|
||||
extern CM17RX m17RX;
|
||||
extern CM17TX m17TX;
|
||||
|
||||
extern CFM fm;
|
||||
|
||||
extern CCalDStarRX calDStarRX;
|
||||
|
||||
@@ -32,6 +32,12 @@ static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 147
|
||||
-553, -847, -731, -340, 104, 401, 0};
|
||||
const uint16_t RRC_0_2_FILTER_LEN = 42U;
|
||||
|
||||
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
|
||||
static q15_t RRC_0_5_FILTER[] = {-147, -88, 72, 220, 223, 46, -197, -285, -79, 334, 623, 390, -498, -1691, -2363, -1556, 1284, 5872, 11033,
|
||||
15109, 16656, 15109, 11033, 5872, 1284, -1556, -2363, -1691, -498, 390, 623, 334, -79, -285, -197, 46, 223,
|
||||
220, 72, -88, -147, 0};
|
||||
const uint16_t RRC_0_5_FILTER_LEN = 42U;
|
||||
|
||||
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
||||
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
|
||||
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
|
||||
@@ -61,12 +67,14 @@ m_txBuffer(TX_RINGBUFFER_SIZE),
|
||||
m_rssiBuffer(RX_RINGBUFFER_SIZE),
|
||||
m_dcFilter(),
|
||||
m_dcState(),
|
||||
m_rrcFilter(),
|
||||
m_rrc02Filter(),
|
||||
m_rrc05Filter(),
|
||||
m_gaussianFilter(),
|
||||
m_boxcarFilter(),
|
||||
m_nxdnFilter(),
|
||||
m_nxdnISincFilter(),
|
||||
m_rrcState(),
|
||||
m_rrc02State(),
|
||||
m_rrc05State(),
|
||||
m_gaussianState(),
|
||||
m_boxcarState(),
|
||||
m_nxdnState(),
|
||||
@@ -79,10 +87,12 @@ m_dmrTXLevel(128 * 128),
|
||||
m_ysfTXLevel(128 * 128),
|
||||
m_p25TXLevel(128 * 128),
|
||||
m_nxdnTXLevel(128 * 128),
|
||||
m_m17TXLevel(128 * 128),
|
||||
m_pocsagTXLevel(128 * 128),
|
||||
m_fmTXLevel(128 * 128),
|
||||
m_rxDCOffset(DC_OFFSET),
|
||||
m_txDCOffset(DC_OFFSET),
|
||||
m_useCOSAsLockout(false),
|
||||
m_ledCount(0U),
|
||||
m_ledValue(true),
|
||||
m_detect(false),
|
||||
@@ -91,7 +101,8 @@ m_dacOverflow(0U),
|
||||
m_watchdog(0U),
|
||||
m_lockout(false)
|
||||
{
|
||||
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t));
|
||||
::memset(m_rrc02State, 0x00U, 70U * sizeof(q15_t));
|
||||
::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t));
|
||||
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
|
||||
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
|
||||
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
|
||||
@@ -103,9 +114,13 @@ m_lockout(false)
|
||||
m_dcFilter.pCoeffs = DC_FILTER;
|
||||
m_dcFilter.postShift = 0;
|
||||
|
||||
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN;
|
||||
m_rrcFilter.pState = m_rrcState;
|
||||
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
|
||||
m_rrc02Filter.numTaps = RRC_0_2_FILTER_LEN;
|
||||
m_rrc02Filter.pState = m_rrc02State;
|
||||
m_rrc02Filter.pCoeffs = RRC_0_2_FILTER;
|
||||
|
||||
m_rrc05Filter.numTaps = RRC_0_5_FILTER_LEN;
|
||||
m_rrc05Filter.pState = m_rrc05State;
|
||||
m_rrc05Filter.pCoeffs = RRC_0_5_FILTER;
|
||||
|
||||
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
|
||||
m_gaussianFilter.pState = m_gaussianState;
|
||||
@@ -132,7 +147,7 @@ void CIO::selfTest()
|
||||
{
|
||||
bool ledValue = false;
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
for (uint8_t i = 0U; i < 6U; i++) {
|
||||
ledValue = !ledValue;
|
||||
|
||||
// We exclude PTT to avoid trigger the transmitter
|
||||
@@ -143,21 +158,40 @@ void CIO::selfTest()
|
||||
setDMRInt(ledValue);
|
||||
setYSFInt(ledValue);
|
||||
setP25Int(ledValue);
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
setNXDNInt(ledValue);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
setM17Int(ledValue);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
setPOCSAGInt(ledValue);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
setFMInt(ledValue);
|
||||
#endif
|
||||
#endif
|
||||
delayInt(250);
|
||||
}
|
||||
|
||||
#if defined(MODE_LEDS)
|
||||
setDStarInt(true);
|
||||
setDStarInt(false);
|
||||
setDMRInt(false);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
setNXDNInt(false);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
setM17Int(false);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
setPOCSAGInt(false);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
setFMInt(false);
|
||||
#endif
|
||||
setDStarInt(true);
|
||||
|
||||
delayInt(250);
|
||||
setDMRInt(true);
|
||||
@@ -173,6 +207,11 @@ void CIO::selfTest()
|
||||
setNXDNInt(true);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
delayInt(250);
|
||||
setM17Int(true);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
delayInt(250);
|
||||
setPOCSAGInt(true);
|
||||
@@ -191,6 +230,11 @@ void CIO::selfTest()
|
||||
setPOCSAGInt(false);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
delayInt(250);
|
||||
setM17Int(false);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
delayInt(250);
|
||||
setNXDNInt(false);
|
||||
@@ -219,7 +263,7 @@ void CIO::start()
|
||||
|
||||
m_started = true;
|
||||
|
||||
setMode();
|
||||
setMode(STATE_IDLE);
|
||||
}
|
||||
|
||||
void CIO::process()
|
||||
@@ -228,11 +272,10 @@ void CIO::process()
|
||||
if (m_started) {
|
||||
// Two seconds timeout
|
||||
if (m_watchdog >= 48000U) {
|
||||
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) {
|
||||
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_M17 || m_modemState == STATE_POCSAG) {
|
||||
if (m_modemState == STATE_DMR && m_tx)
|
||||
dmrTX.setStart(false);
|
||||
m_modemState = STATE_IDLE;
|
||||
setMode();
|
||||
setMode(STATE_IDLE);
|
||||
}
|
||||
|
||||
m_watchdog = 0U;
|
||||
@@ -256,9 +299,8 @@ void CIO::process()
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(USE_COS_AS_LOCKOUT)
|
||||
m_lockout = getCOSInt();
|
||||
#endif
|
||||
if (m_useCOSAsLockout)
|
||||
m_lockout = getCOSInt();
|
||||
|
||||
// Switch off the transmitter if needed
|
||||
if (m_txBuffer.getData() == 0U && m_tx) {
|
||||
@@ -341,19 +383,34 @@ void CIO::process()
|
||||
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_dmrEnable || m_ysfEnable) {
|
||||
if (m_dmrEnable) {
|
||||
q15_t DMRVals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_duplex)
|
||||
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
|
||||
else
|
||||
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_ysfEnable) {
|
||||
q15_t YSFVals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_m17Enable) {
|
||||
q15_t RRCVals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_rrcFilter, samples, RRCVals, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_ysfEnable)
|
||||
ysfRX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_dmrEnable) {
|
||||
if (m_duplex)
|
||||
dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE);
|
||||
else
|
||||
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, RRCVals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_rrc05Filter, samples, RRCVals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
m17RX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_fmEnable) {
|
||||
@@ -377,7 +434,7 @@ void CIO::process()
|
||||
} else if (m_modemState == STATE_DMR) {
|
||||
if (m_dmrEnable) {
|
||||
q15_t DMRVals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_rrcFilter, samples, DMRVals, RX_BLOCK_SIZE);
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_duplex) {
|
||||
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
|
||||
@@ -393,9 +450,9 @@ void CIO::process()
|
||||
if (m_ysfEnable) {
|
||||
q15_t YSFVals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_rrcFilter, samples, YSFVals, RX_BLOCK_SIZE);
|
||||
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
@@ -422,6 +479,16 @@ void CIO::process()
|
||||
|
||||
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_M17) {
|
||||
if (m_m17Enable) {
|
||||
q15_t M17Vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, M17Vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_rrc05Filter, samples, M17Vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
m17RX.samples(M17Vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_FM) {
|
||||
bool cos = getCOSInt();
|
||||
#if defined(USE_DCBLOCKER)
|
||||
@@ -471,6 +538,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
||||
case STATE_NXDN:
|
||||
txLevel = m_nxdnTXLevel;
|
||||
break;
|
||||
case STATE_M17:
|
||||
txLevel = m_m17TXLevel;
|
||||
break;
|
||||
case STATE_POCSAG:
|
||||
txLevel = m_pocsagTXLevel;
|
||||
break;
|
||||
@@ -516,20 +586,39 @@ void CIO::setADCDetection(bool detect)
|
||||
m_detect = detect;
|
||||
}
|
||||
|
||||
void CIO::setMode()
|
||||
void CIO::setMode(MMDVM_STATE state)
|
||||
{
|
||||
if (state == m_modemState)
|
||||
return;
|
||||
|
||||
#if defined(MODE_LEDS)
|
||||
setDStarInt(m_modemState == STATE_DSTAR);
|
||||
setDMRInt(m_modemState == STATE_DMR);
|
||||
setYSFInt(m_modemState == STATE_YSF);
|
||||
setP25Int(m_modemState == STATE_P25);
|
||||
setNXDNInt(m_modemState == STATE_NXDN);
|
||||
setPOCSAGInt(m_modemState == STATE_POCSAG);
|
||||
setFMInt(m_modemState == STATE_FM);
|
||||
switch (m_modemState) {
|
||||
case STATE_DSTAR: setDStarInt(false); break;
|
||||
case STATE_DMR: setDMRInt(false); break;
|
||||
case STATE_YSF: setYSFInt(false); break;
|
||||
case STATE_P25: setP25Int(false); break;
|
||||
case STATE_NXDN: setNXDNInt(false); break;
|
||||
case STATE_M17: setM17Int(false); break;
|
||||
case STATE_POCSAG: setPOCSAGInt(false); break;
|
||||
case STATE_FM: setFMInt(false); break;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case STATE_DSTAR: setDStarInt(true); break;
|
||||
case STATE_DMR: setDMRInt(true); break;
|
||||
case STATE_YSF: setYSFInt(true); break;
|
||||
case STATE_P25: setP25Int(true); break;
|
||||
case STATE_NXDN: setNXDNInt(true); break;
|
||||
case STATE_M17: setM17Int(true); break;
|
||||
case STATE_POCSAG: setPOCSAGInt(true); break;
|
||||
case STATE_FM: setFMInt(true); break;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_modemState = state;
|
||||
}
|
||||
|
||||
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 m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
|
||||
{
|
||||
m_pttInvert = pttInvert;
|
||||
|
||||
@@ -540,11 +629,14 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
||||
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
|
||||
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
||||
m_m17TXLevel = q15_t(m17TXLevel * 128);
|
||||
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
||||
m_fmTXLevel = q15_t(fmTXLevel * 128);
|
||||
|
||||
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
||||
m_txDCOffset = DC_OFFSET + txDCOffset;
|
||||
|
||||
m_useCOSAsLockout = useCOSAsLockout;
|
||||
|
||||
if (rxInvert)
|
||||
m_rxLevel = -m_rxLevel;
|
||||
@@ -555,6 +647,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
||||
m_ysfTXLevel = -m_ysfTXLevel;
|
||||
m_p25TXLevel = -m_p25TXLevel;
|
||||
m_nxdnTXLevel = -m_nxdnTXLevel;
|
||||
m_m17TXLevel = -m_m17TXLevel;
|
||||
m_pocsagTXLevel = -m_pocsagTXLevel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
|
||||
void setDecode(bool dcd);
|
||||
void setADCDetection(bool detect);
|
||||
void setMode();
|
||||
void setMode(MMDVM_STATE state);
|
||||
|
||||
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 m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
|
||||
|
||||
void getOverflow(bool& adcOverflow, bool& dacOverflow);
|
||||
|
||||
@@ -66,14 +66,16 @@ private:
|
||||
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
||||
q31_t m_dcState[4];
|
||||
|
||||
arm_fir_instance_q15 m_rrcFilter;
|
||||
arm_fir_instance_q15 m_rrc02Filter;
|
||||
arm_fir_instance_q15 m_rrc05Filter;
|
||||
arm_fir_instance_q15 m_gaussianFilter;
|
||||
arm_fir_instance_q15 m_boxcarFilter;
|
||||
arm_fir_instance_q15 m_nxdnFilter;
|
||||
arm_fir_instance_q15 m_nxdnISincFilter;
|
||||
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||
q15_t m_rrc02State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||
q15_t m_rrc05State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
|
||||
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
|
||||
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
||||
|
||||
@@ -85,12 +87,15 @@ private:
|
||||
q15_t m_ysfTXLevel;
|
||||
q15_t m_p25TXLevel;
|
||||
q15_t m_nxdnTXLevel;
|
||||
q15_t m_m17TXLevel;
|
||||
q15_t m_pocsagTXLevel;
|
||||
q15_t m_fmTXLevel;
|
||||
|
||||
uint16_t m_rxDCOffset;
|
||||
uint16_t m_txDCOffset;
|
||||
|
||||
bool m_useCOSAsLockout;
|
||||
|
||||
uint32_t m_ledCount;
|
||||
bool m_ledValue;
|
||||
|
||||
@@ -119,6 +124,7 @@ private:
|
||||
void setP25Int(bool on);
|
||||
void setNXDNInt(bool on);
|
||||
void setPOCSAGInt(bool on);
|
||||
void setM17Int(bool on);
|
||||
void setFMInt(bool on);
|
||||
|
||||
void delayInt(unsigned int dly);
|
||||
|
||||
@@ -107,6 +107,9 @@ void CIO::initInt()
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
pinMode(PIN_NXDN, OUTPUT);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
pinMode(PIN_M17, OUTPUT);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
pinMode(PIN_POCSAG, OUTPUT);
|
||||
#endif
|
||||
@@ -254,6 +257,16 @@ void CIO::setNXDNInt(bool on)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setM17Int(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||
#else
|
||||
digitalWrite(PIN_M17, on ? HIGH : LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setPOCSAGInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
|
||||
@@ -62,9 +62,12 @@
|
||||
#elif defined(DRCC_DVM_NQF)
|
||||
#include "pins/pins_f4_drcc_nqf.h"
|
||||
|
||||
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
#include "pins/pins_f4_stm32eda.h"
|
||||
|
||||
#else
|
||||
#error "A valid board type macro need to be defined."
|
||||
|
||||
#endif
|
||||
|
||||
#endif //#ifndef _IO_PINS_H
|
||||
#endif //#ifndef _IO_PINS_H
|
||||
|
||||
@@ -106,6 +106,14 @@ void CIO::initInt()
|
||||
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
// M17 pin
|
||||
RCC_AHB1PeriphClockCmd(RCC_Per_M17, ENABLE);
|
||||
GPIO_InitStruct.GPIO_Pin = PIN_M17;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
|
||||
GPIO_Init(PORT_M17, &GPIO_InitStruct);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
// POCSAG pin
|
||||
RCC_AHB1PeriphClockCmd(RCC_Per_POCSAG, ENABLE);
|
||||
@@ -157,6 +165,14 @@ void CIO::initInt()
|
||||
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
// M17 mode pin
|
||||
RCC_AHB1PeriphClockCmd(RCC_Per_MM17, ENABLE);
|
||||
GPIO_InitStruct.GPIO_Pin = PIN_MM17;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
|
||||
GPIO_Init(PORT_MM17, &GPIO_InitStruct);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
// POCSAG mode pin
|
||||
RCC_AHB1PeriphClockCmd(RCC_Per_MPOCSAG, ENABLE);
|
||||
@@ -441,6 +457,27 @@ void CIO::setNXDNInt(bool on)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setM17Int(bool on)
|
||||
{
|
||||
#if defined(MODE_LEDS)
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
|
||||
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
|
||||
#else
|
||||
GPIO_WriteBit(PORT_M17, PIN_M17, on ? Bit_SET : Bit_RESET);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
|
||||
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
|
||||
#else
|
||||
GPIO_WriteBit(PORT_MM17, PIN_MM17, on ? Bit_SET : Bit_RESET);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setPOCSAGInt(bool on)
|
||||
{
|
||||
#if defined(MODE_LEDS)
|
||||
|
||||
+26
-45
@@ -41,7 +41,6 @@ YSF PB8 output
|
||||
P25 PB9 output
|
||||
NXDN PB10 output
|
||||
POCSAG PB11 output
|
||||
FM PB12 output
|
||||
|
||||
RX PB0 analog input (ADC1_8)
|
||||
RSSI PB1 analog input (ADC2_9)
|
||||
@@ -85,9 +84,6 @@ USART1_RXD PA10 input (AF)
|
||||
#define PIN_POCSAG 11
|
||||
#define PORT_POCSAG GPIOB
|
||||
#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_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)
|
||||
void FancyLEDEffect()
|
||||
{
|
||||
int ledCount = 10;
|
||||
|
||||
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25,
|
||||
#if defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
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;
|
||||
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
|
||||
|
||||
for(int i=0; i<7; i++){
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||
delay(SystemCoreClock/1000*100);
|
||||
for(int i=0; i<ledCount; i++){
|
||||
if(foo[i] != NULL)
|
||||
*foo[i] = 0x00;
|
||||
for(int i=0; i<7; i++){
|
||||
*foo[i] = 0x00;
|
||||
}
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
delay(SystemCoreClock/1000*20);
|
||||
@@ -195,22 +172,18 @@ void FancyLEDEffect()
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
|
||||
*foo[0] = 0x01;
|
||||
for(int i=1; i<ledCount; i++){
|
||||
for(int i=1; i<7; i++){
|
||||
delay(SystemCoreClock/1000*10);
|
||||
if (foo[i-1] != NULL)
|
||||
*foo[i-1] = 0x00;
|
||||
if (foo[i] != NULL)
|
||||
*foo[i] = 0x01;
|
||||
*foo[i-1] = 0x00;
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
for(int i=ledCount - 2; i>=0; i--) {
|
||||
for(int i=5; i>=0; i--){
|
||||
delay(SystemCoreClock/1000*10);
|
||||
if (foo[i+1] != NULL)
|
||||
*foo[i+1] = 0x00;
|
||||
if (foo[i] != NULL)
|
||||
*foo[i] = 0x01;
|
||||
*foo[i+1] = 0x00;
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*foo[0] = 0x00;
|
||||
*foo[5+1-6] = 0x00;
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
@@ -252,12 +225,12 @@ static inline void GPIOInit()
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
GPIOConfigPin(PORT_M17, PIN_M17, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
GPIOConfigPin(PORT_FM, PIN_FM, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
|
||||
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
@@ -480,6 +453,16 @@ void CIO::setNXDNInt(bool on)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setM17Int(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
BB_DSTAR = !!on;
|
||||
BB_P25 = !!on;
|
||||
#else
|
||||
BB_M17 = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setPOCSAGInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
@@ -495,8 +478,6 @@ void CIO::setFMInt(bool on)
|
||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||
BB_DSTAR = !!on;
|
||||
BB_YSF = !!on;
|
||||
#else
|
||||
BB_FM = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ void CIO::initInt()
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
pinMode(PIN_NXDN, OUTPUT);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
pinMode(PIN_M17, OUTPUT);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
pinMode(PIN_POCSAG, OUTPUT);
|
||||
#endif
|
||||
@@ -238,6 +241,16 @@ void CIO::setNXDNInt(bool on)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setM17Int(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||
#else
|
||||
digitalWrite(PIN_M17, on ? HIGH : LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setPOCSAGInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 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
|
||||
* 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(M17DEFINES_H)
|
||||
#define M17DEFINES_H
|
||||
|
||||
const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||
|
||||
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
|
||||
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
|
||||
const unsigned int M17_FRAME_LENGTH_SYMBOLS = M17_FRAME_LENGTH_BITS / 2U;
|
||||
const unsigned int M17_FRAME_LENGTH_SAMPLES = M17_FRAME_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
|
||||
|
||||
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
|
||||
const unsigned int M17_SYNC_LENGTH_SYMBOLS = M17_SYNC_LENGTH_BITS / 2U;
|
||||
const unsigned int M17_SYNC_LENGTH_SAMPLES = M17_SYNC_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
|
||||
|
||||
const uint8_t M17_SYNC_BYTES[] = {0x32U, 0x43U};
|
||||
const uint8_t M17_SYNC_BYTES_LENGTH = 2U;
|
||||
|
||||
const uint16_t M17_SYNC_BITS = 0x3243U;
|
||||
|
||||
// 3 2 4 3
|
||||
// 00 11 00 10 01 00 00 11
|
||||
// +1 -3 +1 -1 +3 +1 +1 -3
|
||||
|
||||
const int8_t M17_SYNC_SYMBOLS_VALUES[] = {+1, -3, +1, -1, +3, +1, +1, -3};
|
||||
|
||||
const uint8_t M17_SYNC_SYMBOLS = 0xAEU;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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
|
||||
* 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 "M17RX.h"
|
||||
#include "Utils.h"
|
||||
|
||||
const q15_t SCALING_FACTOR = 18750; // Q15(0.55)
|
||||
|
||||
const uint8_t MAX_SYNC_BIT_START_ERRS = 2U;
|
||||
const uint8_t MAX_SYNC_BIT_RUN_ERRS = 4U;
|
||||
|
||||
const uint8_t MAX_SYNC_SYMBOLS_ERRS = 3U;
|
||||
|
||||
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||
|
||||
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||
|
||||
const uint8_t NOAVEPTR = 99U;
|
||||
|
||||
const uint16_t NOENDPTR = 9999U;
|
||||
|
||||
const unsigned int MAX_SYNC_FRAMES = 1U + 1U;
|
||||
|
||||
CM17RX::CM17RX() :
|
||||
m_state(M17RXS_NONE),
|
||||
m_bitBuffer(),
|
||||
m_buffer(),
|
||||
m_bitPtr(0U),
|
||||
m_dataPtr(0U),
|
||||
m_startPtr(NOENDPTR),
|
||||
m_endPtr(NOENDPTR),
|
||||
m_syncPtr(NOENDPTR),
|
||||
m_minSyncPtr(NOENDPTR),
|
||||
m_maxSyncPtr(NOENDPTR),
|
||||
m_maxCorr(0),
|
||||
m_lostCount(0U),
|
||||
m_countdown(0U),
|
||||
m_centre(),
|
||||
m_centreVal(0),
|
||||
m_threshold(),
|
||||
m_thresholdVal(0),
|
||||
m_averagePtr(NOAVEPTR),
|
||||
m_rssiAccum(0U),
|
||||
m_rssiCount(0U)
|
||||
{
|
||||
}
|
||||
|
||||
void CM17RX::reset()
|
||||
{
|
||||
m_state = M17RXS_NONE;
|
||||
m_dataPtr = 0U;
|
||||
m_bitPtr = 0U;
|
||||
m_maxCorr = 0;
|
||||
m_averagePtr = NOAVEPTR;
|
||||
m_startPtr = NOENDPTR;
|
||||
m_endPtr = NOENDPTR;
|
||||
m_syncPtr = NOENDPTR;
|
||||
m_minSyncPtr = NOENDPTR;
|
||||
m_maxSyncPtr = NOENDPTR;
|
||||
m_centreVal = 0;
|
||||
m_thresholdVal = 0;
|
||||
m_lostCount = 0U;
|
||||
m_countdown = 0U;
|
||||
m_rssiAccum = 0U;
|
||||
m_rssiCount = 0U;
|
||||
}
|
||||
|
||||
void CM17RX::samples(const q15_t* samples, uint16_t* rssi, uint8_t length)
|
||||
{
|
||||
for (uint8_t i = 0U; i < length; i++) {
|
||||
q15_t sample = samples[i];
|
||||
|
||||
m_rssiAccum += rssi[i];
|
||||
m_rssiCount++;
|
||||
|
||||
m_bitBuffer[m_bitPtr] <<= 1;
|
||||
if (sample < 0)
|
||||
m_bitBuffer[m_bitPtr] |= 0x01U;
|
||||
|
||||
m_buffer[m_dataPtr] = sample;
|
||||
|
||||
switch (m_state) {
|
||||
case M17RXS_DATA:
|
||||
processData(sample);
|
||||
break;
|
||||
default:
|
||||
processNone(sample);
|
||||
break;
|
||||
}
|
||||
|
||||
m_dataPtr++;
|
||||
if (m_dataPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_dataPtr = 0U;
|
||||
|
||||
m_bitPtr++;
|
||||
if (m_bitPtr >= M17_RADIO_SYMBOL_LENGTH)
|
||||
m_bitPtr = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CM17RX::processNone(q15_t sample)
|
||||
{
|
||||
bool ret = correlateSync();
|
||||
if (ret) {
|
||||
// On the first sync, start the countdown to the state change
|
||||
if (m_countdown == 0U) {
|
||||
m_rssiAccum = 0U;
|
||||
m_rssiCount = 0U;
|
||||
|
||||
io.setDecode(true);
|
||||
io.setADCDetection(true);
|
||||
|
||||
m_averagePtr = NOAVEPTR;
|
||||
|
||||
m_countdown = 5U;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_countdown > 0U)
|
||||
m_countdown--;
|
||||
|
||||
if (m_countdown == 1U) {
|
||||
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
|
||||
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_maxSyncPtr = m_syncPtr + 1U;
|
||||
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_state = M17RXS_DATA;
|
||||
m_countdown = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CM17RX::processData(q15_t sample)
|
||||
{
|
||||
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
||||
correlateSync();
|
||||
} else {
|
||||
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
||||
correlateSync();
|
||||
}
|
||||
|
||||
if (m_dataPtr == m_endPtr) {
|
||||
// Only update the centre and threshold if they are from a good sync
|
||||
if (m_lostCount == MAX_SYNC_FRAMES) {
|
||||
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
|
||||
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_maxSyncPtr = m_syncPtr + 1U;
|
||||
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
}
|
||||
|
||||
calculateLevels(m_startPtr, M17_FRAME_LENGTH_SYMBOLS);
|
||||
|
||||
DEBUG4("M17RX: sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
|
||||
|
||||
uint8_t frame[M17_FRAME_LENGTH_BYTES + 3U];
|
||||
samplesToBits(m_startPtr, M17_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
|
||||
|
||||
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
|
||||
m_lostCount--;
|
||||
if (m_lostCount == 0U) {
|
||||
DEBUG1("M17RX: sync timed out, lost lock");
|
||||
|
||||
io.setDecode(false);
|
||||
io.setADCDetection(false);
|
||||
|
||||
serial.writeM17Lost();
|
||||
|
||||
m_state = M17RXS_NONE;
|
||||
m_endPtr = NOENDPTR;
|
||||
m_averagePtr = NOAVEPTR;
|
||||
m_countdown = 0U;
|
||||
m_maxCorr = 0;
|
||||
} else {
|
||||
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
|
||||
writeRSSIData(frame);
|
||||
m_maxCorr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CM17RX::correlateSync()
|
||||
{
|
||||
if (countBits8(m_bitBuffer[m_bitPtr] ^ M17_SYNC_SYMBOLS) <= MAX_SYNC_SYMBOLS_ERRS) {
|
||||
uint16_t ptr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
|
||||
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
ptr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
q31_t corr = 0;
|
||||
q15_t min = 16000;
|
||||
q15_t max = -16000;
|
||||
|
||||
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_SYMBOLS; i++) {
|
||||
q15_t val = m_buffer[ptr];
|
||||
|
||||
if (val > max)
|
||||
max = val;
|
||||
if (val < min)
|
||||
min = val;
|
||||
|
||||
switch (M17_SYNC_SYMBOLS_VALUES[i]) {
|
||||
case +3:
|
||||
corr -= (val + val + val);
|
||||
break;
|
||||
case +1:
|
||||
corr -= val;
|
||||
break;
|
||||
case -1:
|
||||
corr += val;
|
||||
break;
|
||||
default: // -3
|
||||
corr += (val + val + val);
|
||||
break;
|
||||
}
|
||||
|
||||
ptr += M17_RADIO_SYMBOL_LENGTH;
|
||||
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
ptr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
}
|
||||
|
||||
if (corr > m_maxCorr) {
|
||||
if (m_averagePtr == NOAVEPTR) {
|
||||
m_centreVal = (max + min) >> 1;
|
||||
|
||||
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
|
||||
m_thresholdVal = q15_t(v1 >> 15);
|
||||
}
|
||||
|
||||
uint16_t startPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
|
||||
if (startPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
startPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
uint8_t sync[M17_SYNC_BYTES_LENGTH];
|
||||
samplesToBits(startPtr, M17_SYNC_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
|
||||
|
||||
uint8_t maxErrs;
|
||||
if (m_state == M17RXS_NONE)
|
||||
maxErrs = MAX_SYNC_BIT_START_ERRS;
|
||||
else
|
||||
maxErrs = MAX_SYNC_BIT_RUN_ERRS;
|
||||
|
||||
uint8_t errs = 0U;
|
||||
for (uint8_t i = 0U; i < M17_SYNC_BYTES_LENGTH; i++)
|
||||
errs += countBits8(sync[i] ^ M17_SYNC_BYTES[i]);
|
||||
|
||||
if (errs <= maxErrs) {
|
||||
m_maxCorr = corr;
|
||||
m_lostCount = MAX_SYNC_FRAMES;
|
||||
m_syncPtr = m_dataPtr;
|
||||
|
||||
m_startPtr = startPtr;
|
||||
|
||||
m_endPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES - 1U;
|
||||
if (m_endPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||
m_endPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CM17RX::calculateLevels(uint16_t start, uint16_t count)
|
||||
{
|
||||
q15_t maxPos = -16000;
|
||||
q15_t minPos = 16000;
|
||||
q15_t maxNeg = 16000;
|
||||
q15_t minNeg = -16000;
|
||||
|
||||
for (uint16_t i = 0U; i < count; i++) {
|
||||
q15_t sample = m_buffer[start];
|
||||
|
||||
if (sample > 0) {
|
||||
if (sample > maxPos)
|
||||
maxPos = sample;
|
||||
if (sample < minPos)
|
||||
minPos = sample;
|
||||
} else {
|
||||
if (sample < maxNeg)
|
||||
maxNeg = sample;
|
||||
if (sample > minNeg)
|
||||
minNeg = sample;
|
||||
}
|
||||
|
||||
start += M17_RADIO_SYMBOL_LENGTH;
|
||||
if (start >= M17_FRAME_LENGTH_SAMPLES)
|
||||
start -= M17_FRAME_LENGTH_SAMPLES;
|
||||
}
|
||||
|
||||
q15_t posThresh = (maxPos + minPos) >> 1;
|
||||
q15_t negThresh = (maxNeg + minNeg) >> 1;
|
||||
|
||||
q15_t centre = (posThresh + negThresh) >> 1;
|
||||
|
||||
q15_t threshold = posThresh - centre;
|
||||
|
||||
DEBUG5("M17RX: pos/neg/centre/threshold", posThresh, negThresh, centre, threshold);
|
||||
|
||||
if (m_averagePtr == NOAVEPTR) {
|
||||
for (uint8_t i = 0U; i < 16U; i++) {
|
||||
m_centre[i] = centre;
|
||||
m_threshold[i] = threshold;
|
||||
}
|
||||
|
||||
m_averagePtr = 0U;
|
||||
} else {
|
||||
m_centre[m_averagePtr] = centre;
|
||||
m_threshold[m_averagePtr] = threshold;
|
||||
|
||||
m_averagePtr++;
|
||||
if (m_averagePtr >= 16U)
|
||||
m_averagePtr = 0U;
|
||||
}
|
||||
|
||||
m_centreVal = 0;
|
||||
m_thresholdVal = 0;
|
||||
|
||||
for (uint8_t i = 0U; i < 16U; i++) {
|
||||
m_centreVal += m_centre[i];
|
||||
m_thresholdVal += m_threshold[i];
|
||||
}
|
||||
|
||||
m_centreVal >>= 4;
|
||||
m_thresholdVal >>= 4;
|
||||
}
|
||||
|
||||
void CM17RX::samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
|
||||
{
|
||||
for (uint16_t i = 0U; i < count; i++) {
|
||||
q15_t sample = m_buffer[start] - centre;
|
||||
|
||||
if (sample < -threshold) {
|
||||
WRITE_BIT1(buffer, offset, false);
|
||||
offset++;
|
||||
WRITE_BIT1(buffer, offset, true);
|
||||
offset++;
|
||||
} else if (sample < 0) {
|
||||
WRITE_BIT1(buffer, offset, false);
|
||||
offset++;
|
||||
WRITE_BIT1(buffer, offset, false);
|
||||
offset++;
|
||||
} else if (sample < threshold) {
|
||||
WRITE_BIT1(buffer, offset, true);
|
||||
offset++;
|
||||
WRITE_BIT1(buffer, offset, false);
|
||||
offset++;
|
||||
} else {
|
||||
WRITE_BIT1(buffer, offset, true);
|
||||
offset++;
|
||||
WRITE_BIT1(buffer, offset, true);
|
||||
offset++;
|
||||
}
|
||||
|
||||
start += M17_RADIO_SYMBOL_LENGTH;
|
||||
if (start >= M17_FRAME_LENGTH_SAMPLES)
|
||||
start -= M17_FRAME_LENGTH_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
void CM17RX::writeRSSIData(uint8_t* data)
|
||||
{
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
if (m_rssiCount > 0U) {
|
||||
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||
|
||||
data[121U] = (rssi >> 8) & 0xFFU;
|
||||
data[122U] = (rssi >> 0) & 0xFFU;
|
||||
|
||||
serial.writeM17Data(data, M17_FRAME_LENGTH_BYTES + 3U);
|
||||
} else {
|
||||
serial.writeM17Data(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||
}
|
||||
#else
|
||||
serial.writeM17Data(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||
#endif
|
||||
|
||||
m_rssiAccum = 0U;
|
||||
m_rssiCount = 0U;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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
|
||||
* 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(M17RX_H)
|
||||
#define M17RX_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "M17Defines.h"
|
||||
|
||||
enum M17RX_STATE {
|
||||
M17RXS_NONE,
|
||||
M17RXS_DATA
|
||||
};
|
||||
|
||||
class CM17RX {
|
||||
public:
|
||||
CM17RX();
|
||||
|
||||
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
M17RX_STATE m_state;
|
||||
uint8_t m_bitBuffer[M17_RADIO_SYMBOL_LENGTH];
|
||||
q15_t m_buffer[M17_FRAME_LENGTH_SAMPLES];
|
||||
uint16_t m_bitPtr;
|
||||
uint16_t m_dataPtr;
|
||||
uint16_t m_startPtr;
|
||||
uint16_t m_endPtr;
|
||||
uint16_t m_syncPtr;
|
||||
uint16_t m_minSyncPtr;
|
||||
uint16_t m_maxSyncPtr;
|
||||
q31_t m_maxCorr;
|
||||
uint16_t m_lostCount;
|
||||
uint8_t m_countdown;
|
||||
q15_t m_centre[16U];
|
||||
q15_t m_centreVal;
|
||||
q15_t m_threshold[16U];
|
||||
q15_t m_thresholdVal;
|
||||
uint8_t m_averagePtr;
|
||||
uint32_t m_rssiAccum;
|
||||
uint16_t m_rssiCount;
|
||||
|
||||
void processNone(q15_t sample);
|
||||
void processData(q15_t sample);
|
||||
bool correlateSync();
|
||||
void calculateLevels(uint16_t start, uint16_t count);
|
||||
void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
|
||||
void writeRSSIData(uint8_t* data);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 "M17TX.h"
|
||||
|
||||
#include "M17Defines.h"
|
||||
|
||||
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
|
||||
static q15_t RRC_0_5_FILTER[] = {0, 0, 0, 0, -290, -174, 142, 432, 438, 90, -387, -561, -155, 658, 1225, 767,
|
||||
-980, -3326, -4648, -3062, 2527, 11552, 21705, 29724, 32767, 29724, 21705,
|
||||
11552, 2527, -3062, -4648, -3326, -980, 767, 1225, 658, -155, -561, -387, 90,
|
||||
438, 432, 142, -174, -290}; // numTaps = 45, L = 5
|
||||
const uint16_t RRC_0_5_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
||||
|
||||
const q15_t M17_LEVELA = 1683;
|
||||
const q15_t M17_LEVELB = 561;
|
||||
const q15_t M17_LEVELC = -561;
|
||||
const q15_t M17_LEVELD = -1683;
|
||||
|
||||
const uint8_t M17_START_SYNC = 0x77U;
|
||||
const uint8_t M17_END_SYNC = 0xFFU;
|
||||
const uint8_t M17_HANG = 0x00U;
|
||||
|
||||
CM17TX::CM17TX() :
|
||||
m_buffer(TX_BUFFER_LEN),
|
||||
m_modFilter(),
|
||||
m_modState(),
|
||||
m_poBuffer(),
|
||||
m_poLen(0U),
|
||||
m_poPtr(0U),
|
||||
m_txDelay(240U), // 200ms
|
||||
m_txHang(4800U), // 4s
|
||||
m_txCount(0U)
|
||||
{
|
||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||
|
||||
m_modFilter.L = M17_RADIO_SYMBOL_LENGTH;
|
||||
m_modFilter.phaseLength = RRC_0_5_FILTER_PHASE_LEN;
|
||||
m_modFilter.pCoeffs = RRC_0_5_FILTER;
|
||||
m_modFilter.pState = m_modState;
|
||||
}
|
||||
|
||||
void CM17TX::process()
|
||||
{
|
||||
// If we have M17 data to transmit, do so.
|
||||
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||
if (!m_tx) {
|
||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||
m_poBuffer[m_poLen++] = M17_START_SYNC;
|
||||
} else {
|
||||
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++) {
|
||||
uint8_t c = m_buffer.get();
|
||||
m_poBuffer[m_poLen++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
m_poPtr = 0U;
|
||||
}
|
||||
|
||||
if (m_poLen > 0U) {
|
||||
// Transmit M17 data.
|
||||
uint16_t space = io.getSpace();
|
||||
|
||||
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
|
||||
uint8_t c = m_poBuffer[m_poPtr++];
|
||||
writeByte(c);
|
||||
|
||||
// Reduce space and reset the hang timer.
|
||||
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
|
||||
if (m_duplex)
|
||||
m_txCount = m_txHang;
|
||||
|
||||
if (m_poPtr >= m_poLen) {
|
||||
m_poPtr = 0U;
|
||||
m_poLen = 0U;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (m_txCount > 0U) {
|
||||
// Transmit silence until the hang timer has expired.
|
||||
uint16_t space = io.getSpace();
|
||||
|
||||
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
|
||||
writeSilence();
|
||||
|
||||
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
|
||||
m_txCount--;
|
||||
|
||||
if (m_txCount == 0U)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CM17TX::writeData(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length != (M17_FRAME_LENGTH_BYTES + 1U))
|
||||
return 4U;
|
||||
|
||||
uint16_t space = m_buffer.getSpace();
|
||||
if (space < M17_FRAME_LENGTH_BYTES)
|
||||
return 5U;
|
||||
|
||||
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++)
|
||||
m_buffer.put(data[i + 1U]);
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
void CM17TX::writeByte(uint8_t c)
|
||||
{
|
||||
q15_t inBuffer[4U];
|
||||
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
|
||||
|
||||
const uint8_t MASK = 0xC0U;
|
||||
|
||||
for (uint8_t i = 0U; i < 4U; i++, c <<= 2) {
|
||||
switch (c & MASK) {
|
||||
case 0xC0U:
|
||||
inBuffer[i] = M17_LEVELA;
|
||||
break;
|
||||
case 0x80U:
|
||||
inBuffer[i] = M17_LEVELB;
|
||||
break;
|
||||
case 0x00U:
|
||||
inBuffer[i] = M17_LEVELC;
|
||||
break;
|
||||
default:
|
||||
inBuffer[i] = M17_LEVELD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
|
||||
|
||||
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
|
||||
}
|
||||
|
||||
void CM17TX::writeSilence()
|
||||
{
|
||||
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
|
||||
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
|
||||
|
||||
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
|
||||
|
||||
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
|
||||
}
|
||||
|
||||
void CM17TX::setTXDelay(uint8_t delay)
|
||||
{
|
||||
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
|
||||
|
||||
if (m_txDelay > 1200U)
|
||||
m_txDelay = 1200U;
|
||||
}
|
||||
|
||||
uint8_t CM17TX::getSpace() const
|
||||
{
|
||||
return m_buffer.getSpace() / M17_FRAME_LENGTH_BYTES;
|
||||
}
|
||||
|
||||
void CM17TX::setParams(uint8_t txHang)
|
||||
{
|
||||
m_txHang = txHang * 1200U;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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
|
||||
* 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(M17TX_H)
|
||||
#define M17TX_H
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "SerialRB.h"
|
||||
|
||||
class CM17TX {
|
||||
public:
|
||||
CM17TX();
|
||||
|
||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
||||
|
||||
void process();
|
||||
|
||||
void setTXDelay(uint8_t delay);
|
||||
|
||||
uint8_t getSpace() const;
|
||||
|
||||
void setParams(uint8_t txHang);
|
||||
|
||||
private:
|
||||
CSerialRB 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];
|
||||
uint16_t m_poLen;
|
||||
uint16_t m_poPtr;
|
||||
uint16_t m_txDelay;
|
||||
uint32_t m_txHang;
|
||||
uint32_t m_txCount;
|
||||
|
||||
void writeByte(uint8_t c);
|
||||
void writeSilence();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,7 @@ bool m_dmrEnable = true;
|
||||
bool m_ysfEnable = true;
|
||||
bool m_p25Enable = true;
|
||||
bool m_nxdnEnable = true;
|
||||
bool m_m17Enable = true;
|
||||
bool m_pocsagEnable = true;
|
||||
bool m_fmEnable = true;
|
||||
|
||||
@@ -58,6 +59,9 @@ CP25TX p25TX;
|
||||
CNXDNRX nxdnRX;
|
||||
CNXDNTX nxdnTX;
|
||||
|
||||
CM17RX m17RX;
|
||||
CM17TX m17TX;
|
||||
|
||||
CPOCSAGTX pocsagTX;
|
||||
|
||||
CFM fm;
|
||||
@@ -107,6 +111,9 @@ void loop()
|
||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||
nxdnTX.process();
|
||||
|
||||
if (m_m17Enable && m_modemState == STATE_M17)
|
||||
m17TX.process();
|
||||
|
||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||
pocsagTX.process();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ bool m_dmrEnable = true;
|
||||
bool m_ysfEnable = true;
|
||||
bool m_p25Enable = true;
|
||||
bool m_nxdnEnable = true;
|
||||
bool m_m17Enable = true;
|
||||
bool m_pocsagEnable = true;
|
||||
bool m_fmEnable = true;
|
||||
|
||||
@@ -55,6 +56,9 @@ CP25TX p25TX;
|
||||
CNXDNRX nxdnRX;
|
||||
CNXDNTX nxdnTX;
|
||||
|
||||
CM17RX m17RX;
|
||||
CM17TX m17TX;
|
||||
|
||||
CPOCSAGTX pocsagTX;
|
||||
|
||||
CFM fm;
|
||||
@@ -104,6 +108,9 @@ void loop()
|
||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||
nxdnTX.process();
|
||||
|
||||
if (m_m17Enable && m_modemState == STATE_M17)
|
||||
m17TX.process();
|
||||
|
||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||
pocsagTX.process();
|
||||
|
||||
|
||||
@@ -139,6 +139,10 @@ DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VA
|
||||
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||
# DRCC_DVM BG7NQF board:
|
||||
DEFS_DRCC_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DDRCC_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||
# WA0EDA F405 MTR2K, MASTR3 board:
|
||||
DEFS_EDA_405=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_EDA_405 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||
# WA0EDA F446 MTR2K, MASTR3 board:
|
||||
DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||
|
||||
|
||||
# Build compiler flags
|
||||
@@ -229,6 +233,18 @@ drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
||||
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
|
||||
drcc_nqf: release_f4
|
||||
|
||||
eda405: GitVersion.h
|
||||
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
|
||||
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
|
||||
eda405: LDFLAGS+=$(LDFLAGS_F4)
|
||||
eda405: release_f4
|
||||
|
||||
eda446: GitVersion.h
|
||||
eda446: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446)
|
||||
eda446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446)
|
||||
eda446: LDFLAGS+=$(LDFLAGS_F4)
|
||||
eda446: release_f4
|
||||
|
||||
release_f4: $(BINDIR)
|
||||
release_f4: $(OBJDIR_F4)
|
||||
release_f4: $(BINDIR)/$(BINHEX_F4)
|
||||
@@ -350,6 +366,8 @@ endif
|
||||
|
||||
deploy-f4m: deploy-pi
|
||||
deploy-dvm: deploy-pi
|
||||
deploy-eda405: deploy-pi
|
||||
deploy-eda446: deploy-pi
|
||||
|
||||
deploy-pi-f7:
|
||||
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
||||
|
||||
@@ -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.
|
||||
|
||||
+98
-18
@@ -63,6 +63,9 @@ const uint8_t MMDVM_P25_LOST = 0x32U;
|
||||
const uint8_t MMDVM_NXDN_DATA = 0x40U;
|
||||
const uint8_t MMDVM_NXDN_LOST = 0x41U;
|
||||
|
||||
const uint8_t MMDVM_M17_DATA = 0x45U;
|
||||
const uint8_t MMDVM_M17_LOST = 0x46U;
|
||||
|
||||
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
|
||||
|
||||
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
|
||||
@@ -103,7 +106,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 "20201015 (D-Star/DMR/System Fusion/P25/NXDN/M17/POCSAG/FM)"
|
||||
|
||||
#if defined(GITVERSION)
|
||||
#define concat(h, a, b, c) h " " a " " b " GitID #" c ""
|
||||
@@ -158,7 +161,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;
|
||||
@@ -176,6 +179,8 @@ void CSerialPort::getStatus()
|
||||
reply[3U] |= 0x20U;
|
||||
if (m_fmEnable)
|
||||
reply[3U] |= 0x40U;
|
||||
if (m_m17Enable)
|
||||
reply[3U] |= 0x80U;
|
||||
|
||||
reply[4U] = uint8_t(m_modemState);
|
||||
|
||||
@@ -240,7 +245,12 @@ void CSerialPort::getStatus()
|
||||
else
|
||||
reply[12U] = 0U;
|
||||
|
||||
writeInt(1U, reply, 13);
|
||||
if (m_m17Enable)
|
||||
reply[13U] = m17TX.getSpace();
|
||||
else
|
||||
reply[13U] = 0U;
|
||||
|
||||
writeInt(1U, reply, 14);
|
||||
}
|
||||
|
||||
void CSerialPort::getVersion()
|
||||
@@ -264,14 +274,15 @@ void CSerialPort::getVersion()
|
||||
|
||||
uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length < 21U)
|
||||
if (length < 23U)
|
||||
return 4U;
|
||||
|
||||
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
|
||||
bool txInvert = (data[0U] & 0x02U) == 0x02U;
|
||||
bool pttInvert = (data[0U] & 0x04U) == 0x04U;
|
||||
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
|
||||
bool simplex = (data[0U] & 0x80U) == 0x80U;
|
||||
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
|
||||
bool txInvert = (data[0U] & 0x02U) == 0x02U;
|
||||
bool pttInvert = (data[0U] & 0x04U) == 0x04U;
|
||||
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
|
||||
bool useCOSAsLockout = (data[0U] & 0x20U) == 0x20U;
|
||||
bool simplex = (data[0U] & 0x80U) == 0x80U;
|
||||
|
||||
m_debug = (data[0U] & 0x10U) == 0x10U;
|
||||
|
||||
@@ -282,6 +293,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 m17Enable = (data[1U] & 0x80U) == 0x80U;
|
||||
|
||||
uint8_t txDelay = data[2U];
|
||||
if (txDelay > 50U)
|
||||
@@ -289,7 +301,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
|
||||
MMDVM_STATE modemState = MMDVM_STATE(data[3U]);
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !dstarEnable)
|
||||
return 4U;
|
||||
@@ -301,6 +313,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
return 4U;
|
||||
if (modemState == STATE_NXDN && !nxdnEnable)
|
||||
return 4U;
|
||||
if (modemState == STATE_M17 && !m17Enable)
|
||||
return 4U;
|
||||
if (modemState == STATE_POCSAG && !pocsagEnable)
|
||||
return 4U;
|
||||
if (modemState == STATE_FM && !fmEnable)
|
||||
@@ -335,6 +349,9 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
|
||||
uint8_t nxdnTXHang = data[20U];
|
||||
|
||||
uint8_t m17TXLevel = data[21U];
|
||||
uint8_t m17TXHang = data[22U];
|
||||
|
||||
setMode(modemState);
|
||||
|
||||
m_dstarEnable = dstarEnable;
|
||||
@@ -342,6 +359,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
m_ysfEnable = ysfEnable;
|
||||
m_p25Enable = p25Enable;
|
||||
m_nxdnEnable = nxdnEnable;
|
||||
m_m17Enable = m17Enable;
|
||||
m_pocsagEnable = pocsagEnable;
|
||||
m_fmEnable = fmEnable;
|
||||
m_duplex = !simplex;
|
||||
@@ -351,6 +369,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
p25TX.setTXDelay(txDelay);
|
||||
dmrDMOTX.setTXDelay(txDelay);
|
||||
nxdnTX.setTXDelay(txDelay);
|
||||
m17TX.setTXDelay(txDelay);
|
||||
pocsagTX.setTXDelay(txDelay);
|
||||
|
||||
dmrTX.setColorCode(colorCode);
|
||||
@@ -362,8 +381,9 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
ysfTX.setParams(ysfLoDev, ysfTXHang);
|
||||
p25TX.setParams(p25TXHang);
|
||||
nxdnTX.setParams(nxdnTXHang);
|
||||
m17TX.setParams(m17TXHang);
|
||||
|
||||
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, m17TXLevel, pocsagTXLevel, fmTXLevel, txDCOffset, rxDCOffset, useCOSAsLockout);
|
||||
|
||||
io.start();
|
||||
|
||||
@@ -431,14 +451,14 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
||||
uint8_t kerchunkTime = data[6U];
|
||||
uint8_t hangTime = data[7U];
|
||||
|
||||
bool useCOS = (data[8U] & 0x01U) == 0x01U;
|
||||
bool cosInvert = (data[8U] & 0x02U) == 0x02U;
|
||||
uint8_t accessMode = data[8U] & 0x7FU;
|
||||
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, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel);
|
||||
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, rfAudioBoost, maxDev, rxLevel);
|
||||
}
|
||||
|
||||
uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||
@@ -451,7 +471,7 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||
if (modemState == m_modemState)
|
||||
return 0U;
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_POCSAGCAL && modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !m_dstarEnable)
|
||||
return 4U;
|
||||
@@ -463,6 +483,8 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
||||
return 4U;
|
||||
if (modemState == STATE_NXDN && !m_nxdnEnable)
|
||||
return 4U;
|
||||
if (modemState == STATE_M17 && !m_m17Enable)
|
||||
return 4U;
|
||||
if (modemState == STATE_POCSAG && !m_pocsagEnable)
|
||||
return 4U;
|
||||
if (modemState == STATE_FM && !m_fmEnable)
|
||||
@@ -491,6 +513,9 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
||||
case STATE_NXDN:
|
||||
DEBUG1("Mode set to NXDN");
|
||||
break;
|
||||
case STATE_M17:
|
||||
DEBUG1("Mode set to M17");
|
||||
break;
|
||||
case STATE_POCSAG:
|
||||
DEBUG1("Mode set to POCSAG");
|
||||
break;
|
||||
@@ -562,14 +587,15 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
||||
if (modemState != STATE_NXDN)
|
||||
nxdnRX.reset();
|
||||
|
||||
if (modemState != STATE_M17)
|
||||
m17RX.reset();
|
||||
|
||||
if (modemState != STATE_FM)
|
||||
fm.reset();
|
||||
|
||||
cwIdTX.reset();
|
||||
|
||||
m_modemState = modemState;
|
||||
|
||||
io.setMode();
|
||||
io.setMode(modemState);
|
||||
}
|
||||
|
||||
void CSerialPort::start()
|
||||
@@ -871,6 +897,20 @@ void CSerialPort::process()
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_M17_DATA:
|
||||
if (m_m17Enable) {
|
||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_M17)
|
||||
err = m17TX.writeData(m_buffer + 3U, m_len - 3U);
|
||||
}
|
||||
if (err == 0U) {
|
||||
if (m_modemState == STATE_IDLE)
|
||||
setMode(STATE_M17);
|
||||
} else {
|
||||
DEBUG2("Received invalid M17 data", err);
|
||||
sendNAK(err);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_POCSAG_DATA:
|
||||
if (m_pocsagEnable) {
|
||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG)
|
||||
@@ -1197,6 +1237,46 @@ void CSerialPort::writeNXDNLost()
|
||||
writeInt(1U, reply, 3);
|
||||
}
|
||||
|
||||
void CSerialPort::writeM17Data(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (m_modemState != STATE_M17 && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_m17Enable)
|
||||
return;
|
||||
|
||||
uint8_t reply[130U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 0U;
|
||||
reply[2U] = MMDVM_M17_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::writeM17Lost()
|
||||
{
|
||||
if (m_modemState != STATE_M17 && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_m17Enable)
|
||||
return;
|
||||
|
||||
uint8_t reply[3U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 3U;
|
||||
reply[2U] = MMDVM_M17_LOST;
|
||||
|
||||
writeInt(1U, reply, 3);
|
||||
}
|
||||
|
||||
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (m_modemState != STATE_DSTARCAL)
|
||||
|
||||
+4
-1
@@ -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,9 @@ public:
|
||||
void writeNXDNData(const uint8_t* data, uint8_t length);
|
||||
void writeNXDNLost();
|
||||
|
||||
void writeM17Data(const uint8_t* data, uint8_t length);
|
||||
void writeM17Lost();
|
||||
|
||||
void writeCalData(const uint8_t* data, uint8_t length);
|
||||
void writeRSSIData(const uint8_t* data, uint8_t length);
|
||||
|
||||
|
||||
+6
-6
@@ -50,7 +50,7 @@ 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)
|
||||
#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) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
|
||||
volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE];
|
||||
volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE];
|
||||
@@ -841,7 +841,7 @@ void CSerialPort::beginInt(uint8_t n, int speed)
|
||||
case 1U:
|
||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||
InitUSART3(speed);
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
InitUSART1(speed);
|
||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||
InitUSART2(speed);
|
||||
@@ -869,7 +869,7 @@ int CSerialPort::availableInt(uint8_t n)
|
||||
case 1U:
|
||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||
return AvailUSART3();
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
return AvailUSART1();
|
||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||
return AvailUSART2();
|
||||
@@ -895,7 +895,7 @@ int CSerialPort::availableForWriteInt(uint8_t n)
|
||||
case 1U:
|
||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||
return AvailForWriteUSART3();
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
return AvailForWriteUSART1();
|
||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||
return AvailForWriteUSART2();
|
||||
@@ -921,7 +921,7 @@ uint8_t CSerialPort::readInt(uint8_t n)
|
||||
case 1U:
|
||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||
return ReadUSART3();
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
return ReadUSART1();
|
||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||
return ReadUSART2();
|
||||
@@ -949,7 +949,7 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool
|
||||
WriteUSART3(data, length);
|
||||
if (flush)
|
||||
TXSerialFlush3();
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||
WriteUSART1(data, length);
|
||||
if (flush)
|
||||
TXSerialFlush1();
|
||||
|
||||
@@ -30,6 +30,15 @@ uint8_t countBits8(uint8_t bits)
|
||||
return BITS_TABLE[bits];
|
||||
}
|
||||
|
||||
uint8_t countBits16(uint16_t bits)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)&bits;
|
||||
uint8_t n = 0U;
|
||||
n += BITS_TABLE[p[0U]];
|
||||
n += BITS_TABLE[p[1U]];
|
||||
return n;
|
||||
}
|
||||
|
||||
uint8_t countBits32(uint32_t bits)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)&bits;
|
||||
|
||||
@@ -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
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
uint8_t countBits8(uint8_t bits);
|
||||
|
||||
uint8_t countBits16(uint16_t bits);
|
||||
|
||||
uint8_t countBits32(uint32_t bits);
|
||||
|
||||
uint8_t countBits64(uint64_t bits);
|
||||
|
||||
@@ -36,7 +36,7 @@ const uint8_t NOAVEPTR = 99U;
|
||||
|
||||
const uint16_t NOENDPTR = 9999U;
|
||||
|
||||
const unsigned int MAX_SYNC_FRAMES = 4U + 1U;
|
||||
const unsigned int MAX_SYNC_FRAMES = 1U + 1U;
|
||||
|
||||
CYSFRX::CYSFRX() :
|
||||
m_state(YSFRXS_NONE),
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2019,2020 by BG5HHP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PINS_F4_STM32EDA
|
||||
#define _PINS_F4_STM32EDA
|
||||
|
||||
/*
|
||||
Pin definitions for STM32F4 STM32-DVM-MTR2K & STM32-DVM-MASTR3:
|
||||
|
||||
COS PB13 input
|
||||
PTT PB12 output
|
||||
COSLED PB4 output
|
||||
LED PB3 output
|
||||
|
||||
P25 PB8 output
|
||||
NXDN PB9 output
|
||||
DSTAR PB6 output
|
||||
DMR PB5 output
|
||||
YSF PB7 output
|
||||
POCSAG PC10 output
|
||||
FM PC11 output
|
||||
|
||||
RX PB0 analog input
|
||||
RSSI PB1 analog input
|
||||
TX PA4 analog output
|
||||
|
||||
EXT_CLK PA15 input
|
||||
*/
|
||||
|
||||
#define PIN_COS GPIO_Pin_13
|
||||
#define PORT_COS GPIOB
|
||||
#define RCC_Per_COS RCC_AHB1Periph_GPIOB
|
||||
|
||||
|
||||
#define PIN_PTT GPIO_Pin_12
|
||||
#define PORT_PTT GPIOB
|
||||
#define RCC_Per_PTT RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_COSLED GPIO_Pin_4
|
||||
#define PORT_COSLED GPIOB
|
||||
#define RCC_Per_COSLED RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_LED GPIO_Pin_3
|
||||
#define PORT_LED GPIOB
|
||||
#define RCC_Per_LED RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_P25 GPIO_Pin_8
|
||||
#define PORT_P25 GPIOB
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_9
|
||||
#define PORT_NXDN GPIOB
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_6
|
||||
#define PORT_DSTAR GPIOB
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_DMR GPIO_Pin_5
|
||||
#define PORT_DMR GPIOB
|
||||
#define RCC_Per_DMR RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_YSF GPIO_Pin_7
|
||||
#define PORT_YSF GPIOB
|
||||
#define RCC_Per_YSF RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_POCSAG GPIO_Pin_10
|
||||
#define PORT_POCSAG GPIOC
|
||||
#define RCC_Per_POCSAG RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_FM GPIO_Pin_11
|
||||
#define PORT_FM GPIOC
|
||||
#define RCC_Per_FM RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_EXT_CLK GPIO_Pin_15
|
||||
#define SRC_EXT_CLK GPIO_PinSource15
|
||||
#define PORT_EXT_CLK GPIOA
|
||||
|
||||
#define PIN_RX GPIO_Pin_0
|
||||
#define PIN_RX_CH ADC_Channel_8
|
||||
#define PORT_RX GPIOB
|
||||
#define RCC_Per_RX RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_RSSI GPIO_Pin_1
|
||||
#define PIN_RSSI_CH ADC_Channel_9
|
||||
#define PORT_RSSI GPIOB
|
||||
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_TX GPIO_Pin_4
|
||||
#define PIN_TX_CH DAC_Channel_1
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user