First go at VW mode IMBE FEC.

This commit is contained in:
Jonathan Naylor
2016-04-19 07:45:49 +01:00
parent b560594cac
commit 38dc134982
5 changed files with 199 additions and 107 deletions

View File

@@ -17,6 +17,7 @@
*/ */
#include "Golay24128.h" #include "Golay24128.h"
#include "Hamming.h"
#include "AMBEFEC.h" #include "AMBEFEC.h"
#include <cstdio> #include <cstdio>
@@ -453,6 +454,15 @@ const unsigned int DSTAR_B_TABLE[] = {2U, 8U, 14U, 20U, 26U, 32U, 38U, 44U, 50U
const unsigned int DSTAR_C_TABLE[] = {4U, 10U, 16U, 22U, 28U, 34U, 40U, 46U, 52U, 58U, 64U, 70U, const unsigned int DSTAR_C_TABLE[] = {4U, 10U, 16U, 22U, 28U, 34U, 40U, 46U, 52U, 58U, 64U, 70U,
5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 59U, 65U, 71U}; 5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 59U, 65U, 71U};
const unsigned int IMBE_INTERLEAVE[] = {
0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, 72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, 139,
1, 6, 13, 18, 25, 30, 37, 42, 49, 54, 61, 66, 73, 78, 85, 90, 97, 102, 109, 114, 121, 126, 133, 138,
2, 9, 14, 21, 26, 33, 38, 45, 50, 57, 62, 69, 74, 81, 86, 93, 98, 105, 110, 117, 122, 129, 134, 141,
3, 8, 15, 20, 27, 32, 39, 44, 51, 56, 63, 68, 75, 80, 87, 92, 99, 104, 111, 116, 123, 128, 135, 140,
4, 11, 16, 23, 28, 35, 40, 47, 52, 59, 64, 71, 76, 83, 88, 95, 100, 107, 112, 119, 124, 131, 136, 143,
5, 10, 17, 22, 29, 34, 41, 46, 53, 58, 65, 70, 77, 82, 89, 94, 101, 106, 113, 118, 125, 130, 137, 142
};
CAMBEFEC::CAMBEFEC() CAMBEFEC::CAMBEFEC()
{ {
} }
@@ -583,50 +593,132 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned char* bytes) const
return errors; return errors;
} }
unsigned int CAMBEFEC::regenerateYSF1(unsigned char* bytes) const unsigned int CAMBEFEC::regenerateYSF3(unsigned char* bytes) const
{ {
assert(bytes != NULL); assert(bytes != NULL);
unsigned int errors = 0U; bool temp[144U];
unsigned int offset = 72U;
for (unsigned int j = 0U; j < 5U; j++, offset += 144U) {
unsigned int a = 0U;
unsigned int b = 0U;
unsigned int c = 0U;
unsigned int MASK = 0x800000U; // De-interleave
for (unsigned int i = 0U; i < 24U; i++) { for (unsigned int i = 0U; i < 144U; i++) {
unsigned int aPos = DMR_A_TABLE[i] + offset; unsigned int n = IMBE_INTERLEAVE[i];
unsigned int bPos = DMR_B_TABLE[i] + offset; temp[i] = READ_BIT(bytes, n);
unsigned int cPos = DMR_C_TABLE[i] + offset;
if (READ_BIT(bytes, aPos))
a |= MASK;
if (READ_BIT(bytes, bPos))
b |= MASK;
if (READ_BIT(bytes, cPos))
c |= MASK;
MASK >>= 1;
}
errors += regenerate(a, b, c, true);
MASK = 0x800000U;
for (unsigned int i = 0U; i < 24U; i++) {
unsigned int aPos = DMR_A_TABLE[i] + offset;
unsigned int bPos = DMR_B_TABLE[i] + offset;
unsigned int cPos = DMR_C_TABLE[i] + offset;
WRITE_BIT(bytes, aPos, a & MASK);
WRITE_BIT(bytes, bPos, b & MASK);
WRITE_BIT(bytes, cPos, c & MASK);
MASK >>= 1;
}
} }
return errors; // now ..
// 12 voice bits 0
// 11 golay bits 12
//
// 12 voice bits 23
// 11 golay bits 35
//
// 12 voice bits 46
// 11 golay bits 58
//
// 12 voice bits 69
// 11 golay bits 81
//
// 11 voice bits 92
// 4 hamming bits 103
//
// 11 voice bits 107
// 4 hamming bits 118
//
// 11 voice bits 122
// 4 hamming bits 133
//
// 7 voice bits 137
// De-Whiten some bits
unsigned int prn = 0x00U;
for (int i = 0U; i < 12U; i++)
prn = (prn << 1) | (temp[i] & 1);
prn <<= 4;
for (unsigned int i = 23U; i < 137U; i++) {
prn = (unsigned short)((173 * prn) + 13849);
temp[i] ^= (prn >> 15) & 1;
}
// Check/Fix FEC
bool* bit = temp;
// c0
unsigned int g1 = 0U;
for (unsigned int i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] & 1);
unsigned int g3 = CGolay24128::decode23127(g1);
unsigned int g2 = CGolay24128::encode23127(g3);
for (int i = 23; i >= 0; i--) {
bit[i] = g2 & 1;
g2 >>= 1;
}
bit += 23U;
// c1
g1 = 0U;
for (unsigned int i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] & 1);
g3 = CGolay24128::decode23127(g1);
g2 = CGolay24128::encode23127(g3);
for (int i = 23; i >= 0; i--) {
bit[i] = g2 & 1;
g2 >>= 1;
}
bit += 23U;
// c2
g1 = 0;
for (int i = 0; i < 23; i++)
g1 = (g1 << 1) | (bit[i] & 1);
g3 = CGolay24128::decode23127(g1);
g2 = CGolay24128::encode23127(g3);
for (int i = 23; i >= 0; i--) {
bit[i] = g2 & 1;
g2 >>= 1;
}
bit += 23U;
// c3
g1 = 0U;
for (int i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] & 1);
g3 = CGolay24128::decode23127(g1);
g2 = CGolay24128::encode23127(g3);
for (int i = 23; i >= 0; i--) {
bit[i] = g2 & 1;
g2 >>= 1;
}
bit += 23U;
// c4
CHamming::decode15113_1(bit);
bit += 15U;
// c5
CHamming::decode15113_1(bit);
bit += 15U;
// c6
CHamming::decode15113_1(bit);
// Whiten some bits
prn = 0x00U;
for (unsigned int i = 0U; i < 12U; i++)
prn = (prn << 1) | (temp[i] & 1);
prn <<= 4;
for (unsigned int i = 23U; i < 137U; i++) {
prn = (unsigned short)((173 * prn) + 13849);
temp[i] ^= (prn >> 15) & 1;
}
// Interleave
for (unsigned int i = 0U; i < 144U; i++) {
unsigned int n = IMBE_INTERLEAVE[i];
WRITE_BIT(bytes, n, temp[i]);
}
return 0U;
} }
unsigned int CAMBEFEC::regenerate(unsigned int& a, unsigned int& b, unsigned int& c, bool b23) const unsigned int CAMBEFEC::regenerate(unsigned int& a, unsigned int& b, unsigned int& c, bool b23) const

View File

@@ -28,7 +28,7 @@ public:
unsigned int regenerateDStar(unsigned char* bytes) const; unsigned int regenerateDStar(unsigned char* bytes) const;
unsigned int regenerateYSF1(unsigned char* bytes) const; unsigned int regenerateYSF3(unsigned char* bytes) const;
private: private:
unsigned int regenerate(unsigned int& a, unsigned int& b, unsigned int& c, bool b23) const; unsigned int regenerate(unsigned int& a, unsigned int& b, unsigned int& c, bool b23) const;

View File

@@ -108,8 +108,7 @@ bool CYSFControl::writeModem(unsigned char *data)
LogMessage("YSF, EOT, FI=%X FN=%u FT=%u DT=%X", fi, fn, ft, dt); LogMessage("YSF, EOT, FI=%X FN=%u FT=%u DT=%X", fi, fn, ft, dt);
m_payload.decode(data + 2U, fi, fn, ft, dt); m_payload.process(data + 2U, fi, fn, ft, dt);
// m_payload.encode(data + 2U); XXX
m_frames++; m_frames++;
@@ -150,14 +149,19 @@ bool CYSFControl::writeModem(unsigned char *data)
LogMessage("YSF, Valid FICH, FI=%X FN=%u FT=%u DT=%X", fi, fn, ft, dt); LogMessage("YSF, Valid FICH, FI=%X FN=%u FT=%u DT=%X", fi, fn, ft, dt);
m_payload.decode(data + 2U, fi, fn, ft, dt); m_payload.process(data + 2U, fi, fn, ft, dt);
// payload.encode(data + 2U); XXX
bool change = false; bool change = false;
if (cm == 0x00U && m_dest == NULL) { if (m_dest == NULL) {
m_dest = (unsigned char*)"CQCQCQ "; if (cm == YSF_CM_GROUP) {
change = true; m_dest = (unsigned char*)"CQCQCQ ";
change = true;
} else {
m_dest = m_payload.getDest();
if (m_dest != NULL)
change = true;
}
} }
if (m_source == NULL) { if (m_source == NULL) {
@@ -166,12 +170,6 @@ bool CYSFControl::writeModem(unsigned char *data)
change = true; change = true;
} }
if (m_dest == NULL) {
m_dest = m_payload.getDest();
if (m_dest != NULL)
change = true;
}
if (change) { if (change) {
if (m_source != NULL && m_dest != NULL) { if (m_source != NULL && m_dest != NULL) {
m_display->writeFusion((char*)m_source, (char*)m_dest); m_display->writeFusion((char*)m_source, (char*)m_dest);
@@ -188,7 +186,7 @@ bool CYSFControl::writeModem(unsigned char *data)
} }
} else { } else {
// Reconstruct FICH based on the last valid frame // Reconstruct FICH based on the last valid frame
m_fich.setFI(0x01U); // Communication channel m_fich.setFI(YSF_FI_COMMUNICATIONS); // Communication channel
} }
m_frames++; m_frames++;

View File

@@ -75,70 +75,56 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) #define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CYSFPayload::CYSFPayload() : CYSFPayload::CYSFPayload() :
m_data(NULL),
m_uplink(NULL), m_uplink(NULL),
m_downlink(NULL), m_downlink(NULL),
m_source(NULL), m_source(NULL),
m_dest(NULL), m_dest(NULL),
m_fec() m_fec()
{ {
m_data = new unsigned char[90U];
} }
CYSFPayload::~CYSFPayload() CYSFPayload::~CYSFPayload()
{ {
delete[] m_data;
delete[] m_uplink; delete[] m_uplink;
delete[] m_downlink; delete[] m_downlink;
delete[] m_source; delete[] m_source;
delete[] m_dest; delete[] m_dest;
} }
void CYSFPayload::decode(const unsigned char* bytes, unsigned char fi, unsigned char fn, unsigned char ft, unsigned char dt) void CYSFPayload::process(unsigned char* bytes, unsigned char fi, unsigned char fn, unsigned char ft, unsigned char dt)
{ {
assert(bytes != NULL); assert(bytes != NULL);
::memcpy(m_data, bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, 90U);
// Header and trailer // Header and trailer
if (fi == 0U || fi == 2U) { if (fi == 0U || fi == 2U) {
decodeHeader(); processHeader(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
return; return;
} }
// V/D Mode 1 switch (dt) {
if (dt == 0U) { case YSF_DT_VD_MODE1:
decodeVDMode1(fn); processVDMode1(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
return; break;
}
// V/D Mode 2 case YSF_DT_VD_MODE2:
if (dt == 2U) { processVDMode2(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
decodeVDMode2(fn); break;
return;
}
// Data FR Mode case YSF_DT_DATA_FR_MODE:
if (dt == 1U) { processDataFRMode(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, fn);
decodeDataFRMode(fn); break;
return;
}
// Voice FR Mode default: // YSF_DT_VOICE_FR_MODE
processVoiceFRMode(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES);
break;
}
} }
void CYSFPayload::encode(unsigned char* bytes) void CYSFPayload::processHeader(unsigned char* data)
{
assert(bytes != NULL);
::memcpy(bytes + YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES, m_data, 90U);
}
void CYSFPayload::decodeHeader()
{ {
unsigned char dch[45U]; unsigned char dch[45U];
unsigned char* p1 = m_data; unsigned char* p1 = data;
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p2, p1, 9U); ::memcpy(p2, p1, 9U);
@@ -205,7 +191,7 @@ void CYSFPayload::decodeHeader()
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data; p1 = data;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 9U); ::memcpy(p1, p2, 9U);
@@ -244,7 +230,7 @@ void CYSFPayload::decodeHeader()
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data + 9U; p1 = data + 9U;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 9U); ::memcpy(p1, p2, 9U);
@@ -252,16 +238,21 @@ void CYSFPayload::decodeHeader()
} }
} }
void CYSFPayload::decodeVDMode1(unsigned char fn) void CYSFPayload::processVDMode1(unsigned char* data, unsigned char fn)
{ {
// Regenerate the AMBE FEC // Regenerate the AMBE FEC
unsigned int errors = m_fec.regenerateYSF1(m_data); 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) / 235.0F); LogMessage("YSF, V/D Mode 1, AMBE FEC %u/235 (%.1f%%)", errors, float(errors) / 235.0F);
unsigned char dch[45U]; unsigned char dch[45U];
unsigned char* p1 = m_data; unsigned char* p1 = data;
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p2, p1, 9U); ::memcpy(p2, p1, 9U);
@@ -356,7 +347,7 @@ void CYSFPayload::decodeVDMode1(unsigned char fn)
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data; p1 = data;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 9U); ::memcpy(p1, p2, 9U);
@@ -365,11 +356,11 @@ void CYSFPayload::decodeVDMode1(unsigned char fn)
} }
} }
void CYSFPayload::decodeVDMode2(unsigned char fn) void CYSFPayload::processVDMode2(unsigned char* data, unsigned char fn)
{ {
unsigned char dch[25U]; unsigned char dch[25U];
unsigned char* p1 = m_data; unsigned char* p1 = data;
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p2, p1, 5U); ::memcpy(p2, p1, 5U);
@@ -467,7 +458,7 @@ void CYSFPayload::decodeVDMode2(unsigned char fn)
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data; p1 = data;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 5U); ::memcpy(p1, p2, 5U);
@@ -476,11 +467,11 @@ void CYSFPayload::decodeVDMode2(unsigned char fn)
} }
} }
void CYSFPayload::decodeDataFRMode(unsigned char fn) void CYSFPayload::processDataFRMode(unsigned char* data, unsigned char fn)
{ {
unsigned char dch[45U]; unsigned char dch[45U];
unsigned char* p1 = m_data; unsigned char* p1 = data;
unsigned char* p2 = dch; unsigned char* p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p2, p1, 9U); ::memcpy(p2, p1, 9U);
@@ -559,7 +550,7 @@ void CYSFPayload::decodeDataFRMode(unsigned char fn)
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data; p1 = data;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 9U); ::memcpy(p1, p2, 9U);
@@ -567,7 +558,7 @@ void CYSFPayload::decodeDataFRMode(unsigned char fn)
} }
} }
p1 = m_data + 9U; p1 = data + 9U;
p2 = dch; p2 = dch;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p2, p1, 9U); ::memcpy(p2, p1, 9U);
@@ -630,7 +621,7 @@ void CYSFPayload::decodeDataFRMode(unsigned char fn)
WRITE_BIT1(bytes, n, s1); WRITE_BIT1(bytes, n, s1);
} }
p1 = m_data + 9U; p1 = data + 9U;
p2 = bytes; p2 = bytes;
for (unsigned int i = 0U; i < 5U; i++) { for (unsigned int i = 0U; i < 5U; i++) {
::memcpy(p1, p2, 9U); ::memcpy(p1, p2, 9U);
@@ -639,6 +630,19 @@ void CYSFPayload::decodeDataFRMode(unsigned char fn)
} }
} }
void CYSFPayload::processVoiceFRMode(unsigned char* data)
{
// 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);
LogMessage("YSF, V Mode 3, AMBE FEC %u/720 (%.1f%%)", errors, float(errors) / 720.0F);
}
void CYSFPayload::setUplink(const std::string& callsign) void CYSFPayload::setUplink(const std::string& callsign)
{ {
m_uplink = new unsigned char[10U]; m_uplink = new unsigned char[10U];

View File

@@ -28,9 +28,7 @@ public:
CYSFPayload(); CYSFPayload();
~CYSFPayload(); ~CYSFPayload();
void decode(const unsigned char* bytes, unsigned char fi, unsigned char fn, unsigned char ft, unsigned char dt); void process(unsigned char* bytes, unsigned char fi, unsigned char fn, unsigned char ft, unsigned char dt);
void encode(unsigned char* bytes);
unsigned char* getSource(); unsigned char* getSource();
unsigned char* getDest(); unsigned char* getDest();
@@ -41,17 +39,17 @@ public:
void reset(); void reset();
private: private:
unsigned char* m_data;
unsigned char* m_uplink; unsigned char* m_uplink;
unsigned char* m_downlink; unsigned char* m_downlink;
unsigned char* m_source; unsigned char* m_source;
unsigned char* m_dest; unsigned char* m_dest;
CAMBEFEC m_fec; CAMBEFEC m_fec;
void decodeHeader(); void processHeader(unsigned char* bytes);
void decodeVDMode1(unsigned char fn); void processVDMode1(unsigned char* bytes, unsigned char fn);
void decodeVDMode2(unsigned char fn); void processVDMode2(unsigned char* bytes, unsigned char fn);
void decodeDataFRMode(unsigned char fn); void processDataFRMode(unsigned char* bytes, unsigned char fn);
void processVoiceFRMode(unsigned char* bytes);
}; };
#endif #endif