Merge remote-tracking branch 'g4klx/master'

This commit is contained in:
Andy CA6JAU 2017-01-08 19:18:26 -03:00
commit 048888f45b
21 changed files with 201 additions and 229 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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
@ -59,7 +59,6 @@ m_colorCode(0U),
m_state(DMORXS_NONE),
m_n(0U),
m_type(0U),
m_rssiCount(0U),
m_rssi()
{
}
@ -73,7 +72,6 @@ void CDMRDMORX::reset()
m_state = DMORXS_NONE;
m_startPtr = 0U;
m_endPtr = NOENDPTR;
m_rssiCount = 0U;
}
void CDMRDMORX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
@ -146,7 +144,7 @@ bool CDMRDMORX::processSample(q15_t sample, uint16_t rssi)
switch (dataType) {
case DT_DATA_HEADER:
DEBUG4("DMRDMORX: data header found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMORXS_DATA;
m_type = 0x00U;
break;
@ -155,32 +153,32 @@ bool CDMRDMORX::processSample(q15_t sample, uint16_t rssi)
case DT_RATE_1_DATA:
if (m_state == DMORXS_DATA) {
DEBUG4("DMRDMORX: data payload found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_type = dataType;
}
break;
case DT_VOICE_LC_HEADER:
DEBUG4("DMRDMORX: voice header found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMORXS_VOICE;
break;
case DT_VOICE_PI_HEADER:
if (m_state == DMORXS_VOICE) {
DEBUG4("DMRDMORX: voice pi header found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
}
m_state = DMORXS_VOICE;
break;
case DT_TERMINATOR_WITH_LC:
if (m_state == DMORXS_VOICE) {
DEBUG4("DMRDMORX: voice terminator found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
reset();
}
break;
default: // DT_CSBK
DEBUG4("DMRDMORX: csbk found pos/centre/threshold", m_syncPtr, centre, threshold);
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
reset();
break;
}
@ -188,24 +186,7 @@ bool CDMRDMORX::processSample(q15_t sample, uint16_t rssi)
} else if (m_control == CONTROL_VOICE) {
// Voice sync
DEBUG4("DMRDMORX: voice sync found pos/centre/threshold", m_syncPtr, centre, threshold);
#if defined(SEND_RSSI_DATA)
// Send RSSI data approximately every second
if (m_rssiCount == 2U) {
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t rssi_avg = avgRSSI(m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U, DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (rssi_avg >> 8) & 0xFFU;
frame[35U] = (rssi_avg >> 0) & 0xFFU;
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
}
m_rssiCount++;
if (m_rssiCount >= 16U)
m_rssiCount = 0U;
#else
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
writeRSSIData(frame);
m_state = DMORXS_VOICE;
m_syncCount = 0U;
m_n = 0U;
@ -225,28 +206,12 @@ bool CDMRDMORX::processSample(q15_t sample, uint16_t rssi)
} else {
frame[0U] = ++m_n;
}
#if defined(SEND_RSSI_DATA)
// Send RSSI data approximately every second
if (m_rssiCount == 2U) {
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t rssi_avg = avgRSSI(m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U, DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (rssi_avg >> 8) & 0xFFU;
frame[35U] = (rssi_avg >> 0) & 0xFFU;
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
}
m_rssiCount++;
if (m_rssiCount >= 16U)
m_rssiCount = 0U;
#else
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
} else if (m_state == DMORXS_DATA) {
if (m_type != 0x00U) {
frame[0U] = CONTROL_DATA | m_type;
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
}
}
}
@ -337,7 +302,6 @@ void CDMRDMORX::correlateSync(bool first)
m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold;
m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre;
m_averagePtr = 0U;
m_rssiCount = 0U;
} else {
m_threshold[m_averagePtr] = threshold;
m_centre[m_averagePtr] = centre;
@ -373,7 +337,6 @@ void CDMRDMORX::correlateSync(bool first)
m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold;
m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre;
m_averagePtr = 0U;
m_rssiCount = 0U;
} else {
m_threshold[m_averagePtr] = threshold;
m_centre[m_averagePtr] = centre;
@ -400,21 +363,6 @@ void CDMRDMORX::correlateSync(bool first)
}
}
uint16_t CDMRDMORX::avgRSSI(uint16_t start, uint16_t count)
{
float rssi_tmp = 0.0F;
for (uint16_t i = 0U; i < count; i++) {
rssi_tmp += float(m_rssi[start]);
start++;
if (start >= DMO_BUFFER_LENGTH_SAMPLES)
start -= DMO_BUFFER_LENGTH_SAMPLES;
}
return uint16_t(rssi_tmp / count);
}
void CDMRDMORX::samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
{
for (uint8_t i = 0U; i < count; i++) {
@ -453,3 +401,27 @@ void CDMRDMORX::setColorCode(uint8_t colorCode)
m_colorCode = colorCode;
}
void CDMRDMORX::writeRSSIData(uint8_t* frame)
{
#if defined(SEND_RSSI_DATA)
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t start = m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U;
uint32_t accum = 0U;
for (uint16_t i = 0U; i < (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES); i++) {
accum += m_rssi[start];
start++;
if (start >= DMO_BUFFER_LENGTH_SAMPLES)
start -= DMO_BUFFER_LENGTH_SAMPLES;
}
uint16_t avg = accum / (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (avg >> 8) & 0xFFU;
frame[35U] = (avg >> 0) & 0xFFU;
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U);
#else
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -58,13 +58,12 @@ private:
DMORX_STATE m_state;
uint8_t m_n;
uint8_t m_type;
uint16_t m_rssiCount;
uint16_t m_rssi[DMO_BUFFER_LENGTH_SAMPLES];
bool processSample(q15_t sample, uint16_t rssi);
void correlateSync(bool first);
void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
uint16_t avgRSSI(uint16_t start, uint16_t count);
void writeRSSIData(uint8_t* frame);
};
#endif

View File

@ -41,7 +41,7 @@ private:
CSerialRB m_fifo;
arm_fir_instance_q15 m_modFilter;
q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
uint8_t m_poBuffer[80U];
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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
@ -65,7 +65,6 @@ m_delay(0U),
m_state(DMRRXS_NONE),
m_n(0U),
m_type(0U),
m_rssiCount(0U),
m_rssi()
{
}
@ -91,7 +90,6 @@ void CDMRSlotRX::reset()
m_state = DMRRXS_NONE;
m_startPtr = 0U;
m_endPtr = NOENDPTR;
m_rssiCount = 0U;
}
bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
@ -149,7 +147,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
switch (dataType) {
case DT_DATA_HEADER:
DEBUG5("DMRSlotRX: data header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMRRXS_DATA;
m_type = 0x00U;
break;
@ -158,33 +156,33 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
case DT_RATE_1_DATA:
if (m_state == DMRRXS_DATA) {
DEBUG5("DMRSlotRX: data payload found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_type = dataType;
}
break;
case DT_VOICE_LC_HEADER:
DEBUG5("DMRSlotRX: voice header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMRRXS_VOICE;
break;
case DT_VOICE_PI_HEADER:
if (m_state == DMRRXS_VOICE) {
DEBUG5("DMRSlotRX: voice pi header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
}
m_state = DMRRXS_VOICE;
break;
case DT_TERMINATOR_WITH_LC:
if (m_state == DMRRXS_VOICE) {
DEBUG5("DMRSlotRX: voice terminator found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
}
break;
default: // DT_CSBK
DEBUG5("DMRSlotRX: csbk found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
m_state = DMRRXS_NONE;
m_endPtr = NOENDPTR;
break;
@ -193,24 +191,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
} else if (m_control == CONTROL_VOICE) {
// Voice sync
DEBUG5("DMRSlotRX: voice sync found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold);
#if defined(SEND_RSSI_DATA)
// Send RSSI data approximately every second
if (m_rssiCount == 2U) {
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t rssi_avg = avgRSSI(m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U, DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (rssi_avg >> 8) & 0xFFU;
frame[35U] = (rssi_avg >> 0) & 0xFFU;
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
}
m_rssiCount++;
if (m_rssiCount >= 16U)
m_rssiCount = 0U;
#else
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
writeRSSIData(frame);
m_state = DMRRXS_VOICE;
m_syncCount = 0U;
m_n = 0U;
@ -231,28 +212,12 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
} else {
frame[0U] = ++m_n;
}
#if defined(SEND_RSSI_DATA)
// Send RSSI data approximately every second
if (m_rssiCount == 2U) {
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t rssi_avg = avgRSSI(m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U, DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (rssi_avg >> 8) & 0xFFU;
frame[35U] = (rssi_avg >> 0) & 0xFFU;
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
}
m_rssiCount++;
if (m_rssiCount >= 16U)
m_rssiCount = 0U;
#else
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
} else if (m_state == DMRRXS_DATA) {
if (m_type != 0x00U) {
frame[0U] = CONTROL_DATA | m_type;
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(frame);
}
}
}
@ -319,7 +284,6 @@ void CDMRSlotRX::correlateSync(bool first)
m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold;
m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre;
m_averagePtr = 0U;
m_rssiCount = 0U;
} else {
m_threshold[m_averagePtr] = threshold;
m_centre[m_averagePtr] = centre;
@ -345,7 +309,6 @@ void CDMRSlotRX::correlateSync(bool first)
m_threshold[0U] = m_threshold[1U] = m_threshold[2U] = m_threshold[3U] = threshold;
m_centre[0U] = m_centre[1U] = m_centre[2U] = m_centre[3U] = centre;
m_averagePtr = 0U;
m_rssiCount = 0U;
} else {
m_threshold[m_averagePtr] = threshold;
m_centre[m_averagePtr] = centre;
@ -366,21 +329,6 @@ void CDMRSlotRX::correlateSync(bool first)
}
}
uint16_t CDMRSlotRX::avgRSSI(uint16_t start, uint16_t count)
{
float rssi_tmp = 0.0F;
for (uint16_t i = 0U; i < count; i++) {
rssi_tmp += float(m_rssi[start]);
start++;
if (start >= 900U)
start -= 900U;
}
return uint16_t(rssi_tmp / count);
}
void CDMRSlotRX::samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
{
for (uint8_t i = 0U; i < count; i++, start += DMR_RADIO_SYMBOL_LENGTH) {
@ -420,3 +368,22 @@ void CDMRSlotRX::setDelay(uint8_t delay)
m_delay = delay;
}
void CDMRSlotRX::writeRSSIData(uint8_t* frame)
{
#if defined(SEND_RSSI_DATA)
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
uint16_t start = m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U;
uint32_t accum = 0U;
for (uint16_t i = 0U; i < (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES); i++)
accum += m_rssi[start++];
uint16_t avg = accum / (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
frame[34U] = (avg >> 8) & 0xFFU;
frame[35U] = (avg >> 0) & 0xFFU;
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 3U);
#else
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -62,12 +62,11 @@ private:
DMRRX_STATE m_state;
uint8_t m_n;
uint8_t m_type;
uint16_t m_rssiCount;
uint16_t m_rssi[900U];
void correlateSync(bool first);
void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
uint16_t avgRSSI(uint16_t start, uint16_t count);
void writeRSSIData(uint8_t* frame);
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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
@ -275,7 +275,7 @@ void CDStarRX::reset()
m_samplesPtr = 0U;
}
void CDStarRX::samples(const q15_t* samples, uint8_t length)
void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
{
for (uint16_t i = 0U; i < length; i++) {
m_samples[m_samplesPtr] = samples[i];
@ -298,13 +298,13 @@ void CDStarRX::samples(const q15_t* samples, uint8_t length)
switch (m_rxState) {
case DSRXS_NONE:
processNone(bit);
processNone(bit, rssi[i]);
break;
case DSRXS_HEADER:
processHeader(bit);
processHeader(bit, rssi[i]);
break;
case DSRXS_DATA:
processData(bit);
processData(bit, rssi[i]);
break;
default:
break;
@ -317,7 +317,7 @@ void CDStarRX::samples(const q15_t* samples, uint8_t length)
}
}
void CDStarRX::processNone(bool bit)
void CDStarRX::processNone(bool bit, uint16_t rssi)
{
m_patternBuffer <<= 1;
if (bit)
@ -341,7 +341,8 @@ void CDStarRX::processNone(bool bit)
io.setDecode(true);
io.setADCDetection(true);
serial.writeDStarData(DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
writeRSSIData(m_rxBuffer, rssi);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
@ -352,7 +353,7 @@ void CDStarRX::processNone(bool bit)
}
}
void CDStarRX::processHeader(bool bit)
void CDStarRX::processHeader(bool bit, uint16_t rssi)
{
m_patternBuffer <<= 1;
if (bit)
@ -370,7 +371,7 @@ void CDStarRX::processHeader(bool bit)
io.setDecode(true);
io.setADCDetection(true);
serial.writeDStarHeader(header, DSTAR_HEADER_LENGTH_BYTES);
writeRSSIHeader(header, rssi);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
@ -384,7 +385,7 @@ void CDStarRX::processHeader(bool bit)
}
}
void CDStarRX::processData(bool bit)
void CDStarRX::processData(bool bit, uint16_t rssi)
{
m_patternBuffer <<= 1;
if (bit)
@ -457,9 +458,10 @@ void CDStarRX::processData(bool bit)
m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
}
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
writeRSSIData(m_rxBuffer, rssi);
} else {
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
}
// Start the next frame
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
@ -467,6 +469,30 @@ void CDStarRX::processData(bool bit)
}
}
void CDStarRX::writeRSSIHeader(unsigned char* header, uint16_t rssi)
{
#if defined(SEND_RSSI_DATA)
header[41U] = (rssi >> 8) & 0xFFU;
header[42U] = (rssi >> 0) & 0xFFU;
serial.writeDStarHeader(header, DSTAR_HEADER_LENGTH_BYTES + 2U);
#else
serial.writeDStarHeader(header, DSTAR_HEADER_LENGTH_BYTES + 0U);
#endif
}
void CDStarRX::writeRSSIData(unsigned char* data, uint16_t rssi)
{
#if defined(SEND_RSSI_DATA)
data[12U] = (rssi >> 8) & 0xFFU;
data[13U] = (rssi >> 0) & 0xFFU;
serial.writeDStarData(data, DSTAR_DATA_LENGTH_BYTES + 2U);
#else
serial.writeDStarData(data, DSTAR_DATA_LENGTH_BYTES + 0U);
#endif
}
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
{
int i;
@ -682,4 +708,3 @@ bool CDStarRX::checksum(const uint8_t* header) const
return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -32,7 +32,7 @@ class CDStarRX {
public:
CDStarRX();
void samples(const q15_t* samples, uint8_t length);
void samples(const q15_t* samples, const uint16_t* rssi, uint8_t length);
void reset();
@ -54,9 +54,11 @@ private:
q15_t m_samples[DSTAR_DATA_SYNC_LENGTH_BITS];
uint8_t m_samplesPtr;
void processNone(bool bit);
void processHeader(bool bit);
void processData(bool bit);
void processNone(bool bit, uint16_t rssi);
void processHeader(bool bit, uint16_t rssi);
void processData(bool bit, uint16_t rssi);
void writeRSSIHeader(unsigned char* header, uint16_t rssi);
void writeRSSIData(unsigned char* data, uint16_t rssi);
bool rxHeader(uint8_t* in, uint8_t* out);
void acs(int* metric);
void viterbiDecode(int* data);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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
@ -457,7 +457,7 @@ void CDStarTX::writeByte(uint8_t c)
void CDStarTX::setTXDelay(uint8_t delay)
{
m_txDelay = 150U + uint16_t(delay) * 6U; // 250ms + tx delay
m_txDelay = 300U + uint16_t(delay) * 6U; // 250ms + tx delay
}
uint16_t CDStarTX::getSpace() const

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -41,7 +41,7 @@ private:
CSerialRB m_buffer;
arm_fir_instance_q15 m_modFilter;
q15_t m_modState[60U]; // NoTaps + BlockSize - 1, 12 + 40 - 1 plus some spare
uint8_t m_poBuffer[500U];
uint8_t m_poBuffer[600U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay; // In bytes

14
IO.cpp
View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@ -184,7 +184,7 @@ void CIO::process()
q15_t GMSKVals[RX_BLOCK_SIZE + 1U];
::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, blockSize);
dstarRX.samples(GMSKVals, blockSize);
dstarRX.samples(GMSKVals, rssi, blockSize);
}
if (m_dmrEnable || m_ysfEnable || m_p25Enable) {
@ -199,17 +199,17 @@ void CIO::process()
}
if (m_ysfEnable)
ysfRX.samples(C4FSKVals, blockSize);
ysfRX.samples(C4FSKVals, rssi, blockSize);
if (m_p25Enable)
p25RX.samples(C4FSKVals, blockSize);
p25RX.samples(C4FSKVals, rssi, blockSize);
}
} else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE + 1U];
::arm_fir_fast_q15(&m_GMSKFilter, samples, GMSKVals, blockSize);
dstarRX.samples(GMSKVals, blockSize);
dstarRX.samples(GMSKVals, rssi, blockSize);
}
} else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) {
@ -231,14 +231,14 @@ void CIO::process()
q15_t C4FSKVals[RX_BLOCK_SIZE + 1U];
::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize);
ysfRX.samples(C4FSKVals, blockSize);
ysfRX.samples(C4FSKVals, rssi, blockSize);
}
} else if (m_modemState == STATE_P25) {
if (m_p25Enable) {
q15_t C4FSKVals[RX_BLOCK_SIZE + 1U];
::arm_fir_fast_q15(&m_C4FSKFilter, samples, C4FSKVals, blockSize);
p25RX.samples(C4FSKVals, blockSize);
p25RX.samples(C4FSKVals, rssi, blockSize);
}
} else if (m_modemState == STATE_DSTARCAL) {
q15_t GMSKVals[RX_BLOCK_SIZE + 1U];

4
IO.h
View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -40,7 +40,7 @@ public:
void setADCDetection(bool detect);
void setMode();
void interrupt(uint8_t source);
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);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@ -77,7 +77,7 @@ const uint16_t DC_OFFSET = 2048U;
extern "C" {
void ADC_Handler()
{
io.interrupt(0U);
io.interrupt();
}
}
@ -101,7 +101,7 @@ void CIO::initInt()
void CIO::startInt()
{
if (ADC->ADC_ISR & ADC_ISR_EOC_Chan) // Ensure there was an End-of-Conversion and we read the ISR reg
io.interrupt(0U);
io.interrupt();
// Set up the ADC
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt vector
@ -164,7 +164,7 @@ void CIO::startInt()
digitalWrite(PIN_LED, HIGH);
}
void CIO::interrupt(uint8_t source)
void CIO::interrupt()
{
if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg
uint8_t control = MARK_NONE;

View File

@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016 by Andy Uribe CA6JAU
* Copyright (C) 2017 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
@ -213,7 +214,7 @@ extern "C" {
void TIM2_IRQHandler() {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
io.interrupt(0U);
io.interrupt();
}
}
}
@ -280,7 +281,7 @@ void CIO::initInt()
void CIO::startInt()
{
if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET))
io.interrupt(0U);
io.interrupt();
// Init the ADC
GPIO_InitTypeDef GPIO_InitStruct;
@ -421,7 +422,7 @@ void CIO::startInt()
GPIO_SetBits(PORT_LED, PIN_LED);
}
void CIO::interrupt(uint8_t source)
void CIO::interrupt()
{
uint8_t control = MARK_NONE;
uint16_t sample = DC_OFFSET;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -45,15 +45,8 @@ const uint16_t DC_OFFSET = 2048U;
extern "C" {
void adc0_isr()
{
io.interrupt(0U);
io.interrupt();
}
#if defined(SEND_RSSI_DATA)
void adc1_isr()
{
io.interrupt(1U);
}
#endif
}
void CIO::initInt()
@ -116,7 +109,6 @@ void CIO::startInt()
ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
sum1 = (sum1 / 2U) | 0x8000U;
ADC1_PG = sum1;
#endif
#if defined(EXTERNAL_OSC)
@ -149,42 +141,33 @@ void CIO::startInt()
digitalWrite(PIN_LED, HIGH);
}
void CIO::interrupt(uint8_t source)
void CIO::interrupt()
{
if (source == 0U) { // ADC0
uint8_t control = MARK_NONE;
uint16_t sample = DC_OFFSET;
uint8_t control = MARK_NONE;
uint16_t sample = DC_OFFSET;
m_txBuffer.get(sample, control);
*(int16_t *)&(DAC0_DAT0L) = sample;
m_txBuffer.get(sample, control);
*(int16_t *)&(DAC0_DAT0L) = sample;
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
sample = ADC0_RA;
m_rxBuffer.put(sample, control);
}
#if defined(SEND_RSSI_DATA)
if ((ADC1_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
uint16_t rssi = ADC1_RA;
m_rssiBuffer.put(rssi);
}
else {
m_rssiBuffer.put(0U);
}
ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; //start the next RSSI conversion
#else
m_rssiBuffer.put(0U);
#endif
m_watchdog++;
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
sample = ADC0_RA;
m_rxBuffer.put(sample, control);
}
#if defined(SEND_RSSI_DATA)
if ((ADC1_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
uint16_t rssi = ADC1_RA;
m_rssiBuffer.put(rssi);
} else {
m_rssiBuffer.put(0U);
}
ADC1_SC1A = PIN_RSSI; // Start the next RSSI conversion
#else
m_rssiBuffer.put(0U);
#endif
m_watchdog++;
}
bool CIO::getCOSInt()

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -73,7 +73,7 @@ void CP25RX::reset()
m_threshold = 0;
}
void CP25RX::samples(const q15_t* samples, uint8_t length)
void CP25RX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
{
for (uint16_t i = 0U; i < length; i++) {
bool bit = samples[i] < 0;
@ -95,7 +95,7 @@ void CP25RX::samples(const q15_t* samples, uint8_t length)
if (m_state == P25RXS_NONE)
processNone(samples[i]);
else
processData(samples[i]);
processData(samples[i], rssi[i]);
}
}
}
@ -173,7 +173,7 @@ void CP25RX::processNone(q15_t sample)
m_symbolPtr = 0U;
}
void CP25RX::processData(q15_t sample)
void CP25RX::processData(q15_t sample, uint16_t rssi)
{
sample -= m_centre;
@ -251,7 +251,7 @@ void CP25RX::processData(q15_t sample)
} else {
m_outBuffer[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
serial.writeP25Ldu(m_outBuffer, P25_LDU_FRAME_LENGTH_BYTES + 1U);
writeRSSILdu(m_outBuffer, rssi);
// Start the next frame
::memset(m_outBuffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U);
@ -260,3 +260,14 @@ void CP25RX::processData(q15_t sample)
}
}
void CP25RX::writeRSSILdu(uint8_t* ldu, uint16_t rssi)
{
#if defined(SEND_RSSI_DATA)
ldu[216U] = (rssi >> 8) & 0xFFU;
ldu[217U] = (rssi >> 0) & 0xFFU;
serial.writeP25Ldu(ldu, P25_LDU_FRAME_LENGTH_BYTES + 3U);
#else
serial.writeP25Ldu(ldu, P25_LDU_FRAME_LENGTH_BYTES + 1U);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -31,7 +31,7 @@ class CP25RX {
public:
CP25RX();
void samples(const q15_t* samples, uint8_t length);
void samples(const q15_t* samples, const uint16_t* rssi, uint8_t length);
void reset();
@ -51,7 +51,8 @@ private:
q15_t m_threshold;
void processNone(q15_t sample);
void processData(q15_t sample);
void processData(q15_t sample, uint16_t rssi);
void writeRSSILdu(uint8_t* data, uint16_t rssi);
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@ -41,7 +41,7 @@ private:
arm_fir_instance_q15 m_lpFilter;
q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare
uint8_t m_poBuffer[920U];
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;

View File

@ -1,6 +1,6 @@
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion and P25.
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion and P25 modes.
It runs on the Arduino Due and the ST-Micro STM32F4xx platforms. Support for the Teensy (3.1/3.2 and 3.5/3.6) is being added.
It runs on the Arduino Due, the ST-Micro STM32F407-DISCO and STM32F446-NUCLEO, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3 or M4 processor with a clock speed greater than 70 MHz, and access to at least one analogue to digital converter and one digital to analogue converter. A Cortex-M7 processor is also probably adequate.
In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is being supplied via the Coocox IDE with ARM GCC. The Teensy support is via the latest beta of Teensyduino.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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
@ -73,7 +73,7 @@ void CYSFRX::reset()
m_threshold = 0;
}
void CYSFRX::samples(const q15_t* samples, uint8_t length)
void CYSFRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
{
for (uint16_t i = 0U; i < length; i++) {
bool bit = samples[i] < 0;
@ -95,7 +95,7 @@ void CYSFRX::samples(const q15_t* samples, uint8_t length)
if (m_state == YSFRXS_NONE)
processNone(samples[i]);
else
processData(samples[i]);
processData(samples[i], rssi[i]);
}
}
}
@ -173,7 +173,7 @@ void CYSFRX::processNone(q15_t sample)
m_symbolPtr = 0U;
}
void CYSFRX::processData(q15_t sample)
void CYSFRX::processData(q15_t sample, uint16_t rssi)
{
sample -= m_centre;
@ -233,7 +233,7 @@ void CYSFRX::processData(q15_t sample)
} else {
m_outBuffer[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
serial.writeYSFData(m_outBuffer, YSF_FRAME_LENGTH_BYTES + 1U);
writeRSSIData(m_outBuffer, rssi);
// Start the next frame
::memset(m_outBuffer, 0x00U, YSF_FRAME_LENGTH_BYTES + 3U);
@ -242,3 +242,14 @@ void CYSFRX::processData(q15_t sample)
}
}
void CYSFRX::writeRSSIData(uint8_t* data, uint16_t rssi)
{
#if defined(SEND_RSSI_DATA)
data[120U] = (rssi >> 8) & 0xFFU;
data[121U] = (rssi >> 0) & 0xFFU;
serial.writeYSFData(data, YSF_FRAME_LENGTH_BYTES + 3U);
#else
serial.writeYSFData(data, YSF_FRAME_LENGTH_BYTES + 1U);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -31,7 +31,7 @@ class CYSFRX {
public:
CYSFRX();
void samples(const q15_t* samples, uint8_t length);
void samples(const q15_t* samples, const uint16_t* rssi, uint8_t length);
void reset();
@ -51,7 +51,8 @@ private:
q15_t m_threshold;
void processNone(q15_t sample);
void processData(q15_t sample);
void processData(q15_t sample, uint16_t rssi);
void writeRSSIData(unsigned char* data, uint16_t rssi);
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@ -39,7 +39,7 @@ private:
CSerialRB m_buffer;
arm_fir_instance_q15 m_modFilter;
q15_t m_modState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
uint8_t m_poBuffer[920U];
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;