mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-21 23:27:09 +08:00
Restructure YSF again.
This commit is contained in:
@@ -32,6 +32,9 @@ m_state(RS_RF_LISTENING),
|
|||||||
m_timeoutTimer(1000U, timeout),
|
m_timeoutTimer(1000U, timeout),
|
||||||
m_interval(),
|
m_interval(),
|
||||||
m_frames(0U),
|
m_frames(0U),
|
||||||
|
m_errs(0U),
|
||||||
|
m_bits(0U),
|
||||||
|
m_headerSeen(false),
|
||||||
m_source(NULL),
|
m_source(NULL),
|
||||||
m_dest(NULL),
|
m_dest(NULL),
|
||||||
m_payload(),
|
m_payload(),
|
||||||
@@ -61,7 +64,7 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
unsigned char type = data[0U];
|
unsigned char type = data[0U];
|
||||||
|
|
||||||
if (type == TAG_LOST && m_state == RS_RF_AUDIO) {
|
if (type == TAG_LOST && m_state == RS_RF_AUDIO) {
|
||||||
LogMessage("YSF, transmission lost, %.1f seconds", float(m_frames) / 10.0F);
|
LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 10.0F, float(m_errs * 100U) / float(m_bits));
|
||||||
|
|
||||||
if (m_parrot != NULL)
|
if (m_parrot != NULL)
|
||||||
m_parrot->end();
|
m_parrot->end();
|
||||||
@@ -82,6 +85,9 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_frames = 0U;
|
m_frames = 0U;
|
||||||
|
m_errs = 0U;
|
||||||
|
m_bits = 1U;
|
||||||
|
m_headerSeen = false;
|
||||||
m_timeoutTimer.start();
|
m_timeoutTimer.start();
|
||||||
m_payload.reset();
|
m_payload.reset();
|
||||||
m_state = RS_RF_AUDIO;
|
m_state = RS_RF_AUDIO;
|
||||||
@@ -93,6 +99,9 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
if (m_state != RS_RF_AUDIO)
|
if (m_state != RS_RF_AUDIO)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
unsigned char orig[YSF_FRAME_LENGTH_BYTES];
|
||||||
|
::memcpy(orig, data + 2U, YSF_FRAME_LENGTH_BYTES);
|
||||||
|
|
||||||
unsigned char fi = fich.getFI();
|
unsigned char fi = fich.getFI();
|
||||||
if (valid && fi == YSF_FI_HEADER) {
|
if (valid && fi == YSF_FI_HEADER) {
|
||||||
CSync::addYSFSync(data + 2U);
|
CSync::addYSFSync(data + 2U);
|
||||||
@@ -102,15 +111,19 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
unsigned char dt = fich.getDT();
|
unsigned char dt = fich.getDT();
|
||||||
unsigned char cm = fich.getCM();
|
unsigned char cm = fich.getCM();
|
||||||
|
|
||||||
unsigned char orig[YSF_FRAME_LENGTH_BYTES];
|
|
||||||
::memcpy(orig, data + 2U, YSF_FRAME_LENGTH_BYTES);
|
|
||||||
|
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
// valid = m_payload.processHeader(data + 2U);
|
|
||||||
|
|
||||||
unsigned int errs = calculateBER(orig, data + 2U);
|
unsigned int errs = calculateBER(orig, data + 2U, YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
|
||||||
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
||||||
|
|
||||||
|
m_errs += errs;
|
||||||
|
m_bits += 240U;
|
||||||
|
|
||||||
|
m_frames++;
|
||||||
|
m_headerSeen = true;
|
||||||
|
|
||||||
|
// valid = m_payload.processHeaderData(data + 2U);
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
fich.setMR(YSF_MR_BUSY);
|
fich.setMR(YSF_MR_BUSY);
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
@@ -158,17 +171,18 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
unsigned char ft = fich.getFT();
|
unsigned char ft = fich.getFT();
|
||||||
unsigned char dt = fich.getDT();
|
unsigned char dt = fich.getDT();
|
||||||
|
|
||||||
unsigned char orig[YSF_FRAME_LENGTH_BYTES];
|
|
||||||
::memcpy(orig, data + 2U, YSF_FRAME_LENGTH_BYTES);
|
|
||||||
|
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
// m_payload.processTrailer(data + 2U);
|
|
||||||
|
|
||||||
unsigned int errs = calculateBER(orig, data + 2U);
|
unsigned int errs = calculateBER(orig, data + 2U, YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
|
||||||
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
||||||
|
|
||||||
|
m_errs += errs;
|
||||||
|
m_bits += 240U;
|
||||||
|
|
||||||
m_frames++;
|
m_frames++;
|
||||||
|
|
||||||
|
// m_payload.processHeaderData(data + 2U);
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
fich.setMR(YSF_MR_BUSY);
|
fich.setMR(YSF_MR_BUSY);
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
@@ -191,7 +205,7 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
writeFile(data + 2U);
|
writeFile(data + 2U);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LogMessage("YSF, received RF end of transmission, %.1f seconds", float(m_frames) / 10.0F);
|
LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_frames) / 10.0F, float(m_errs * 100U) / float(m_bits));
|
||||||
writeEndOfTransmission();
|
writeEndOfTransmission();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -203,15 +217,45 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
unsigned char ft = fich.getFT();
|
unsigned char ft = fich.getFT();
|
||||||
unsigned char dt = fich.getDT();
|
unsigned char dt = fich.getDT();
|
||||||
|
|
||||||
unsigned char orig[YSF_FRAME_LENGTH_BYTES];
|
|
||||||
::memcpy(orig, data + 2U, YSF_FRAME_LENGTH_BYTES);
|
|
||||||
|
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
// m_payload.processData(data + 2U, fn, dt);
|
|
||||||
|
|
||||||
unsigned int errs = calculateBER(orig, data + 2U);
|
unsigned int errs = calculateBER(orig, data + 2U, YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
|
||||||
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
LogDebug("YSF, FI=%u FN=%u FT=%u DT=%u BER=%.1f%%", fi, fn, ft, dt, float(errs) / 2.4F);
|
||||||
|
|
||||||
|
m_errs += errs;
|
||||||
|
m_bits += 240U;
|
||||||
|
|
||||||
|
m_frames++;
|
||||||
|
|
||||||
|
switch (dt) {
|
||||||
|
case YSF_DT_VD_MODE1:
|
||||||
|
valid = m_payload.processVDMode1Data(data + 2U, fn);
|
||||||
|
m_errs += m_payload.processVDMode1Audio(data + 2U);
|
||||||
|
m_bits += 235U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case YSF_DT_VD_MODE2:
|
||||||
|
valid = m_payload.processVDMode2Data(data + 2U, fn);
|
||||||
|
m_errs += m_payload.processVDMode2Audio(data + 2U);
|
||||||
|
m_bits += 135U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case YSF_DT_DATA_FR_MODE:
|
||||||
|
valid = m_payload.processDataFRModeData(data + 2U, fn);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // YSF_DT_VOICE_FR_MODE
|
||||||
|
if (!m_headerSeen) {
|
||||||
|
// The first packet after the header is odd, don't try and regenerate it
|
||||||
|
m_errs += m_payload.processVoiceFRModeAudio(data + 2U);
|
||||||
|
m_bits += 720U;
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_headerSeen = false;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
|
|
||||||
if (m_dest == NULL) {
|
if (m_dest == NULL) {
|
||||||
@@ -246,8 +290,6 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_frames++;
|
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
fich.setMR(YSF_MR_BUSY);
|
fich.setMR(YSF_MR_BUSY);
|
||||||
fich.encode(data + 2U);
|
fich.encode(data + 2U);
|
||||||
@@ -272,7 +314,15 @@ bool CYSFControl::writeModem(unsigned char *data)
|
|||||||
} else {
|
} else {
|
||||||
CSync::addYSFSync(data + 2U);
|
CSync::addYSFSync(data + 2U);
|
||||||
|
|
||||||
|
// Only calculate the BER on the sync word
|
||||||
|
unsigned int errs = calculateBER(orig, data + 2U, YSF_SYNC_LENGTH_BYTES);
|
||||||
|
LogDebug("YSF, invalid FICH, BER=%.1f%%", float(errs) / 0.4F);
|
||||||
|
|
||||||
|
m_errs += errs;
|
||||||
|
m_bits += 40U;
|
||||||
|
|
||||||
m_frames++;
|
m_frames++;
|
||||||
|
m_headerSeen = false;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
data[0U] = TAG_DATA;
|
data[0U] = TAG_DATA;
|
||||||
@@ -422,11 +472,11 @@ void CYSFControl::closeFile()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CYSFControl::calculateBER(const unsigned char* orig, const unsigned char *curr) const
|
unsigned int CYSFControl::calculateBER(const unsigned char* orig, const unsigned char *curr, unsigned int length) const
|
||||||
{
|
{
|
||||||
unsigned int errors = 0U;
|
unsigned int errors = 0U;
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < (YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES); i++) {
|
for (unsigned int i = 0U; i < length; i++) {
|
||||||
unsigned char v = orig[i] ^ curr[i];
|
unsigned char v = orig[i] ^ curr[i];
|
||||||
while (v != 0U) {
|
while (v != 0U) {
|
||||||
v &= v - 1U;
|
v &= v - 1U;
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ private:
|
|||||||
CTimer m_timeoutTimer;
|
CTimer m_timeoutTimer;
|
||||||
CStopWatch m_interval;
|
CStopWatch m_interval;
|
||||||
unsigned int m_frames;
|
unsigned int m_frames;
|
||||||
|
unsigned int m_errs;
|
||||||
|
unsigned int m_bits;
|
||||||
|
bool m_headerSeen;
|
||||||
unsigned char* m_source;
|
unsigned char* m_source;
|
||||||
unsigned char* m_dest;
|
unsigned char* m_dest;
|
||||||
CYSFPayload m_payload;
|
CYSFPayload m_payload;
|
||||||
@@ -65,7 +68,7 @@ private:
|
|||||||
bool writeFile(const unsigned char* data);
|
bool writeFile(const unsigned char* data);
|
||||||
void closeFile();
|
void closeFile();
|
||||||
|
|
||||||
unsigned int calculateBER(const unsigned char* orig, const unsigned char* curr) const;
|
unsigned int calculateBER(const unsigned char* orig, const unsigned char* curr, unsigned int length) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
254
YSFPayload.cpp
254
YSFPayload.cpp
@@ -98,31 +98,10 @@ CYSFPayload::~CYSFPayload()
|
|||||||
delete[] m_dest;
|
delete[] m_dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processData(unsigned char* bytes, unsigned char fn, unsigned char dt)
|
bool CYSFPayload::processHeaderData(unsigned char* data)
|
||||||
{
|
{
|
||||||
assert(bytes != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
switch (dt) {
|
|
||||||
case YSF_DT_VD_MODE1:
|
|
||||||
processVDMode1(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case YSF_DT_VD_MODE2:
|
|
||||||
processVDMode2(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case YSF_DT_DATA_FR_MODE:
|
|
||||||
processDataFRMode(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: // YSF_DT_VOICE_FR_MODE
|
|
||||||
processVoiceFRMode(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CYSFPayload::processHeader(unsigned char* data)
|
|
||||||
{
|
|
||||||
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned char dch[45U];
|
unsigned char dch[45U];
|
||||||
@@ -155,8 +134,8 @@ bool CYSFPayload::processHeader(unsigned char* data)
|
|||||||
for (unsigned int i = 0U; i < 20U; i++)
|
for (unsigned int i = 0U; i < 20U; i++)
|
||||||
output[i] ^= WHITENING_DATA[i];
|
output[i] ^= WHITENING_DATA[i];
|
||||||
|
|
||||||
CUtils::dump("Header, Source", output + 0U, 10U);
|
CUtils::dump(1U, "Header, Source", output + 0U, 10U);
|
||||||
CUtils::dump("Header, Destination", output + 10U, 10U);
|
CUtils::dump(1U, "Header, Destination", output + 10U, 10U);
|
||||||
|
|
||||||
if (m_source == NULL) {
|
if (m_source == NULL) {
|
||||||
m_source = new unsigned char[10U];
|
m_source = new unsigned char[10U];
|
||||||
@@ -243,127 +222,30 @@ bool CYSFPayload::processHeader(unsigned char* data)
|
|||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processTrailer(unsigned char* data)
|
unsigned int CYSFPayload::processVDMode1Audio(unsigned char* data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned char dch[45U];
|
// Regenerate the AMBE FEC
|
||||||
|
unsigned int errors = 0U;
|
||||||
|
errors += m_fec.regenerateDMR(data + 9U);
|
||||||
|
errors += m_fec.regenerateDMR(data + 27U);
|
||||||
|
errors += m_fec.regenerateDMR(data + 45U);
|
||||||
|
errors += m_fec.regenerateDMR(data + 63U);
|
||||||
|
errors += m_fec.regenerateDMR(data + 81U);
|
||||||
|
|
||||||
unsigned char* p1 = data;
|
LogDebug("YSF, V/D Mode 1, AMBE FEC %u/235 (%.1f%%)", errors, float(errors) / 2.35F);
|
||||||
unsigned char* p2 = dch;
|
|
||||||
for (unsigned int i = 0U; i < 5U; i++) {
|
|
||||||
::memcpy(p2, p1, 9U);
|
|
||||||
p1 += 18U; p2 += 9U;
|
|
||||||
}
|
|
||||||
|
|
||||||
CYSFConvolution conv;
|
return errors;
|
||||||
conv.start();
|
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 180U; i++) {
|
|
||||||
unsigned int n = INTERLEAVE_TABLE_9_20[i];
|
|
||||||
uint8_t s0 = READ_BIT1(dch, n) ? 1U : 0U;
|
|
||||||
|
|
||||||
n++;
|
|
||||||
uint8_t s1 = READ_BIT1(dch, n) ? 1U : 0U;
|
|
||||||
|
|
||||||
conv.decode(s0, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char output[23U];
|
|
||||||
conv.chainback(output, 180U);
|
|
||||||
|
|
||||||
bool valid = CCRC::checkCCITT162(output, 22U);
|
|
||||||
if (valid) {
|
|
||||||
for (unsigned int i = 0U; i < 20U; i++)
|
|
||||||
output[i] ^= WHITENING_DATA[i];
|
|
||||||
|
|
||||||
CUtils::dump("Trailer, Source", output + 0U, 10U);
|
|
||||||
CUtils::dump("Trailer, Destination", output + 10U, 10U);
|
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 20U; i++)
|
|
||||||
output[i] ^= WHITENING_DATA[i];
|
|
||||||
|
|
||||||
CCRC::addCCITT162(output, 22U);
|
|
||||||
output[22U] = 0x00U;
|
|
||||||
|
|
||||||
unsigned char convolved[45U];
|
|
||||||
conv.encode(output, convolved, 180U);
|
|
||||||
|
|
||||||
unsigned char bytes[45U];
|
|
||||||
unsigned int j = 0U;
|
|
||||||
for (unsigned int i = 0U; i < 180U; i++) {
|
|
||||||
unsigned int n = INTERLEAVE_TABLE_9_20[i];
|
|
||||||
|
|
||||||
bool s0 = READ_BIT1(convolved, j) != 0U;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
bool s1 = READ_BIT1(convolved, j) != 0U;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
WRITE_BIT1(bytes, n, s0);
|
|
||||||
|
|
||||||
n++;
|
|
||||||
WRITE_BIT1(bytes, n, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
p1 = data;
|
|
||||||
p2 = bytes;
|
|
||||||
for (unsigned int i = 0U; i < 5U; i++) {
|
|
||||||
::memcpy(p1, p2, 9U);
|
|
||||||
p1 += 18U; p2 += 9U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::memset(output, ' ', 20U);
|
|
||||||
if (m_downlink != NULL)
|
|
||||||
::memcpy(output + 0U, m_downlink, 10U);
|
|
||||||
if (m_uplink != NULL)
|
|
||||||
::memcpy(output + 10U, m_uplink, 10U);
|
|
||||||
for (unsigned int i = 0U; i < 20U; i++)
|
|
||||||
output[i] ^= WHITENING_DATA[i];
|
|
||||||
|
|
||||||
CCRC::addCCITT162(output, 22U);
|
|
||||||
output[22U] = 0x00U;
|
|
||||||
|
|
||||||
unsigned char convolved[45U];
|
|
||||||
conv.encode(output, convolved, 180U);
|
|
||||||
|
|
||||||
unsigned char bytes[45U];
|
|
||||||
unsigned int j = 0U;
|
|
||||||
for (unsigned int i = 0U; i < 180U; i++) {
|
|
||||||
unsigned int n = INTERLEAVE_TABLE_9_20[i];
|
|
||||||
|
|
||||||
bool s0 = READ_BIT1(convolved, j) != 0U;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
bool s1 = READ_BIT1(convolved, j) != 0U;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
WRITE_BIT1(bytes, n, s0);
|
|
||||||
|
|
||||||
n++;
|
|
||||||
WRITE_BIT1(bytes, n, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
p1 = data + 9U;
|
|
||||||
p2 = bytes;
|
|
||||||
for (unsigned int i = 0U; i < 5U; i++) {
|
|
||||||
::memcpy(p1, p2, 9U);
|
|
||||||
p1 += 18U; p2 += 9U;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processVDMode1(unsigned char* data, unsigned char fn)
|
bool CYSFPayload::processVDMode1Data(unsigned char* data, unsigned char fn)
|
||||||
{
|
{
|
||||||
// Regenerate the AMBE FEC
|
assert(data != NULL);
|
||||||
// unsigned int errors = 0U;
|
|
||||||
// errors += m_fec.regenerateDMR(data + 9U);
|
|
||||||
// errors += m_fec.regenerateDMR(data + 27U);
|
|
||||||
// errors += m_fec.regenerateDMR(data + 45U);
|
|
||||||
// errors += m_fec.regenerateDMR(data + 63U);
|
|
||||||
// errors += m_fec.regenerateDMR(data + 81U);
|
|
||||||
|
|
||||||
// LogMessage("YSF, V/D Mode 1, AMBE FEC %u/235 (%.1f%%)", errors, float(errors) / 2.35F);
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned char dch[45U];
|
unsigned char dch[45U];
|
||||||
|
|
||||||
@@ -397,8 +279,8 @@ void CYSFPayload::processVDMode1(unsigned char* data, unsigned char fn)
|
|||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case 0U:
|
case 0U:
|
||||||
CUtils::dump("V/D Mode 1, Destination", output + 0U, 10U);
|
CUtils::dump(1U, "V/D Mode 1, Destination", output + 0U, 10U);
|
||||||
CUtils::dump("V/D Mode 1, Source", output + 10U, 10U);
|
CUtils::dump(1U, "V/D Mode 1, Source", output + 10U, 10U);
|
||||||
|
|
||||||
if (m_dest == NULL) {
|
if (m_dest == NULL) {
|
||||||
m_dest = new unsigned char[10U];
|
m_dest = new unsigned char[10U];
|
||||||
@@ -464,10 +346,16 @@ void CYSFPayload::processVDMode1(unsigned char* data, unsigned char fn)
|
|||||||
p1 += 18U; p2 += 9U;
|
p1 += 18U; p2 += 9U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret && (fn == 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
|
unsigned int CYSFPayload::processVDMode2Audio(unsigned char* data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned int errors = 0U;
|
unsigned int errors = 0U;
|
||||||
unsigned int offset = 40U; // DCH(0)
|
unsigned int offset = 40U; // DCH(0)
|
||||||
|
|
||||||
@@ -476,9 +364,9 @@ void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
|
|||||||
unsigned char vch[13U];
|
unsigned char vch[13U];
|
||||||
|
|
||||||
// Deinterleave
|
// Deinterleave
|
||||||
for(unsigned int i = 0U; i < 104U; i++) {
|
for (unsigned int i = 0U; i < 104U; i++) {
|
||||||
unsigned int n = INTERLEAVE_TABLE_26_4[i];
|
unsigned int n = INTERLEAVE_TABLE_26_4[i];
|
||||||
bool s = READ_BIT1(data, offset+n);
|
bool s = READ_BIT1(data, offset + n);
|
||||||
WRITE_BIT1(vch, i, s);
|
WRITE_BIT1(vch, i, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,43 +374,49 @@ void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
|
|||||||
for (unsigned int i = 0U; i < 13U; i++)
|
for (unsigned int i = 0U; i < 13U; i++)
|
||||||
vch[i] ^= WHITENING_DATA[i];
|
vch[i] ^= WHITENING_DATA[i];
|
||||||
|
|
||||||
// errors += READ_BIT1(vch, 103); // Padding bit must be zero but apparently it is not...
|
// errors += READ_BIT1(vch, 103); // Padding bit must be zero but apparently it is not...
|
||||||
|
|
||||||
for(unsigned int i = 0U; i < 81U; i += 3) {
|
for (unsigned int i = 0U; i < 81U; i += 3) {
|
||||||
uint8_t vote = bool(READ_BIT1(vch, i)) + bool(READ_BIT1(vch, i+1)) + bool(READ_BIT1(vch, i+2));
|
uint8_t vote = bool(READ_BIT1(vch, i)) + bool(READ_BIT1(vch, i + 1)) + bool(READ_BIT1(vch, i + 2));
|
||||||
if(vote == 1 || vote == 2)
|
if (vote == 1 || vote == 2) {
|
||||||
{
|
|
||||||
bool decision = vote / 2; // exploit integer division: 1/2 == 0, 2/2 == 1.
|
bool decision = vote / 2; // exploit integer division: 1/2 == 0, 2/2 == 1.
|
||||||
WRITE_BIT1(vch, i, decision);
|
WRITE_BIT1(vch, i, decision);
|
||||||
WRITE_BIT1(vch, i+1, decision);
|
WRITE_BIT1(vch, i + 1, decision);
|
||||||
WRITE_BIT1(vch, i+2, decision);
|
WRITE_BIT1(vch, i + 2, decision);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct only if we have bit errors. Technically we could even
|
// Reconstruct only if we have bit errors. Technically we could even
|
||||||
// constrain it individually to the 5 VCH sections.
|
// constrain it individually to the 5 VCH sections.
|
||||||
if(errors)
|
if (errors > 0U) {
|
||||||
{
|
|
||||||
// Scramble
|
// Scramble
|
||||||
for (unsigned int i = 0U; i < 13U; i++)
|
for (unsigned int i = 0U; i < 13U; i++)
|
||||||
vch[i] ^= WHITENING_DATA[i];
|
vch[i] ^= WHITENING_DATA[i];
|
||||||
|
|
||||||
// Interleave
|
// Interleave
|
||||||
for(unsigned int i = 0U; i < 104U; i++) {
|
for (unsigned int i = 0U; i < 104U; i++) {
|
||||||
unsigned int n = INTERLEAVE_TABLE_26_4[i];
|
unsigned int n = INTERLEAVE_TABLE_26_4[i];
|
||||||
bool s = READ_BIT1(vch, i);
|
bool s = READ_BIT1(vch, i);
|
||||||
WRITE_BIT1(data, offset+n, s);
|
WRITE_BIT1(data, offset + n, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogDebug("YSF, V/D Mode 2, Repetition FEC %u/135 (%.1f%%)", errors, float(errors) / 1.35F);
|
||||||
// "errors" is the number of triplets that were recognized to be corrupted
|
// "errors" is the number of triplets that were recognized to be corrupted
|
||||||
// and that were corrected. There are 27 of those per VCH and 5 VCH per CC,
|
// and that were corrected. There are 27 of those per VCH and 5 VCH per CC,
|
||||||
// yielding a total of 27*5 = 135. I believe the expected value of this
|
// yielding a total of 27*5 = 135. I believe the expected value of this
|
||||||
// error distribution to be Bin(1;3,BER)+Bin(2;3,BER) which entails 75% for
|
// error distribution to be Bin(1;3,BER)+Bin(2;3,BER) which entails 75% for
|
||||||
// BER = 0.5.
|
// BER = 0.5.
|
||||||
LogMessage("YSF, V/D Mode 2, Repetition FEC %u/135 (%.1f%%)", errors, float(errors) / 135.0F);
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CYSFPayload::processVDMode2Data(unsigned char* data, unsigned char fn)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned char dch[25U];
|
unsigned char dch[25U];
|
||||||
|
|
||||||
@@ -556,14 +450,14 @@ void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
|
|||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case 0U:
|
case 0U:
|
||||||
CUtils::dump("V/D Mode 2, Destination", output, 10U);
|
CUtils::dump(1U, "V/D Mode 2, Destination", output, 10U);
|
||||||
if (m_dest == NULL) {
|
if (m_dest == NULL) {
|
||||||
m_dest = new unsigned char[10U];
|
m_dest = new unsigned char[10U];
|
||||||
::memcpy(m_dest, output, 10U);
|
::memcpy(m_dest, output, 10U);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1U:
|
case 1U:
|
||||||
CUtils::dump("V/D Mode 2, Source", output, 10U);
|
CUtils::dump(1U, "V/D Mode 2, Source", output, 10U);
|
||||||
if (m_source == NULL) {
|
if (m_source == NULL) {
|
||||||
m_source = new unsigned char[10U];
|
m_source = new unsigned char[10U];
|
||||||
::memcpy(m_source, output, 10U);
|
::memcpy(m_source, output, 10U);
|
||||||
@@ -625,10 +519,16 @@ void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
|
|||||||
p1 += 18U; p2 += 5U;
|
p1 += 18U; p2 += 5U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret && (fn == 0U || fn == 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
|
bool CYSFPayload::processDataFRModeData(unsigned char* data, unsigned char fn)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
unsigned char dch[45U];
|
unsigned char dch[45U];
|
||||||
|
|
||||||
unsigned char* p1 = data;
|
unsigned char* p1 = data;
|
||||||
@@ -654,15 +554,15 @@ void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
|
|||||||
unsigned char output[23U];
|
unsigned char output[23U];
|
||||||
conv.chainback(output, 180U);
|
conv.chainback(output, 180U);
|
||||||
|
|
||||||
bool ret = CCRC::checkCCITT162(output, 22U);
|
bool ret1 = CCRC::checkCCITT162(output, 22U);
|
||||||
if (ret) {
|
if (ret1) {
|
||||||
for (unsigned int i = 0U; i < 20U; i++)
|
for (unsigned int i = 0U; i < 20U; i++)
|
||||||
output[i] ^= WHITENING_DATA[i];
|
output[i] ^= WHITENING_DATA[i];
|
||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case 0U:
|
case 0U:
|
||||||
CUtils::dump("Data FR Mode, Destination", output + 0U, 10U);
|
CUtils::dump(1U, "Data FR Mode, Destination", output + 0U, 10U);
|
||||||
CUtils::dump("Data FR Mode, Source", output + 10U, 10U);
|
CUtils::dump(1U, "Data FR Mode, Source", output + 10U, 10U);
|
||||||
|
|
||||||
if (m_dest == NULL) {
|
if (m_dest == NULL) {
|
||||||
m_dest = new unsigned char[10U];
|
m_dest = new unsigned char[10U];
|
||||||
@@ -735,7 +635,7 @@ void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
|
|||||||
|
|
||||||
conv.chainback(output, 180U);
|
conv.chainback(output, 180U);
|
||||||
|
|
||||||
ret = CCRC::checkCCITT162(output, 22U);
|
bool ret2 = CCRC::checkCCITT162(output, 22U);
|
||||||
|
|
||||||
if (fn == 0U) {
|
if (fn == 0U) {
|
||||||
::memset(output, ' ', 20U);
|
::memset(output, ' ', 20U);
|
||||||
@@ -746,11 +646,11 @@ void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
|
|||||||
if (m_uplink != NULL)
|
if (m_uplink != NULL)
|
||||||
::memcpy(output + 10U, m_uplink, 10U);
|
::memcpy(output + 10U, m_uplink, 10U);
|
||||||
|
|
||||||
ret = true;
|
ret2 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data isn't corrupt so regenerate it
|
// Data isn't corrupt so regenerate it
|
||||||
if (ret) {
|
if (ret2) {
|
||||||
for (unsigned int i = 0U; i < 20U; i++)
|
for (unsigned int i = 0U; i < 20U; i++)
|
||||||
output[i] ^= WHITENING_DATA[i];
|
output[i] ^= WHITENING_DATA[i];
|
||||||
|
|
||||||
@@ -784,19 +684,27 @@ void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
|
|||||||
p1 += 18U; p2 += 9U;
|
p1 += 18U; p2 += 9U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret1 && (fn == 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::processVoiceFRMode(unsigned char* data)
|
unsigned int CYSFPayload::processVoiceFRModeAudio(unsigned char* data)
|
||||||
{
|
{
|
||||||
// Regenerate the AMBE FEC
|
assert(data != NULL);
|
||||||
// unsigned int errors = 0U;
|
|
||||||
// errors += m_fec.regenerateYSF3(data + 0U);
|
|
||||||
// errors += m_fec.regenerateYSF3(data + 18U);
|
|
||||||
// errors += m_fec.regenerateYSF3(data + 36U);
|
|
||||||
// errors += m_fec.regenerateYSF3(data + 54U);
|
|
||||||
// errors += m_fec.regenerateYSF3(data + 72U);
|
|
||||||
|
|
||||||
// LogMessage("YSF, V Mode 3, AMBE FEC %u/720 (%.1f%%)", errors, float(errors) / 7.2F);
|
data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES;
|
||||||
|
|
||||||
|
// Regenerate the AMBE FEC
|
||||||
|
unsigned int errors = 0U;
|
||||||
|
errors += m_fec.regenerateYSF3(data + 0U);
|
||||||
|
errors += m_fec.regenerateYSF3(data + 18U);
|
||||||
|
errors += m_fec.regenerateYSF3(data + 36U);
|
||||||
|
errors += m_fec.regenerateYSF3(data + 54U);
|
||||||
|
errors += m_fec.regenerateYSF3(data + 72U);
|
||||||
|
|
||||||
|
LogDebug("YSF, V Mode 3, AMBE FEC %u/720 (%.1f%%)", errors, float(errors) / 7.2F);
|
||||||
|
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CYSFPayload::setUplink(const std::string& callsign)
|
void CYSFPayload::setUplink(const std::string& callsign)
|
||||||
|
|||||||
19
YSFPayload.h
19
YSFPayload.h
@@ -28,9 +28,17 @@ public:
|
|||||||
CYSFPayload();
|
CYSFPayload();
|
||||||
~CYSFPayload();
|
~CYSFPayload();
|
||||||
|
|
||||||
bool processHeader(unsigned char* bytes);
|
bool processHeaderData(unsigned char* bytes);
|
||||||
void processData(unsigned char* bytes, unsigned char fn, unsigned char dt);
|
|
||||||
void processTrailer(unsigned char* bytes);
|
bool processVDMode1Data(unsigned char* bytes, unsigned char fn);
|
||||||
|
unsigned int processVDMode1Audio(unsigned char* bytes);
|
||||||
|
|
||||||
|
bool processVDMode2Data(unsigned char* bytes, unsigned char fn);
|
||||||
|
unsigned int processVDMode2Audio(unsigned char* bytes);
|
||||||
|
|
||||||
|
bool processDataFRModeData(unsigned char* bytes, unsigned char fn);
|
||||||
|
|
||||||
|
unsigned int processVoiceFRModeAudio(unsigned char* bytes);
|
||||||
|
|
||||||
unsigned char* getSource();
|
unsigned char* getSource();
|
||||||
unsigned char* getDest();
|
unsigned char* getDest();
|
||||||
@@ -46,11 +54,6 @@ private:
|
|||||||
unsigned char* m_source;
|
unsigned char* m_source;
|
||||||
unsigned char* m_dest;
|
unsigned char* m_dest;
|
||||||
CAMBEFEC m_fec;
|
CAMBEFEC m_fec;
|
||||||
|
|
||||||
void processVDMode1(unsigned char* bytes, unsigned char fn);
|
|
||||||
void processVDMode2(unsigned char* bytes, unsigned char fn);
|
|
||||||
void processDataFRMode(unsigned char* bytes, unsigned char fn);
|
|
||||||
void processVoiceFRMode(unsigned char* bytes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user