mirror of https://github.com/markqvist/MMDVM.git
Merge branch 'master' into boxcar
commit
dbd84d7803
77
CalDMR.cpp
77
CalDMR.cpp
|
@ -21,25 +21,37 @@
|
|||
#include "Globals.h"
|
||||
#include "CalDMR.h"
|
||||
|
||||
// Voice LC Header, CC: 1, srcID: 1, dstID: TG9
|
||||
// Voice LC BS Header, CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t VH_1K[] = {0x00U,
|
||||
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
|
||||
0x60U, 0x84U, 0x6DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xDEU, 0x30U, 0x30U,
|
||||
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU};
|
||||
|
||||
// Voice Term with LC, CC: 1, srcID: 1, dstID: TG9
|
||||
// Voice Term BS with LC, CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t VT_1K[] = {0x00U,
|
||||
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
|
||||
0xC0U, 0x84U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x24U,
|
||||
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU};
|
||||
|
||||
// Voice LC MS Header, CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t VH_DMO1K[] = {0x00U,
|
||||
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
|
||||
0x60U, 0x84U, 0x6DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x7EU, 0x30U, 0x30U,
|
||||
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU};
|
||||
|
||||
// Voice Term MS with LC, CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t VT_DMO1K[] = {0x00U,
|
||||
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
|
||||
0xC0U, 0x84U, 0xADU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x79U, 0x65U, 0x24U,
|
||||
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU};
|
||||
|
||||
// Voice coding data + FEC, 1031 Hz Test Pattern
|
||||
const uint8_t VOICE_1K[] = {0x00U,
|
||||
0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU, 0xCEU, 0xA8U,
|
||||
0xFEU, 0x83U, 0xA0U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x0CU, 0xC4U, 0x58U,
|
||||
0x20U, 0x0AU, 0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU};
|
||||
|
||||
// Embedded LC: CC: 1, srcID: 1, dstID: TG9
|
||||
// Embedded LC BS: CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t SYNCEMB_1K[6][7] = {
|
||||
{0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U}, // BS VOICE SYNC (audio seq 0)
|
||||
{0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U}, // EMB + Embedded LC1 (audio seq 1)
|
||||
|
@ -48,6 +60,15 @@ const uint8_t SYNCEMB_1K[6][7] = {
|
|||
{0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U}, // EMB + Embedded LC4 (audio seq 4)
|
||||
{0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U}}; // EMB (audio seq 5)
|
||||
|
||||
// Embedded LC MS: CC: 1, srcID: 1, dstID: TG9
|
||||
const uint8_t SYNCEMB_DMO1K[6][7] = {
|
||||
{0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U}, // MS VOICE SYNC (audio seq 0)
|
||||
{0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U}, // EMB + Embedded LC1 (audio seq 1)
|
||||
{0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U}, // EMB + Embedded LC2 (audio seq 2)
|
||||
{0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U}, // EMB + Embedded LC3 (audio seq 3)
|
||||
{0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U}, // EMB + Embedded LC4 (audio seq 4)
|
||||
{0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U}}; // EMB (audio seq 5)
|
||||
|
||||
// Short LC:
|
||||
// TS1: dstID: 0, ACTIVITY_NONE
|
||||
// TS2: dstID: TG9, ACTIVITY_VOICE
|
||||
|
@ -78,6 +99,9 @@ void CCalDMR::process()
|
|||
case STATE_DMRCAL1K:
|
||||
dmr1kcal();
|
||||
break;
|
||||
case STATE_DMRDMO1K:
|
||||
dmrdmo1k();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -94,6 +118,17 @@ void CCalDMR::createData1k(uint8_t n)
|
|||
m_dmr1k[20U] |= SYNCEMB_1K[n][6] & 0xF0U;
|
||||
}
|
||||
|
||||
void CCalDMR::createDataDMO1k(uint8_t n)
|
||||
{
|
||||
for(uint8_t i = 0; i < 5U; i++)
|
||||
m_dmr1k[i + 15U] = SYNCEMB_DMO1K[n][i + 1U];
|
||||
|
||||
m_dmr1k[14U] &= 0xF0U;
|
||||
m_dmr1k[20U] &= 0x0FU;
|
||||
m_dmr1k[14U] |= SYNCEMB_DMO1K[n][0] & 0x0FU;
|
||||
m_dmr1k[20U] |= SYNCEMB_DMO1K[n][6] & 0xF0U;
|
||||
}
|
||||
|
||||
void CCalDMR::dmr1kcal()
|
||||
{
|
||||
dmrTX.process();
|
||||
|
@ -139,6 +174,40 @@ void CCalDMR::dmr1kcal()
|
|||
}
|
||||
}
|
||||
|
||||
void CCalDMR::dmrdmo1k()
|
||||
{
|
||||
dmrDMOTX.process();
|
||||
|
||||
uint16_t space = dmrDMOTX.getSpace();
|
||||
if (space < 1U)
|
||||
return;
|
||||
|
||||
switch (m_state) {
|
||||
case DMRCAL1K_VH:
|
||||
dmrDMOTX.writeData(VH_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||
m_state = DMRCAL1K_VOICE;
|
||||
break;
|
||||
case DMRCAL1K_VOICE:
|
||||
createDataDMO1k(m_audioSeq);
|
||||
dmrDMOTX.writeData(m_dmr1k, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||
if(m_audioSeq == 5U) {
|
||||
m_audioSeq = 0U;
|
||||
if(!m_transmit)
|
||||
m_state = DMRCAL1K_VT;
|
||||
} else
|
||||
m_audioSeq++;
|
||||
break;
|
||||
case DMRCAL1K_VT:
|
||||
dmrDMOTX.writeData(VT_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||
m_state = DMRCAL1K_IDLE;
|
||||
break;
|
||||
default:
|
||||
m_state = DMRCAL1K_IDLE;
|
||||
m_audioSeq = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length != 1U)
|
||||
|
@ -146,7 +215,7 @@ uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
|
|||
|
||||
m_transmit = data[0U] == 1U;
|
||||
|
||||
if(m_transmit && m_state == DMRCAL1K_IDLE && m_modemState == STATE_DMRCAL1K)
|
||||
if(m_transmit && m_state == DMRCAL1K_IDLE && (m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K))
|
||||
m_state = DMRCAL1K_VH;
|
||||
|
||||
return 0U;
|
||||
|
|
2
CalDMR.h
2
CalDMR.h
|
@ -37,7 +37,9 @@ public:
|
|||
|
||||
void process();
|
||||
void dmr1kcal();
|
||||
void dmrdmo1k();
|
||||
void createData1k(uint8_t n);
|
||||
void createDataDMO1k(uint8_t n);
|
||||
|
||||
uint8_t write(const uint8_t* data, uint8_t length);
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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 "CalNXDN.h"
|
||||
|
||||
// NXDN 1031 Hz Test Pattern, RAN: 1, Unit ID: 1, Dst Group ID: 1, Outbound Direction
|
||||
const uint8_t NXDN_CAL1K[4][49] = {
|
||||
{0x00U,
|
||||
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0xFAU, 0x0AU, 0x6EU, 0x8AU, 0x23U, 0x56U, 0xE8U,
|
||||
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
|
||||
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
|
||||
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
|
||||
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
|
||||
|
||||
{0x00U,
|
||||
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0x6DU, 0xBBU, 0x0EU, 0xB3U, 0xA4U, 0x26U, 0xA8U,
|
||||
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
|
||||
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
|
||||
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
|
||||
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
|
||||
|
||||
{0x00U,
|
||||
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x76U, 0x3AU, 0x1BU, 0x4AU, 0x81U, 0xA8U, 0xE2U, 0x80U,
|
||||
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
|
||||
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
|
||||
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
|
||||
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
|
||||
|
||||
{0x00U,
|
||||
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x74U, 0x28U, 0x83U, 0x02U, 0xB0U, 0x2DU, 0x07U, 0xE2U,
|
||||
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
|
||||
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
|
||||
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
|
||||
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U}};
|
||||
|
||||
CCalNXDN::CCalNXDN() :
|
||||
m_transmit(false),
|
||||
m_state(NXDNCAL1K_IDLE),
|
||||
m_audioSeq(0U)
|
||||
{
|
||||
}
|
||||
|
||||
void CCalNXDN::process()
|
||||
{
|
||||
nxdnTX.process();
|
||||
|
||||
uint16_t space = nxdnTX.getSpace();
|
||||
if (space < 1U)
|
||||
return;
|
||||
|
||||
switch (m_state) {
|
||||
case NXDNCAL1K_TX:
|
||||
nxdnTX.writeData(NXDN_CAL1K[m_audioSeq], NXDN_FRAME_LENGTH_BYTES + 1U);
|
||||
m_audioSeq = (m_audioSeq + 1U) % 4U;
|
||||
if(!m_transmit)
|
||||
m_state = NXDNCAL1K_IDLE;
|
||||
break;
|
||||
default:
|
||||
m_state = NXDNCAL1K_IDLE;
|
||||
m_audioSeq = 0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length != 1U)
|
||||
return 4U;
|
||||
|
||||
m_transmit = data[0U] == 1U;
|
||||
|
||||
if(m_transmit && m_state == NXDNCAL1K_IDLE)
|
||||
m_state = NXDNCAL1K_TX;
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
#if !defined(CALNXDN_H)
|
||||
#define CALNXDN_H
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
enum NXDNCAL1K {
|
||||
NXDNCAL1K_IDLE,
|
||||
NXDNCAL1K_TX
|
||||
};
|
||||
|
||||
class CCalNXDN {
|
||||
public:
|
||||
CCalNXDN();
|
||||
|
||||
void process();
|
||||
|
||||
uint8_t write(const uint8_t* data, uint8_t length);
|
||||
|
||||
private:
|
||||
bool m_transmit;
|
||||
NXDNCAL1K m_state;
|
||||
uint8_t m_audioSeq;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
3
Config.h
3
Config.h
|
@ -66,4 +66,7 @@
|
|||
// Use the modem as a serial repeater for Nextion displays
|
||||
// #define SERIAL_REPEATER
|
||||
|
||||
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
|
||||
#define USE_DCBLOCKER
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,6 +54,7 @@ const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02
|
|||
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||
|
||||
const uint32_t STARTUP_COUNT = 20U;
|
||||
const uint32_t ABORT_COUNT = 6U;
|
||||
|
||||
CDMRTX::CDMRTX() :
|
||||
m_fifo(),
|
||||
|
@ -69,6 +70,7 @@ m_poBuffer(),
|
|||
m_poLen(0U),
|
||||
m_poPtr(0U),
|
||||
m_frameCount(0U),
|
||||
m_abortCount(),
|
||||
m_abort()
|
||||
{
|
||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||
|
@ -83,6 +85,9 @@ m_abort()
|
|||
|
||||
m_abort[0U] = false;
|
||||
m_abort[1U] = false;
|
||||
|
||||
m_abortCount[0U] = 0U;
|
||||
m_abortCount[1U] = 0U;
|
||||
}
|
||||
|
||||
void CDMRTX::process()
|
||||
|
@ -210,10 +215,12 @@ uint8_t CDMRTX::writeAbort(const uint8_t* data, uint8_t length)
|
|||
|
||||
switch (data[0U]) {
|
||||
case 1U:
|
||||
m_abortCount[0U] = 0U;
|
||||
m_abort[0U] = true;
|
||||
return 0U;
|
||||
|
||||
case 2U:
|
||||
m_abortCount[1U] = 0U;
|
||||
m_abort[1U] = true;
|
||||
return 0U;
|
||||
|
||||
|
@ -227,6 +234,8 @@ void CDMRTX::setStart(bool start)
|
|||
m_state = start ? DMRTXSTATE_SLOT1 : DMRTXSTATE_IDLE;
|
||||
|
||||
m_frameCount = 0U;
|
||||
m_abortCount[0U] = 0U;
|
||||
m_abortCount[1U] = 0U;
|
||||
|
||||
m_abort[0U] = false;
|
||||
m_abort[1U] = false;
|
||||
|
@ -282,7 +291,7 @@ uint8_t CDMRTX::getSpace2() const
|
|||
|
||||
void CDMRTX::createData(uint8_t slotIndex)
|
||||
{
|
||||
if (m_fifo[slotIndex].getData() > 0U && m_frameCount >= STARTUP_COUNT) {
|
||||
if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) {
|
||||
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
||||
m_poBuffer[i] = m_fifo[slotIndex].get();
|
||||
m_markBuffer[i] = MARK_NONE;
|
||||
|
@ -335,6 +344,8 @@ void CDMRTX::createCal()
|
|||
void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
|
||||
{
|
||||
m_frameCount++;
|
||||
m_abortCount[0U]++;
|
||||
m_abortCount[1U]++;
|
||||
|
||||
if (m_cachPtr >= 12U)
|
||||
m_cachPtr = 0U;
|
||||
|
|
|
@ -72,6 +72,7 @@ private:
|
|||
uint16_t m_poLen;
|
||||
uint16_t m_poPtr;
|
||||
uint32_t m_frameCount;
|
||||
uint32_t m_abortCount[2U];
|
||||
bool m_abort[2U];
|
||||
|
||||
void createData(uint8_t slotIndex);
|
||||
|
|
13
Globals.h
13
Globals.h
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -48,8 +48,11 @@ enum MMDVM_STATE {
|
|||
STATE_DMR = 2,
|
||||
STATE_YSF = 3,
|
||||
STATE_P25 = 4,
|
||||
STATE_NXDN = 5,
|
||||
|
||||
// Dummy states start at 90
|
||||
STATE_NXDNCAL1K = 91,
|
||||
STATE_DMRDMO1K = 92,
|
||||
STATE_P25CAL1K = 93,
|
||||
STATE_DMRCAL1K = 94,
|
||||
STATE_LFCAL = 95,
|
||||
|
@ -71,10 +74,13 @@ enum MMDVM_STATE {
|
|||
#include "YSFTX.h"
|
||||
#include "P25RX.h"
|
||||
#include "P25TX.h"
|
||||
#include "NXDNRX.h"
|
||||
#include "NXDNTX.h"
|
||||
#include "CalDStarRX.h"
|
||||
#include "CalDStarTX.h"
|
||||
#include "CalDMR.h"
|
||||
#include "CalP25.h"
|
||||
#include "CalNXDN.h"
|
||||
#include "CalRSSI.h"
|
||||
#include "CWIdTX.h"
|
||||
#include "Debug.h"
|
||||
|
@ -95,6 +101,7 @@ extern bool m_dstarEnable;
|
|||
extern bool m_dmrEnable;
|
||||
extern bool m_ysfEnable;
|
||||
extern bool m_p25Enable;
|
||||
extern bool m_nxdnEnable;
|
||||
|
||||
extern bool m_duplex;
|
||||
|
||||
|
@ -120,10 +127,14 @@ extern CYSFTX ysfTX;
|
|||
extern CP25RX p25RX;
|
||||
extern CP25TX p25TX;
|
||||
|
||||
extern CNXDNRX nxdnRX;
|
||||
extern CNXDNTX nxdnTX;
|
||||
|
||||
extern CCalDStarRX calDStarRX;
|
||||
extern CCalDStarTX calDStarTX;
|
||||
extern CCalDMR calDMR;
|
||||
extern CCalP25 calP25;
|
||||
extern CCalNXDN calNXDN;
|
||||
extern CCalRSSI calRSSI;
|
||||
|
||||
extern CCWIdTX cwIdTX;
|
||||
|
|
184
IO.cpp
184
IO.cpp
|
@ -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) 2016 by Colin Durbridge G4EML
|
||||
*
|
||||
|
@ -26,9 +26,12 @@
|
|||
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
|
||||
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
|
||||
|
||||
// One symbol boxcar filter
|
||||
static q15_t BOXCAR_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
|
||||
const uint16_t BOXCAR_FILTER_LEN = 6U;
|
||||
// One symbol boxcar filters
|
||||
static q15_t BOXCAR5_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
|
||||
const uint16_t BOXCAR5_FILTER_LEN = 6U;
|
||||
|
||||
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
|
||||
const uint16_t BOXCAR10_FILTER_LEN = 10U;
|
||||
|
||||
const uint16_t DC_OFFSET = 2048U;
|
||||
|
||||
|
@ -39,8 +42,12 @@ m_txBuffer(TX_RINGBUFFER_SIZE),
|
|||
m_rssiBuffer(RX_RINGBUFFER_SIZE),
|
||||
m_dcFilter(),
|
||||
m_dcState(),
|
||||
m_boxcarFilter(),
|
||||
m_boxcarState(),
|
||||
m_boxcar5Filter1(),
|
||||
m_boxcar5Filter2(),
|
||||
m_boxcar10Filter(),
|
||||
m_boxcar5State1(),
|
||||
m_boxcar5State2(),
|
||||
m_boxcar10State(),
|
||||
m_pttInvert(false),
|
||||
m_rxLevel(128 * 128),
|
||||
m_cwIdTXLevel(128 * 128),
|
||||
|
@ -48,6 +55,7 @@ m_dstarTXLevel(128 * 128),
|
|||
m_dmrTXLevel(128 * 128),
|
||||
m_ysfTXLevel(128 * 128),
|
||||
m_p25TXLevel(128 * 128),
|
||||
m_nxdnTXLevel(128 * 128),
|
||||
m_rxDCOffset(DC_OFFSET),
|
||||
m_txDCOffset(DC_OFFSET),
|
||||
m_ledCount(0U),
|
||||
|
@ -58,18 +66,28 @@ m_dacOverflow(0U),
|
|||
m_watchdog(0U),
|
||||
m_lockout(false)
|
||||
{
|
||||
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
|
||||
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
|
||||
::memset(m_boxcar5State1, 0x00U, 30U * sizeof(q15_t));
|
||||
::memset(m_boxcar5State2, 0x00U, 30U * sizeof(q15_t));
|
||||
::memset(m_boxcar10State, 0x00U, 40U * 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_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
|
||||
m_boxcarFilter.pState = m_boxcarState;
|
||||
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
|
||||
|
||||
m_boxcar5Filter1.numTaps = BOXCAR5_FILTER_LEN;
|
||||
m_boxcar5Filter1.pState = m_boxcar5State1;
|
||||
m_boxcar5Filter1.pCoeffs = BOXCAR5_FILTER;
|
||||
|
||||
m_boxcar5Filter2.numTaps = BOXCAR5_FILTER_LEN;
|
||||
m_boxcar5Filter2.pState = m_boxcar5State2;
|
||||
m_boxcar5Filter2.pCoeffs = BOXCAR5_FILTER;
|
||||
|
||||
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
|
||||
m_boxcar10Filter.pState = m_boxcar10State;
|
||||
m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER;
|
||||
|
||||
initInt();
|
||||
|
||||
selfTest();
|
||||
|
@ -90,6 +108,7 @@ void CIO::selfTest()
|
|||
setDMRInt(ledValue);
|
||||
setYSFInt(ledValue);
|
||||
setP25Int(ledValue);
|
||||
setNXDNInt(ledValue);
|
||||
#endif
|
||||
delayInt(250);
|
||||
}
|
||||
|
@ -99,6 +118,7 @@ void CIO::selfTest()
|
|||
setDMRInt(false);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -106,6 +126,7 @@ void CIO::selfTest()
|
|||
setDMRInt(true);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -113,6 +134,7 @@ void CIO::selfTest()
|
|||
setDMRInt(true);
|
||||
setYSFInt(true);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -120,6 +142,23 @@ void CIO::selfTest()
|
|||
setDMRInt(true);
|
||||
setYSFInt(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);
|
||||
|
||||
|
@ -127,6 +166,7 @@ void CIO::selfTest()
|
|||
setDMRInt(true);
|
||||
setYSFInt(true);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -134,6 +174,7 @@ void CIO::selfTest()
|
|||
setDMRInt(true);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -141,6 +182,7 @@ void CIO::selfTest()
|
|||
setDMRInt(false);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
|
||||
delayInt(250);
|
||||
|
||||
|
@ -148,6 +190,7 @@ void CIO::selfTest()
|
|||
setDMRInt(false);
|
||||
setYSFInt(false);
|
||||
setP25Int(false);
|
||||
setNXDNInt(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -169,7 +212,7 @@ 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) {
|
||||
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)
|
||||
dmrTX.setStart(false);
|
||||
m_modemState = STATE_IDLE;
|
||||
|
@ -225,47 +268,80 @@ void CIO::process()
|
|||
if (m_lockout)
|
||||
return;
|
||||
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, vals, RX_BLOCK_SIZE);
|
||||
#if defined(USE_DCBLOCKER)
|
||||
q31_t q31Samples[RX_BLOCK_SIZE];
|
||||
::arm_q15_to_q31(samples, q31Samples, RX_BLOCK_SIZE);
|
||||
|
||||
q31_t dcValues[RX_BLOCK_SIZE];
|
||||
::arm_biquad_cascade_df1_q31(&m_dcFilter, q31Samples, dcValues, RX_BLOCK_SIZE);
|
||||
|
||||
q31_t dcLevel = 0;
|
||||
q31_t dcValues[RX_BLOCK_SIZE];
|
||||
q31_t q31Vals[RX_BLOCK_SIZE];
|
||||
|
||||
::arm_q15_to_q31(vals, q31Vals, RX_BLOCK_SIZE);
|
||||
::arm_biquad_cascade_df1_q31(&m_dcFilter, q31Vals, dcValues, RX_BLOCK_SIZE);
|
||||
|
||||
for (uint8_t i = 0U; i < RX_BLOCK_SIZE; i++)
|
||||
dcLevel += dcValues[i];
|
||||
dcLevel /= RX_BLOCK_SIZE;
|
||||
|
||||
q15_t offset = q15_t(__SSAT((dcLevel >> 16), 16));;
|
||||
|
||||
q15_t dcVals[RX_BLOCK_SIZE];
|
||||
q15_t dcSamples[RX_BLOCK_SIZE];
|
||||
for (uint8_t i = 0U; i < RX_BLOCK_SIZE; i++)
|
||||
dcVals[i] = vals[i] - offset;
|
||||
dcSamples[i] = samples[i] - offset;
|
||||
#endif
|
||||
|
||||
if (m_modemState == STATE_IDLE) {
|
||||
if (m_dstarEnable)
|
||||
dstarRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_dstarEnable || m_ysfEnable || m_p25Enable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
|
||||
if (m_p25Enable)
|
||||
p25RX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_dstarEnable)
|
||||
dstarRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_p25Enable)
|
||||
p25RX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_ysfEnable)
|
||||
ysfRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_dmrEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter2, samples, vals, RX_BLOCK_SIZE);
|
||||
|
||||
if (m_duplex)
|
||||
dmrIdleRX.samples(vals, RX_BLOCK_SIZE);
|
||||
else
|
||||
dmrDMORX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (m_ysfEnable)
|
||||
ysfRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_nxdnEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar10Filter, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
|
||||
nxdnRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_DSTAR) {
|
||||
if (m_dstarEnable)
|
||||
dstarRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_dstarEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
|
||||
dstarRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_DMR) {
|
||||
if (m_dmrEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter2, samples, vals, 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)
|
||||
|
@ -277,12 +353,42 @@ void CIO::process()
|
|||
}
|
||||
}
|
||||
} else if (m_modemState == STATE_YSF) {
|
||||
if (m_ysfEnable)
|
||||
ysfRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_ysfEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
ysfRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_P25) {
|
||||
if (m_p25Enable)
|
||||
p25RX.samples(dcVals, rssi, RX_BLOCK_SIZE);
|
||||
if (m_p25Enable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
p25RX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_NXDN) {
|
||||
if (m_nxdnEnable) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar10Filter, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
nxdnRX.samples(vals, rssi, RX_BLOCK_SIZE);
|
||||
}
|
||||
} else if (m_modemState == STATE_DSTARCAL) {
|
||||
q15_t vals[RX_BLOCK_SIZE];
|
||||
#if defined(USE_DCBLOCKER)
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, dcSamples, vals, RX_BLOCK_SIZE);
|
||||
#else
|
||||
::arm_fir_fast_q15(&m_boxcar5Filter1, samples, vals, RX_BLOCK_SIZE);
|
||||
#endif
|
||||
calDStarRX.samples(vals, RX_BLOCK_SIZE);
|
||||
} else if (m_modemState == STATE_RSSICAL) {
|
||||
calRSSI.samples(rssi, RX_BLOCK_SIZE);
|
||||
|
@ -318,6 +424,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||
case STATE_P25:
|
||||
txLevel = m_p25TXLevel;
|
||||
break;
|
||||
case STATE_NXDN:
|
||||
txLevel = m_nxdnTXLevel;
|
||||
break;
|
||||
default:
|
||||
txLevel = m_cwIdTXLevel;
|
||||
break;
|
||||
|
@ -364,10 +473,11 @@ void CIO::setMode()
|
|||
setDMRInt(m_modemState == STATE_DMR);
|
||||
setYSFInt(m_modemState == STATE_YSF);
|
||||
setP25Int(m_modemState == STATE_P25);
|
||||
setNXDNInt(m_modemState == STATE_NXDN);
|
||||
#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;
|
||||
|
||||
|
@ -377,6 +487,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||
m_dmrTXLevel = q15_t(dmrTXLevel * 128);
|
||||
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
|
||||
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
||||
|
||||
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
||||
m_txDCOffset = DC_OFFSET + txDCOffset;
|
||||
|
@ -389,6 +500,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||
m_dmrTXLevel = -m_dmrTXLevel;
|
||||
m_ysfTXLevel = -m_ysfTXLevel;
|
||||
m_p25TXLevel = -m_p25TXLevel;
|
||||
m_nxdnTXLevel = -m_nxdnTXLevel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
IO.h
14
IO.h
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
|
@ -66,8 +66,12 @@ private:
|
|||
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
||||
q31_t m_dcState[4];
|
||||
|
||||
arm_fir_instance_q15 m_boxcarFilter;
|
||||
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
arm_fir_instance_q15 m_boxcar5Filter1;
|
||||
arm_fir_instance_q15 m_boxcar5Filter2;
|
||||
arm_fir_instance_q15 m_boxcar10Filter;
|
||||
q15_t m_boxcar5State1[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
q15_t m_boxcar5State2[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare
|
||||
|
||||
bool m_pttInvert;
|
||||
q15_t m_rxLevel;
|
||||
|
@ -76,6 +80,7 @@ private:
|
|||
q15_t m_dmrTXLevel;
|
||||
q15_t m_ysfTXLevel;
|
||||
q15_t m_p25TXLevel;
|
||||
q15_t m_nxdnTXLevel;
|
||||
|
||||
uint16_t m_rxDCOffset;
|
||||
uint16_t m_txDCOffset;
|
||||
|
@ -106,6 +111,7 @@ private:
|
|||
void setDMRInt(bool on);
|
||||
void setYSFInt(bool on);
|
||||
void setP25Int(bool on);
|
||||
void setNXDNInt(bool on);
|
||||
|
||||
void delayInt(unsigned int dly);
|
||||
};
|
||||
|
|
12
IODue.cpp
12
IODue.cpp
|
@ -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) 2016 by Colin Durbridge G4EML
|
||||
*
|
||||
|
@ -33,6 +33,7 @@
|
|||
#define PIN_DMR 17
|
||||
#define PIN_YSF 18
|
||||
#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_ISR_EOC_Chan ADC_ISR_EOC7
|
||||
#define ADC_CDR_Chan 7
|
||||
|
@ -46,6 +47,7 @@
|
|||
#define PIN_DMR 8
|
||||
#define PIN_YSF 7
|
||||
#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_ISR_EOC_Chan ADC_ISR_EOC13
|
||||
#define ADC_CDR_Chan 13
|
||||
|
@ -61,6 +63,7 @@
|
|||
#define PIN_DMR 8
|
||||
#define PIN_YSF 7
|
||||
#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_ISR_EOC_Chan ADC_ISR_EOC7
|
||||
#define ADC_CDR_Chan 7
|
||||
|
@ -95,6 +98,7 @@ void CIO::initInt()
|
|||
pinMode(PIN_DMR, OUTPUT);
|
||||
pinMode(PIN_YSF, OUTPUT);
|
||||
pinMode(PIN_P25, OUTPUT);
|
||||
pinMode(PIN_NXDN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -226,9 +230,15 @@ void CIO::setP25Int(bool on)
|
|||
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||
}
|
||||
|
||||
void CIO::setNXDNInt(bool on)
|
||||
{
|
||||
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
|
||||
}
|
||||
|
||||
void CIO::delayInt(unsigned int dly)
|
||||
{
|
||||
delay(dly);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
71
IOSTM.cpp
71
IOSTM.cpp
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 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
|
||||
|
@ -37,6 +37,7 @@ DSTAR PD12 output P1 Pin44
|
|||
DMR PD13 output P1 Pin45
|
||||
YSF PD14 output P1 Pin46
|
||||
P25 PD11 output P1 Pin43
|
||||
NXDN PD10 output P1 Pin42
|
||||
|
||||
RX PA0 analog input P1 Pin12
|
||||
RSSI PA1 analog input P1 Pin11
|
||||
|
@ -65,6 +66,10 @@ EXT_CLK PA15 input P2 Pin40
|
|||
#define PORT_P25 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 PORT_DSTAR GPIOD
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOD
|
||||
|
@ -107,6 +112,7 @@ DSTAR PC7 output
|
|||
DMR PC8 output
|
||||
YSF PA8 output
|
||||
P25 PC9 output
|
||||
NXDN PB1 output
|
||||
|
||||
RX PA0 analog input
|
||||
RSSI PA7 analog input
|
||||
|
@ -135,6 +141,10 @@ EXT_CLK PA15 input
|
|||
#define PORT_P25 GPIOC
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_1
|
||||
#define PORT_NXDN GPIOB
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_7
|
||||
#define PORT_DSTAR GPIOC
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
|
||||
|
@ -177,6 +187,7 @@ DSTAR PC7 output
|
|||
DMR PC8 output
|
||||
YSF PA8 output
|
||||
P25 PC9 output
|
||||
NXDN PB1 output
|
||||
|
||||
RX PA0 analog input
|
||||
RSSI PA7 analog input
|
||||
|
@ -205,6 +216,10 @@ EXT_CLK PA15 input
|
|||
#define PORT_P25 GPIOC
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_1
|
||||
#define PORT_NXDN GPIOB
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_7
|
||||
#define PORT_DSTAR GPIOC
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
|
||||
|
@ -247,6 +262,7 @@ DSTAR PC7 output
|
|||
DMR PC8 output
|
||||
YSF PA8 output
|
||||
P25 PC9 output
|
||||
NXDN PB1 output
|
||||
|
||||
RX PA0 analog input
|
||||
RSSI PA7 analog input
|
||||
|
@ -275,6 +291,10 @@ EXT_CLK PA15 input
|
|||
#define PORT_P25 GPIOC
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_1
|
||||
#define PORT_NXDN GPIOB
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_7
|
||||
#define PORT_DSTAR GPIOC
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
|
||||
|
@ -319,11 +339,13 @@ DSTAR PB10 output CN10 Pin25
|
|||
DMR PB4 output CN10 Pin27
|
||||
YSF PB5 output CN10 Pin29
|
||||
P25 PB3 output CN10 Pin31
|
||||
NXDN PA10 output CN10 Pin33
|
||||
|
||||
MDSTAR PC4 output CN10 Pin34
|
||||
MDMR PC5 output CN10 Pin6
|
||||
MYSF PC2 output CN7 Pin35
|
||||
MP25 PC3 output CN7 Pin37
|
||||
MNXDN PC6 output CN10 Pin4
|
||||
|
||||
RX PA0 analog input CN7 Pin28
|
||||
RSSI PA1 analog input CN7 Pin30
|
||||
|
@ -352,6 +374,10 @@ EXT_CLK PA15 input CN7 Pin17
|
|||
#define PORT_P25 GPIOB
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_10
|
||||
#define PORT_NXDN GPIOA
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOA
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_10
|
||||
#define PORT_DSTAR GPIOB
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
|
||||
|
@ -369,6 +395,10 @@ EXT_CLK PA15 input CN7 Pin17
|
|||
#define PORT_MP25 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 PORT_MDSTAR GPIOC
|
||||
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
|
||||
|
@ -412,6 +442,7 @@ DSTAR PA1 output CN8 Pin2
|
|||
DMR PA4 output CN8 Pin3
|
||||
YSF PB0 output CN8 Pin4
|
||||
P25 PC1 output CN8 Pin5
|
||||
NXDN PC0 output CN8 Pin6
|
||||
|
||||
RX PA0 analog input CN8 Pin1
|
||||
RSSI PC0 analog input CN8 Pin6
|
||||
|
@ -440,6 +471,10 @@ EXT_CLK PB8 input CN5 Pin10
|
|||
#define PORT_P25 GPIOC
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_0
|
||||
#define PORT_NXDN GPIOC
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOC
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_1
|
||||
#define PORT_DSTAR GPIOA
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOA
|
||||
|
@ -486,11 +521,13 @@ DSTAR PB10 output CN12 Pin25
|
|||
DMR PB4 output CN12 Pin27
|
||||
YSF PB5 output CN12 Pin29
|
||||
P25 PB3 output CN12 Pin31
|
||||
NXDN PA10 output CN12 Pin33
|
||||
|
||||
MDSTAR PC4 output CN12 Pin34
|
||||
MDMR PC5 output CN12 Pin6
|
||||
MYSF PC2 output CN11 Pin35
|
||||
MP25 PC3 output CN11 Pin37
|
||||
MNXDN PC6 output CN12 Pin4
|
||||
|
||||
RX PA0 analog input CN11 Pin28
|
||||
RSSI PA1 analog input CN11 Pin30
|
||||
|
@ -519,6 +556,10 @@ EXT_CLK PA15 input CN11 Pin17
|
|||
#define PORT_P25 GPIOB
|
||||
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
|
||||
|
||||
#define PIN_NXDN GPIO_Pin_10
|
||||
#define PORT_NXDN GPIOA
|
||||
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOA
|
||||
|
||||
#define PIN_DSTAR GPIO_Pin_10
|
||||
#define PORT_DSTAR GPIOB
|
||||
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
|
||||
|
@ -536,6 +577,10 @@ EXT_CLK PA15 input CN11 Pin17
|
|||
#define PORT_MP25 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 PORT_MDSTAR GPIOC
|
||||
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
|
||||
|
@ -640,6 +685,12 @@ void CIO::initInt()
|
|||
GPIO_InitStruct.GPIO_Pin = PIN_P25;
|
||||
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
|
||||
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
|
||||
|
||||
#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_Mode = GPIO_Mode_OUT;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -855,7 +912,7 @@ void CIO::interrupt()
|
|||
|
||||
bool CIO::getCOSInt()
|
||||
{
|
||||
return GPIO_ReadOutputDataBit(PORT_COS, PIN_COS) == Bit_SET;
|
||||
return GPIO_ReadInputDataBit(PORT_COS, PIN_COS) == Bit_SET;
|
||||
}
|
||||
|
||||
void CIO::setLEDInt(bool on)
|
||||
|
@ -905,6 +962,14 @@ void CIO::setP25Int(bool on)
|
|||
#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
|
||||
// Example from: http://thehackerworkshop.com/?p=1209
|
||||
void CIO::delayInt(unsigned int dly)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||
* 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
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -39,6 +39,7 @@ DSTAR PB7 output
|
|||
DMR PB6 output
|
||||
YSF PB8 output
|
||||
P25 PB9 output
|
||||
NXDN PB10 output
|
||||
|
||||
RX PB0 analog input (ADC1_8)
|
||||
RSSI PB1 analog input (ADC2_9)
|
||||
|
@ -76,6 +77,9 @@ USART1_RXD PA10 input (AF)
|
|||
#define PIN_P25 9
|
||||
#define PORT_P25 GPIOB
|
||||
#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_ADC_CH 8
|
||||
|
@ -214,6 +218,7 @@ static inline void GPIOInit()
|
|||
GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_YSF, PIN_YSF, 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);
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
|
@ -424,6 +429,11 @@ void CIO::setP25Int(bool on)
|
|||
BB_P25 = !!on;
|
||||
}
|
||||
|
||||
void CIO::setNXDNInt(bool on)
|
||||
{
|
||||
BB_NXDN = !!on;
|
||||
}
|
||||
|
||||
void CIO::delayInt(unsigned int dly)
|
||||
{
|
||||
delay(dly);
|
||||
|
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -34,6 +34,7 @@
|
|||
#define PIN_DMR 10
|
||||
#define PIN_YSF 11
|
||||
#define PIN_P25 12
|
||||
#define PIN_NXDN 8
|
||||
#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
|
||||
|
||||
|
@ -63,6 +64,7 @@ void CIO::initInt()
|
|||
pinMode(PIN_DMR, OUTPUT);
|
||||
pinMode(PIN_YSF, OUTPUT);
|
||||
pinMode(PIN_P25, OUTPUT);
|
||||
pinMode(PIN_NXDN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -210,6 +212,11 @@ void CIO::setP25Int(bool on)
|
|||
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||
}
|
||||
|
||||
void CIO::setNXDNInt(bool on)
|
||||
{
|
||||
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
|
||||
}
|
||||
|
||||
void CIO::delayInt(unsigned int dly)
|
||||
{
|
||||
delay(dly);
|
||||
|
|
16
MMDVM.cpp
16
MMDVM.cpp
|
@ -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 Colin Durbridge G4EML
|
||||
*
|
||||
|
@ -30,6 +30,7 @@ bool m_dstarEnable = true;
|
|||
bool m_dmrEnable = true;
|
||||
bool m_ysfEnable = true;
|
||||
bool m_p25Enable = true;
|
||||
bool m_nxdnEnable = true;
|
||||
|
||||
bool m_duplex = true;
|
||||
|
||||
|
@ -52,10 +53,14 @@ CYSFTX ysfTX;
|
|||
CP25RX p25RX;
|
||||
CP25TX p25TX;
|
||||
|
||||
CNXDNRX nxdnRX;
|
||||
CNXDNTX nxdnTX;
|
||||
|
||||
CCalDStarRX calDStarRX;
|
||||
CCalDStarTX calDStarTX;
|
||||
CCalDMR calDMR;
|
||||
CCalP25 calP25;
|
||||
CCalNXDN calNXDN;
|
||||
CCalRSSI calRSSI;
|
||||
|
||||
CCWIdTX cwIdTX;
|
||||
|
@ -91,15 +96,21 @@ void loop()
|
|||
if (m_p25Enable && m_modemState == STATE_P25)
|
||||
p25TX.process();
|
||||
|
||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||
nxdnTX.process();
|
||||
|
||||
if (m_modemState == STATE_DSTARCAL)
|
||||
calDStarTX.process();
|
||||
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||
calDMR.process();
|
||||
|
||||
if (m_modemState == STATE_P25CAL1K)
|
||||
calP25.process();
|
||||
|
||||
if (m_modemState == STATE_NXDNCAL1K)
|
||||
calNXDN.process();
|
||||
|
||||
if (m_modemState == STATE_IDLE)
|
||||
cwIdTX.process();
|
||||
}
|
||||
|
@ -113,4 +124,3 @@ int main()
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
15
MMDVM.ino
15
MMDVM.ino
|
@ -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
|
||||
*
|
||||
* 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_ysfEnable = true;
|
||||
bool m_p25Enable = true;
|
||||
bool m_nxdnEnable = true;
|
||||
|
||||
bool m_duplex = true;
|
||||
|
||||
|
@ -49,10 +50,14 @@ CYSFTX ysfTX;
|
|||
CP25RX p25RX;
|
||||
CP25TX p25TX;
|
||||
|
||||
CNXDNRX nxdnRX;
|
||||
CNXDNTX nxdnTX;
|
||||
|
||||
CCalDStarRX calDStarRX;
|
||||
CCalDStarTX calDStarTX;
|
||||
CCalDMR calDMR;
|
||||
CCalP25 calP25;
|
||||
CCalNXDN calNXDN;
|
||||
CCalRSSI calRSSI;
|
||||
|
||||
CCWIdTX cwIdTX;
|
||||
|
@ -88,15 +93,21 @@ void loop()
|
|||
if (m_p25Enable && m_modemState == STATE_P25)
|
||||
p25TX.process();
|
||||
|
||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||
nxdnTX.process();
|
||||
|
||||
if (m_modemState == STATE_DSTARCAL)
|
||||
calDStarTX.process();
|
||||
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||
calDMR.process();
|
||||
|
||||
if (m_modemState == STATE_P25CAL1K)
|
||||
calP25.process();
|
||||
|
||||
if (m_modemState == STATE_NXDNCAL1K)
|
||||
calNXDN.process();
|
||||
|
||||
if (m_modemState == STATE_IDLE)
|
||||
cwIdTX.process();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 = 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;
|
||||
const unsigned int NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U;
|
||||
const unsigned int NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
|
||||
|
||||
const unsigned int NXDN_FSW_LENGTH_BITS = 20U;
|
||||
const unsigned int NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U;
|
||||
const unsigned int NXDN_FSW_LENGTH_SAMPLES = NXDN_FSW_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
|
||||
|
||||
const uint8_t NXDN_FSW_BYTES[] = {0xCDU, 0xF5U, 0x90U};
|
||||
const uint8_t NXDN_FSW_BYTES_MASK[] = {0xFFU, 0xFFU, 0xF0U};
|
||||
const uint8_t NXDN_FSW_BYTES_LENGTH = 3U;
|
||||
|
||||
const uint32_t NXDN_FSW_BITS = 0x000CDF59U;
|
||||
const uint32_t NXDN_FSW_BITS_MASK = 0x000FFFFFU;
|
||||
|
||||
// C D F 5 9
|
||||
// 11 00 11 01 11 11 01 01 10 01
|
||||
// -3 +1 -3 +3 -3 -3 +3 +3 -1 +3
|
||||
|
||||
const int8_t NXDN_FSW_SYMBOLS_VALUES[] = {-3, +1, -3, +3, -3, -3, +3, +3, -1, +3};
|
||||
|
||||
const uint16_t NXDN_FSW_SYMBOLS = 0x014DU;
|
||||
const uint16_t NXDN_FSW_SYMBOLS_MASK = 0x03FFU;
|
||||
|
||||
#endif
|
||||
|
|
@ -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_FSW_BIT_START_ERRS = 1U;
|
||||
const uint8_t MAX_FSW_BIT_RUN_ERRS = 3U;
|
||||
|
||||
const uint8_t MAX_FSW_SYMBOLS_ERRS = 2U;
|
||||
|
||||
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_FSW_FRAMES = 5U + 1U;
|
||||
|
||||
CNXDNRX::CNXDNRX() :
|
||||
m_state(NXDNRXS_NONE),
|
||||
m_bitBuffer(),
|
||||
m_buffer(),
|
||||
m_bitPtr(0U),
|
||||
m_dataPtr(0U),
|
||||
m_startPtr(NOENDPTR),
|
||||
m_endPtr(NOENDPTR),
|
||||
m_fswPtr(NOENDPTR),
|
||||
m_minFSWPtr(NOENDPTR),
|
||||
m_maxFSWPtr(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_fswPtr = NOENDPTR;
|
||||
m_minFSWPtr = NOENDPTR;
|
||||
m_maxFSWPtr = 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 = correlateFSW();
|
||||
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_minFSWPtr = m_fswPtr + NXDN_FRAME_LENGTH_SAMPLES - 1U;
|
||||
if (m_minFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
|
||||
m_minFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_maxFSWPtr = m_fswPtr + 1U;
|
||||
if (m_maxFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
|
||||
m_maxFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_state = NXDNRXS_DATA;
|
||||
m_countdown = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CNXDNRX::processData(q15_t sample)
|
||||
{
|
||||
if (m_minFSWPtr < m_maxFSWPtr) {
|
||||
if (m_dataPtr >= m_minFSWPtr && m_dataPtr <= m_maxFSWPtr)
|
||||
correlateFSW();
|
||||
} else {
|
||||
if (m_dataPtr >= m_minFSWPtr || m_dataPtr <= m_maxFSWPtr)
|
||||
correlateFSW();
|
||||
}
|
||||
|
||||
if (m_dataPtr == m_endPtr) {
|
||||
// Only update the centre and threshold if they are from a good sync
|
||||
if (m_lostCount == MAX_FSW_FRAMES) {
|
||||
m_minFSWPtr = m_fswPtr + NXDN_FRAME_LENGTH_SAMPLES - 1U;
|
||||
if (m_minFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
|
||||
m_minFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
m_maxFSWPtr = m_fswPtr + 1U;
|
||||
if (m_maxFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
|
||||
m_maxFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
|
||||
}
|
||||
|
||||
calculateLevels(m_startPtr, NXDN_FRAME_LENGTH_SYMBOLS);
|
||||
|
||||
DEBUG4("NXDNRX: sync found pos/centre/threshold", m_fswPtr, 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_FSW_FRAMES - 1U) ? 0x01U : 0x00U;
|
||||
writeRSSIData(frame);
|
||||
m_maxCorr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CNXDNRX::correlateFSW()
|
||||
{
|
||||
if (countBits32((m_bitBuffer[m_bitPtr] & NXDN_FSW_SYMBOLS_MASK) ^ NXDN_FSW_SYMBOLS) <= MAX_FSW_SYMBOLS_ERRS) {
|
||||
uint16_t ptr = m_dataPtr + NXDN_FRAME_LENGTH_SAMPLES - NXDN_FSW_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_FSW_LENGTH_SYMBOLS; i++) {
|
||||
q15_t val = m_buffer[ptr];
|
||||
|
||||
if (val > max)
|
||||
max = val;
|
||||
if (val < min)
|
||||
min = val;
|
||||
|
||||
switch (NXDN_FSW_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_FSW_LENGTH_SAMPLES + NXDN_RADIO_SYMBOL_LENGTH;
|
||||
if (startPtr >= NXDN_FRAME_LENGTH_SAMPLES)
|
||||
startPtr -= NXDN_FRAME_LENGTH_SAMPLES;
|
||||
|
||||
uint8_t sync[NXDN_FSW_BYTES_LENGTH];
|
||||
samplesToBits(startPtr, NXDN_FSW_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
|
||||
|
||||
uint8_t maxErrs;
|
||||
if (m_state == NXDNRXS_NONE)
|
||||
maxErrs = MAX_FSW_BIT_START_ERRS;
|
||||
else
|
||||
maxErrs = MAX_FSW_BIT_RUN_ERRS;
|
||||
|
||||
uint8_t errs = 0U;
|
||||
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
|
||||
errs += countBits8((sync[i] & NXDN_FSW_BYTES_MASK[i]) ^ NXDN_FSW_BYTES[i]);
|
||||
|
||||
if (errs <= maxErrs) {
|
||||
m_maxCorr = corr;
|
||||
m_lostCount = MAX_FSW_FRAMES;
|
||||
m_fswPtr = m_dataPtr;
|
||||
|
||||
m_startPtr = startPtr;
|
||||
|
||||
m_endPtr = m_dataPtr + NXDN_FRAME_LENGTH_SAMPLES - NXDN_FSW_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[49U] = (rssi >> 8) & 0xFFU;
|
||||
data[50U] = (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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
uint16_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_fswPtr;
|
||||
uint16_t m_minFSWPtr;
|
||||
uint16_t m_maxFSWPtr;
|
||||
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 correlateFSW();
|
||||
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,170 @@
|
|||
/*
|
||||
* 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, 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
|
||||
|
||||
static q15_t NXDN_SINC_FILTER[] = {572, -1003, -253, 254, 740, 1290, 1902, 2527, 3090, 3517, 3747, 3747, 3517, 3090, 2527, 1902,
|
||||
1290, 740, 254, -253, -1003, 572};
|
||||
const uint16_t NXDN_SINC_FILTER_LEN = 22U;
|
||||
|
||||
const q15_t NXDN_LEVELA = 735;
|
||||
const q15_t NXDN_LEVELB = 245;
|
||||
const q15_t NXDN_LEVELC = -245;
|
||||
const q15_t NXDN_LEVELD = -735;
|
||||
|
||||
const uint8_t NXDN_PREAMBLE[] = {0x57U, 0x75U, 0xFDU};
|
||||
const uint8_t NXDN_SYNC = 0x5FU;
|
||||
|
||||
CNXDNTX::CNXDNTX() :
|
||||
m_buffer(2000U),
|
||||
m_modFilter(),
|
||||
m_sincFilter(),
|
||||
m_modState(),
|
||||
m_sincState(),
|
||||
m_poBuffer(),
|
||||
m_poLen(0U),
|
||||
m_poPtr(0U),
|
||||
m_txDelay(240U) // 200ms
|
||||
{
|
||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||
::memset(m_sincState, 0x00U, 70U * 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;
|
||||
|
||||
m_sincFilter.numTaps = NXDN_SINC_FILTER_LEN;
|
||||
m_sincFilter.pState = m_sincState;
|
||||
m_sincFilter.pCoeffs = NXDN_SINC_FILTER;
|
||||
}
|
||||
|
||||
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_SYNC;
|
||||
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[0U];
|
||||
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[1U];
|
||||
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
|
||||
} 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 intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 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, intBuffer, 4U);
|
||||
|
||||
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||
|
||||
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||
}
|
||||
|
||||
void CNXDNTX::setTXDelay(uint8_t delay)
|
||||
{
|
||||
m_txDelay = 300U + uint16_t(delay) * 6U; // 500ms + tx delay
|
||||
|
||||
if (m_txDelay > 1200U)
|
||||
m_txDelay = 1200U;
|
||||
}
|
||||
|
||||
uint8_t CNXDNTX::getSpace() const
|
||||
{
|
||||
return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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;
|
||||
arm_fir_instance_q15 m_sincFilter;
|
||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||
q15_t m_sincState[70U]; // NoTaps + BlockSize - 1, 22 + 40 - 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
|
||||
|
12
P25TX.cpp
12
P25TX.cpp
|
@ -30,12 +30,10 @@ static q15_t RC_0_2_FILTER[] = {-897, -1636, -1840, -1278, 0, 1613, 2936, 3310,
|
|||
-3011, 0, 2315, 3310, 2936, 1613, 0, -1278, -1840, -1636, -897, 0}; // numTaps = 40, L = 5
|
||||
const uint16_t RC_0_2_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L
|
||||
|
||||
// Generated in MATLAB using the following commands, and then normalised for unity gain
|
||||
// shape2 = 'Inverse-sinc Lowpass';
|
||||
// d2 = fdesign.interpolator(1, shape2);
|
||||
// h2 = design(d2, 'SystemObject', true);
|
||||
static q15_t LOWPASS_FILTER[] = {1294, -2251, 4312, -8402, 20999, 20999, -8402, 4312, -2251, 1294};
|
||||
const uint16_t LOWPASS_FILTER_LEN = 10U;
|
||||
static q15_t LOWPASS_FILTER[] = {124, -188, -682, 1262, 556, -621, -1912, -911, 2058, 3855, 1234, -4592, -7692, -2799,
|
||||
8556, 18133, 18133, 8556, -2799, -7692, -4592, 1234, 3855, 2058, -911, -1912, -621,
|
||||
556, 1262, -682, -188, 124};
|
||||
const uint16_t LOWPASS_FILTER_LEN = 32U;
|
||||
|
||||
const q15_t P25_LEVELA = 1260;
|
||||
const q15_t P25_LEVELB = 420;
|
||||
|
@ -56,7 +54,7 @@ m_poPtr(0U),
|
|||
m_txDelay(240U) // 200ms
|
||||
{
|
||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||
::memset(m_lpState, 0x00U, 70U * sizeof(q15_t));
|
||||
::memset(m_lpState, 0x00U, 60U * sizeof(q15_t));
|
||||
|
||||
m_modFilter.L = P25_RADIO_SYMBOL_LENGTH;
|
||||
m_modFilter.phaseLength = RC_0_2_FILTER_PHASE_LEN;
|
||||
|
|
2
P25TX.h
2
P25TX.h
|
@ -40,7 +40,7 @@ private:
|
|||
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||
arm_fir_instance_q15 m_lpFilter;
|
||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||
q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare
|
||||
q15_t m_lpState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
||||
uint8_t m_poBuffer[1200U];
|
||||
uint16_t m_poLen;
|
||||
uint16_t m_poPtr;
|
||||
|
|
137
SerialPort.cpp
137
SerialPort.cpp
|
@ -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
|
||||
*
|
||||
* 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_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_NAK = 0x7FU;
|
||||
|
||||
|
@ -73,9 +76,9 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
|
|||
|
||||
|
||||
#if defined(EXTERNAL_OSC)
|
||||
#define DESCRIPTION "MMDVM 20170501 TCXO (D-Star/DMR/System Fusion/P25/RSSI/CW Id)"
|
||||
#define DESCRIPTION "MMDVM 20180223 TCXO (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
|
||||
#else
|
||||
#define DESCRIPTION "MMDVM 20170501 (D-Star/DMR/System Fusion/P25/RSSI/CW Id)"
|
||||
#define DESCRIPTION "MMDVM 20180223 (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
|
||||
#endif
|
||||
|
||||
#if defined(GITVERSION)
|
||||
|
@ -143,6 +146,8 @@ void CSerialPort::getStatus()
|
|||
reply[3U] |= 0x04U;
|
||||
if (m_p25Enable)
|
||||
reply[3U] |= 0x08U;
|
||||
if (m_nxdnEnable)
|
||||
reply[3U] |= 0x10U;
|
||||
|
||||
reply[4U] = uint8_t(m_modemState);
|
||||
|
||||
|
@ -197,7 +202,12 @@ void CSerialPort::getStatus()
|
|||
else
|
||||
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()
|
||||
|
@ -221,7 +231,7 @@ void CSerialPort::getVersion()
|
|||
|
||||
uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (length < 15U)
|
||||
if (length < 16U)
|
||||
return 4U;
|
||||
|
||||
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 ysfEnable = (data[1U] & 0x04U) == 0x04U;
|
||||
bool p25Enable = (data[1U] & 0x08U) == 0x08U;
|
||||
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
|
||||
|
||||
uint8_t txDelay = data[2U];
|
||||
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]);
|
||||
|
||||
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 && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !dstarEnable)
|
||||
return 4U;
|
||||
|
@ -253,6 +264,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||
return 4U;
|
||||
if (modemState == STATE_P25 && !p25Enable)
|
||||
return 4U;
|
||||
if (modemState == STATE_NXDN && !nxdnEnable)
|
||||
return 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 rxDCOffset = int16_t(data[14U]) - 128;
|
||||
|
||||
uint8_t nxdnTXLevel = data[15U];
|
||||
|
||||
m_modemState = modemState;
|
||||
|
||||
m_dstarEnable = dstarEnable;
|
||||
m_dmrEnable = dmrEnable;
|
||||
m_ysfEnable = ysfEnable;
|
||||
m_p25Enable = p25Enable;
|
||||
m_nxdnEnable = nxdnEnable;
|
||||
m_duplex = !simplex;
|
||||
|
||||
dstarTX.setTXDelay(txDelay);
|
||||
ysfTX.setTXDelay(txDelay);
|
||||
p25TX.setTXDelay(txDelay);
|
||||
dmrDMOTX.setTXDelay(txDelay);
|
||||
nxdnTX.setTXDelay(txDelay);
|
||||
|
||||
dmrTX.setColorCode(colorCode);
|
||||
dmrRX.setColorCode(colorCode);
|
||||
|
@ -292,7 +309,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||
|
||||
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();
|
||||
|
||||
|
@ -309,7 +326,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_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 && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K)
|
||||
return 4U;
|
||||
if (modemState == STATE_DSTAR && !m_dstarEnable)
|
||||
return 4U;
|
||||
|
@ -319,6 +336,8 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
|||
return 4U;
|
||||
if (modemState == STATE_P25 && !m_p25Enable)
|
||||
return 4U;
|
||||
if (modemState == STATE_NXDN && !m_nxdnEnable)
|
||||
return 4U;
|
||||
|
||||
setMode(modemState);
|
||||
|
||||
|
@ -333,6 +352,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_DSTAR:
|
||||
|
@ -342,6 +362,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dmrRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_YSF:
|
||||
|
@ -351,6 +372,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dmrRX.reset();
|
||||
dstarRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_P25:
|
||||
|
@ -360,6 +382,17 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dmrRX.reset();
|
||||
dstarRX.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();
|
||||
break;
|
||||
case STATE_DSTARCAL:
|
||||
|
@ -370,6 +403,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_DMRCAL:
|
||||
|
@ -380,6 +414,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_RSSICAL:
|
||||
|
@ -390,6 +425,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_LFCAL:
|
||||
|
@ -400,16 +436,18 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_DMRCAL1K:
|
||||
DEBUG1("Mode set to DMR 1031 Hz Calibrate");
|
||||
DEBUG1("Mode set to DMR BS 1031 Hz Calibrate");
|
||||
dmrIdleRX.reset();
|
||||
dmrDMORX.reset();
|
||||
dmrRX.reset();
|
||||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_P25CAL1K:
|
||||
|
@ -420,6 +458,29 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
|||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_DMRDMO1K:
|
||||
DEBUG1("Mode set to DMR MS 1031 Hz Calibrate");
|
||||
dmrIdleRX.reset();
|
||||
dmrDMORX.reset();
|
||||
dmrRX.reset();
|
||||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
case STATE_NXDNCAL1K:
|
||||
DEBUG1("Mode set to NXDN 1031 Hz Calibrate");
|
||||
dmrIdleRX.reset();
|
||||
dmrDMORX.reset();
|
||||
dmrRX.reset();
|
||||
dstarRX.reset();
|
||||
ysfRX.reset();
|
||||
p25RX.reset();
|
||||
nxdnRX.reset();
|
||||
cwIdTX.reset();
|
||||
break;
|
||||
default:
|
||||
|
@ -502,10 +563,12 @@ void CSerialPort::process()
|
|||
case MMDVM_CAL_DATA:
|
||||
if (m_modemState == STATE_DSTARCAL)
|
||||
err = calDStarTX.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
|
||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||
err = calDMR.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_P25CAL1K)
|
||||
err = calP25.write(m_buffer + 3U, m_len - 3U);
|
||||
if (m_modemState == STATE_NXDNCAL1K)
|
||||
err = calNXDN.write(m_buffer + 3U, m_len - 3U);
|
||||
if (err == 0U) {
|
||||
sendACK();
|
||||
} else {
|
||||
|
@ -681,6 +744,20 @@ void CSerialPort::process()
|
|||
}
|
||||
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)
|
||||
case MMDVM_SERIAL: {
|
||||
for (uint8_t i = 3U; i < m_len; i++)
|
||||
|
@ -948,6 +1025,46 @@ void CSerialPort::writeP25Lost()
|
|||
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)
|
||||
{
|
||||
if (m_modemState != STATE_DSTARCAL)
|
||||
|
|
|
@ -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
|
||||
* 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 writeP25Lost();
|
||||
|
||||
void writeNXDNData(const uint8_t* data, uint8_t length);
|
||||
void writeNXDNLost();
|
||||
|
||||
void writeCalData(const uint8_t* data, uint8_t length);
|
||||
void writeRSSIData(const uint8_t* data, uint8_t length);
|
||||
|
||||
|
@ -80,3 +83,4 @@ private:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue