diff --git a/DMRSlot.cpp b/DMRSlot.cpp index c7f98ba..de5784a 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -74,7 +74,7 @@ void CDMRSlot::writeModem(unsigned char *data) { if (data[0U] == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, transmission lost, %.1f seconds, BER: %u%%", m_slotNo, float(m_frames) / 16.667F, (m_errs * 100U) / m_bits); + LogMessage("DMR Slot %u, transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, float(m_errs * 100U) / float(m_bits)); writeEndOfTransmission(); return; } @@ -184,7 +184,7 @@ void CDMRSlot::writeModem(unsigned char *data) writeQueue(data); if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %u%%", m_slotNo, float(m_frames) / 16.667F, (m_errs * 100U) / m_bits); + LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, float(m_errs * 100U) / float(m_bits)); writeEndOfTransmission(); } else if (dataType == DT_DATA_HEADER) { @@ -560,7 +560,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // We've received the voice header and terminator haven't we? m_frames += 2U; if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %u%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits); + LogMessage("DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); } else if (dataType == DT_DATA_HEADER) { if (m_state == RS_RELAYING_NETWORK_DATA) return; @@ -800,7 +800,7 @@ void CDMRSlot::clock(unsigned int ms) // We've received the voice header haven't we? m_frames += 1U; if (m_bits == 0U) m_bits = 1U; - LogMessage("DMR Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %u%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits); + LogMessage("DMR Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", m_slotNo, float(m_frames) / 16.667F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); writeEndOfTransmission(); #if defined(DUMP_DMR) closeFile(); diff --git a/DStarControl.cpp b/DStarControl.cpp index 09249a3..9683eab 100644 --- a/DStarControl.cpp +++ b/DStarControl.cpp @@ -29,6 +29,7 @@ m_network(network), m_display(display), m_duplex(duplex), m_queue(1000U), +m_header(), m_state(RS_LISTENING), m_net(false), m_slowData(), @@ -37,6 +38,7 @@ m_networkWatchdog(1000U, 0U, 1500U), m_holdoffTimer(1000U, 0U, 500U), m_timeoutTimer(1000U, timeout), m_packetTimer(1000U, 0U, 300U), +m_ackTimer(1000U, 0U, 750U), m_elapsed(), m_frames(0U), m_lost(0U), @@ -82,7 +84,8 @@ void CDStarControl::writeModem(unsigned char *data) if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, transmission lost, %.1f seconds, BER: %u%%", float(m_frames) / 50.0F, (m_errs * 100U) / m_bits); + LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits)); + m_ackTimer.start(); writeEndOfTransmission(); return; } @@ -124,18 +127,24 @@ void CDStarControl::writeModem(unsigned char *data) m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; if (m_state == RS_LISTENING) { + // Only reset the timeout if the ack is not pending + if (!m_ackTimer.isRunning()) { + m_timeoutTimer.start(); + m_bits = 1U; + m_errs = 0U; + } + + m_header = header; + m_networkWatchdog.stop(); - m_timeoutTimer.start(); m_holdoffTimer.stop(); + m_ackTimer.stop(); m_frames = 1U; m_lost = 0U; m_n = 0U; - m_bits = 1U; - m_errs = 0U; - if (m_duplex) { // Modify the header header.setRepeater(false); @@ -186,8 +195,10 @@ void CDStarControl::writeModem(unsigned char *data) writeQueueData(data); } + m_ackTimer.start(); + if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %u%%", float(m_frames) / 50.0F, (m_errs * 100U) / m_bits); + LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits)); writeEndOfTransmission(); } else if (m_state == RS_RELAYING_NETWORK_AUDIO) { @@ -268,9 +279,18 @@ void CDStarControl::writeModem(unsigned char *data) m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0; + // Only reset the timeout if the ack is not pending + if (!m_ackTimer.isRunning()) { + m_timeoutTimer.start(); + m_bits = 1U; + m_errs = 0U; + } + // Create a dummy start frame to replace the received frame m_networkWatchdog.stop(); - m_timeoutTimer.start(); + m_ackTimer.stop(); + + m_header = *header; m_frames = 1U; m_lost = 0U; @@ -307,8 +327,8 @@ void CDStarControl::writeModem(unsigned char *data) delete header; unsigned int errors = m_fec.regenerateDMR(data + 1U); - m_errs = errors; - m_bits = 48U; + m_errs += errors; + m_bits += 48U; if (m_net) writeNetworkData(data, errors, false, false); @@ -351,15 +371,8 @@ void CDStarControl::writeEndOfTransmission() m_display->clearDStar(); m_networkWatchdog.stop(); - m_timeoutTimer.stop(); m_packetTimer.stop(); - m_frames = 0U; - m_lost = 0U; - - m_errs = 0U; - m_bits = 0U; - #if defined(DUMP_DSTAR) closeFile(); #endif @@ -397,8 +410,11 @@ void CDStarControl::writeNetwork() unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH]; header.getYourCall(your); + m_header = header; + m_timeoutTimer.start(); m_elapsed.start(); + m_ackTimer.stop(); m_frames = 0U; m_lost = 0U; @@ -424,6 +440,8 @@ void CDStarControl::writeNetwork() if (m_state != RS_RELAYING_NETWORK_AUDIO) return; + m_timeoutTimer.stop(); + data[1U] = TAG_EOT; for (unsigned int i = 0U; i < 3U; i++) writeQueueData(data + 1U); @@ -435,7 +453,7 @@ void CDStarControl::writeNetwork() // We've received the header and EOT haven't we? m_frames += 2U; if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %u%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits); + LogMessage("D-Star, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); writeEndOfTransmission(); } else { @@ -472,6 +490,13 @@ void CDStarControl::clock(unsigned int ms) if (m_network != NULL) writeNetwork(); + m_ackTimer.clock(ms); + if (m_ackTimer.isRunning() && m_ackTimer.hasExpired()) { + sendAck(); + m_timeoutTimer.stop(); + m_ackTimer.stop(); + } + m_holdoffTimer.clock(ms); if (m_holdoffTimer.isRunning() && m_holdoffTimer.hasExpired()) m_holdoffTimer.stop(); @@ -485,7 +510,8 @@ void CDStarControl::clock(unsigned int ms) // We're received the header haven't we? m_frames += 1U; if (m_bits == 0U) m_bits = 1U; - LogMessage("D-Star, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %u%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits); + LogMessage("D-Star, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits)); + m_timeoutTimer.stop(); writeEndOfTransmission(); #if defined(DUMP_DSTAR) closeFile(); @@ -639,24 +665,15 @@ void CDStarControl::insertSilence(unsigned int count) unsigned char n = (m_n + 1U) % 21U; for (unsigned int i = 0U; i < count; i++) { - unsigned char data[DSTAR_FRAME_LENGTH_BYTES + 1U]; - if (i < 3U) - ::memcpy(data + 1U, m_lastFrame + 1U, DSTAR_FRAME_LENGTH_BYTES); - else - ::memcpy(data + 1U, DSTAR_NULL_AMBE_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES); - - if (n == 0U) { - // Regenerate the sync - ::memcpy(data + DSTAR_VOICE_FRAME_LENGTH_BYTES + 1U, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES); + if (i < 3U) { + writeQueueData(m_lastFrame); } else { - // Dummy slow data values - ::memcpy(data + DSTAR_VOICE_FRAME_LENGTH_BYTES + 1U, DSTAR_NULL_SLOW_DATA_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES); + if (n == 0U) + writeQueueData(DSTAR_NULL_FRAME_SYNC_BYTES); + else + writeQueueData(DSTAR_NULL_FRAME_DATA_BYTES); } - data[0U] = TAG_DATA; - - writeQueueData(data); - m_n = n; m_frames++; @@ -699,3 +716,45 @@ unsigned int CDStarControl::matchSync(const unsigned char* data) const return errors; } + +void CDStarControl::sendAck() +{ + unsigned char user[DSTAR_LONG_CALLSIGN_LENGTH]; + m_header.getMyCall1(user); + + CDStarHeader header; + header.setUnavailable(true); + header.setMyCall1(m_callsign); + header.setYourCall(user); + header.setRPTCall1(m_gateway); + header.setRPTCall2(m_callsign); + + unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 1U]; + header.get(data + 1U); + data[0U] = TAG_HEADER; + + writeQueueHeader(data); + + writeQueueData(DSTAR_NULL_FRAME_SYNC_BYTES); + + LINK_STATUS status = LS_NONE; + unsigned char reflector[DSTAR_LONG_CALLSIGN_LENGTH]; + if (m_network != NULL) + m_network->getStatus(status, reflector); + + char text[20U]; + if (status == LS_LINKED_DEXTRA || status == LS_LINKED_DPLUS || status == LS_LINKED_DCS || status == LS_LINKED_CCS || status == LS_LINKED_LOOPBACK) + ::sprintf(text, "%-8.8s BER: %.1f%% ", reflector, float(m_errs * 100U) / float(m_bits)); + else + ::sprintf(text, "BER: %.1f%% ", float(m_errs * 100U) / float(m_bits)); + m_slowData.setText(text); + + ::memcpy(data, DSTAR_NULL_FRAME_DATA_BYTES, DSTAR_FRAME_LENGTH_BYTES + 1U); + + for (unsigned int i = 0U; i < 19U; i++) { + m_slowData.get(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES); + writeQueueData(data); + } + + writeQueueData(DSTAR_END_PATTERN_BYTES); +} diff --git a/DStarControl.h b/DStarControl.h index 8b722e1..c709451 100644 --- a/DStarControl.h +++ b/DStarControl.h @@ -51,6 +51,7 @@ private: IDisplay* m_display; bool m_duplex; CRingBuffer m_queue; + CDStarHeader m_header; RPT_STATE m_state; bool m_net; CDStarSlowData m_slowData; @@ -59,6 +60,7 @@ private: CTimer m_holdoffTimer; CTimer m_timeoutTimer; CTimer m_packetTimer; + CTimer m_ackTimer; CStopWatch m_elapsed; unsigned int m_frames; unsigned int m_lost; @@ -86,6 +88,8 @@ private: void blankDTMF(unsigned char* data) const; unsigned int matchSync(const unsigned char* data) const; + + void sendAck(); }; #endif diff --git a/DStarDefines.h b/DStarDefines.h index cee49f8..dfbac46 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -19,10 +19,12 @@ #if !defined(DStarDefines_H) #define DStarDefines_H +#include "Defines.h" + const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U; const unsigned int DSTAR_FRAME_LENGTH_BYTES = 12U; -const unsigned char DSTAR_END_PATTERN_BYTES[] = { 0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +const unsigned char DSTAR_END_PATTERN_BYTES[] = { TAG_EOT, 0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const unsigned int DSTAR_END_PATTERN_LENGTH_BYTES = 6U; const unsigned char DSTAR_NULL_AMBE_DATA_BYTES[] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 }; @@ -30,7 +32,8 @@ const unsigned char DSTAR_NULL_AMBE_DATA_BYTES[] = { 0x9E, 0x8D, 0x32, 0x88, 0x2 // Note that these are already scrambled, 0x66 0x66 0x66 otherwise const unsigned char DSTAR_NULL_SLOW_DATA_BYTES[] = { 0x16, 0x29, 0xF5 }; -const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 }; +const unsigned char DSTAR_NULL_FRAME_SYNC_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16 }; +const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 }; const unsigned int DSTAR_VOICE_FRAME_LENGTH_BYTES = 9U; const unsigned int DSTAR_DATA_FRAME_LENGTH_BYTES = 3U; @@ -52,6 +55,12 @@ const unsigned char DSTAR_REPEATER_MASK = 0x40U; const unsigned char DSTAR_INTERRUPTED_MASK = 0x20U; const unsigned char DSTAR_CONTROL_SIGNAL_MASK = 0x10U; const unsigned char DSTAR_URGENT_MASK = 0x08U; +const unsigned char DSTAR_REPEATER_CONTROL = 0x07U; +const unsigned char DSTAR_AUTO_REPLY = 0x06U; +const unsigned char DSTAR_RESEND_REQUESTED = 0x04U; +const unsigned char DSTAR_ACK_FLAG = 0x03U; +const unsigned char DSTAR_NO_RESPONSE = 0x02U; +const unsigned char DSTAR_RELAY_UNAVAILABLE = 0x01U; const unsigned char DSTAR_SYNC_BYTES[] = {0x55U, 0x2DU, 0x16U}; @@ -60,4 +69,19 @@ const unsigned char DSTAR_DTMF_SIG[] = { 0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x0 const unsigned int DSTAR_FRAME_TIME = 20U; +enum LINK_STATUS { + LS_NONE, + LS_PENDING_IRCDDB, + LS_LINKING_LOOPBACK, + LS_LINKING_DEXTRA, + LS_LINKING_DPLUS, + LS_LINKING_DCS, + LS_LINKING_CCS, + LS_LINKED_LOOPBACK, + LS_LINKED_DEXTRA, + LS_LINKED_DPLUS, + LS_LINKED_DCS, + LS_LINKED_CCS +}; + #endif diff --git a/DStarHeader.cpp b/DStarHeader.cpp index 91ca3df..5b29f9a 100644 --- a/DStarHeader.cpp +++ b/DStarHeader.cpp @@ -34,11 +34,31 @@ m_header(NULL) ::memcpy(m_header, header, DSTAR_HEADER_LENGTH_BYTES); } +CDStarHeader::CDStarHeader() : +m_header(NULL) +{ + m_header = new unsigned char[DSTAR_HEADER_LENGTH_BYTES]; + + ::memset(m_header, ' ', DSTAR_HEADER_LENGTH_BYTES); + + m_header[0U] = 0x00U; + m_header[1U] = 0x00U; + m_header[2U] = 0x00U; +} + CDStarHeader::~CDStarHeader() { delete[] m_header; } +CDStarHeader& CDStarHeader::operator=(const CDStarHeader& header) +{ + if (&header != this) + ::memcpy(m_header, header.m_header, DSTAR_HEADER_LENGTH_BYTES); + + return *this; +} + bool CDStarHeader::isRepeater() const { return (m_header[0U] & DSTAR_REPEATER_MASK) == DSTAR_REPEATER_MASK; @@ -52,6 +72,14 @@ void CDStarHeader::setRepeater(bool on) m_header[0U] &= ~DSTAR_REPEATER_MASK; } +void CDStarHeader::setUnavailable(bool on) +{ + if (on) + m_header[0U] |= DSTAR_RELAY_UNAVAILABLE; + else + m_header[0U] &= ~DSTAR_RELAY_UNAVAILABLE; +} + void CDStarHeader::getMyCall1(unsigned char* call1) const { ::memcpy(call1, m_header + 27U, DSTAR_LONG_CALLSIGN_LENGTH); @@ -62,6 +90,16 @@ void CDStarHeader::getMyCall2(unsigned char* call2) const ::memcpy(call2, m_header + 35U, DSTAR_SHORT_CALLSIGN_LENGTH); } +void CDStarHeader::setMyCall1(const unsigned char* call1) +{ + ::memcpy(m_header + 27U, call1, DSTAR_LONG_CALLSIGN_LENGTH); +} + +void CDStarHeader::setMyCall2(const unsigned char* call2) +{ + ::memcpy(m_header + 35U, call2, DSTAR_SHORT_CALLSIGN_LENGTH); +} + void CDStarHeader::getRPTCall1(unsigned char* call1) const { ::memcpy(call1, m_header + 11U, DSTAR_LONG_CALLSIGN_LENGTH); @@ -87,6 +125,11 @@ void CDStarHeader::getYourCall(unsigned char* call) const ::memcpy(call, m_header + 19U, DSTAR_LONG_CALLSIGN_LENGTH); } +void CDStarHeader::setYourCall(const unsigned char* call) +{ + ::memcpy(m_header + 19U, call, DSTAR_LONG_CALLSIGN_LENGTH); +} + void CDStarHeader::get(unsigned char* header) const { assert(header != NULL); diff --git a/DStarHeader.h b/DStarHeader.h index 733dc2f..2c75380 100644 --- a/DStarHeader.h +++ b/DStarHeader.h @@ -22,14 +22,20 @@ class CDStarHeader { public: CDStarHeader(const unsigned char* header); + CDStarHeader(); ~CDStarHeader(); bool isRepeater() const; void setRepeater(bool on); + void setUnavailable(bool on); + void getMyCall1(unsigned char* call1) const; void getMyCall2(unsigned char* call2) const; + void setMyCall1(const unsigned char* call1); + void setMyCall2(const unsigned char* call2); + void getRPTCall1(unsigned char* call1) const; void getRPTCall2(unsigned char* call2) const; @@ -37,9 +43,12 @@ public: void setRPTCall2(const unsigned char* call2); void getYourCall(unsigned char* call) const; + void setYourCall(const unsigned char* call); void get(unsigned char* header) const; + CDStarHeader& operator=(const CDStarHeader& header); + private: unsigned char* m_header; }; diff --git a/DStarNetwork.cpp b/DStarNetwork.cpp index 7759c45..583ba8c 100644 --- a/DStarNetwork.cpp +++ b/DStarNetwork.cpp @@ -40,16 +40,21 @@ m_outId(0U), m_outSeq(0U), m_inId(0U), m_buffer(1000U), -m_pollTimer(1000U, 60U) +m_pollTimer(1000U, 60U), +m_linkStatus(LS_NONE), +m_linkReflector(NULL) { m_address = CUDPSocket::lookup(gatewayAddress); + m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH]; + CStopWatch stopWatch; ::srand(stopWatch.start()); } CDStarNetwork::~CDStarNetwork() { + delete[] m_linkReflector; } bool CDStarNetwork::open() @@ -200,6 +205,10 @@ void CDStarNetwork::clock(unsigned int ms) switch (buffer[4]) { case 0x00U: // NETWORK_TEXT; + m_linkStatus = LINK_STATUS(buffer[25U]); + ::memcpy(m_linkReflector, buffer + 26U, DSTAR_LONG_CALLSIGN_LENGTH); + return; + case 0x01U: // NETWORK_TEMPTEXT; case 0x04U: // NETWORK_STATUS1..5 case 0x24U: // NETWORK_DD_DATA @@ -296,3 +305,12 @@ void CDStarNetwork::enable(bool enabled) { m_enabled = enabled; } + +void CDStarNetwork::getStatus(LINK_STATUS& status, unsigned char* reflector) +{ + assert(reflector != NULL); + + status = m_linkStatus; + + ::memcpy(reflector, m_linkReflector, DSTAR_LONG_CALLSIGN_LENGTH); +} diff --git a/DStarNetwork.h b/DStarNetwork.h index 288715f..6cc03b0 100644 --- a/DStarNetwork.h +++ b/DStarNetwork.h @@ -39,6 +39,8 @@ public: bool writeHeader(const unsigned char* header, unsigned int length, bool busy); bool writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy); + void getStatus(LINK_STATUS& status, unsigned char* reflector); + unsigned int read(unsigned char* data, unsigned int length); void reset(); @@ -48,17 +50,19 @@ public: void clock(unsigned int ms); private: - CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; - std::string m_version; - bool m_debug; - bool m_enabled; - uint16_t m_outId; - uint8_t m_outSeq; - uint16_t m_inId; + CUDPSocket m_socket; + in_addr m_address; + unsigned int m_port; + std::string m_version; + bool m_debug; + bool m_enabled; + uint16_t m_outId; + uint8_t m_outSeq; + uint16_t m_inId; CRingBuffer m_buffer; - CTimer m_pollTimer; + CTimer m_pollTimer; + LINK_STATUS m_linkStatus; + unsigned char* m_linkReflector; bool writePoll(const char* text); }; diff --git a/DStarSlowData.cpp b/DStarSlowData.cpp index 1f72a77..719a47b 100644 --- a/DStarSlowData.cpp +++ b/DStarSlowData.cpp @@ -28,16 +28,20 @@ CDStarSlowData::CDStarSlowData() : m_header(NULL), m_ptr(0U), m_buffer(NULL), +m_text(NULL), +m_textPtr(0U), m_state(SDD_FIRST) { m_header = new unsigned char[50U]; // DSTAR_HEADER_LENGTH_BYTES m_buffer = new unsigned char[DSTAR_DATA_FRAME_LENGTH_BYTES * 2U]; + m_text = new unsigned char[24U]; } CDStarSlowData::~CDStarSlowData() { delete[] m_header; delete[] m_buffer; + delete[] m_text; } CDStarHeader* CDStarSlowData::add(const unsigned char* data) @@ -106,3 +110,53 @@ void CDStarSlowData::reset() m_ptr = 0U; m_state = SDD_FIRST; } + +void CDStarSlowData::setText(const char* text) +{ + assert(text != NULL); + + m_text[0U] = DSTAR_SLOW_DATA_TYPE_TEXT | 0U; + m_text[1U] = text[0U]; + m_text[2U] = text[1U]; + m_text[3U] = text[2U]; + m_text[4U] = text[3U]; + m_text[5U] = text[4U]; + + m_text[6U] = DSTAR_SLOW_DATA_TYPE_TEXT | 1U; + m_text[7U] = text[5U]; + m_text[8U] = text[6U]; + m_text[9U] = text[7U]; + m_text[10U] = text[8U]; + m_text[11U] = text[9U]; + + m_text[12U] = DSTAR_SLOW_DATA_TYPE_TEXT | 2U; + m_text[13U] = text[10U]; + m_text[14U] = text[11U]; + m_text[15U] = text[12U]; + m_text[16U] = text[13U]; + m_text[17U] = text[14U]; + + m_text[18U] = DSTAR_SLOW_DATA_TYPE_TEXT | 3U; + m_text[19U] = text[15U]; + m_text[20U] = text[16U]; + m_text[21U] = text[17U]; + m_text[22U] = text[18U]; + m_text[23U] = text[19U]; + + m_textPtr = 0U; +} + +void CDStarSlowData::get(unsigned char* data) +{ + assert(data != NULL); + + if (m_textPtr < 24U) { + data[0U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[0U]; + data[1U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[1U]; + data[2U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[2U]; + } else { + data[0U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[0U]; + data[1U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[1U]; + data[2U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[2U]; + } +} diff --git a/DStarSlowData.h b/DStarSlowData.h index f288df7..52e0f5c 100644 --- a/DStarSlowData.h +++ b/DStarSlowData.h @@ -31,10 +31,15 @@ public: void start(); void reset(); + void setText(const char* text); + void get(unsigned char* data); + private: unsigned char* m_header; unsigned int m_ptr; unsigned char* m_buffer; + unsigned char* m_text; + unsigned int m_textPtr; enum SDD_STATE { SDD_FIRST,