Skip to content

Commit

Permalink
Add support for NXDN 4800.
Browse files Browse the repository at this point in the history
  • Loading branch information
g4klx committed Feb 7, 2018
1 parent b34d3c3 commit 4652812
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 49 deletions.
100 changes: 63 additions & 37 deletions IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,18 @@ const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage

// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
-553, -847, -731, -340, 104, 401, 0};
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
-553, -847, -731, -340, 104, 401, 0};
const uint16_t RRC_0_2_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,
10134, 10731, 10935, 10731, 10134, 9184, 7946, 6502, 4946, 3376, 1886, 557, -545, -1375, -1914, -2164, -2150,
-1915, -1516, -1016, -477, 39, 483, 819, 1026, 1097, 1041, 880, 643, 364, 79, -181, -391, -533, -599, -590,
-517, -393, -240, -78, 73, 198, 284, 0};
const uint16_t NXDN_0_2_FILTER_LEN = 82U;

// Generated using gaussfir(0.5, 4, 5) in MATLAB
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
Expand All @@ -49,12 +57,16 @@ m_txBuffer(TX_RINGBUFFER_SIZE),
m_rssiBuffer(RX_RINGBUFFER_SIZE),
m_dcFilter(),
m_dcState(),
m_rrcFilter(),
m_dmrFilter(),
m_gaussianFilter(),
m_boxcarFilter(),
m_rrcState(),
m_nxdnFilter(),
m_ysfFilter(),
m_dmrState(),
m_gaussianState(),
m_boxcarState(),
m_nxdnState(),
m_ysfState(),
m_pttInvert(false),
m_rxLevel(128 * 128),
m_cwIdTXLevel(128 * 128),
Expand All @@ -73,19 +85,21 @@ m_dacOverflow(0U),
m_watchdog(0U),
m_lockout(false)
{
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t));
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
::memset(m_dmrState, 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));
::memset(m_ysfState, 0x00U, 70U * sizeof(q15_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));

m_dcFilter.numStages = DC_FILTER_STAGES;
m_dcFilter.pState = m_dcState;
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_dmrFilter.numTaps = RRC_0_2_FILTER_LEN;
m_dmrFilter.pState = m_dmrState;
m_dmrFilter.pCoeffs = RRC_0_2_FILTER;

m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
m_gaussianFilter.pState = m_gaussianState;
Expand All @@ -95,6 +109,14 @@ m_lockout(false)
m_boxcarFilter.pState = m_boxcarState;
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;

m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN;
m_nxdnFilter.pState = m_nxdnState;
m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER;

m_ysfFilter.numTaps = RRC_0_2_FILTER_LEN;
m_ysfFilter.pState = m_ysfState;
m_ysfFilter.pCoeffs = RRC_0_2_FILTER;

initInt();

selfTest();
Expand Down Expand Up @@ -300,31 +322,35 @@ void CIO::process()
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
}

if (m_p25Enable || m_nxdnEnable) {
if (m_p25Enable) {
q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, C4FSKVals, RX_BLOCK_SIZE);

if (m_p25Enable)
p25RX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
p25RX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
}

if (m_nxdnEnable)
nxdnRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNVals, RX_BLOCK_SIZE);

nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}

// XXX YSF should use dcSamples, but DMR not
if (m_dmrEnable || m_ysfEnable) {
q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, C4FSKVals, RX_BLOCK_SIZE);
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_ysfFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);

if (m_dmrEnable) {
if (m_duplex)
dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
}
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}

if (m_ysfEnable)
ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_dmrFilter, samples, DMRVals, RX_BLOCK_SIZE);

if (m_duplex)
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) {
Expand All @@ -335,25 +361,25 @@ void CIO::process()
}
} else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) {
q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, C4FSKVals, RX_BLOCK_SIZE);
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_dmrFilter, samples, DMRVals, RX_BLOCK_SIZE);

if (m_duplex) {
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
if (m_tx)
dmrRX.samples(C4FSKVals, rssi, control, RX_BLOCK_SIZE);
dmrRX.samples(DMRVals, rssi, control, RX_BLOCK_SIZE);
else
dmrIdleRX.samples(C4FSKVals, RX_BLOCK_SIZE);
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
} else {
dmrDMORX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
}
}
} else if (m_modemState == STATE_YSF) {
if (m_ysfEnable) {
q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, C4FSKVals, RX_BLOCK_SIZE);
q15_t YSFVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_ysfFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);

ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_P25) {
if (m_p25Enable) {
Expand All @@ -365,7 +391,7 @@ void CIO::process()
} else if (m_modemState == STATE_NXDN) {
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNVals, RX_BLOCK_SIZE);

nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}
Expand Down
8 changes: 6 additions & 2 deletions IO.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@ class CIO {
arm_biquad_casd_df1_inst_q31 m_dcFilter;
q31_t m_dcState[4];

arm_fir_instance_q15 m_rrcFilter;
arm_fir_instance_q15 m_dmrFilter;
arm_fir_instance_q15 m_gaussianFilter;
arm_fir_instance_q15 m_boxcarFilter;
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
arm_fir_instance_q15 m_nxdnFilter;
arm_fir_instance_q15 m_ysfFilter;
q15_t m_dmrState[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_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
q15_t m_ysfState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare

bool m_pttInvert;
q15_t m_rxLevel;
Expand Down
2 changes: 1 addition & 1 deletion NXDNDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#if !defined(NXDNDEFINES_H)
#define NXDNDEFINES_H

const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate

const unsigned int NXDN_FRAME_LENGTH_BITS = 384U;
const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
Expand Down
21 changes: 12 additions & 9 deletions NXDNTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@

#include "NXDNDefines.h"

// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179, -1548, -1769, -1795, -1597, -1172,
-544, 237, 1092, 1927, 2637, 3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739, -6442,
-6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822, 19484, 23810, 27520, 30367, 32156, 32767,
32156, 30367, 27520, 23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735, -6483, -6442,
-5739, -4544, -3043, -1431, 116, 1447, 2454, 3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172,
-1597, -1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L

const q15_t NXDN_LEVELA = 1680;
const q15_t NXDN_LEVELB = 560;
const q15_t NXDN_LEVELC = -560;
const q15_t NXDN_LEVELD = -1680;
const q15_t NXDN_LEVELA = 840;
const q15_t NXDN_LEVELB = 280;
const q15_t NXDN_LEVELC = -280;
const q15_t NXDN_LEVELD = -840;

const uint8_t NXDN_PREAMBLE[] = {0x57U, 0x75U, 0xFDU};
const uint8_t NXDN_SYNC = 0x5FU;
Expand Down Expand Up @@ -148,6 +151,6 @@ void CNXDNTX::setTXDelay(uint8_t delay)

uint8_t CNXDNTX::getSpace() const
{
return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES;
return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES;
}

1 comment on commit 4652812

@phl0
Copy link
Collaborator

@phl0 phl0 commented on 4652812 Aug 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit causes issues with the Teensy implementation. Upon starting MMDVMCal the SVC LED stops blinking and switching the PTT does not work any more. Some tests revealed that the changes in IO.h and IO.cpp obviously go ok. So its probably the NXDN implementation that is to blame.

Please sign in to comment.