diff --git a/P25Defines.h b/P25Defines.h index 408ff5f..2419821 100644 --- a/P25Defines.h +++ b/P25Defines.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 by Jonathan Naylor G4KLX + * Copyright (C) 2018 by Andy Uribe CA6JAU * * 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 @@ -21,26 +22,27 @@ const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U; const unsigned int P25_HDR_FRAME_LENGTH_BITS = P25_HDR_FRAME_LENGTH_BYTES * 8U; -const unsigned int P25_HDR_FRAME_LENGTH_SYMBOLS = P25_HDR_FRAME_LENGTH_BYTES * 4U; const unsigned int P25_LDU_FRAME_LENGTH_BYTES = 216U; const unsigned int P25_LDU_FRAME_LENGTH_BITS = P25_LDU_FRAME_LENGTH_BYTES * 8U; -const unsigned int P25_LDU_FRAME_LENGTH_SYMBOLS = P25_LDU_FRAME_LENGTH_BYTES * 4U; const unsigned int P25_TERMLC_FRAME_LENGTH_BYTES = 54U; const unsigned int P25_TERMLC_FRAME_LENGTH_BITS = P25_TERMLC_FRAME_LENGTH_BYTES * 8U; -const unsigned int P25_TERMLC_FRAME_LENGTH_SYMBOLS = P25_TERMLC_FRAME_LENGTH_BYTES * 4U; const unsigned int P25_TERM_FRAME_LENGTH_BYTES = 18U; const unsigned int P25_TERM_FRAME_LENGTH_BITS = P25_TERM_FRAME_LENGTH_BYTES * 8U; -const unsigned int P25_TERM_FRAME_LENGTH_SYMBOLS = P25_TERM_FRAME_LENGTH_BYTES * 4U; -const unsigned int P25_SYNC_LENGTH_BYTES = 6U; -const unsigned int P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U; -const unsigned int P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U; +const unsigned int P25_TSDU_FRAME_LENGTH_BYTES = 45U; +const unsigned int P25_TSDU_FRAME_LENGTH_BITS = P25_TSDU_FRAME_LENGTH_BYTES * 8U; -const unsigned int P25_NID_LENGTH_BITS = 64U; -const unsigned int P25_NID_LENGTH_SYMBOLS = 32U; +const unsigned int P25_PDU_HDR_FRAME_LENGTH_BYTES = 45U; +const unsigned int P25_PDU_HDR_FRAME_LENGTH_BITS = P25_PDU_HDR_FRAME_LENGTH_BYTES * 8U; + +const unsigned int P25_SYNC_LENGTH_BYTES = 6U; +const unsigned int P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U; + +const unsigned int P25_NID_LENGTH_BYTES = 8U; +const unsigned int P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U; const uint8_t P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU}; const uint8_t P25_SYNC_BYTES_LENGTH = 6U; @@ -48,11 +50,12 @@ const uint8_t P25_SYNC_BYTES_LENGTH = 6U; const uint64_t P25_SYNC_BITS = 0x00005575F5FF77FFU; const uint64_t P25_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; -// 5 5 7 5 F 5 F F 7 7 F F -// 01 01 01 01 01 11 01 01 11 11 01 01 11 11 11 11 01 11 01 11 11 11 11 11 -// +3 +3 +3 +3 +3 -3 +3 +3 -3 -3 +3 +3 -3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 -3 - -const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U; -const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; +const uint8_t P25_DUID_HDU = 0x00U; // Header Data Unit +const uint8_t P25_DUID_TDU = 0x03U; // Simple Terminator Data Unit +const uint8_t P25_DUID_LDU1 = 0x05U; // Logical Link Data Unit 1 +const uint8_t P25_DUID_TSDU = 0x07U; // Trunking System Data Unit +const uint8_t P25_DUID_LDU2 = 0x0AU; // Logical Link Data Unit 2 +const uint8_t P25_DUID_PDU = 0x0CU; // Packet Data Unit +const uint8_t P25_DUID_TDULC = 0x0FU; // Terminator Data Unit with Link Control #endif diff --git a/P25RX.cpp b/P25RX.cpp index 47e7e30..cd9f69c 100644 --- a/P25RX.cpp +++ b/P25RX.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016,2017 by Jonathan Naylor G4KLX - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,33 +31,44 @@ const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02 #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]) +const uint16_t NOENDPTR = 9999U; + CP25RX::CP25RX() : -m_prev(false), m_state(P25RXS_NONE), m_bitBuffer(0x00U), m_outBuffer(), m_buffer(NULL), m_bufferPtr(0U), -m_lostCount(0U) +m_endPtr(NOENDPTR), +m_lostCount(0U), +m_duid(0U) { m_buffer = m_outBuffer + 1U; } void CP25RX::reset() { - m_prev = false; m_state = P25RXS_NONE; m_bitBuffer = 0x00U; m_bufferPtr = 0U; + m_endPtr = NOENDPTR; m_lostCount = 0U; + m_duid = 0U; } void CP25RX::databit(bool bit) { - if (m_state == P25RXS_NONE) - processNone(bit); - else - processData(bit); + switch (m_state) { + case P25RXS_HDR: + processHdr(bit); + break; + case P25RXS_LDU: + processLdu(bit); + break; + default: + processNone(bit); + break; + } } void CP25RX::processNone(bool bit) @@ -71,72 +82,106 @@ void CP25RX::processNone(bool bit) DEBUG1("P25RX: sync found in None"); for (uint8_t i = 0U; i < P25_SYNC_LENGTH_BYTES; i++) m_buffer[i] = P25_SYNC_BYTES[i]; - + m_lostCount = MAX_SYNC_FRAMES; m_bufferPtr = P25_SYNC_LENGTH_BITS; - m_state = P25RXS_DATA; - + m_state = P25RXS_HDR; + io.setDecode(true); } } -void CP25RX::processData(bool bit) +void CP25RX::processHdr(bool bit) { m_bitBuffer <<= 1; if (bit) m_bitBuffer |= 0x01U; WRITE_BIT1(m_buffer, m_bufferPtr, bit); - m_bufferPtr++; - // Search for an early sync to indicate an LDU following a header - if (m_bufferPtr >= (P25_HDR_FRAME_LENGTH_BITS + P25_SYNC_LENGTH_BITS - 1U) && m_bufferPtr <= (P25_HDR_FRAME_LENGTH_BITS + P25_SYNC_LENGTH_BITS + 1U)) { - // Fuzzy matching of the data sync bit sequence - if (countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS) <= SYNC_BIT_RUN_ERRS) { - DEBUG2("P25RX: found LDU sync in Data, pos", m_bufferPtr - P25_SYNC_LENGTH_BITS); - - m_outBuffer[0U] = 0x01U; - serial.writeP25Hdr(m_outBuffer, P25_HDR_FRAME_LENGTH_BYTES + 1U); + m_bufferPtr++; + if (m_bufferPtr > P25_LDU_FRAME_LENGTH_BITS) + reset(); - // Restore the sync that's now in the wrong place - for (uint8_t i = 0U; i < P25_SYNC_LENGTH_BYTES; i++) - m_buffer[i] = P25_SYNC_BYTES[i]; + if (m_bufferPtr == P25_SYNC_LENGTH_BITS + 16U) { + // FIXME: we should check and correct for errors in NID first! + m_duid = m_buffer[7U] & 0x0F; + if (m_duid != P25_DUID_HDU && m_duid != P25_DUID_TSDU && + m_duid != P25_DUID_TDU && m_duid != P25_DUID_TDULC) { m_lostCount = MAX_SYNC_FRAMES; - m_bufferPtr = P25_SYNC_LENGTH_BITS; + m_state = P25RXS_LDU; + return; } + + setEndPtr(); + DEBUG2("P25RX: DUID", m_duid); + } + + // Search for end of header frame + if (m_bufferPtr == m_endPtr) { + m_outBuffer[0U] = 0x01U; + serial.writeP25Hdr(m_outBuffer, (m_endPtr / 8U) + 1U); + + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = 0U; + m_state = P25RXS_LDU; } +} + +void CP25RX::processLdu(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + WRITE_BIT1(m_buffer, m_bufferPtr, bit); + + m_bufferPtr++; + if (m_bufferPtr > P25_LDU_FRAME_LENGTH_BITS) + reset(); - // Only search for a sync in the right place +-2 symbols + // Only search for a sync in the right place +-2 bits if (m_bufferPtr >= (P25_SYNC_LENGTH_BITS - 2U) && m_bufferPtr <= (P25_SYNC_LENGTH_BITS + 2U)) { // Fuzzy matching of the data sync bit sequence if (countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS) <= SYNC_BIT_RUN_ERRS) { - DEBUG2("P25RX: found sync in Data, pos", m_bufferPtr - P25_SYNC_LENGTH_BITS); + DEBUG1("P25RX: found sync in LDU"); m_lostCount = MAX_SYNC_FRAMES; m_bufferPtr = P25_SYNC_LENGTH_BITS; } } + if (m_bufferPtr == P25_SYNC_LENGTH_BITS + 16U) { + // We use DUID here only to detect TDU for EOT + // FIXME: we should check and correct for errors in NID first! + m_duid = m_buffer[7U] & 0x0F; + setEndPtr(); + DEBUG2("P25RX: DUID", m_duid); + } + // Send a data frame to the host if the required number of bits have been received if (m_bufferPtr == P25_LDU_FRAME_LENGTH_BITS) { - // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE m_lostCount--; + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE if (m_lostCount == 0U) { DEBUG1("P25RX: sync timed out, lost lock"); io.setDecode(false); - serial.writeP25Lost(); - - m_state = P25RXS_NONE; + reset(); } else { + // Write data to host m_outBuffer[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U; - writeRSSILdu(m_outBuffer); - + // Start the next frame ::memset(m_outBuffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U); m_bufferPtr = 0U; } + + // Check if we found a TDU to avoid a false "lost lock" + if (m_duid == P25_DUID_TDU || m_duid == P25_DUID_TDULC) { + reset(); + } } } @@ -144,14 +189,42 @@ void CP25RX::writeRSSILdu(uint8_t* ldu) { #if defined(SEND_RSSI_DATA) uint16_t rssi = io.readRSSI(); - + ldu[217U] = (rssi >> 8) & 0xFFU; ldu[218U] = (rssi >> 0) & 0xFFU; - + serial.writeP25Ldu(ldu, P25_LDU_FRAME_LENGTH_BYTES + 3U); #else serial.writeP25Ldu(ldu, P25_LDU_FRAME_LENGTH_BYTES + 1U); #endif } - +void CP25RX::setEndPtr() +{ + switch (m_duid) { + case P25_DUID_HDU: + DEBUG1("P25RX: sync found in HDU"); + m_endPtr = P25_HDR_FRAME_LENGTH_BITS; + break; + case P25_DUID_TDU: + DEBUG1("P25RX: sync found in TDU"); + m_endPtr = P25_TERM_FRAME_LENGTH_BITS; + break; + case P25_DUID_TSDU: + DEBUG1("P25RX: sync found in TSDU"); + m_endPtr = P25_TSDU_FRAME_LENGTH_BITS; + break; + case P25_DUID_PDU: + // FIXME: not sure about PDU lengths since they have arbitrary length... + DEBUG1("P25RX: sync found in PDU"); + m_endPtr = P25_PDU_HDR_FRAME_LENGTH_BITS; + break; + case P25_DUID_TDULC: + DEBUG1("P25RX: sync found in TDULC"); + m_endPtr = P25_TERMLC_FRAME_LENGTH_BITS; + break; + default: + m_endPtr = P25_LDU_FRAME_LENGTH_BITS; + break; + } +} diff --git a/P25RX.h b/P25RX.h index 25eea77..ef0cbfb 100644 --- a/P25RX.h +++ b/P25RX.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU * * 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 @@ -24,7 +24,8 @@ enum P25RX_STATE { P25RXS_NONE, - P25RXS_DATA + P25RXS_HDR, + P25RXS_LDU }; class CP25RX { @@ -36,17 +37,20 @@ class CP25RX { void reset(); private: - bool m_prev; P25RX_STATE m_state; uint64_t m_bitBuffer; uint8_t m_outBuffer[P25_LDU_FRAME_LENGTH_BYTES + 3U]; uint8_t* m_buffer; uint16_t m_bufferPtr; + uint16_t m_endPtr; uint16_t m_lostCount; + uint8_t m_duid; void processNone(bool bit); - void processData(bool bit); + void processHdr(bool bit); + void processLdu(bool bit); void writeRSSILdu(uint8_t* data); + void setEndPtr(); }; #endif diff --git a/version.h b/version.h index ea871a3..47dc04b 100644 --- a/version.h +++ b/version.h @@ -24,8 +24,8 @@ #define VER_MAJOR "1" #define VER_MINOR "4" -#define VER_REV "10" -#define VERSION_DATE "20181008" +#define VER_REV "11" +#define VERSION_DATE "20181028" #if defined(ZUMSPOT_ADF7021) #define BOARD_INFO "ZUMspot"