From d2ae736764ff6b0852d5d64e0e5d185e9055e7ca Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Mon, 29 Jan 2018 23:03:40 +0200 Subject: [PATCH 01/12] fix: ArduiPi_OLED wants -li2c /usr/local/lib/libArduiPi_OLED.so: undefined reference to `i2c_smbus_write_i2c_block_data' /usr/local/lib/libArduiPi_OLED.so: undefined reference to `i2c_smbus_write_word_data' /usr/local/lib/libArduiPi_OLED.so: undefined reference to `i2c_smbus_write_byte_data' collect2: error: ld returned 1 exit status --- Makefile.Pi.OLED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 1845bc2..4cf1b2e 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -3,7 +3,7 @@ CC = gcc CXX = g++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include -LIBS = -lArduiPi_OLED -lpthread +LIBS = -lArduiPi_OLED -li2c -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ From 6d3973d413644397207026e40df300c0f61fbf56 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jan 2018 21:41:14 +0000 Subject: [PATCH 02/12] Add the detailed processing for the FACCH1 and UDCH. --- NXDNFACCH1.cpp | 111 ++++++++++++++++++++++++++++++++++++++++-- NXDNFACCH1.h | 5 +- NXDNSACCH.cpp | 10 ++-- NXDNUDCH.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 242 insertions(+), 12 deletions(-) diff --git a/NXDNFACCH1.cpp b/NXDNFACCH1.cpp index f548a8d..d0c1aba 100644 --- a/NXDNFACCH1.cpp +++ b/NXDNFACCH1.cpp @@ -28,6 +28,22 @@ #include #include +const unsigned int INTERLEAVE_TABLE[] = { + 0U, 9U, 18U, 27U, 36U, 45U, 54U, 63U, 72U, 81U, 90U, 99U, 108U, 117U, 126U, 135U, + 1U, 10U, 19U, 28U, 37U, 46U, 55U, 64U, 73U, 82U, 91U, 100U, 109U, 118U, 127U, 136U, + 2U, 11U, 20U, 29U, 38U, 47U, 56U, 65U, 74U, 83U, 92U, 101U, 110U, 119U, 128U, 137U, + 3U, 12U, 21U, 30U, 39U, 48U, 57U, 66U, 75U, 84U, 93U, 102U, 111U, 120U, 129U, 138U, + 4U, 13U, 22U, 31U, 40U, 49U, 58U, 67U, 76U, 85U, 94U, 103U, 112U, 121U, 130U, 139U, + 5U, 14U, 23U, 32U, 41U, 50U, 59U, 68U, 77U, 86U, 95U, 104U, 113U, 122U, 131U, 140U, + 6U, 15U, 24U, 33U, 42U, 51U, 60U, 69U, 78U, 87U, 96U, 105U, 114U, 123U, 132U, 141U, + 7U, 16U, 25U, 34U, 43U, 52U, 61U, 70U, 79U, 88U, 97U, 106U, 115U, 124U, 133U, 142U, + 8U, 17U, 26U, 35U, 44U, 53U, 62U, 71U, 80U, 89U, 98U, 107U, 116U, 125U, 134U, 143U }; + +const unsigned int PUNCTURE_LIST[] = { 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U, + 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U, + 81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U, + 121U, 125U, 129U, 133U, 137U, 141U}; + const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; #define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) @@ -51,16 +67,105 @@ CNXDNFACCH1::~CNXDNFACCH1() delete[] m_data; } -bool CNXDNFACCH1::decode(const unsigned char* data) +bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) { assert(data != NULL); - return true; + CUtils::dump("NXDN, FACCH1 input", data, 18U); + + unsigned char temp1[18U]; + + for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + unsigned int n = INTERLEAVE_TABLE[i] + offset; + bool b = READ_BIT1(data, n); + WRITE_BIT1(temp1, i, b); + } + + CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U); + + uint8_t temp2[192U]; + + char text[500U]; + ::strcpy(text, "NXDN, FACCH1 de-punctured: "); + + unsigned int n = 0U; + unsigned int index = 0U; + for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + if (n == PUNCTURE_LIST[index]) { + ::strcat(text, "X, "); + temp2[n++] = 99U; + index++; + } + + bool b = READ_BIT1(temp1, i); + temp2[n++] = b ? 1U : 0U; + ::strcat(text, b ? "1, " : "0, "); + } + + LogMessage(text); + + CNXDNConvolution conv; + conv.start(); + + n = 0U; + for (unsigned int i = 0U; i < 96U; i++) { + uint8_t s0 = temp2[n++]; + uint8_t s1 = temp2[n++]; + + conv.decode(s0, s1); + } + + conv.chainback(m_data, 92U); + + CUtils::dump("NXDN, FACCH1 decoded", m_data, 12U); + + return CNXDNCRC::checkCRC12(m_data, 80U); } -void CNXDNFACCH1::encode(unsigned char* data) const +void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const { assert(data != NULL); + + unsigned char temp1[12U]; + ::memset(temp1, 0x00U, 12U); + + for (unsigned int i = 0U; i < 80U; i++) { + bool b = READ_BIT1(m_data, i); + WRITE_BIT1(temp1, i, b); + } + + CNXDNCRC::encodeCRC12(temp1, 80U); + + CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U); + + unsigned char temp2[24U]; + + CNXDNConvolution conv; + conv.encode(temp1, temp2, 96U); + + CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U); + + unsigned char temp3[18U]; + + unsigned int n = 0U; + unsigned int index = 0U; + for (unsigned int i = 0U; i < 192U; i++) { + if (i != PUNCTURE_LIST[index]) { + bool b = READ_BIT1(temp2, i); + WRITE_BIT1(temp3, n, b); + n++; + } else { + index++; + } + } + + CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U); + + for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { + unsigned int n = INTERLEAVE_TABLE[i] + offset; + bool b = READ_BIT1(temp3, i); + WRITE_BIT1(data, n, b); + } } void CNXDNFACCH1::getData(unsigned char* data) const diff --git a/NXDNFACCH1.h b/NXDNFACCH1.h index 3c9c664..adb4112 100644 --- a/NXDNFACCH1.h +++ b/NXDNFACCH1.h @@ -25,9 +25,10 @@ public: CNXDNFACCH1(); ~CNXDNFACCH1(); - bool decode(const unsigned char* data); + bool decode(const unsigned char* data, unsigned int offset); + + void encode(unsigned char* data, unsigned int offset) const; - void encode(unsigned char* data) const; void getData(unsigned char* data) const; void setData(const unsigned char* data); diff --git a/NXDNSACCH.cpp b/NXDNSACCH.cpp index 262cde2..803e702 100755 --- a/NXDNSACCH.cpp +++ b/NXDNSACCH.cpp @@ -111,7 +111,7 @@ bool CNXDNSACCH::decode(const unsigned char* data) conv.chainback(m_data, 32U); - CUtils::dump("NXDN, SACCH decoded", m_data, 5U); + CUtils::dump("NXDN, SACCH decoded", m_data, 4U); return CNXDNCRC::checkCRC6(m_data, 26U); } @@ -130,14 +130,14 @@ void CNXDNSACCH::encode(unsigned char* data) const CNXDNCRC::encodeCRC6(temp1, 26U); - CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 5U); + CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 4U); - unsigned char temp2[9U]; + unsigned char temp2[8U]; CNXDNConvolution conv; conv.encode(temp1, temp2, 36U); - CUtils::dump("NXDN, SACCH convolved", temp2, 9U); + CUtils::dump("NXDN, SACCH convolved", temp2, 8U); unsigned char temp3[8U]; @@ -160,8 +160,6 @@ void CNXDNSACCH::encode(unsigned char* data) const bool b = READ_BIT1(temp3, i); WRITE_BIT1(data, n, b); } - - CUtils::dump("NXDN, SACCH re-encoded", data, 12U); } unsigned char CNXDNSACCH::getRAN() const diff --git a/NXDNUDCH.cpp b/NXDNUDCH.cpp index 1d194b9..4c1d707 100644 --- a/NXDNUDCH.cpp +++ b/NXDNUDCH.cpp @@ -28,6 +28,43 @@ #include #include +const unsigned int INTERLEAVE_TABLE[] = { + 0U, 29U, 58U, 87U, 116U, 145U, 174U, 203U, 232U, 261U, 290U, 319U, + 1U, 30U, 59U, 88U, 117U, 146U, 175U, 204U, 233U, 262U, 291U, 320U, + 2U, 31U, 60U, 89U, 118U, 147U, 176U, 205U, 234U, 263U, 292U, 321U, + 3U, 32U, 61U, 90U, 119U, 148U, 177U, 206U, 235U, 264U, 293U, 322U, + 4U, 33U, 62U, 91U, 120U, 149U, 178U, 207U, 236U, 265U, 294U, 323U, + 5U, 34U, 63U, 92U, 121U, 150U, 179U, 208U, 237U, 266U, 295U, 324U, + 6U, 35U, 64U, 93U, 122U, 151U, 180U, 209U, 238U, 267U, 296U, 325U, + 7U, 36U, 65U, 94U, 123U, 152U, 181U, 210U, 239U, 268U, 297U, 326U, + 8U, 37U, 66U, 95U, 124U, 153U, 182U, 211U, 240U, 269U, 298U, 327U, + 9U, 38U, 67U, 96U, 125U, 154U, 183U, 212U, 241U, 270U, 299U, 328U, + 10U, 39U, 68U, 97U, 126U, 155U, 184U, 213U, 242U, 271U, 300U, 329U, + 11U, 40U, 69U, 98U, 127U, 156U, 185U, 214U, 243U, 272U, 301U, 330U, + 12U, 41U, 70U, 99U, 128U, 157U, 186U, 215U, 244U, 273U, 302U, 331U, + 13U, 42U, 71U, 100U, 129U, 158U, 187U, 216U, 245U, 274U, 303U, 332U, + 14U, 43U, 72U, 101U, 130U, 159U, 188U, 217U, 246U, 275U, 304U, 333U, + 15U, 44U, 73U, 102U, 131U, 160U, 189U, 218U, 247U, 276U, 305U, 334U, + 16U, 45U, 74U, 103U, 132U, 161U, 190U, 219U, 248U, 277U, 306U, 335U, + 17U, 46U, 75U, 104U, 133U, 162U, 191U, 220U, 249U, 278U, 307U, 336U, + 18U, 47U, 76U, 105U, 134U, 163U, 192U, 221U, 250U, 279U, 308U, 337U, + 19U, 48U, 77U, 106U, 135U, 164U, 193U, 222U, 251U, 280U, 309U, 338U, + 20U, 49U, 78U, 107U, 136U, 165U, 194U, 223U, 252U, 281U, 310U, 339U, + 21U, 50U, 79U, 108U, 137U, 166U, 195U, 224U, 253U, 282U, 311U, 340U, + 22U, 51U, 80U, 109U, 138U, 167U, 196U, 225U, 254U, 283U, 312U, 341U, + 23U, 52U, 81U, 110U, 139U, 168U, 197U, 226U, 255U, 284U, 313U, 342U, + 24U, 53U, 82U, 111U, 140U, 169U, 198U, 227U, 256U, 285U, 314U, 343U, + 25U, 54U, 83U, 112U, 141U, 170U, 199U, 228U, 257U, 286U, 315U, 344U, + 26U, 55U, 84U, 113U, 142U, 171U, 200U, 229U, 258U, 287U, 316U, 345U, + 27U, 56U, 85U, 114U, 143U, 172U, 201U, 230U, 259U, 288U, 317U, 346U, + 28U, 57U, 86U, 115U, 144U, 173U, 202U, 231U, 260U, 289U, 318U, 347U }; + +const unsigned int PUNCTURE_LIST[] = { 3U, 11U, 17U, 25U, 31U, 39U, 45U, 53U, 59U, 67U, + 73U, 81U, 87U, 95U, 101U, 109U, 115U, 123U, 129U, 137U, + 143U, 151U, 157U, 165U, 171U, 179U, 185U, 193U, 199U, 207U, + 213U, 221U, 227U, 235U, 241U, 249U, 255U, 263U, 269U, 277U, + 283U, 291U, 297U, 305U, 311U, 319U, 325U, 333U, 339U, 347U }; + const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; #define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) @@ -55,12 +92,101 @@ bool CNXDNUDCH::decode(const unsigned char* data) { assert(data != NULL); - return true; + CUtils::dump("NXDN, UDCH/FACCH2 input", data, 44U); + + unsigned char temp1[44U]; + + for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; + bool b = READ_BIT1(data, n); + WRITE_BIT1(temp1, i, b); + } + + CUtils::dump("NXDN, UDCH/FACCH2 de-interleaved", temp1, 44U); + + uint8_t temp2[406U]; + + char text[500U]; + ::strcpy(text, "NXDN, UDCH/FACCH2 de-punctured: "); + + unsigned int n = 0U; + unsigned int index = 0U; + for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + if (n == PUNCTURE_LIST[index]) { + ::strcat(text, "X, "); + temp2[n++] = 99U; + index++; + } + + bool b = READ_BIT1(temp1, i); + temp2[n++] = b ? 1U : 0U; + ::strcat(text, b ? "1, " : "0, "); + } + + LogMessage(text); + + CNXDNConvolution conv; + conv.start(); + + n = 0U; + for (unsigned int i = 0U; i < 203U; i++) { + uint8_t s0 = temp2[n++]; + uint8_t s1 = temp2[n++]; + + conv.decode(s0, s1); + } + + conv.chainback(m_data, 199U); + + CUtils::dump("NXDN, UDCH/FACCH2 decoded", m_data, 25U); + + return CNXDNCRC::checkCRC15(m_data, 184U); } void CNXDNUDCH::encode(unsigned char* data) const { assert(data != NULL); + + unsigned char temp1[25U]; + ::memset(temp1, 0x00U, 25U); + + for (unsigned int i = 0U; i < 184U; i++) { + bool b = READ_BIT1(m_data, i); + WRITE_BIT1(temp1, i, b); + } + + CNXDNCRC::encodeCRC15(temp1, 184U); + + CUtils::dump("NXDN, UDCH/FACCH2 encoded with CRC", temp1, 25U); + + unsigned char temp2[51U]; + + CNXDNConvolution conv; + conv.encode(temp1, temp2, 203U); + + CUtils::dump("NXDN, UDCH/FACCH2 convolved", temp2, 51U); + + unsigned char temp3[44U]; + + unsigned int n = 0U; + unsigned int index = 0U; + for (unsigned int i = 0U; i < 406U; i++) { + if (i != PUNCTURE_LIST[index]) { + bool b = READ_BIT1(temp2, i); + WRITE_BIT1(temp3, n, b); + n++; + } else { + index++; + } + } + + CUtils::dump("NXDN, UDCH/FACCH2 punctured", temp3, 44U); + + for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { + unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS; + bool b = READ_BIT1(temp3, i); + WRITE_BIT1(data, n, b); + } } void CNXDNUDCH::getData(unsigned char* data) const From b694f85461e789f98cff5a65fd32176da3e3e1ab Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jan 2018 23:08:48 +0000 Subject: [PATCH 03/12] Remove quotes from config values if found. --- Conf.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Conf.cpp b/Conf.cpp index dd12307..5afec64 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -273,7 +273,14 @@ bool CConf::read() char* value = ::strtok(NULL, "\r\n"); if (value == NULL) continue; - + + // Remove quotes from the value + size_t len = ::strlen(value); + if (len > 1U && *value == '"' && value[len - 1U] == '"') { + value[len - 1U] = '\0'; + value++; + } + if (section == SECTION_GENERAL) { if (::strcmp(key, "Callsign") == 0) { // Convert the callsign to upper case From 7e22cdfa7eadba98e7cab524bc22beebc6915a6e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 29 Jan 2018 23:32:44 +0000 Subject: [PATCH 04/12] Add more sophistication to the network side of NXDN. --- NXDNControl.cpp | 2 +- NXDNNetwork.cpp | 40 +++++++++++++++++++++++++++++----------- NXDNNetwork.h | 4 ++-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/NXDNControl.cpp b/NXDNControl.cpp index fd0809f..4aef87c 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -983,7 +983,7 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count) if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; - m_network->write(data + 2U, count, data[0U] == TAG_EOT); + // m_network->write(data + 2U, count, data[0U] == TAG_EOT); } void CNXDNControl::scrambler(unsigned char* data) const diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp index 5476766..8d3ee92 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -56,11 +56,11 @@ bool CNXDNNetwork::open() return m_socket.open(); } -bool CNXDNNetwork::write(const unsigned char* data, unsigned int count, bool end) +bool CNXDNNetwork::write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned int cnt, bool end) { assert(data != NULL); - unsigned char buffer[200U]; + unsigned char buffer[100U]; buffer[0U] = 'N'; buffer[1U] = 'X'; @@ -68,15 +68,23 @@ bool CNXDNNetwork::write(const unsigned char* data, unsigned int count, bool end buffer[3U] = 'N'; buffer[4U] = 'D'; - buffer[5U] = end ? 0x01U : 0x00U; - buffer[5U] |= (count & 0x7FU) << 1; + buffer[5U] = (src >> 8) & 0xFFU; + buffer[6U] = (src >> 8) & 0xFFU; - ::memcpy(buffer + 6U, data, NXDN_FRAME_LENGTH_BYTES); + buffer[7U] = grp ? 0x01U : 0x00U; + + buffer[8U] = (dst >> 8) & 0xFFU; + buffer[9U] = (dst >> 8) & 0xFFU; + + buffer[10U] = end ? 0x80U : 0x00U; + buffer[10U] |= (cnt & 0x7FU) << 1; + + ::memcpy(buffer + 11U, data, NXDN_FRAME_LENGTH_BYTES); if (m_debug) - CUtils::dump(1U, "NXDN Network Data Sent", buffer, 54U); + CUtils::dump(1U, "NXDN Network Data Sent", buffer, 59U); - return m_socket.write(buffer, 54U, m_address, m_port); + return m_socket.write(buffer, 59U, m_address, m_port); } bool CNXDNNetwork::writePoll() @@ -131,19 +139,29 @@ void CNXDNNetwork::clock(unsigned int ms) if (m_debug) CUtils::dump(1U, "NXDN Network Data Received", buffer, length); - m_buffer.addData(buffer, 54U); + m_buffer.addData(buffer, 59U); } -unsigned int CNXDNNetwork::read(unsigned char* data) +unsigned int CNXDNNetwork::read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned int& cnt, bool& end) { assert(data != NULL); if (m_buffer.isEmpty()) return 0U; - m_buffer.getData(data, 54U); + unsigned char buffer[100U]; + m_buffer.getData(buffer, 59U); - return 155U; + src = (buffer[5U] << 8) + buffer[6U]; + grp = (buffer[7U] & 0x01U) == 0x01U; + dst = (buffer[8U] << 8) + buffer[9U]; + + end = (buffer[10U] & 0x80U) == 0x80U; + cnt = buffer[10U] & 0x7FU; + + ::memcpy(data, buffer + 11U, NXDN_FRAME_LENGTH_BYTES); + + return NXDN_FRAME_LENGTH_BYTES; } void CNXDNNetwork::reset() diff --git a/NXDNNetwork.h b/NXDNNetwork.h index ea96826..15f59f4 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -36,9 +36,9 @@ public: void enable(bool enabled); - bool write(const unsigned char* data, unsigned int count, bool end); + bool write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned int cnt, bool end); - unsigned int read(unsigned char* data); + unsigned int read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned int& cnt, bool& end); void reset(); From a2b1b965ede12ca384355cb51cf570629cd8c331 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jan 2018 07:50:55 +0000 Subject: [PATCH 05/12] Increase the Viterbit decision size for the larger messages. --- NXDNConvolution.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NXDNConvolution.cpp b/NXDNConvolution.cpp index 2881412..049bdb6 100755 --- a/NXDNConvolution.cpp +++ b/NXDNConvolution.cpp @@ -45,7 +45,7 @@ m_dp(NULL) { m_metrics1 = new uint16_t[16U]; m_metrics2 = new uint16_t[16U]; - m_decisions = new uint64_t[180U]; + m_decisions = new uint64_t[300U]; } CNXDNConvolution::~CNXDNConvolution() @@ -98,7 +98,7 @@ void CNXDNConvolution::decode(uint8_t s0, uint8_t s1) ++m_dp; - assert((m_dp - m_decisions) <= 180); + assert((m_dp - m_decisions) <= 300); uint16_t* tmp = m_oldMetrics; m_oldMetrics = m_newMetrics; From ba31b6d8a717a55a91d8a505336e130d5f72e09b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jan 2018 19:51:47 +0000 Subject: [PATCH 06/12] Add decoding of the Layer 3 messages. --- MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 6 +++ Makefile | 6 +-- Makefile.Pi | 6 +-- Makefile.Pi.Adafruit | 6 +-- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 6 +-- Makefile.Pi.PCF8574 | 2 +- Makefile.Solaris | 6 +-- NXDNControl.cpp | 87 ++++++++++++++++++++++++++++++++--- NXDNControl.h | 5 +- NXDNDefines.h | 22 +++++++++ NXDNLayer3.cpp | 97 +++++++++++++++++++++++++++++++++++++++ NXDNLayer3.h | 43 +++++++++++++++++ 14 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 NXDNLayer3.cpp create mode 100644 NXDNLayer3.h diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 21583f8..ef4390c 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -199,6 +199,7 @@ + @@ -281,6 +282,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index c0b4ae1..8bd9368 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -263,6 +263,9 @@ Header Files + + Header Files + @@ -493,5 +496,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 9176107..57470a5 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,9 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ - P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ - StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi b/Makefile.Pi index 900cfc0..97e713e 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -10,9 +10,9 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ - P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ - StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index a46caee..7de9641 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,9 +10,9 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ - P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o \ - Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ + StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 5bde70a..9b1d770 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index c2974e8..008bc77 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -10,9 +10,9 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ - P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ - StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index d4dacca..f16f7ff 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Solaris b/Makefile.Solaris index 3a93712..1fede3a 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -10,9 +10,9 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ - P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ - StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 4aef87c..ddb1f0f 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -63,7 +63,9 @@ m_rfErrs(0U), m_rfBits(1U), m_netErrs(0U), m_netBits(1U), -m_lastLICH(), +m_rfLastLICH(), +m_rfSACCHMessage(), +m_rfMask(0x00U), m_netN(0U), m_rssiMapper(rssiMapper), m_rssi(0U), @@ -139,21 +141,21 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len) bool valid = lich.decode(data + 2U); if (valid) - m_lastLICH = lich; + m_rfLastLICH = lich; // Stop repeater packets coming through, unless we're acting as a remote gateway if (m_remoteGateway) { - unsigned char direction = m_lastLICH.getDirection(); + unsigned char direction = m_rfLastLICH.getDirection(); if (direction == NXDN_LICH_DIRECTION_INBOUND) return false; } else { - unsigned char direction = m_lastLICH.getDirection(); + unsigned char direction = m_rfLastLICH.getDirection(); if (direction == NXDN_LICH_DIRECTION_OUTBOUND) return false; } - unsigned char usc = m_lastLICH.getFCT(); - unsigned char option = m_lastLICH.getOption(); + unsigned char usc = m_rfLastLICH.getFCT(); + unsigned char option = m_rfLastLICH.getOption(); bool ret; if (usc == NXDN_LICH_USC_UDCH) @@ -174,6 +176,77 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne return false; } + if (m_rfState == RS_RF_LISTENING && !valid) + return false; + + if (m_rfState == RS_RF_LISTENING) { + unsigned char message[3U]; + sacch.getData(message); + + unsigned char structure = sacch.getStructure(); + switch (structure) { + case NXDN_SR_1_4: + m_rfMask |= 0x01U; + m_rfSACCHMessage.decode(message, 18U, 0U); + break; + case NXDN_SR_2_4: + m_rfMask |= 0x02U; + m_rfSACCHMessage.decode(message, 18U, 18U); + break; + case NXDN_SR_3_4: + m_rfMask |= 0x04U; + m_rfSACCHMessage.decode(message, 18U, 36U); + break; + case NXDN_SR_4_4: + m_rfMask |= 0x08U; + m_rfSACCHMessage.decode(message, 18U, 54U); + break; + default: + break; + } + + if (m_rfMask != 0x0FU) + return false; + + unsigned char messageType = m_rfSACCHMessage.getMessageType(); + if (messageType == NXDN_MESSAGE_TYPE_IDLE) + return false; + + unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); + unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); + bool grp = m_rfSACCHMessage.getIsGroup(); + + if (m_selfOnly) { + if (srcId != m_id) { + m_rfState = RS_RF_REJECTED; + return false; + } + } + + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 1U; + m_rfTimeoutTimer.start(); + m_rfState = RS_RF_AUDIO; + + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; +#if defined(DUMP_NXDN) + openFile(); +#endif + std::string source = m_lookup->find(srcId); + LogMessage("NXDN, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId); + m_display->writeNXDN(source.c_str(), grp, dstId, "R"); + + m_rfState = RS_RF_AUDIO; + } + + // XXX What about rejected? + if (m_rfState != RS_RF_AUDIO) + return false; + if (option == NXDN_LICH_STEAL_NONE) { CAMBEFEC ambe; unsigned int errors = 0U; @@ -749,6 +822,8 @@ void CNXDNControl::writeEndRF() { m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; + m_rfTimeoutTimer.stop(); if (m_netState == RS_NET_IDLE) { diff --git a/NXDNControl.h b/NXDNControl.h index da2fd12..f181b81 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -22,6 +22,7 @@ #include "RSSIInterpolator.h" #include "NXDNNetwork.h" #include "NXDNDefines.h" +#include "NXDNLayer3.h" #include "NXDNLookup.h" #include "RingBuffer.h" #include "StopWatch.h" @@ -68,7 +69,9 @@ private: unsigned int m_rfBits; unsigned int m_netErrs; unsigned int m_netBits; - CNXDNLICH m_lastLICH; + CNXDNLICH m_rfLastLICH; + CNXDNLayer3 m_rfSACCHMessage; + unsigned char m_rfMask; unsigned char m_netN; CRSSIInterpolator* m_rssiMapper; unsigned char m_rssi; diff --git a/NXDNDefines.h b/NXDNDefines.h index c9ab105..2cefccc 100644 --- a/NXDNDefines.h +++ b/NXDNDefines.h @@ -66,4 +66,26 @@ const unsigned char NXDN_SR_3_4 = 1U; const unsigned char NXDN_SR_2_4 = 2U; const unsigned char NXDN_SR_1_4 = 3U; +const unsigned char NXDN_MESSAGE_TYPE_VCALL = 0x01U; +const unsigned char NXDN_MESSAGE_TYPE_VCALL_IV = 0x03U; +const unsigned char NXDN_MESSAGE_TYPE_DCALL_HDR = 0x09U; +const unsigned char NXDN_MESSAGE_TYPE_DCALL_DATA = 0x0BU; +const unsigned char NXDN_MESSAGE_TYPE_DCALL_ACK = 0x0CU; +const unsigned char NXDN_MESSAGE_TYPE_TX_REL = 0x08U; +const unsigned char NXDN_MESSAGE_TYPE_HEAD_DLY = 0x0FU; +const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_HDR = 0x38U; +const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_DATA = 0x39U; +const unsigned char NXDN_MESSAGE_TYPE_SDCALL_RESP = 0x3BU; +const unsigned char NXDN_MESSAGE_TYPE_SDCALL_IV = 0x3AU; +const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_REQ = 0x30U; +const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_RESP = 0x31U; +const unsigned char NXDN_MESSAGE_TYPE_STAT_REQ = 0x32U; +const unsigned char NXDN_MESSAGE_TYPE_STAT_RESP = 0x33U; +const unsigned char NXDN_MESSAGE_TYPE_REM_CON_REQ = 0x34U; +const unsigned char NXDN_MESSAGE_TYPE_REM_CON_RESP = 0x35U; +const unsigned char NXDN_MESSAGE_TYPE_IDLE = 0x10U; +const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_REQ = 0x28U; +const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_RESP = 0x29U; +const unsigned char NXDN_MESSAGE_TYPE_PROP_FORM = 0x3FU; + #endif diff --git a/NXDNLayer3.cpp b/NXDNLayer3.cpp new file mode 100644 index 0000000..bde954c --- /dev/null +++ b/NXDNLayer3.cpp @@ -0,0 +1,97 @@ +/* +* Copyright (C) 2018 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "NXDNDefines.h" +#include "NXDNLayer3.h" +#include "Log.h" + +#include +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CNXDNLayer3::CNXDNLayer3(const CNXDNLayer3& layer3) : +m_data(NULL) +{ + m_data = new unsigned char[22U]; + ::memcpy(m_data, layer3.m_data, 22U); +} + +CNXDNLayer3::CNXDNLayer3() : +m_data(NULL) +{ + m_data = new unsigned char[22U]; + ::memset(m_data, 0x00U, 22U); +} + +CNXDNLayer3::~CNXDNLayer3() +{ + delete[] m_data; +} + +void CNXDNLayer3::decode(const unsigned char* bytes, unsigned int length, unsigned int offset) +{ + assert(bytes != NULL); + + for (unsigned int i = 0U; i < length; i++, offset++) { + bool b = READ_BIT1(bytes, offset); + WRITE_BIT1(m_data, i, b); + } +} + +void CNXDNLayer3::encode(unsigned char* bytes, unsigned int length, unsigned int offset) +{ + assert(bytes != NULL); + + for (unsigned int i = 0U; i < length; i++, offset++) { + bool b = READ_BIT1(m_data, i); + WRITE_BIT1(bytes, offset, b); + } +} + +unsigned char CNXDNLayer3::getMessageType() const +{ + return m_data[0U] & 0x3FU; +} + +unsigned short CNXDNLayer3::getSourceUnitId() const +{ + return (m_data[3U] << 8) | m_data[4U]; +} + +unsigned short CNXDNLayer3::getDestinationGroupId() const +{ + return (m_data[5U] << 8) | m_data[6U]; +} + +bool CNXDNLayer3::getIsGroup() const +{ + return (m_data[2U] & 0x80U) != 0x80U; +} + +CNXDNLayer3& CNXDNLayer3::operator=(const CNXDNLayer3& layer3) +{ + if (&layer3 != this) + ::memcpy(m_data, layer3.m_data, 22U); + + return *this; +} diff --git a/NXDNLayer3.h b/NXDNLayer3.h new file mode 100644 index 0000000..f91d34d --- /dev/null +++ b/NXDNLayer3.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 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(NXDNLayer3_H) +#define NXDNLayer3_H + +class CNXDNLayer3 { +public: + CNXDNLayer3(const CNXDNLayer3& layer3); + CNXDNLayer3(); + ~CNXDNLayer3(); + + void decode(const unsigned char* bytes, unsigned int length, unsigned int offset = 0U); + + void encode(unsigned char* bytes, unsigned int length, unsigned int offset = 0U); + + unsigned char getMessageType() const; + unsigned short getSourceUnitId() const; + unsigned short getDestinationGroupId() const; + bool getIsGroup() const; + + CNXDNLayer3& operator=(const CNXDNLayer3& layer3); + +private: + unsigned char* m_data; +}; + +#endif From d8086e468c20c6107bdd454c735594f48406949c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jan 2018 20:41:43 +0000 Subject: [PATCH 07/12] Remove FACCH2 processing and add voice body processing. --- MMDVMHost.vcxproj | 2 - MMDVMHost.vcxproj.filters | 6 -- Makefile | 2 +- Makefile.Pi | 2 +- Makefile.Pi.Adafruit | 2 +- Makefile.Pi.HD44780 | 2 +- Makefile.Pi.OLED | 2 +- Makefile.Pi.PCF8574 | 2 +- Makefile.Solaris | 2 +- NXDNControl.cpp | 149 ++++++++++++++++++++++---------------- NXDNDefines.h | 13 ++++ NXDNFACCH1.cpp | 7 -- NXDNFACCH2.cpp | 109 ---------------------------- NXDNFACCH2.h | 46 ------------ NXDNLayer3.cpp | 5 ++ NXDNLayer3.h | 1 + NXDNSACCH.cpp | 7 -- NXDNUDCH.cpp | 22 +++--- NXDNUDCH.h | 4 + 19 files changed, 131 insertions(+), 254 deletions(-) delete mode 100644 NXDNFACCH2.cpp delete mode 100644 NXDNFACCH2.h diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index ef4390c..5e39637 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -198,7 +198,6 @@ - @@ -281,7 +280,6 @@ - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 8bd9368..8eedd67 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -257,9 +257,6 @@ Header Files - - Header Files - Header Files @@ -490,9 +487,6 @@ Source Files - - Source Files - Source Files diff --git a/Makefile b/Makefile index 57470a5..12f36e8 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi b/Makefile.Pi index 97e713e..7379f9f 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 7de9641..564c4a4 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 9b1d770..dbb7df5 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 008bc77..19c0c62 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index f16f7ff..5d28a2b 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \ P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Solaris b/Makefile.Solaris index 1fede3a..d40317f 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -10,7 +10,7 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \ - NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/NXDNControl.cpp b/NXDNControl.cpp index ddb1f0f..43e3165 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -13,7 +13,6 @@ #include "NXDNControl.h" #include "NXDNFACCH1.h" -#include "NXDNFACCH2.h" #include "NXDNSACCH.h" #include "NXDNUDCH.h" #include "AMBEFEC.h" @@ -209,7 +208,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne return false; unsigned char messageType = m_rfSACCHMessage.getMessageType(); - if (messageType == NXDN_MESSAGE_TYPE_IDLE) + if (messageType != NXDN_MESSAGE_TYPE_VCALL) return false; unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); @@ -247,17 +246,74 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne if (m_rfState != RS_RF_AUDIO) return false; + unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U; + if (option == NXDN_LICH_STEAL_NONE) { CAMBEFEC ambe; unsigned int errors = 0U; - //errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - //errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); - //errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - //errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); - //LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F); - //errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - //errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - //LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F); + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + m_rfErrs += errors; + m_rfBits += 288U; + m_display->writeNXDNBER(float(errors) / 2.88F); + LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); + m_rfErrs += errors; + m_rfBits += 188U; + m_display->writeNXDNBER(float(errors) / 1.88F); + LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F); + } + } else if (option == NXDN_LICH_STEAL_FACCH1_1) { + CNXDNFACCH1 facch1; + facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CAMBEFEC ambe; + unsigned int errors = 0U; + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + m_rfErrs += errors; + m_rfBits += 144U; + m_display->writeNXDNBER(float(errors) / 1.44F); + LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); + m_rfErrs += errors; + m_rfBits += 94U; + m_display->writeNXDNBER(float(errors) / 0.94F); + LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); + } + } else if (option == NXDN_LICH_STEAL_FACCH1_2) { + CAMBEFEC ambe; + unsigned int errors = 0U; + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + m_rfErrs += errors; + m_rfBits += 144U; + m_display->writeNXDNBER(float(errors) / 1.44F); + LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); + m_rfErrs += errors; + m_rfBits += 94U; + m_display->writeNXDNBER(float(errors) / 0.94F); + LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); + } + + CNXDNFACCH1 facch1; + facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + } else { + CNXDNFACCH1 facch11; + facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CNXDNFACCH1 facch12; + facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); } #ifdef notdef @@ -579,65 +635,36 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne bool CNXDNControl::processData(unsigned char option, unsigned char *data) { - if (option == NXDN_LICH_STEAL_FACCH) { - CNXDNFACCH2 facch2; - bool valid = facch2.decode(data + 2U); - if (valid) { - unsigned char ran = facch2.getRAN(); - if (ran != m_ran && ran != 0U) - return false; + CNXDNUDCH udch; + bool valid = udch.decode(data + 2U); + if (valid) { + unsigned char ran = udch.getRAN(); + if (ran != m_ran && ran != 0U) + return false; - data[0U] = TAG_DATA; - data[1U] = 0x00U; + data[0U] = TAG_DATA; + data[1U] = 0x00U; - CSync::addNXDNSync(data + 2U); + CSync::addNXDNSync(data + 2U); - CNXDNLICH lich; - lich.setRFCT(NXDN_LICH_RFCT_RDCH); - lich.setFCT(NXDN_LICH_USC_UDCH); - lich.setOption(NXDN_LICH_STEAL_FACCH); - lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); - lich.encode(data + 2U); + CNXDNLICH lich; + lich.setRFCT(NXDN_LICH_RFCT_RDCH); + lich.setFCT(NXDN_LICH_USC_UDCH); + lich.setOption(option); + lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); + lich.encode(data + 2U); - facch2.setRAN(m_ran); - facch2.encode(data + 2U); + udch.setRAN(m_ran); + udch.encode(data + 2U); - writeQueueNet(data); + writeQueueNet(data); - if (m_duplex) - writeQueueRF(data); + if (m_duplex) + writeQueueRF(data); #if defined(DUMP_NXDN) - writeFile(data + 2U); + writeFile(data + 2U); #endif - return true; - } - } else { - CNXDNUDCH udch; - bool valid = udch.decode(data + 2U); - if (valid) { - data[0U] = TAG_DATA; - data[1U] = 0x00U; - - CSync::addNXDNSync(data + 2U); - - CNXDNLICH lich; - lich.setRFCT(NXDN_LICH_RFCT_RDCH); - lich.setFCT(NXDN_LICH_USC_UDCH); - lich.setOption(NXDN_LICH_STEAL_NONE); - lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); - lich.encode(data + 2U); - - udch.encode(data + 2U); - - writeQueueNet(data); - - if (m_duplex) - writeQueueRF(data); -#if defined(DUMP_NXDN) - writeFile(data + 2U); -#endif - return true; - } + return true; } #ifdef notdef diff --git a/NXDNDefines.h b/NXDNDefines.h index 2cefccc..79f6a2d 100644 --- a/NXDNDefines.h +++ b/NXDNDefines.h @@ -88,4 +88,17 @@ const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_REQ = 0x28U; const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_RESP = 0x29U; const unsigned char NXDN_MESSAGE_TYPE_PROP_FORM = 0x3FU; +const unsigned char NXDN_VOICE_CALL_OPTION_HALF_DUPLEX = 0x00U; +const unsigned char NXDN_VOICE_CALL_OPTION_DUPLEX = 0x10U; + +const unsigned char NXDN_VOICE_CALL_OPTION_4800_EHR = 0x00U; +const unsigned char NXDN_VOICE_CALL_OPTION_9600_EHR = 0x02U; +const unsigned char NXDN_VOICE_CALL_OPTION_9600_EFR = 0x03U; + +const unsigned char NXDN_DATA_CALL_OPTION_HALF_DUPLEX = 0x00U; +const unsigned char NXDN_DATA_CALL_OPTION_DUPLEX = 0x10U; + +const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U; +const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U; + #endif diff --git a/NXDNFACCH1.cpp b/NXDNFACCH1.cpp index d0c1aba..4e14eb7 100644 --- a/NXDNFACCH1.cpp +++ b/NXDNFACCH1.cpp @@ -85,25 +85,18 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) uint8_t temp2[192U]; - char text[500U]; - ::strcpy(text, "NXDN, FACCH1 de-punctured: "); - unsigned int n = 0U; unsigned int index = 0U; for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - ::strcat(text, "X, "); temp2[n++] = 99U; index++; } bool b = READ_BIT1(temp1, i); temp2[n++] = b ? 1U : 0U; - ::strcat(text, b ? "1, " : "0, "); } - LogMessage(text); - CNXDNConvolution conv; conv.start(); diff --git a/NXDNFACCH2.cpp b/NXDNFACCH2.cpp deleted file mode 100644 index ac705fa..0000000 --- a/NXDNFACCH2.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -* Copyright (C) 2018 by Jonathan Naylor G4KLX -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "NXDNFACCH2.h" - -#include "NXDNDefines.h" -#include "NXDNUDCH.h" -#include "Utils.h" -#include "Log.h" - -#include -#include -#include - -const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; - -#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) -#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) - -CNXDNFACCH2::CNXDNFACCH2(const CNXDNFACCH2& facch2) : -m_data(NULL) -{ - m_data = new unsigned char[23U]; - ::memcpy(m_data, facch2.m_data, 23U); -} - -CNXDNFACCH2::CNXDNFACCH2() : -m_data(NULL) -{ - m_data = new unsigned char[23U]; -} - -CNXDNFACCH2::~CNXDNFACCH2() -{ - delete[] m_data; -} - -bool CNXDNFACCH2::decode(const unsigned char* data) -{ - assert(data != NULL); - - CNXDNUDCH udch; - bool valid = udch.decode(data); - if (!valid) - return false; - - udch.getData(m_data); - - return true; -} - -void CNXDNFACCH2::encode(unsigned char* data) const -{ - assert(data != NULL); - - CNXDNUDCH udch; - - udch.setData(m_data); - - udch.encode(data); -} - -unsigned char CNXDNFACCH2::getRAN() const -{ - return m_data[0U] & 0x3FU; -} - -void CNXDNFACCH2::getData(unsigned char* data) const -{ - assert(data != NULL); - - ::memcpy(data, m_data + 1U, 22U); -} - -void CNXDNFACCH2::setRAN(unsigned char ran) -{ - m_data[0U] &= 0xC0U; - m_data[0U] |= ran; -} - -void CNXDNFACCH2::setData(const unsigned char* data) -{ - assert(data != NULL); - - ::memcpy(m_data + 1U, data, 22U); -} - -CNXDNFACCH2& CNXDNFACCH2::operator=(const CNXDNFACCH2& facch2) -{ - if (&facch2 != this) - ::memcpy(m_data, facch2.m_data, 23U); - - return *this; -} diff --git a/NXDNFACCH2.h b/NXDNFACCH2.h deleted file mode 100644 index 7f8ee57..0000000 --- a/NXDNFACCH2.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Copyright (C) 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(NXDNFACCH2_H) -#define NXDNFACCH2_H - -class CNXDNFACCH2 { -public: - CNXDNFACCH2(const CNXDNFACCH2& facch); - CNXDNFACCH2(); - ~CNXDNFACCH2(); - - bool decode(const unsigned char* data); - - void encode(unsigned char* data) const; - - unsigned char getRAN() const; - - void getData(unsigned char* data) const; - - void setRAN(unsigned char ran); - - void setData(const unsigned char* data); - - CNXDNFACCH2& operator=(const CNXDNFACCH2& facch); - -private: - unsigned char* m_data; -}; - -#endif diff --git a/NXDNLayer3.cpp b/NXDNLayer3.cpp index bde954c..f4da16b 100644 --- a/NXDNLayer3.cpp +++ b/NXDNLayer3.cpp @@ -88,6 +88,11 @@ bool CNXDNLayer3::getIsGroup() const return (m_data[2U] & 0x80U) != 0x80U; } +unsigned char CNXDNLayer3::getCallOptions() const +{ + return m_data[2U] & 0x1FU; +} + CNXDNLayer3& CNXDNLayer3::operator=(const CNXDNLayer3& layer3) { if (&layer3 != this) diff --git a/NXDNLayer3.h b/NXDNLayer3.h index f91d34d..81aff2b 100644 --- a/NXDNLayer3.h +++ b/NXDNLayer3.h @@ -33,6 +33,7 @@ public: unsigned short getSourceUnitId() const; unsigned short getDestinationGroupId() const; bool getIsGroup() const; + unsigned char getCallOptions() const; CNXDNLayer3& operator=(const CNXDNLayer3& layer3); diff --git a/NXDNSACCH.cpp b/NXDNSACCH.cpp index 803e702..94fee46 100755 --- a/NXDNSACCH.cpp +++ b/NXDNSACCH.cpp @@ -79,25 +79,18 @@ bool CNXDNSACCH::decode(const unsigned char* data) uint8_t temp2[72U]; - char text[500U]; - ::strcpy(text, "NXDN, SACCH de-punctured: "); - unsigned int n = 0U; unsigned int index = 0U; for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - ::strcat(text, "X, "); temp2[n++] = 99U; index++; } bool b = READ_BIT1(temp1, i); temp2[n++] = b ? 1U : 0U; - ::strcat(text, b ? "1, " : "0, "); } - LogMessage(text); - CNXDNConvolution conv; conv.start(); diff --git a/NXDNUDCH.cpp b/NXDNUDCH.cpp index 4c1d707..e58460e 100644 --- a/NXDNUDCH.cpp +++ b/NXDNUDCH.cpp @@ -106,25 +106,18 @@ bool CNXDNUDCH::decode(const unsigned char* data) uint8_t temp2[406U]; - char text[500U]; - ::strcpy(text, "NXDN, UDCH/FACCH2 de-punctured: "); - unsigned int n = 0U; unsigned int index = 0U; for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) { if (n == PUNCTURE_LIST[index]) { - ::strcat(text, "X, "); temp2[n++] = 99U; index++; } bool b = READ_BIT1(temp1, i); temp2[n++] = b ? 1U : 0U; - ::strcat(text, b ? "1, " : "0, "); } - LogMessage(text); - CNXDNConvolution conv; conv.start(); @@ -189,18 +182,29 @@ void CNXDNUDCH::encode(unsigned char* data) const } } +unsigned char CNXDNUDCH::getRAN() const +{ + return m_data[0U] & 0x3FU; +} + void CNXDNUDCH::getData(unsigned char* data) const { assert(data != NULL); - ::memcpy(data, m_data, 23U); + ::memcpy(data, m_data + 1U, 22U); +} + +void CNXDNUDCH::setRAN(unsigned char ran) +{ + m_data[0U] &= 0xC0U; + m_data[0U] |= ran; } void CNXDNUDCH::setData(const unsigned char* data) { assert(data != NULL); - ::memcpy(m_data, data, 23U); + ::memcpy(m_data + 1U, data, 22U); } CNXDNUDCH& CNXDNUDCH::operator=(const CNXDNUDCH& udch) diff --git a/NXDNUDCH.h b/NXDNUDCH.h index 6847c9c..366cd09 100644 --- a/NXDNUDCH.h +++ b/NXDNUDCH.h @@ -29,8 +29,12 @@ public: void encode(unsigned char* data) const; + unsigned char getRAN() const; + void getData(unsigned char* data) const; + void setRAN(unsigned char ran); + void setData(const unsigned char* data); CNXDNUDCH& operator=(const CNXDNUDCH& udch); From 90933a52c2199f3539624997faef5603cca1c68e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jan 2018 21:12:21 +0000 Subject: [PATCH 08/12] Improve the audio processing and logic. --- NXDNControl.cpp | 486 ++++++++++++------------------------------------ 1 file changed, 116 insertions(+), 370 deletions(-) diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 43e3165..0f5b7ca 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -98,8 +98,13 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len) return false; } + if (type == TAG_LOST && m_rfState == RS_RF_DATA) { + writeEndRF(); + return false; + } + if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) { - m_rfState = RS_RF_LISTENING; + m_rfState = RS_RF_LISTENING; return false; } @@ -178,6 +183,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne if (m_rfState == RS_RF_LISTENING && !valid) return false; + // XXX the FACCH1 data in the header may also be useful if (m_rfState == RS_RF_LISTENING) { unsigned char message[3U]; sacch.getData(message); @@ -242,395 +248,135 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfState = RS_RF_AUDIO; } - // XXX What about rejected? - if (m_rfState != RS_RF_AUDIO) - return false; + if (m_rfState == RS_RF_AUDIO) { + // Regenerate the sync + CSync::addNXDNSync(data + 2U); - unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U; + // Regenerate the LICH + CNXDNLICH lich; + lich.setRFCT(NXDN_LICH_RFCT_RDCH); + lich.setFCT(usc); + lich.setOption(option); + lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); + lich.encode(data + 2U); - if (option == NXDN_LICH_STEAL_NONE) { - CAMBEFEC ambe; - unsigned int errors = 0U; - if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { - errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - m_rfErrs += errors; - m_rfBits += 288U; - m_display->writeNXDNBER(float(errors) / 2.88F); - LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F); - } else { - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); - m_rfErrs += errors; - m_rfBits += 188U; - m_display->writeNXDNBER(float(errors) / 1.88F); - LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F); - } - } else if (option == NXDN_LICH_STEAL_FACCH1_1) { - CNXDNFACCH1 facch1; - facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + // XXX Regenerate SACCH here - CAMBEFEC ambe; - unsigned int errors = 0U; - if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { - errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - m_rfErrs += errors; - m_rfBits += 144U; - m_display->writeNXDNBER(float(errors) / 1.44F); - LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); + // Regenerate the audio and interpret the FACCH1 data + unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U; + + if (option == NXDN_LICH_STEAL_NONE) { + CAMBEFEC ambe; + unsigned int errors = 0U; + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + m_rfErrs += errors; + m_rfBits += 288U; + m_display->writeNXDNBER(float(errors) / 2.88F); + LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); + m_rfErrs += errors; + m_rfBits += 188U; + m_display->writeNXDNBER(float(errors) / 1.88F); + LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F); + } + } else if (option == NXDN_LICH_STEAL_FACCH1_1) { + CNXDNFACCH1 facch1; + bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + if (valid) + facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CAMBEFEC ambe; + unsigned int errors = 0U; + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + m_rfErrs += errors; + m_rfBits += 144U; + m_display->writeNXDNBER(float(errors) / 1.44F); + LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); + m_rfErrs += errors; + m_rfBits += 94U; + m_display->writeNXDNBER(float(errors) / 0.94F); + LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); + } + } else if (option == NXDN_LICH_STEAL_FACCH1_2) { + CAMBEFEC ambe; + unsigned int errors = 0U; + if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { + errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + m_rfErrs += errors; + m_rfBits += 144U; + m_display->writeNXDNBER(float(errors) / 1.44F); + LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); + } else { + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); + errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); + m_rfErrs += errors; + m_rfBits += 94U; + m_display->writeNXDNBER(float(errors) / 0.94F); + LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); + } + + CNXDNFACCH1 facch1; + bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + if (valid) + facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); } else { - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U); - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U); - m_rfErrs += errors; - m_rfBits += 94U; - m_display->writeNXDNBER(float(errors) / 0.94F); - LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); - } - } else if (option == NXDN_LICH_STEAL_FACCH1_2) { - CAMBEFEC ambe; - unsigned int errors = 0U; - if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) { - errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - m_rfErrs += errors; - m_rfBits += 144U; - m_display->writeNXDNBER(float(errors) / 1.44F); - LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F); - } else { - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES); - errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U); - m_rfErrs += errors; - m_rfBits += 94U; - m_display->writeNXDNBER(float(errors) / 0.94F); - LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F); + CNXDNFACCH1 facch11; + bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + if (valid1) + facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CNXDNFACCH1 facch12; + bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + if (valid2) + facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); } - CNXDNFACCH1 facch1; - facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); - } else { - CNXDNFACCH1 facch11; - facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + data[0U] = TAG_DATA; + data[1U] = 0x00U; - CNXDNFACCH1 facch12; - facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + writeNetwork(data, m_rfFrames % 128U); + +#if defined(DUMP_NXDN) + writeFile(data + 2U); +#endif + + if (m_duplex) + writeQueueRF(data); + + m_rfFrames++; + + m_display->writeNXDNRSSI(m_rssi); } #ifdef notdef - unsigned char fi = m_lastFICH.getFI(); - if (valid && fi == YSF_FI_HEADER) { - if (m_rfState == RS_RF_LISTENING) { - bool valid = m_rfPayload.processHeaderData(data + 2U); - if (!valid) - return false; - - m_rfSource = m_rfPayload.getSource(); - - if (m_selfOnly) { - bool ret = checkCallsign(m_rfSource); - if (!ret) { - LogMessage("NXDN, invalid access attempt from %10.10s", m_rfSource); - m_rfState = RS_RF_REJECTED; - return false; - } - } - - unsigned char cm = m_lastFICH.getCM(); - if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2) - m_rfDest = (unsigned char*)"ALL "; - else - m_rfDest = m_rfPayload.getDest(); - - m_rfFrames = 0U; - m_rfErrs = 0U; - m_rfBits = 1U; - m_rfTimeoutTimer.start(); - m_rfState = RS_RF_AUDIO; - - m_minRSSI = m_rssi; - m_maxRSSI = m_rssi; - m_aveRSSI = m_rssi; - m_rssiCount = 1U; -#if defined(DUMP_NXDN) - openFile(); -#endif - - m_display->writeFusion((char*)m_rfSource, (char*)m_rfDest, "R", " "); - LogMessage("NXDN, received RF header from %10.10s to %10.10s", m_rfSource, m_rfDest); - - CSync::addNXDNSync(data + 2U); - - CYSFFICH fich = m_lastFICH; - - // Remove any DSQ information - fich.setSQL(false); - fich.setSQ(0U); - fich.encode(data + 2U); - - data[0U] = TAG_DATA; - data[1U] = 0x00U; - - writeNetwork(data, m_rfFrames % 128U); - -#if defined(DUMP_NXDN) - writeFile(data + 2U); -#endif - - if (m_duplex) { - fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); - fich.encode(data + 2U); - writeQueueRF(data); - } - - m_rfFrames++; - - m_display->writeFusionRSSI(m_rssi); - - return true; - } - } else if (valid && fi == YSF_FI_TERMINATOR) { - if (m_rfState == RS_RF_REJECTED) { - m_rfPayload.reset(); - m_rfSource = NULL; - m_rfDest = NULL; - m_rfState = RS_RF_LISTENING; - } else if (m_rfState == RS_RF_AUDIO) { - m_rfPayload.processHeaderData(data + 2U); - - CSync::addNXDNSync(data + 2U); - - CYSFFICH fich = m_lastFICH; - - // Remove any DSQ information - fich.setSQL(false); - fich.setSQ(0U); - fich.encode(data + 2U); - - data[0U] = TAG_EOT; - data[1U] = 0x00U; - - writeNetwork(data, m_rfFrames % 128U); - -#if defined(DUMP_NXDN) - writeFile(data + 2U); -#endif - - if (m_duplex) { - fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); - fich.encode(data + 2U); - writeQueueRF(data); - } - - m_rfFrames++; - + // Process end of audio here + if (endofdata) { + if (m_rfState == RS_RF_AUDIO) { if (m_rssi != 0U) LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); else LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits)); writeEndRF(); - } - } else { - if (m_rfState == RS_RF_AUDIO) { - // If valid is false, update the m_lastFICH for this transmission - if (!valid) { - unsigned char ft = m_lastFICH.getFT(); - unsigned char fn = m_lastFICH.getFN() + 1U; - - if (fn > ft) - fn = 0U; - - m_lastFICH.setFN(fn); - } - - CSync::addNXDNSync(data + 2U); - - unsigned char fn = m_lastFICH.getFN(); - unsigned char dt = m_lastFICH.getDT(); - - switch (dt) { - case YSF_DT_VD_MODE1: { - m_rfPayload.processVDMode1Data(data + 2U, fn); - unsigned int errors = m_rfPayload.processVDMode1Audio(data + 2U); - m_rfErrs += errors; - m_rfBits += 235U; - m_display->writeFusionBER(float(errors) / 2.35F); - LogDebug("NXDN, V/D Mode 1, seq %u, AMBE FEC %u/235 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 2.35F); - } - break; - - case YSF_DT_VD_MODE2: { - m_rfPayload.processVDMode2Data(data + 2U, fn); - unsigned int errors = m_rfPayload.processVDMode2Audio(data + 2U); - m_rfErrs += errors; - m_rfBits += 135U; - m_display->writeFusionBER(float(errors) / 1.35F); - LogDebug("NXDN, V/D Mode 2, seq %u, Repetition FEC %u/135 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 1.35F); - } - break; - - default: - break; - } - - CYSFFICH fich = m_lastFICH; - - // Remove any DSQ information - fich.setSQL(false); - fich.setSQ(0U); - fich.encode(data + 2U); - - data[0U] = TAG_DATA; - data[1U] = 0x00U; - - writeNetwork(data, m_rfFrames % 128U); - - if (m_duplex) { - fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); - fich.encode(data + 2U); - writeQueueRF(data); - } - -#if defined(DUMP_NXDN) - writeFile(data + 2U); -#endif - - m_rfFrames++; - - m_display->writeFusionRSSI(m_rssi); - - return true; - } else if (valid && m_rfState == RS_RF_LISTENING) { - // Only use clean frames for late entry. - unsigned char fn = m_lastFICH.getFN(); - unsigned char dt = m_lastFICH.getDT(); - - switch (dt) { - case YSF_DT_VD_MODE1: - valid = m_rfPayload.processVDMode1Data(data + 2U, fn); - break; - - case YSF_DT_VD_MODE2: - valid = m_rfPayload.processVDMode2Data(data + 2U, fn); - break; - - default: - valid = false; - break; - } - - if (!valid) - return false; - - unsigned char cm = m_lastFICH.getCM(); - if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2) - m_rfDest = (unsigned char*)"ALL "; - else - m_rfDest = m_rfPayload.getDest(); - - m_rfSource = m_rfPayload.getSource(); - - if (m_rfSource == NULL || m_rfDest == NULL) - return false; - - if (m_selfOnly) { - bool ret = checkCallsign(m_rfSource); - if (!ret) { - LogMessage("NXDN, invalid access attempt from %10.10s", m_rfSource); - m_rfState = RS_RF_REJECTED; - return false; - } - } - - m_rfFrames = 0U; - m_rfErrs = 0U; - m_rfBits = 1U; - m_rfTimeoutTimer.start(); - m_rfState = RS_RF_AUDIO; - - m_minRSSI = m_rssi; - m_maxRSSI = m_rssi; - m_aveRSSI = m_rssi; - m_rssiCount = 1U; -#if defined(DUMP_NXDN) - openFile(); -#endif - - // Build a new header and transmit it - unsigned char buffer[YSF_FRAME_LENGTH_BYTES + 2U]; - - CSync::addNXDNSync(buffer + 2U); - - CYSFFICH fich = m_lastFICH; - fich.setFI(YSF_FI_HEADER); - fich.setSQL(false); - fich.setSQ(0U); - fich.encode(buffer + 2U); - - unsigned char csd1[20U], csd2[20U]; - memcpy(csd1 + YSF_CALLSIGN_LENGTH, m_rfSource, YSF_CALLSIGN_LENGTH); - memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH); - - if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2) - memset(csd1 + 0U, '*', YSF_CALLSIGN_LENGTH); - else - memcpy(csd1 + 0U, m_rfDest, YSF_CALLSIGN_LENGTH); - - CYSFPayload payload; - payload.writeHeader(buffer + 2U, csd1, csd2); - - buffer[0U] = TAG_DATA; - buffer[1U] = 0x00U; - - writeNetwork(buffer, m_rfFrames % 128U); - - if (m_duplex) { - fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); - fich.encode(buffer + 2U); - writeQueueRF(buffer); - } - -#if defined(DUMP_NXDN) - writeFile(buffer + 2U); -#endif - - m_display->writeFusion((char*)m_rfSource, (char*)m_rfDest, "R", " "); - LogMessage("NXDN, received RF late entry from %10.10s to %10.10s", m_rfSource, m_rfDest); - - CSync::addNXDNSync(data + 2U); - - fich = m_lastFICH; - - // Remove any DSQ information - fich.setSQL(false); - fich.setSQ(0U); - fich.encode(data + 2U); - - data[0U] = TAG_DATA; - data[1U] = 0x00U; - - writeNetwork(data, m_rfFrames % 128U); - - if (m_duplex) { - fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); - fich.encode(data + 2U); - writeQueueRF(data); - } - -#if defined(DUMP_NXDN) - writeFile(data + 2U); -#endif - - m_rfFrames++; - - m_display->writeFusionRSSI(m_rssi); - - return true; + } else { + m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; + return false; } } #endif - return false; + return true; } bool CNXDNControl::processData(unsigned char option, unsigned char *data) From f048caa5976d73ea987914adc569666975addeb1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 30 Jan 2018 22:02:14 +0000 Subject: [PATCH 09/12] Add the scrambler. --- NXDNControl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 0f5b7ca..e9dc931 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -344,6 +344,8 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne data[0U] = TAG_DATA; data[1U] = 0x00U; + scrambler(data + 2U); + writeNetwork(data, m_rfFrames % 128U); #if defined(DUMP_NXDN) @@ -403,6 +405,8 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data) udch.setRAN(m_ran); udch.encode(data + 2U); + scrambler(data + 2U); + writeQueueNet(data); if (m_duplex) From e78320fc18a0170df1dad16e58764872cd17c762 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 31 Jan 2018 07:55:59 +0000 Subject: [PATCH 10/12] More changes to the NXDN networking. --- NXDNControl.cpp | 24 ++++++++++++++---------- NXDNControl.h | 2 +- NXDNNetwork.cpp | 14 +++++++------- NXDNNetwork.h | 4 ++-- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/NXDNControl.cpp b/NXDNControl.cpp index e9dc931..cb697ba 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -180,8 +180,8 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne return false; } - if (m_rfState == RS_RF_LISTENING && !valid) - return false; + // if (m_rfState == RS_RF_LISTENING && !valid) + // return false; // XXX the FACCH1 data in the header may also be useful if (m_rfState == RS_RF_LISTENING) { @@ -248,7 +248,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfState = RS_RF_AUDIO; } - if (m_rfState == RS_RF_AUDIO) { + // if (m_rfState == RS_RF_AUDIO) { // Regenerate the sync CSync::addNXDNSync(data + 2U); @@ -346,7 +346,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne scrambler(data + 2U); - writeNetwork(data, m_rfFrames % 128U); + // writeNetwork(data, m_rfFrames, ); #if defined(DUMP_NXDN) writeFile(data + 2U); @@ -358,7 +358,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfFrames++; m_display->writeNXDNRSSI(m_rssi); - } + // } #ifdef notdef // Process end of audio here @@ -468,7 +468,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeNetwork(data, m_rfFrames % 128U); + writeNetwork(data, m_rfFrames); #if defined(DUMP_NXDN) writeFile(data + 2U); @@ -507,7 +507,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data) data[0U] = TAG_EOT; data[1U] = 0x00U; - writeNetwork(data, m_rfFrames % 128U); + writeNetwork(data, m_rfFrames); #if defined(DUMP_NXDN) writeFile(data + 2U); @@ -557,7 +557,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data) data[0U] = TAG_DATA; data[1U] = 0x00U; - writeNetwork(data, m_rfFrames % 128U); + writeNetwork(data, m_rfFrames); if (m_duplex) { fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY); @@ -825,7 +825,7 @@ void CNXDNControl::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count) +void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count, bool end) { assert(data != NULL); @@ -835,7 +835,11 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count) if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; - // m_network->write(data + 2U, count, data[0U] == TAG_EOT); + unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); + unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); + bool grp = m_rfSACCHMessage.getIsGroup(); + + m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end); } void CNXDNControl::scrambler(unsigned char* data) const diff --git a/NXDNControl.h b/NXDNControl.h index f181b81..da97aeb 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -86,7 +86,7 @@ private: void writeQueueRF(const unsigned char* data); void writeQueueNet(const unsigned char* data); - void writeNetwork(const unsigned char* data, unsigned int count); + void writeNetwork(const unsigned char* data, unsigned int count, bool end); void writeNetwork(); void scrambler(unsigned char* data) const; diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp index 8d3ee92..6453829 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -56,7 +56,7 @@ bool CNXDNNetwork::open() return m_socket.open(); } -bool CNXDNNetwork::write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned int cnt, bool end) +bool CNXDNNetwork::write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned char cnt, bool end) { assert(data != NULL); @@ -71,13 +71,13 @@ bool CNXDNNetwork::write(const unsigned char* data, unsigned short src, bool grp buffer[5U] = (src >> 8) & 0xFFU; buffer[6U] = (src >> 8) & 0xFFU; - buffer[7U] = grp ? 0x01U : 0x00U; + buffer[7U] = grp ? 0x01U : 0x00U; + buffer[7U] |= end ? 0x80U : 0x00U; buffer[8U] = (dst >> 8) & 0xFFU; buffer[9U] = (dst >> 8) & 0xFFU; - buffer[10U] = end ? 0x80U : 0x00U; - buffer[10U] |= (cnt & 0x7FU) << 1; + buffer[10U] = cnt; ::memcpy(buffer + 11U, data, NXDN_FRAME_LENGTH_BYTES); @@ -142,7 +142,7 @@ void CNXDNNetwork::clock(unsigned int ms) m_buffer.addData(buffer, 59U); } -unsigned int CNXDNNetwork::read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned int& cnt, bool& end) +unsigned int CNXDNNetwork::read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned char& cnt, bool& end) { assert(data != NULL); @@ -154,10 +154,10 @@ unsigned int CNXDNNetwork::read(unsigned char* data, unsigned short& src, bool& src = (buffer[5U] << 8) + buffer[6U]; grp = (buffer[7U] & 0x01U) == 0x01U; + end = (buffer[7U] & 0x80U) == 0x80U; dst = (buffer[8U] << 8) + buffer[9U]; - end = (buffer[10U] & 0x80U) == 0x80U; - cnt = buffer[10U] & 0x7FU; + cnt = buffer[10U]; ::memcpy(data, buffer + 11U, NXDN_FRAME_LENGTH_BYTES); diff --git a/NXDNNetwork.h b/NXDNNetwork.h index 15f59f4..c69602a 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -36,9 +36,9 @@ public: void enable(bool enabled); - bool write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned int cnt, bool end); + bool write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned char cnt, bool end); - unsigned int read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned int& cnt, bool& end); + unsigned int read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned char& cnt, bool& end); void reset(); From 63a2ea330d2bf08783f5d2b81f42b832952c7d97 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 31 Jan 2018 18:16:31 +0000 Subject: [PATCH 11/12] Disable the jitter buffer. --- DMRNetwork.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index d296b57..51843db 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -498,6 +498,9 @@ void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length) if (slotNo == 2U && !m_slot2) return; + m_jitterBuffers[slotNo]->appendData(data, length); + + /* unsigned char dataType = data[15U] & 0x3FU; if (dataType == (0x20U | DT_CSBK) || dataType == (0x20U | DT_DATA_HEADER) || @@ -511,6 +514,7 @@ void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length) unsigned char seqNo = data[4U]; m_jitterBuffers[slotNo]->addData(data, length, seqNo); } + */ } bool CDMRNetwork::writeLogin() From c4fe7f7759cd14f52546f280eb1ac6120eaf0419 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 31 Jan 2018 21:05:34 +0000 Subject: [PATCH 12/12] Experimenting using real data, moving forward with start and end blocks. --- NXDNControl.cpp | 147 ++++++++++++++++++++++++++++++++++++++++-------- NXDNControl.h | 2 +- NXDNDefines.h | 2 + NXDNFACCH1.cpp | 10 ++-- NXDNLICH.cpp | 2 +- NXDNSACCH.cpp | 8 +-- 6 files changed, 137 insertions(+), 34 deletions(-) diff --git a/NXDNControl.cpp b/NXDNControl.cpp index cb697ba..74b2991 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -63,7 +63,7 @@ m_rfBits(1U), m_netErrs(0U), m_netBits(1U), m_rfLastLICH(), -m_rfSACCHMessage(), +m_rfLayer3(), m_rfMask(0x00U), m_netN(0U), m_rssiMapper(rssiMapper), @@ -103,13 +103,9 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len) return false; } - if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) { - m_rfState = RS_RF_LISTENING; - return false; - } - if (type == TAG_LOST) { m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; return false; } @@ -180,11 +176,117 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne return false; } - // if (m_rfState == RS_RF_LISTENING && !valid) - // return false; + // XXX Reconstruct invalid LICH - // XXX the FACCH1 data in the header may also be useful - if (m_rfState == RS_RF_LISTENING) { + if (usc == NXDN_LICH_USC_SACCH_NS) { + // The SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN. + CNXDNFACCH1 facch11; + bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + + CNXDNFACCH1 facch12; + bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + + unsigned char buffer[10U]; + if (valid1) + facch11.getData(buffer); + else if (valid2) + facch12.getData(buffer); + + if (valid1 || valid2) { + CNXDNLayer3 layer3; + layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS); + + unsigned char type = layer3.getMessageType(); + if (type == NXDN_MESSAGE_TYPE_TX_REL) { + if (m_rfState != RS_RF_AUDIO) { + m_rfState = RS_RF_LISTENING; + m_rfMask = 0x00U; + return false; + } + } else { + if (m_selfOnly) { + unsigned short srcId = layer3.getSourceUnitId(); + if (srcId != m_id) { + m_rfState = RS_RF_REJECTED; + return false; + } + } + } + + data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA; + data[1U] = 0x00U; + + CSync::addNXDNSync(data + 2U); + + CNXDNLICH lich = m_rfLastLICH; + lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND); + lich.encode(data + 2U); + + CNXDNSACCH sacch; + sacch.setRAN(m_ran); + sacch.setStructure(NXDN_SR_SINGLE); + sacch.setData(SACCH_IDLE); + sacch.encode(data + 2U); + + if (valid1) { + facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + } else { + facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); + facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); + } + + scrambler(data + 2U); + + // writeNetwork(data, m_rfFrames, ); + +#if defined(DUMP_NXDN) + writeFile(data + 2U); +#endif + + if (m_duplex) + writeQueueRF(data); + + if (type == NXDN_MESSAGE_TYPE_TX_REL) { + m_rfFrames++; + if (m_rssi != 0U) + LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); + else + LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits)); + writeEndRF(); + return true; + } else { + m_rfFrames = 0U; + m_rfErrs = 0U; + m_rfBits = 1U; + m_rfTimeoutTimer.start(); + m_rfState = RS_RF_AUDIO; + + m_minRSSI = m_rssi; + m_maxRSSI = m_rssi; + m_aveRSSI = m_rssi; + m_rssiCount = 1U; +#if defined(DUMP_NXDN) + openFile(); +#endif + m_rfLayer3 = layer3; + + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); + + std::string source = m_lookup->find(srcId); + LogMessage("NXDN, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId); + m_display->writeNXDN(source.c_str(), grp, dstId, "R"); + + m_rfState = RS_RF_AUDIO; + + return true; + } + } + + return false; + } else { unsigned char message[3U]; sacch.getData(message); @@ -192,19 +294,19 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne switch (structure) { case NXDN_SR_1_4: m_rfMask |= 0x01U; - m_rfSACCHMessage.decode(message, 18U, 0U); + m_rfLayer3.decode(message, 18U, 0U); break; case NXDN_SR_2_4: m_rfMask |= 0x02U; - m_rfSACCHMessage.decode(message, 18U, 18U); + m_rfLayer3.decode(message, 18U, 18U); break; case NXDN_SR_3_4: m_rfMask |= 0x04U; - m_rfSACCHMessage.decode(message, 18U, 36U); + m_rfLayer3.decode(message, 18U, 36U); break; case NXDN_SR_4_4: m_rfMask |= 0x08U; - m_rfSACCHMessage.decode(message, 18U, 54U); + m_rfLayer3.decode(message, 18U, 54U); break; default: break; @@ -213,13 +315,13 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne if (m_rfMask != 0x0FU) return false; - unsigned char messageType = m_rfSACCHMessage.getMessageType(); + unsigned char messageType = m_rfLayer3.getMessageType(); if (messageType != NXDN_MESSAGE_TYPE_VCALL) return false; - unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); - unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); - bool grp = m_rfSACCHMessage.getIsGroup(); + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); if (m_selfOnly) { if (srcId != m_id) { @@ -263,7 +365,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne // XXX Regenerate SACCH here // Regenerate the audio and interpret the FACCH1 data - unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U; + unsigned char voiceMode = m_rfLayer3.getCallOptions() & 0x07U; if (option == NXDN_LICH_STEAL_NONE) { CAMBEFEC ambe; @@ -358,7 +460,6 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne m_rfFrames++; m_display->writeNXDNRSSI(m_rssi); - // } #ifdef notdef // Process end of audio here @@ -835,9 +936,9 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count, b if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) return; - unsigned short srcId = m_rfSACCHMessage.getSourceUnitId(); - unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId(); - bool grp = m_rfSACCHMessage.getIsGroup(); + unsigned short srcId = m_rfLayer3.getSourceUnitId(); + unsigned short dstId = m_rfLayer3.getDestinationGroupId(); + bool grp = m_rfLayer3.getIsGroup(); m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end); } diff --git a/NXDNControl.h b/NXDNControl.h index da97aeb..5f000e7 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -70,7 +70,7 @@ private: unsigned int m_netErrs; unsigned int m_netBits; CNXDNLICH m_rfLastLICH; - CNXDNLayer3 m_rfSACCHMessage; + CNXDNLayer3 m_rfLayer3; unsigned char m_rfMask; unsigned char m_netN; CRSSIInterpolator* m_rssiMapper; diff --git a/NXDNDefines.h b/NXDNDefines.h index 79f6a2d..463ca61 100644 --- a/NXDNDefines.h +++ b/NXDNDefines.h @@ -101,4 +101,6 @@ const unsigned char NXDN_DATA_CALL_OPTION_DUPLEX = 0x10U; const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U; const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U; +const unsigned char SACCH_IDLE[] = { NXDN_MESSAGE_TYPE_IDLE, 0x00U, 0x00U }; + #endif diff --git a/NXDNFACCH1.cpp b/NXDNFACCH1.cpp index 4e14eb7..48f4639 100644 --- a/NXDNFACCH1.cpp +++ b/NXDNFACCH1.cpp @@ -71,7 +71,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) { assert(data != NULL); - CUtils::dump("NXDN, FACCH1 input", data, 18U); + // CUtils::dump("NXDN, FACCH1 input", data, 18U); unsigned char temp1[18U]; @@ -81,7 +81,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset) WRITE_BIT1(temp1, i, b); } - CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U); + // CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U); uint8_t temp2[192U]; @@ -129,14 +129,14 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const CNXDNCRC::encodeCRC12(temp1, 80U); - CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U); + // CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U); unsigned char temp2[24U]; CNXDNConvolution conv; conv.encode(temp1, temp2, 96U); - CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U); + // CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U); unsigned char temp3[18U]; @@ -152,7 +152,7 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const } } - CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U); + // CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U); for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) { unsigned int n = INTERLEAVE_TABLE[i] + offset; diff --git a/NXDNLICH.cpp b/NXDNLICH.cpp index b5e363c..df735b9 100644 --- a/NXDNLICH.cpp +++ b/NXDNLICH.cpp @@ -61,7 +61,7 @@ bool CNXDNLICH::decode(const unsigned char* bytes) bool parity = b[7U] ^ b[6U] ^ b[5U] ^ b[4U]; - LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0); + // LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0); if (parity != b[0U]) return false; diff --git a/NXDNSACCH.cpp b/NXDNSACCH.cpp index 94fee46..304b20d 100755 --- a/NXDNSACCH.cpp +++ b/NXDNSACCH.cpp @@ -65,7 +65,7 @@ bool CNXDNSACCH::decode(const unsigned char* data) { assert(data != NULL); - CUtils::dump("NXDN, SACCH input", data, 12U); + // CUtils::dump("NXDN, SACCH input", data, 12U); unsigned char temp1[8U]; @@ -75,7 +75,7 @@ bool CNXDNSACCH::decode(const unsigned char* data) WRITE_BIT1(temp1, i, b); } - CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U); + // CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U); uint8_t temp2[72U]; @@ -130,7 +130,7 @@ void CNXDNSACCH::encode(unsigned char* data) const CNXDNConvolution conv; conv.encode(temp1, temp2, 36U); - CUtils::dump("NXDN, SACCH convolved", temp2, 8U); + // CUtils::dump("NXDN, SACCH convolved", temp2, 8U); unsigned char temp3[8U]; @@ -146,7 +146,7 @@ void CNXDNSACCH::encode(unsigned char* data) const } } - CUtils::dump("NXDN, SACCH punctured", temp3, 8U); + // CUtils::dump("NXDN, SACCH punctured", temp3, 8U); for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) { unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;