parent
cc2b47de4f
commit
7e9f4079f3
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "Globals.h"
|
||||
#include "nxdn/CalNXDN.h"
|
||||
|
||||
using namespace nxdn;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// 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 }
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CalNXDN class.
|
||||
/// </summary>
|
||||
CalNXDN::CalNXDN() :
|
||||
m_transmit(false),
|
||||
m_state(NXDNCAL1K_IDLE),
|
||||
m_audioSeq(0U)
|
||||
{
|
||||
/* stub */
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process local state and transmit on the air interface.
|
||||
/// </summary>
|
||||
void CalNXDN::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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write P25 calibration data to the local buffer.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
uint8_t CalNXDN::write(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (length != 1U)
|
||||
return RSN_ILLEGAL_LENGTH;
|
||||
|
||||
m_transmit = data[0U] == 1U;
|
||||
|
||||
if(m_transmit && m_state == NXDNCAL1K_IDLE)
|
||||
m_state = NXDNCAL1K_TX;
|
||||
|
||||
return RSN_OK;
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(__CAL_NXDN_H__)
|
||||
#define __CAL_NXDN_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "nxdn/NXDNDefines.h"
|
||||
|
||||
namespace nxdn
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum NXDNCAL1K {
|
||||
NXDNCAL1K_IDLE,
|
||||
NXDNCAL1K_TX
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements logic for NXDN calibration mode.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class DSP_FW_API CalNXDN {
|
||||
public:
|
||||
/// <summary>Initializes a new instance of the CalNXDN class.</summary>
|
||||
CalNXDN();
|
||||
|
||||
/// <summary>Process local state and transmit on the air interface.</summary>
|
||||
void process();
|
||||
|
||||
/// <summary>Write NXDN calibration state.</summary>
|
||||
uint8_t write(const uint8_t* data, uint16_t length);
|
||||
|
||||
private:
|
||||
bool m_transmit;
|
||||
NXDNCAL1K m_state;
|
||||
|
||||
uint8_t m_audioSeq;
|
||||
};
|
||||
} // namespace nxdn
|
||||
|
||||
#endif // __CAL_NXDN_H__
|
||||
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* 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(__NXDN_DEFINES_H__)
|
||||
#define __NXDN_DEFINES_H__
|
||||
|
||||
#include "Defines.h"
|
||||
|
||||
namespace nxdn
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const uint32_t NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate
|
||||
|
||||
const uint32_t NXDN_FRAME_LENGTH_BITS = 384U;
|
||||
const uint32_t NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
|
||||
const uint32_t NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U;
|
||||
const uint32_t NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
|
||||
|
||||
const uint32_t NXDN_FSW_LENGTH_BITS = 20U;
|
||||
const uint32_t NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U;
|
||||
const uint32_t 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;
|
||||
|
||||
const uint8_t NXDN_PREAMBLE[] = { 0x57U, 0x75U, 0xFDU };
|
||||
const uint8_t NXDN_SYNC = 0x5FU;
|
||||
|
||||
// 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;
|
||||
|
||||
const uint32_t NXDN_TX_BUFFER_LEN = 2000U;
|
||||
} // namespace nxdn
|
||||
|
||||
#endif // __NXDN_DEFINES_H__
|
||||
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "Globals.h"
|
||||
#include "nxdn/NXDNRX.h"
|
||||
#include "Utils.h"
|
||||
|
||||
using namespace nxdn;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const uint8_t MAX_FSW_BIT_START_ERRS = 0U;
|
||||
const uint8_t MAX_FSW_BIT_RUN_ERRS = 3U;
|
||||
|
||||
const unsigned int MAX_FSW_FRAMES = 5U + 1U;
|
||||
|
||||
const uint16_t NOENDPTR = 9999U;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the NXDNRX class.
|
||||
/// </summary>
|
||||
NXDNRX::NXDNRX() :
|
||||
m_bitBuffer(0x00U),
|
||||
m_buffer(),
|
||||
m_dataPtr(0U),
|
||||
m_endPtr(NOENDPTR),
|
||||
m_lostCount(0U),
|
||||
m_state(NXDNRXS_NONE)
|
||||
{
|
||||
::memset(m_buffer, 0x00U, NXDN_FRAME_LENGTH_BYTES + 3U);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to reset data values to defaults.
|
||||
/// </summary>
|
||||
void NXDNRX::reset()
|
||||
{
|
||||
m_bitBuffer = 0x00U;
|
||||
m_dataPtr = 0U;
|
||||
|
||||
m_endPtr = NOENDPTR;
|
||||
|
||||
m_lostCount = 0U;
|
||||
|
||||
m_state = NXDNRXS_NONE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample NXDN bits from the air interface.
|
||||
/// </summary>
|
||||
/// <param name="bit"></param>
|
||||
void NXDNRX::databit(bool bit)
|
||||
{
|
||||
m_bitBuffer <<= 1;
|
||||
if (bit)
|
||||
m_bitBuffer |= 0x01U;
|
||||
|
||||
if (m_state != NXDNRXS_NONE) {
|
||||
_WRITE_BIT(m_buffer, m_dataPtr, bit);
|
||||
|
||||
m_dataPtr++;
|
||||
if (m_dataPtr > NXDN_FRAME_LENGTH_BITS) {
|
||||
m_dataPtr = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == NXDNRXS_DATA) {
|
||||
processData(bit);
|
||||
}
|
||||
else {
|
||||
bool ret = correlateSync();
|
||||
if (ret) {
|
||||
DEBUG3("P25RX: databit(): dataPtr/endPtr", m_dataPtr, m_endPtr);
|
||||
m_state = NXDNRXS_DATA;
|
||||
}
|
||||
|
||||
io.setDecode(m_state != NXDNRXS_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Helper to process NXDN data bits.
|
||||
/// </summary>
|
||||
/// <param name="bit"></param>
|
||||
void NXDNRX::processData(bool bit)
|
||||
{
|
||||
// only search for a sync in the right place +-2 bits
|
||||
if (m_dataPtr >= (NXDN_FSW_LENGTH_BITS - 2U) && m_dataPtr <= (NXDN_FSW_LENGTH_BITS + 2U)) {
|
||||
correlateSync();
|
||||
}
|
||||
|
||||
// process voice frame
|
||||
if (m_dataPtr == m_endPtr) {
|
||||
m_lostCount--;
|
||||
|
||||
// we've not seen a data sync for too long, signal sync lost and change to NXDNRXS_NONE
|
||||
if (m_lostCount == 0U) {
|
||||
DEBUG1("NXDNRX: processData(): sync timeout in PDU, lost lock");
|
||||
|
||||
io.setDecode(false);
|
||||
|
||||
serial.writeP25Lost();
|
||||
reset();
|
||||
}
|
||||
else {
|
||||
DEBUG2("NXDNRX: processData(): sync found in PDU pos", m_dataPtr);
|
||||
|
||||
uint8_t frame[NXDN_FRAME_LENGTH_BYTES + 1U];
|
||||
::memcpy(frame + 1U, m_buffer, m_endPtr / 8U);
|
||||
|
||||
frame[0U] = m_lostCount == (MAX_FSW_FRAMES - 1U) ? 0x01U : 0x00U; // set sync flag
|
||||
serial.writeP25Data(frame, NXDN_FRAME_LENGTH_BYTES + 1U);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frame synchronization correlator.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool NXDNRX::correlateSync()
|
||||
{
|
||||
uint8_t maxErrs;
|
||||
if (m_state == NXDNRXS_NONE)
|
||||
maxErrs = MAX_FSW_BIT_START_ERRS;
|
||||
else
|
||||
maxErrs = MAX_FSW_BIT_RUN_ERRS;
|
||||
|
||||
// unpack sync bytes
|
||||
uint8_t sync[NXDN_FSW_BYTES_LENGTH];
|
||||
sync[0U] = (uint8_t)((m_bitBuffer >> 16) & 0xFFU);
|
||||
sync[1U] = (uint8_t)((m_bitBuffer >> 8) & 0xFFU);
|
||||
sync[2U] = (uint8_t)((m_bitBuffer >> 0) & 0xF0U);
|
||||
|
||||
uint8_t errs = 0U;
|
||||
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
|
||||
errs += countBits8(sync[i] ^ NXDN_FSW_BYTES[i]);
|
||||
|
||||
if (errs <= maxErrs) {
|
||||
::memset(m_buffer, 0x00U, NXDN_FRAME_LENGTH_BYTES + 3U);
|
||||
|
||||
DEBUG2("NXDNRX: correlateSync(): correlateSync errs", errs);
|
||||
|
||||
DEBUG4("NXDNRX: correlateSync(): sync [b0 - b2]", sync[0], sync[1], sync[2]);
|
||||
|
||||
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
|
||||
m_buffer[i] = sync[i];
|
||||
|
||||
// DEBUG1("NXDNRX: m_buffer dump");
|
||||
// DEBUG_DUMP(m_buffer, P25_LDU_FRAME_LENGTH_BYTES);
|
||||
|
||||
m_endPtr = m_dataPtr + NXDN_FRAME_LENGTH_BITS - NXDN_FSW_LENGTH_BITS;
|
||||
if (m_endPtr >= NXDN_FRAME_LENGTH_BITS)
|
||||
m_endPtr -= NXDN_FRAME_LENGTH_BITS;
|
||||
|
||||
m_lostCount = MAX_FSW_FRAMES;
|
||||
m_dataPtr = NXDN_FSW_LENGTH_BITS;
|
||||
|
||||
DEBUG3("NXDNRX: correlateSync(): dataPtr/endPtr", m_dataPtr, m_endPtr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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(__NXDN_RX_H__)
|
||||
#define __NXDN_RX_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "nxdn/NXDNDefines.h"
|
||||
|
||||
namespace nxdn
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum NXDNRX_STATE {
|
||||
NXDNRXS_NONE,
|
||||
NXDNRXS_DATA
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements receiver logic for DMR slots.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class DSP_FW_API NXDNRX {
|
||||
public:
|
||||
/// <summary>Initializes a new instance of the NXDNRX class.</summary>
|
||||
NXDNRX();
|
||||
|
||||
/// <summary>Helper to reset data values to defaults.</summary>
|
||||
void reset();
|
||||
|
||||
/// <summary>Sample NXDN bits from the air interface.</summary>
|
||||
void databit(bool bit);
|
||||
|
||||
private:
|
||||
uint64_t m_bitBuffer;
|
||||
uint8_t m_buffer[NXDN_FRAME_LENGTH_BYTES + 3U];
|
||||
|
||||
uint16_t m_dataPtr;
|
||||
|
||||
uint16_t m_endPtr;
|
||||
|
||||
uint16_t m_lostCount;
|
||||
|
||||
NXDNRX_STATE m_state;
|
||||
|
||||
/// <summary>Helper to process NXDN data bits.</summary>
|
||||
void processData(bool bit);
|
||||
|
||||
/// <summary>Frame synchronization correlator.</summary>
|
||||
bool correlateSync();
|
||||
};
|
||||
} // namespace nxdn
|
||||
|
||||
#endif // __NXDN_RX_H__
|
||||
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
|
||||
*
|
||||
* 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 "Globals.h"
|
||||
#include "nxdn/NXDNTX.h"
|
||||
#include "nxdn/NXDNDefines.h"
|
||||
|
||||
using namespace nxdn;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the NXDNTX class.
|
||||
/// </summary>
|
||||
NXDNTX::NXDNTX() :
|
||||
m_fifo(NXDN_TX_BUFFER_LEN),
|
||||
m_poBuffer(),
|
||||
m_poLen(0U),
|
||||
m_poPtr(0U),
|
||||
m_preambleCnt(240U), // 200ms
|
||||
m_txHang(3000U), // 5s
|
||||
m_tailCnt(0U)
|
||||
{
|
||||
/* stub */
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process local buffer and transmit on the air interface.
|
||||
/// </summary>
|
||||
void NXDNTX::process()
|
||||
{
|
||||
if (m_fifo.getData() == 0U && m_poLen == 0U && m_tailCnt > 0U) {
|
||||
// transmit silence until the hang timer has expired
|
||||
uint16_t space = io.getSpace();
|
||||
|
||||
while (space > 8U) {
|
||||
writeSilence();
|
||||
|
||||
space -= 8U;
|
||||
m_tailCnt--;
|
||||
|
||||
if (m_tailCnt == 0U)
|
||||
return;
|
||||
if (m_fifo.getData() > 0U) {
|
||||
m_tailCnt = 0U;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fifo.getData() == 0U && m_poLen == 0U)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_poLen == 0U) {
|
||||
if (m_fifo.getData() == 0U)
|
||||
return;
|
||||
|
||||
createData();
|
||||
DEBUG2("NXDNTX: process(): poLen", m_poLen);
|
||||
}
|
||||
|
||||
if (m_poLen > 0U) {
|
||||
uint16_t space = io.getSpace();
|
||||
|
||||
while (space > 8U) {
|
||||
uint8_t c = m_poBuffer[m_poPtr++];
|
||||
|
||||
writeByte(c);
|
||||
|
||||
space -= 8U;
|
||||
m_tailCnt = m_txHang;
|
||||
|
||||
if (m_poPtr >= m_poLen) {
|
||||
m_poPtr = 0U;
|
||||
m_poLen = 0U;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the local buffer.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
uint8_t NXDNTX::writeData(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
|
||||
return RSN_ILLEGAL_LENGTH;
|
||||
|
||||
uint16_t space = m_fifo.getSpace();
|
||||
DEBUG3("NXDNTX: writeData(): dataLength/fifoLength", length, space);
|
||||
if (space < length) {
|
||||
m_fifo.reset();
|
||||
return RSN_RINGBUFF_FULL;
|
||||
}
|
||||
|
||||
if (space < NXDN_FRAME_LENGTH_BYTES)
|
||||
return RSN_RINGBUFF_FULL;
|
||||
|
||||
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++)
|
||||
m_fifo.put(data[i + 1U]);
|
||||
|
||||
return RSN_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the local buffer.
|
||||
/// </summary>
|
||||
void NXDNTX::clear()
|
||||
{
|
||||
m_fifo.reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the FDMA preamble count.
|
||||
/// </summary>
|
||||
/// <param name="preambleCnt">Count of preambles.</param>
|
||||
void NXDNTX::setPreambleCount(uint8_t preambleCnt)
|
||||
{
|
||||
m_preambleCnt = 300U + uint16_t(preambleCnt) * 6U; // 500ms + tx delay
|
||||
|
||||
if (m_preambleCnt > 1200U)
|
||||
m_preambleCnt = 1200U;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Tx hang time.
|
||||
/// </summary>
|
||||
/// <param name="txHang">Transmit hang time in seconds.</param>
|
||||
void NXDNTX::setTxHang(uint8_t txHang)
|
||||
{
|
||||
m_txHang = txHang * 600U;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to get how much space the ring buffer has for samples.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
uint8_t NXDNTX::getSpace() const
|
||||
{
|
||||
return m_fifo.getSpace() / NXDN_FRAME_LENGTH_BYTES;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Private Class Members
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void NXDNTX::createData()
|
||||
{
|
||||
if (!m_tx) {
|
||||
for (uint16_t i = 0U; i < m_preambleCnt; 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 {
|
||||
uint8_t length = m_fifo.get();
|
||||
DEBUG3("P25TX: createData(): dataLength/fifoSpace", length, m_fifo.getSpace());
|
||||
for (uint8_t i = 0U; i < length; i++) {
|
||||
m_poBuffer[m_poLen++] = m_fifo.get();
|
||||
}
|
||||
}
|
||||
|
||||
m_poPtr = 0U;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
void NXDNTX::writeByte(uint8_t c)
|
||||
{
|
||||
uint8_t bit;
|
||||
uint8_t mask = 0x80U;
|
||||
|
||||
for (uint8_t i = 0U; i < 8U; i++, c <<= 1) {
|
||||
if ((c & mask) == mask)
|
||||
bit = 1U;
|
||||
else
|
||||
bit = 0U;
|
||||
|
||||
io.write(&bit, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void NXDNTX::writeSilence()
|
||||
{
|
||||
uint8_t bit;
|
||||
for (uint8_t i = 0U; i < 4U; i++) {
|
||||
bit = 0U;
|
||||
io.write(&bit, 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Digital Voice Modem - DSP Firmware
|
||||
* GPLv2 Open Source. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* @package DVM / DSP Firmware
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||
//
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
|
||||
*
|
||||
* 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(__NXDN_TX_H__)
|
||||
#define __NXDN_TX_H__
|
||||
|
||||
#include "Defines.h"
|
||||
#include "SerialBuffer.h"
|
||||
|
||||
namespace nxdn
|
||||
{
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class Declaration
|
||||
// Implements transmitter logic for NXDN mode operation.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class DSP_FW_API NXDNTX {
|
||||
public:
|
||||
/// <summary>Initializes a new instance of the NXDNTX class.</summary>
|
||||
NXDNTX();
|
||||
|
||||
/// <summary>Process local buffer and transmit on the air interface.</summary>
|
||||
void process();
|
||||
|
||||
/// <summary>Write data to the local buffer.</summary>
|
||||
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||
|
||||
/// <summary>Clears the local buffer.</summary>
|
||||
void clear();
|
||||
|
||||
/// <summary>Sets the FDMA preamble count.</summary>
|
||||
void setPreambleCount(uint8_t preambleCnt);
|
||||
/// <summary>Sets the transmit hang time.</summary>
|
||||
void setTxHang(uint8_t txHang);
|
||||
|
||||
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
|
||||
uint8_t getSpace() const;
|
||||
|
||||
private:
|
||||
SerialBuffer m_fifo;
|
||||
|
||||
uint8_t m_poBuffer[60U];
|
||||
uint16_t m_poLen;
|
||||
uint16_t m_poPtr;
|
||||
|
||||
uint16_t m_preambleCnt;
|
||||
uint32_t m_txHang;
|
||||
uint32_t m_tailCnt;
|
||||
|
||||
/// <summary></summary>
|
||||
void createData();
|
||||
|
||||
/// <summary></summary>
|
||||
void writeByte(uint8_t c);
|
||||
/// <summary></summary>
|
||||
void writeSilence();
|
||||
};
|
||||
} // namespace nxdn
|
||||
|
||||
#endif // __NXDN_TX_H__
|
||||
Loading…
Reference in new issue