NXDN first cut, not working yet.

nxdn
Jonathan Naylor 2018-01-10 20:30:35 +00:00
parent 78a51d416d
commit b5ca5e3839
16 changed files with 1005 additions and 23 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -48,6 +48,7 @@ enum MMDVM_STATE {
STATE_DMR = 2, STATE_DMR = 2,
STATE_YSF = 3, STATE_YSF = 3,
STATE_P25 = 4, STATE_P25 = 4,
STATE_NXDN = 5,
// Dummy states start at 90 // Dummy states start at 90
STATE_P25CAL1K = 93, STATE_P25CAL1K = 93,
@ -71,6 +72,8 @@ enum MMDVM_STATE {
#include "YSFTX.h" #include "YSFTX.h"
#include "P25RX.h" #include "P25RX.h"
#include "P25TX.h" #include "P25TX.h"
#include "NXDNRX.h"
#include "NXDNTX.h"
#include "CalDStarRX.h" #include "CalDStarRX.h"
#include "CalDStarTX.h" #include "CalDStarTX.h"
#include "CalDMR.h" #include "CalDMR.h"
@ -95,6 +98,7 @@ extern bool m_dstarEnable;
extern bool m_dmrEnable; extern bool m_dmrEnable;
extern bool m_ysfEnable; extern bool m_ysfEnable;
extern bool m_p25Enable; extern bool m_p25Enable;
extern bool m_nxdnEnable;
extern bool m_duplex; extern bool m_duplex;
@ -120,6 +124,9 @@ extern CYSFTX ysfTX;
extern CP25RX p25RX; extern CP25RX p25RX;
extern CP25TX p25TX; extern CP25TX p25TX;
extern CNXDNRX nxdnRX;
extern CNXDNTX nxdnTX;
extern CCalDStarRX calDStarRX; extern CCalDStarRX calDStarRX;
extern CCalDStarTX calDStarTX; extern CCalDStarTX calDStarTX;
extern CCalDMR calDMR; extern CCalDMR calDMR;

50
IO.cpp
View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM * Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@ -62,6 +62,7 @@ m_dstarTXLevel(128 * 128),
m_dmrTXLevel(128 * 128), m_dmrTXLevel(128 * 128),
m_ysfTXLevel(128 * 128), m_ysfTXLevel(128 * 128),
m_p25TXLevel(128 * 128), m_p25TXLevel(128 * 128),
m_nxdnTXLevel(128 * 128),
m_rxDCOffset(DC_OFFSET), m_rxDCOffset(DC_OFFSET),
m_txDCOffset(DC_OFFSET), m_txDCOffset(DC_OFFSET),
m_ledCount(0U), m_ledCount(0U),
@ -114,6 +115,7 @@ void CIO::selfTest()
setDMRInt(ledValue); setDMRInt(ledValue);
setYSFInt(ledValue); setYSFInt(ledValue);
setP25Int(ledValue); setP25Int(ledValue);
setNXDNInt(ledValue);
#endif #endif
delayInt(250); delayInt(250);
} }
@ -123,6 +125,7 @@ void CIO::selfTest()
setDMRInt(false); setDMRInt(false);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -130,6 +133,7 @@ void CIO::selfTest()
setDMRInt(true); setDMRInt(true);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -137,6 +141,7 @@ void CIO::selfTest()
setDMRInt(true); setDMRInt(true);
setYSFInt(true); setYSFInt(true);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -144,6 +149,23 @@ void CIO::selfTest()
setDMRInt(true); setDMRInt(true);
setYSFInt(true); setYSFInt(true);
setP25Int(true); setP25Int(true);
setNXDNInt(false);
delayInt(250);
setDStarInt(true);
setDMRInt(true);
setYSFInt(true);
setP25Int(true);
setNXDNInt(true);
delayInt(250);
setDStarInt(true);
setDMRInt(true);
setYSFInt(true);
setP25Int(true);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -151,6 +173,7 @@ void CIO::selfTest()
setDMRInt(true); setDMRInt(true);
setYSFInt(true); setYSFInt(true);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -158,6 +181,7 @@ void CIO::selfTest()
setDMRInt(true); setDMRInt(true);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -165,6 +189,7 @@ void CIO::selfTest()
setDMRInt(false); setDMRInt(false);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
delayInt(250); delayInt(250);
@ -172,6 +197,7 @@ void CIO::selfTest()
setDMRInt(false); setDMRInt(false);
setYSFInt(false); setYSFInt(false);
setP25Int(false); setP25Int(false);
setNXDNInt(false);
#endif #endif
} }
@ -193,7 +219,7 @@ void CIO::process()
if (m_started) { if (m_started) {
// Two seconds timeout // Two seconds timeout
if (m_watchdog >= 48000U) { if (m_watchdog >= 48000U) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF) { if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN) {
if (m_modemState == STATE_DMR && m_tx) if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false); dmrTX.setStart(false);
m_modemState = STATE_IDLE; m_modemState = STATE_IDLE;
@ -282,7 +308,7 @@ void CIO::process()
} }
// XXX YSF should use dcSamples, but DMR not // XXX YSF should use dcSamples, but DMR not
if (m_dmrEnable || m_ysfEnable) { if (m_dmrEnable || m_ysfEnable || m_nxdnEnable) {
q15_t C4FSKVals[RX_BLOCK_SIZE]; q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, C4FSKVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_rrcFilter, samples, C4FSKVals, RX_BLOCK_SIZE);
@ -295,6 +321,9 @@ void CIO::process()
if (m_ysfEnable) if (m_ysfEnable)
ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE); ysfRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
if (m_nxdnEnable)
nxdnRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_DSTAR) { } else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) { if (m_dstarEnable) {
@ -332,6 +361,13 @@ void CIO::process()
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE); p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
} }
} else if (m_modemState == STATE_NXDN) {
if (m_nxdnEnable) {
q15_t C4FSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, C4FSKVals, RX_BLOCK_SIZE);
nxdnRX.samples(C4FSKVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_DSTARCAL) { } else if (m_modemState == STATE_DSTARCAL) {
q15_t GMSKVals[RX_BLOCK_SIZE]; q15_t GMSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE); ::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
@ -371,6 +407,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
case STATE_P25: case STATE_P25:
txLevel = m_p25TXLevel; txLevel = m_p25TXLevel;
break; break;
case STATE_NXDN:
txLevel = m_nxdnTXLevel;
break;
default: default:
txLevel = m_cwIdTXLevel; txLevel = m_cwIdTXLevel;
break; break;
@ -417,10 +456,11 @@ void CIO::setMode()
setDMRInt(m_modemState == STATE_DMR); setDMRInt(m_modemState == STATE_DMR);
setYSFInt(m_modemState == STATE_YSF); setYSFInt(m_modemState == STATE_YSF);
setP25Int(m_modemState == STATE_P25); setP25Int(m_modemState == STATE_P25);
setNXDNInt(m_modemState == STATE_NXDN);
#endif #endif
} }
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, 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, int16_t txDCOffset, int16_t rxDCOffset)
{ {
m_pttInvert = pttInvert; m_pttInvert = pttInvert;
@ -430,6 +470,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_dmrTXLevel = q15_t(dmrTXLevel * 128); m_dmrTXLevel = q15_t(dmrTXLevel * 128);
m_ysfTXLevel = q15_t(ysfTXLevel * 128); m_ysfTXLevel = q15_t(ysfTXLevel * 128);
m_p25TXLevel = q15_t(p25TXLevel * 128); m_p25TXLevel = q15_t(p25TXLevel * 128);
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
m_rxDCOffset = DC_OFFSET + rxDCOffset; m_rxDCOffset = DC_OFFSET + rxDCOffset;
m_txDCOffset = DC_OFFSET + txDCOffset; m_txDCOffset = DC_OFFSET + txDCOffset;
@ -442,6 +483,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_dmrTXLevel = -m_dmrTXLevel; m_dmrTXLevel = -m_dmrTXLevel;
m_ysfTXLevel = -m_ysfTXLevel; m_ysfTXLevel = -m_ysfTXLevel;
m_p25TXLevel = -m_p25TXLevel; m_p25TXLevel = -m_p25TXLevel;
m_nxdnTXLevel = -m_nxdnTXLevel;
} }
} }

6
IO.h
View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -42,7 +42,7 @@ public:
void interrupt(); void interrupt();
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, 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 nxdnLevel, int16_t txDCOffset, int16_t rxDCOffset);
void getOverflow(bool& adcOverflow, bool& dacOverflow); void getOverflow(bool& adcOverflow, bool& dacOverflow);
@ -80,6 +80,7 @@ private:
q15_t m_dmrTXLevel; q15_t m_dmrTXLevel;
q15_t m_ysfTXLevel; q15_t m_ysfTXLevel;
q15_t m_p25TXLevel; q15_t m_p25TXLevel;
q15_t m_nxdnTXLevel;
uint16_t m_rxDCOffset; uint16_t m_rxDCOffset;
uint16_t m_txDCOffset; uint16_t m_txDCOffset;
@ -110,6 +111,7 @@ private:
void setDMRInt(bool on); void setDMRInt(bool on);
void setYSFInt(bool on); void setYSFInt(bool on);
void setP25Int(bool on); void setP25Int(bool on);
void setNXDNInt(bool on);
void delayInt(unsigned int dly); void delayInt(unsigned int dly);
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM * Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@ -33,6 +33,7 @@
#define PIN_DMR 17 #define PIN_DMR 17
#define PIN_YSF 18 #define PIN_YSF 18
#define PIN_P25 19 #define PIN_P25 19
#define PIN_NXDN 20
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7) #define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7 #define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7 #define ADC_CDR_Chan 7
@ -46,6 +47,7 @@
#define PIN_DMR 8 #define PIN_DMR 8
#define PIN_YSF 7 #define PIN_YSF 7
#define PIN_P25 6 #define PIN_P25 6
#define PIN_NXDN 5
#define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13) #define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC13 #define ADC_ISR_EOC_Chan ADC_ISR_EOC13
#define ADC_CDR_Chan 13 #define ADC_CDR_Chan 13
@ -61,6 +63,7 @@
#define PIN_DMR 8 #define PIN_DMR 8
#define PIN_YSF 7 #define PIN_YSF 7
#define PIN_P25 6 #define PIN_P25 6
#define PIN_NXDN 5
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7) #define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7 #define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7 #define ADC_CDR_Chan 7
@ -95,6 +98,7 @@ void CIO::initInt()
pinMode(PIN_DMR, OUTPUT); pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT); pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT); pinMode(PIN_P25, OUTPUT);
pinMode(PIN_NXDN, OUTPUT);
#endif #endif
} }
@ -226,9 +230,15 @@ void CIO::setP25Int(bool on)
digitalWrite(PIN_P25, on ? HIGH : LOW); digitalWrite(PIN_P25, on ? HIGH : LOW);
} }
void CIO::setNXDNInt(bool on)
{
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
}
void CIO::delayInt(unsigned int dly) void CIO::delayInt(unsigned int dly)
{ {
delay(dly); delay(dly);
} }
#endif #endif

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM * Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU * Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Jonathan Naylor G4KLX * Copyright (C) 2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -37,6 +37,7 @@ DSTAR PD12 output P1 Pin44
DMR PD13 output P1 Pin45 DMR PD13 output P1 Pin45
YSF PD14 output P1 Pin46 YSF PD14 output P1 Pin46
P25 PD11 output P1 Pin43 P25 PD11 output P1 Pin43
NXDN PD10 output P1 Pin42
RX PA0 analog input P1 Pin12 RX PA0 analog input P1 Pin12
RSSI PA1 analog input P1 Pin11 RSSI PA1 analog input P1 Pin11
@ -65,6 +66,10 @@ EXT_CLK PA15 input P2 Pin40
#define PORT_P25 GPIOD #define PORT_P25 GPIOD
#define RCC_Per_P25 RCC_AHB1Periph_GPIOD #define RCC_Per_P25 RCC_AHB1Periph_GPIOD
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOD
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOD
#define PIN_DSTAR GPIO_Pin_12 #define PIN_DSTAR GPIO_Pin_12
#define PORT_DSTAR GPIOD #define PORT_DSTAR GPIOD
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOD #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOD
@ -107,6 +112,7 @@ DSTAR PC7 output
DMR PC8 output DMR PC8 output
YSF PA8 output YSF PA8 output
P25 PC9 output P25 PC9 output
P25 PC10 output
RX PA0 analog input RX PA0 analog input
RSSI PA7 analog input RSSI PA7 analog input
@ -135,6 +141,10 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC #define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC #define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_P25 GPIO_Pin_10
#define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_DSTAR GPIO_Pin_7 #define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC #define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@ -177,6 +187,7 @@ DSTAR PC7 output
DMR PC8 output DMR PC8 output
YSF PA8 output YSF PA8 output
P25 PC9 output P25 PC9 output
NXDN PC10 output
RX PA0 analog input RX PA0 analog input
RSSI PA7 analog input RSSI PA7 analog input
@ -205,6 +216,10 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC #define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC #define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOC
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOC
#define PIN_DSTAR GPIO_Pin_7 #define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC #define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@ -247,6 +262,7 @@ DSTAR PC7 output
DMR PC8 output DMR PC8 output
YSF PA8 output YSF PA8 output
P25 PC9 output P25 PC9 output
NXDN PC10 output
RX PA0 analog input RX PA0 analog input
RSSI PA7 analog input RSSI PA7 analog input
@ -275,6 +291,10 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC #define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC #define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOC
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOC
#define PIN_DSTAR GPIO_Pin_7 #define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC #define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@ -319,11 +339,13 @@ DSTAR PB10 output CN10 Pin25
DMR PB4 output CN10 Pin27 DMR PB4 output CN10 Pin27
YSF PB5 output CN10 Pin29 YSF PB5 output CN10 Pin29
P25 PB3 output CN10 Pin31 P25 PB3 output CN10 Pin31
NXDN PB2 output CN10 Pin32
MDSTAR PC4 output CN10 Pin34 MDSTAR PC4 output CN10 Pin34
MDMR PC5 output CN10 Pin6 MDMR PC5 output CN10 Pin6
MYSF PC2 output CN7 Pin35 MYSF PC2 output CN7 Pin35
MP25 PC3 output CN7 Pin37 MP25 PC3 output CN7 Pin37
MNXDN PC6 output CN10 Pin??
RX PA0 analog input CN7 Pin28 RX PA0 analog input CN7 Pin28
RSSI PA1 analog input CN7 Pin30 RSSI PA1 analog input CN7 Pin30
@ -352,6 +374,10 @@ EXT_CLK PA15 input CN7 Pin17
#define PORT_P25 GPIOB #define PORT_P25 GPIOB
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB #define RCC_Per_P25 RCC_AHB1Periph_GPIOB
#define PIN_NXDN GPIO_Pin_2
#define PORT_NXDN GPIOB
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
#define PIN_DSTAR GPIO_Pin_10 #define PIN_DSTAR GPIO_Pin_10
#define PORT_DSTAR GPIOB #define PORT_DSTAR GPIOB
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
@ -369,6 +395,10 @@ EXT_CLK PA15 input CN7 Pin17
#define PORT_MP25 GPIOC #define PORT_MP25 GPIOC
#define RCC_Per_MP25 RCC_AHB1Periph_GPIOC #define RCC_Per_MP25 RCC_AHB1Periph_GPIOC
#define PIN_MNXDN GPIO_Pin_1
#define PORT_MNXDN GPIOC
#define RCC_Per_MNXDN RCC_AHB1Periph_GPIOC
#define PIN_MDSTAR GPIO_Pin_4 #define PIN_MDSTAR GPIO_Pin_4
#define PORT_MDSTAR GPIOC #define PORT_MDSTAR GPIOC
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC #define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
@ -412,6 +442,7 @@ DSTAR PA1 output CN8 Pin2
DMR PA4 output CN8 Pin3 DMR PA4 output CN8 Pin3
YSF PB0 output CN8 Pin4 YSF PB0 output CN8 Pin4
P25 PC1 output CN8 Pin5 P25 PC1 output CN8 Pin5
NXDN PC? output CN8 Pin6
RX PA0 analog input CN8 Pin1 RX PA0 analog input CN8 Pin1
RSSI PC0 analog input CN8 Pin6 RSSI PC0 analog input CN8 Pin6
@ -440,6 +471,10 @@ EXT_CLK PB8 input CN5 Pin10
#define PORT_P25 GPIOC #define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC #define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_6
#define PORT_NXDN GPIOC
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOC
#define PIN_DSTAR GPIO_Pin_1 #define PIN_DSTAR GPIO_Pin_1
#define PORT_DSTAR GPIOA #define PORT_DSTAR GPIOA
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOA #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOA
@ -486,11 +521,13 @@ DSTAR PB10 output CN12 Pin25
DMR PB4 output CN12 Pin27 DMR PB4 output CN12 Pin27
YSF PB5 output CN12 Pin29 YSF PB5 output CN12 Pin29
P25 PB3 output CN12 Pin31 P25 PB3 output CN12 Pin31
NXDN PB2 output CN12 Pin32
MDSTAR PC4 output CN12 Pin34 MDSTAR PC4 output CN12 Pin34
MDMR PC5 output CN12 Pin6 MDMR PC5 output CN12 Pin6
MYSF PC2 output CN11 Pin35 MYSF PC2 output CN11 Pin35
MP25 PC3 output CN11 Pin37 MP25 PC3 output CN11 Pin37
MNXDN PC6 output CN11 Pin??
RX PA0 analog input CN11 Pin28 RX PA0 analog input CN11 Pin28
RSSI PA1 analog input CN11 Pin30 RSSI PA1 analog input CN11 Pin30
@ -519,6 +556,10 @@ EXT_CLK PA15 input CN11 Pin17
#define PORT_P25 GPIOB #define PORT_P25 GPIOB
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB #define RCC_Per_P25 RCC_AHB1Periph_GPIOB
#define PIN_NXDN GPIO_Pin_2
#define PORT_NXDN GPIOB
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
#define PIN_DSTAR GPIO_Pin_10 #define PIN_DSTAR GPIO_Pin_10
#define PORT_DSTAR GPIOB #define PORT_DSTAR GPIOB
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB #define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
@ -536,6 +577,10 @@ EXT_CLK PA15 input CN11 Pin17
#define PORT_MP25 GPIOC #define PORT_MP25 GPIOC
#define RCC_Per_MP25 RCC_AHB1Periph_GPIOC #define RCC_Per_MP25 RCC_AHB1Periph_GPIOC
#define PIN_MNXDN GPIO_Pin_6
#define PORT_MNXDN GPIOC
#define RCC_Per_MNXDN RCC_AHB1Periph_GPIOC
#define PIN_MDSTAR GPIO_Pin_4 #define PIN_MDSTAR GPIO_Pin_4
#define PORT_MDSTAR GPIOC #define PORT_MDSTAR GPIOC
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC #define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
@ -640,6 +685,12 @@ void CIO::initInt()
GPIO_InitStruct.GPIO_Pin = PIN_P25; GPIO_InitStruct.GPIO_Pin = PIN_P25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_P25, &GPIO_InitStruct); GPIO_Init(PORT_P25, &GPIO_InitStruct);
// NXDN pin
RCC_AHB1PeriphClockCmd(RCC_Per_NXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_NXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
#endif #endif
#if defined(STM32F4_NUCLEO_MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && defined(STM32F4_NUCLEO) #if defined(STM32F4_NUCLEO_MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && defined(STM32F4_NUCLEO)
@ -666,6 +717,12 @@ void CIO::initInt()
GPIO_InitStruct.GPIO_Pin = PIN_MP25; GPIO_InitStruct.GPIO_Pin = PIN_MP25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MP25, &GPIO_InitStruct); GPIO_Init(PORT_MP25, &GPIO_InitStruct);
// NXDN mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MNXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MNXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
#endif #endif
} }
@ -905,6 +962,14 @@ void CIO::setP25Int(bool on)
#endif #endif
} }
void CIO::setNXDNInt(bool on)
{
GPIO_WriteBit(PORT_NXDN, PIN_NXDN, on ? Bit_SET : Bit_RESET);
#if defined(STM32F4_NUCLEO_MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && defined(STM32F4_NUCLEO)
GPIO_WriteBit(PORT_MNXDN, PIN_MNXDN, on ? Bit_SET : Bit_RESET);
#endif
}
// Simple delay function for STM32 // Simple delay function for STM32
// Example from: http://thehackerworkshop.com/?p=1209 // Example from: http://thehackerworkshop.com/?p=1209
void CIO::delayInt(unsigned int dly) void CIO::delayInt(unsigned int dly)

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM * Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU * Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017 by Jonathan Naylor G4KLX * Copyright (C) 2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Wojciech Krutnik N0CALL * Copyright (C) 2017 by Wojciech Krutnik N0CALL
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -39,6 +39,7 @@ DSTAR PB7 output
DMR PB6 output DMR PB6 output
YSF PB8 output YSF PB8 output
P25 PB9 output P25 PB9 output
NXDN PB10 output
RX PB0 analog input (ADC1_8) RX PB0 analog input (ADC1_8)
RSSI PB1 analog input (ADC2_9) RSSI PB1 analog input (ADC2_9)
@ -76,6 +77,9 @@ USART1_RXD PA10 input (AF)
#define PIN_P25 9 #define PIN_P25 9
#define PORT_P25 GPIOB #define PORT_P25 GPIOB
#define BB_P25 *((bitband_t)BITBAND_PERIPH(&PORT_P25->ODR, PIN_P25)) #define BB_P25 *((bitband_t)BITBAND_PERIPH(&PORT_P25->ODR, PIN_P25))
#define PIN_NXDN 10
#define PORT_NXDN GPIOB
#define BB_NXDN *((bitband_t)BITBAND_PERIPH(&PORT_NXDN->ODR, PIN_NXDN))
#define PIN_RX 0 #define PIN_RX 0
#define PIN_RX_ADC_CH 8 #define PIN_RX_ADC_CH 8
@ -214,6 +218,7 @@ static inline void GPIOInit()
GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1); GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_YSF, PIN_YSF, GPIO_CRL_MODE0_1); GPIOConfigPin(PORT_YSF, PIN_YSF, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_P25, PIN_P25, GPIO_CRL_MODE0_1); GPIOConfigPin(PORT_P25, PIN_P25, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_RX, PIN_RX, 0); GPIOConfigPin(PORT_RX, PIN_RX, 0);
#if defined(SEND_RSSI_DATA) #if defined(SEND_RSSI_DATA)
@ -424,6 +429,11 @@ void CIO::setP25Int(bool on)
BB_P25 = !!on; BB_P25 = !!on;
} }
void CIO::setNXDNInt(bool on)
{
BB_NXDN = !!on;
}
void CIO::delayInt(unsigned int dly) void CIO::delayInt(unsigned int dly)
{ {
delay(dly); delay(dly);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -34,6 +34,7 @@
#define PIN_DMR 10 #define PIN_DMR 10
#define PIN_YSF 11 #define PIN_YSF 11
#define PIN_P25 12 #define PIN_P25 12
#define PIN_NXDN 8
#define PIN_ADC 5 // A0, Pin 14 #define PIN_ADC 5 // A0, Pin 14
#define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28 #define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28
@ -63,6 +64,7 @@ void CIO::initInt()
pinMode(PIN_DMR, OUTPUT); pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT); pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT); pinMode(PIN_P25, OUTPUT);
pinMode(PIN_NXDN, OUTPUT);
#endif #endif
} }
@ -210,6 +212,11 @@ void CIO::setP25Int(bool on)
digitalWrite(PIN_P25, on ? HIGH : LOW); digitalWrite(PIN_P25, on ? HIGH : LOW);
} }
void CIO::setNXDNInt(bool on)
{
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
}
void CIO::delayInt(unsigned int dly) void CIO::delayInt(unsigned int dly)
{ {
delay(dly); delay(dly);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT * Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@ -30,6 +30,7 @@ bool m_dstarEnable = true;
bool m_dmrEnable = true; bool m_dmrEnable = true;
bool m_ysfEnable = true; bool m_ysfEnable = true;
bool m_p25Enable = true; bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_duplex = true; bool m_duplex = true;
@ -52,6 +53,9 @@ CYSFTX ysfTX;
CP25RX p25RX; CP25RX p25RX;
CP25TX p25TX; CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDStarRX calDStarRX; CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX; CCalDStarTX calDStarTX;
CCalDMR calDMR; CCalDMR calDMR;
@ -91,6 +95,9 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_modemState == STATE_DSTARCAL) if (m_modemState == STATE_DSTARCAL)
calDStarTX.process(); calDStarTX.process();
@ -113,4 +120,3 @@ int main()
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -27,6 +27,7 @@ bool m_dstarEnable = true;
bool m_dmrEnable = true; bool m_dmrEnable = true;
bool m_ysfEnable = true; bool m_ysfEnable = true;
bool m_p25Enable = true; bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_duplex = true; bool m_duplex = true;
@ -49,6 +50,9 @@ CYSFTX ysfTX;
CP25RX p25RX; CP25RX p25RX;
CP25TX p25TX; CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDStarRX calDStarRX; CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX; CCalDStarTX calDStarTX;
CCalDMR calDMR; CCalDMR calDMR;
@ -88,6 +92,9 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_modemState == STATE_DSTARCAL) if (m_modemState == STATE_DSTARCAL)
calDStarTX.process(); calDStarTX.process();

54
NXDNDefines.h 100644
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2016,2017,2018 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(NXDNDEFINES_H)
#define NXDNDEFINES_H
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int NXDN_FRAME_LENGTH_BYTES = 120U;
const unsigned int NXDN_FRAME_LENGTH_BITS = NXDN_FRAME_LENGTH_BYTES * 8U;
const unsigned int NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BYTES * 4U;
const unsigned int NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const unsigned int NXDN_SYNC_LENGTH_BYTES = 5U;
const unsigned int NXDN_SYNC_LENGTH_BITS = NXDN_SYNC_LENGTH_BYTES * 8U;
const unsigned int NXDN_SYNC_LENGTH_SYMBOLS = NXDN_SYNC_LENGTH_BYTES * 4U;
const unsigned int NXDN_SYNC_LENGTH_SAMPLES = NXDN_SYNC_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const unsigned int NXDN_FICH_LENGTH_BITS = 200U;
const unsigned int NXDN_FICH_LENGTH_SYMBOLS = 100U;
const unsigned int NXDN_FICH_LENGTH_SAMPLES = NXDN_FICH_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const uint8_t NXDN_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
const uint8_t NXDN_SYNC_BYTES_LENGTH = 5U;
const uint64_t NXDN_SYNC_BITS = 0x000000D471C9634DU;
const uint64_t NXDN_SYNC_BITS_MASK = 0x000000FFFFFFFFFFU;
// D 4 7 1 C 9 6 3 4 D
// 11 01 01 00 01 11 00 01 11 00 10 01 01 10 00 11 01 00 11 01
// -3 +3 +3 +1 +3 -3 +1 +3 -3 +1 -1 +3 +3 -1 +3 -3 +3 +1 -3 +3
const int8_t NXDN_SYNC_SYMBOLS_VALUES[] = {-3, +3, +3, +1, +3, -3, +1, +3, -3, +1, -1, +3, +3, -1, +3, -3, +3, +1, -3, +3};
const uint32_t NXDN_SYNC_SYMBOLS = 0x0007B5ADU;
const uint32_t NXDN_SYNC_SYMBOLS_MASK = 0x000FFFFFU;
#endif

405
NXDNRX.cpp 100644
View File

@ -0,0 +1,405 @@
/*
* Copyright (C) 2009-2018 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 "NXDNRX.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 = 4U + 1U;
CNXDNRX::CNXDNRX() :
m_state(NXDNRXS_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 CNXDNRX::reset()
{
m_state = NXDNRXS_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 CNXDNRX::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 NXDNRXS_DATA:
processData(sample);
break;
default:
processNone(sample);
break;
}
m_dataPtr++;
if (m_dataPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_bitPtr++;
if (m_bitPtr >= NXDN_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U;
}
}
void CNXDNRX::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 + NXDN_FRAME_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_minSyncPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_maxSyncPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_state = NXDNRXS_DATA;
m_countdown = 0U;
}
}
void CNXDNRX::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 + NXDN_FRAME_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_minSyncPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_maxSyncPtr -= NXDN_FRAME_LENGTH_SAMPLES;
}
calculateLevels(m_startPtr, NXDN_FRAME_LENGTH_SYMBOLS);
DEBUG4("NXDNRX: sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
uint8_t frame[NXDN_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, NXDN_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("NXDNRX: sync timed out, lost lock");
io.setDecode(false);
io.setADCDetection(false);
serial.writeNXDNLost();
m_state = NXDNRXS_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 CNXDNRX::correlateSync()
{
if (countBits32((m_bitBuffer[m_bitPtr] & NXDN_SYNC_SYMBOLS_MASK) ^ NXDN_SYNC_SYMBOLS) <= MAX_SYNC_SYMBOLS_ERRS) {
uint16_t ptr = m_dataPtr + NXDN_FRAME_LENGTH_SAMPLES - NXDN_SYNC_LENGTH_SAMPLES + NXDN_RADIO_SYMBOL_LENGTH;
if (ptr >= NXDN_FRAME_LENGTH_SAMPLES)
ptr -= NXDN_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < NXDN_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (NXDN_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 += NXDN_RADIO_SYMBOL_LENGTH;
if (ptr >= NXDN_FRAME_LENGTH_SAMPLES)
ptr -= NXDN_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 + NXDN_FRAME_LENGTH_SAMPLES - NXDN_SYNC_LENGTH_SAMPLES + NXDN_RADIO_SYMBOL_LENGTH;
if (startPtr >= NXDN_FRAME_LENGTH_SAMPLES)
startPtr -= NXDN_FRAME_LENGTH_SAMPLES;
uint8_t sync[NXDN_SYNC_BYTES_LENGTH];
samplesToBits(startPtr, NXDN_SYNC_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t maxErrs;
if (m_state == NXDNRXS_NONE)
maxErrs = MAX_SYNC_BIT_START_ERRS;
else
maxErrs = MAX_SYNC_BIT_RUN_ERRS;
uint8_t errs = 0U;
for (uint8_t i = 0U; i < NXDN_SYNC_BYTES_LENGTH; i++)
errs += countBits8(sync[i] ^ NXDN_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 + NXDN_FRAME_LENGTH_SAMPLES - NXDN_SYNC_LENGTH_SAMPLES - 1U;
if (m_endPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_endPtr -= NXDN_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
void CNXDNRX::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 += NXDN_RADIO_SYMBOL_LENGTH;
if (start >= NXDN_FRAME_LENGTH_SAMPLES)
start -= NXDN_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("NXDNRX: 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 CNXDNRX::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 += NXDN_RADIO_SYMBOL_LENGTH;
if (start >= NXDN_FRAME_LENGTH_SAMPLES)
start -= NXDN_FRAME_LENGTH_SAMPLES;
}
}
void CNXDNRX::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.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}

69
NXDNRX.h 100644
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2015,2016,2017,2018 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(NXDNRX_H)
#define NXDNRX_H
#include "Config.h"
#include "NXDNDefines.h"
enum NXDNRX_STATE {
NXDNRXS_NONE,
NXDNRXS_DATA
};
class CNXDNRX {
public:
CNXDNRX();
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
void reset();
private:
NXDNRX_STATE m_state;
uint32_t m_bitBuffer[NXDN_RADIO_SYMBOL_LENGTH];
q15_t m_buffer[NXDN_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

150
NXDNTX.cpp 100644
View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* 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 "NXDNTX.h"
#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
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t NXDN_LEVELA = 1893;
const q15_t NXDN_LEVELB = 631;
const q15_t NXDN_LEVELC = -631;
const q15_t NXDN_LEVELD = -1893;
const uint8_t NXDN_START_SYNC = 0x77U;
const uint8_t NXDN_END_SYNC = 0xFFU;
CNXDNTX::CNXDNTX() :
m_buffer(1500U),
m_modFilter(),
m_modState(),
m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(240U) // 200ms
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
m_modFilter.L = NXDN_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = RRC_0_2_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = RRC_0_2_FILTER;
m_modFilter.pState = m_modState;
}
void CNXDNTX::process()
{
if (m_buffer.getData() == 0U && m_poLen == 0U)
return;
if (m_poLen == 0U) {
if (!m_tx) {
for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = NXDN_START_SYNC;
} else {
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
uint8_t c = m_buffer.get();
m_poBuffer[m_poLen++] = c;
}
}
m_poPtr = 0U;
}
if (m_poLen > 0U) {
uint16_t space = io.getSpace();
while (space > (4U * NXDN_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c);
space -= 4U * NXDN_RADIO_SYMBOL_LENGTH;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
m_poLen = 0U;
return;
}
}
}
}
uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length)
{
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < NXDN_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
void CNXDNTX::writeByte(uint8_t c)
{
q15_t inBuffer[4U];
q15_t outBuffer[NXDN_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] = NXDN_LEVELA;
break;
case 0x80U:
inBuffer[i] = NXDN_LEVELB;
break;
case 0x00U:
inBuffer[i] = NXDN_LEVELC;
break;
default:
inBuffer[i] = NXDN_LEVELD;
break;
}
}
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
}
void CNXDNTX::setTXDelay(uint8_t delay)
{
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
if (m_txDelay > 1200U)
m_txDelay = 1200U;
}
uint8_t CNXDNTX::getSpace() const
{
return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES;
}

51
NXDNTX.h 100644
View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2015,2016,2017,2018 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(NXDNTX_H)
#define NXDNTX_H
#include "Config.h"
#include "SerialRB.h"
class CNXDNTX {
public:
CNXDNTX();
uint8_t writeData(const uint8_t* data, uint8_t length);
void process();
void setTXDelay(uint8_t delay);
uint8_t getSpace() const;
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;
void writeByte(uint8_t c);
};
#endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2013,2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2013,2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -60,6 +60,9 @@ const uint8_t MMDVM_P25_HDR = 0x30U;
const uint8_t MMDVM_P25_LDU = 0x31U; const uint8_t MMDVM_P25_LDU = 0x31U;
const uint8_t MMDVM_P25_LOST = 0x32U; 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_ACK = 0x70U; const uint8_t MMDVM_ACK = 0x70U;
const uint8_t MMDVM_NAK = 0x7FU; const uint8_t MMDVM_NAK = 0x7FU;
@ -73,9 +76,9 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
#if defined(EXTERNAL_OSC) #if defined(EXTERNAL_OSC)
#define DESCRIPTION "MMDVM 20170501 TCXO (D-Star/DMR/System Fusion/P25/RSSI/CW Id)" #define DESCRIPTION "MMDVM 20170501 TCXO (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
#else #else
#define DESCRIPTION "MMDVM 20170501 (D-Star/DMR/System Fusion/P25/RSSI/CW Id)" #define DESCRIPTION "MMDVM 20170501 (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
#endif #endif
#if defined(GITVERSION) #if defined(GITVERSION)
@ -143,6 +146,8 @@ void CSerialPort::getStatus()
reply[3U] |= 0x04U; reply[3U] |= 0x04U;
if (m_p25Enable) if (m_p25Enable)
reply[3U] |= 0x08U; reply[3U] |= 0x08U;
if (m_nxdnEnable)
reply[3U] |= 0x10U;
reply[4U] = uint8_t(m_modemState); reply[4U] = uint8_t(m_modemState);
@ -197,7 +202,12 @@ void CSerialPort::getStatus()
else else
reply[10U] = 0U; reply[10U] = 0U;
writeInt(1U, reply, 11); if (m_nxdnEnable)
reply[11U] = nxdnTX.getSpace();
else
reply[11U] = 0U;
writeInt(1U, reply, 12);
} }
void CSerialPort::getVersion() void CSerialPort::getVersion()
@ -221,7 +231,7 @@ void CSerialPort::getVersion()
uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
{ {
if (length < 15U) if (length < 16U)
return 4U; return 4U;
bool rxInvert = (data[0U] & 0x01U) == 0x01U; bool rxInvert = (data[0U] & 0x01U) == 0x01U;
@ -236,6 +246,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
bool dmrEnable = (data[1U] & 0x02U) == 0x02U; bool dmrEnable = (data[1U] & 0x02U) == 0x02U;
bool ysfEnable = (data[1U] & 0x04U) == 0x04U; bool ysfEnable = (data[1U] & 0x04U) == 0x04U;
bool p25Enable = (data[1U] & 0x08U) == 0x08U; bool p25Enable = (data[1U] & 0x08U) == 0x08U;
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
uint8_t txDelay = data[2U]; uint8_t txDelay = data[2U];
if (txDelay > 50U) if (txDelay > 50U)
@ -243,7 +254,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
MMDVM_STATE modemState = MMDVM_STATE(data[3U]); 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_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K) if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K)
return 4U; return 4U;
if (modemState == STATE_DSTAR && !dstarEnable) if (modemState == STATE_DSTAR && !dstarEnable)
return 4U; return 4U;
@ -253,6 +264,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
return 4U; return 4U;
if (modemState == STATE_P25 && !p25Enable) if (modemState == STATE_P25 && !p25Enable)
return 4U; return 4U;
if (modemState == STATE_NXDN && !nxdnEnable)
return 4U;
uint8_t rxLevel = data[4U]; uint8_t rxLevel = data[4U];
@ -271,18 +284,22 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
int16_t txDCOffset = int16_t(data[13U]) - 128; int16_t txDCOffset = int16_t(data[13U]) - 128;
int16_t rxDCOffset = int16_t(data[14U]) - 128; int16_t rxDCOffset = int16_t(data[14U]) - 128;
uint8_t nxdnTXLevel = data[15U];
m_modemState = modemState; m_modemState = modemState;
m_dstarEnable = dstarEnable; m_dstarEnable = dstarEnable;
m_dmrEnable = dmrEnable; m_dmrEnable = dmrEnable;
m_ysfEnable = ysfEnable; m_ysfEnable = ysfEnable;
m_p25Enable = p25Enable; m_p25Enable = p25Enable;
m_nxdnEnable = nxdnEnable;
m_duplex = !simplex; m_duplex = !simplex;
dstarTX.setTXDelay(txDelay); dstarTX.setTXDelay(txDelay);
ysfTX.setTXDelay(txDelay); ysfTX.setTXDelay(txDelay);
p25TX.setTXDelay(txDelay); p25TX.setTXDelay(txDelay);
dmrDMOTX.setTXDelay(txDelay); dmrDMOTX.setTXDelay(txDelay);
nxdnTX.setTXDelay(txDelay);
dmrTX.setColorCode(colorCode); dmrTX.setColorCode(colorCode);
dmrRX.setColorCode(colorCode); dmrRX.setColorCode(colorCode);
@ -292,7 +309,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
ysfTX.setLoDev(ysfLoDev); ysfTX.setLoDev(ysfLoDev);
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, txDCOffset, rxDCOffset); io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, txDCOffset, rxDCOffset);
io.start(); io.start();
@ -309,7 +326,7 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
if (modemState == m_modemState) if (modemState == m_modemState)
return 0U; return 0U;
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K) if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K)
return 4U; return 4U;
if (modemState == STATE_DSTAR && !m_dstarEnable) if (modemState == STATE_DSTAR && !m_dstarEnable)
return 4U; return 4U;
@ -319,6 +336,8 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
return 4U; return 4U;
if (modemState == STATE_P25 && !m_p25Enable) if (modemState == STATE_P25 && !m_p25Enable)
return 4U; return 4U;
if (modemState == STATE_NXDN && !m_nxdnEnable)
return 4U;
setMode(modemState); setMode(modemState);
@ -333,6 +352,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_DSTAR: case STATE_DSTAR:
@ -342,6 +362,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset(); dmrRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_YSF: case STATE_YSF:
@ -351,6 +372,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset(); dmrRX.reset();
dstarRX.reset(); dstarRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_P25: case STATE_P25:
@ -360,6 +382,17 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset(); dmrRX.reset();
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_NXDN:
DEBUG1("Mode set to NXDN");
dmrIdleRX.reset();
dmrDMORX.reset();
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_DSTARCAL: case STATE_DSTARCAL:
@ -370,6 +403,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_DMRCAL: case STATE_DMRCAL:
@ -380,6 +414,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_RSSICAL: case STATE_RSSICAL:
@ -390,6 +425,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_LFCAL: case STATE_LFCAL:
@ -400,6 +436,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_DMRCAL1K: case STATE_DMRCAL1K:
@ -410,6 +447,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
case STATE_P25CAL1K: case STATE_P25CAL1K:
@ -420,6 +458,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
nxdnRX.reset();
cwIdTX.reset(); cwIdTX.reset();
break; break;
default: default:
@ -682,6 +721,20 @@ void CSerialPort::process()
} }
break; break;
case MMDVM_NXDN_DATA:
if (m_nxdnEnable) {
if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN)
err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U);
}
if (err == 0U) {
if (m_modemState == STATE_IDLE)
setMode(STATE_NXDN);
} else {
DEBUG2("Received invalid NXDN data", err);
sendNAK(err);
}
break;
#if defined(SERIAL_REPEATER) #if defined(SERIAL_REPEATER)
case MMDVM_SERIAL: { case MMDVM_SERIAL: {
for (uint8_t i = 3U; i < m_len; i++) for (uint8_t i = 3U; i < m_len; i++)
@ -949,6 +1002,46 @@ void CSerialPort::writeP25Lost()
writeInt(1U, reply, 3); writeInt(1U, reply, 3);
} }
void CSerialPort::writeNXDNData(const uint8_t* data, uint8_t length)
{
if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE)
return;
if (!m_nxdnEnable)
return;
uint8_t reply[130U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 0U;
reply[2U] = MMDVM_NXDN_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::writeNXDNLost()
{
if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE)
return;
if (!m_nxdnEnable)
return;
uint8_t reply[3U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 3U;
reply[2U] = MMDVM_NXDN_LOST;
writeInt(1U, reply, 3);
}
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length) void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
{ {
if (m_modemState != STATE_DSTARCAL) if (m_modemState != STATE_DSTARCAL)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -47,6 +47,9 @@ public:
void writeP25Ldu(const uint8_t* data, uint8_t length); void writeP25Ldu(const uint8_t* data, uint8_t length);
void writeP25Lost(); void writeP25Lost();
void writeNXDNData(const uint8_t* data, uint8_t length);
void writeNXDNLost();
void writeCalData(const uint8_t* data, uint8_t length); void writeCalData(const uint8_t* data, uint8_t length);
void writeRSSIData(const uint8_t* data, uint8_t length); void writeRSSIData(const uint8_t* data, uint8_t length);
@ -80,3 +83,4 @@ private:
}; };
#endif #endif