From a696fd454c88b2efd9561ef46563bcd0c772a641 Mon Sep 17 00:00:00 2001 From: adrian Date: Sat, 18 Apr 2026 11:29:48 +0300 Subject: [PATCH] DMR trunking patches to DMRTX and SerialPort --- DMRTX.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++------ DMRTX.h | 6 ++++++ SerialPort.cpp | 13 ++++++++++++- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/DMRTX.cpp b/DMRTX.cpp index 594ccff..a9a4690 100644 --- a/DMRTX.cpp +++ b/DMRTX.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2017 by Andy Uribe CA6JAU + * Copyright (C) 2022,2023,2026 by Adrian Musceac YO8RZZ * * 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 @@ -42,6 +43,12 @@ const uint8_t IDLE_DATA[] = 0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U, 0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U}; +// DT Terminator with LC, empty +const uint8_t TERMINATOR_DATA[] = + {0x00U, 0xCCU, 0x01U, 0x80U, 0x01U, 0x94U, 0x01U, 0x48U, 0x08U, 0xB0U, 0x08U, + 0x80U, 0x04U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x90U, + 0x01U, 0x78U, 0x00U, 0xD0U, 0x08U, 0x40U, 0x14U, 0x00U, 0x0DU, 0x80U, 0x15U}; + const uint8_t CACH_INTERLEAVE[] = { 1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U, 25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U, @@ -65,6 +72,7 @@ m_modFilter(), m_modState(), m_state(DMRTXSTATE_IDLE), m_idle(), +m_aloha(), m_cachPtr(0U), m_shortLC(), m_newShortLC(), @@ -74,7 +82,9 @@ m_poLen(0U), m_poPtr(0U), m_frameCount(0U), m_abortCount(), -m_abort() +m_abort(), +m_controlChannel(false), +m_trunking(false) { ::memset(m_modState, 0x00U, 16U * sizeof(q15_t)); @@ -211,6 +221,15 @@ uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint16_t length) return 0U; } +uint8_t CDMRTX::writeAloha(const uint8_t* data, uint16_t length) +{ + if (length != DMR_FRAME_LENGTH_BYTES) + return 4U; + ::memcpy(m_aloha, data, length); + m_controlChannel = true; + return 0U; +} + uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length) { if (length != 1U) @@ -303,7 +322,12 @@ void CDMRTX::createData(uint8_t slotIndex) m_abort[slotIndex] = false; // Transmit an idle message for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) { - m_poBuffer[i] = m_idle[i]; + if(slotIndex == 0 && m_controlChannel && m_trunking) { + m_poBuffer[i] = m_aloha[i]; + } + else { + m_poBuffer[i] = m_idle[i]; + } m_markBuffer[i] = MARK_NONE; } } @@ -355,8 +379,6 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) if (m_cachPtr == 0U) { if (m_fifo[0U].getData() == 0U && m_fifo[1U].getData() == 0U) - ::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U); - else ::memcpy(m_shortLC, m_newShortLC, 12U); } @@ -397,10 +419,19 @@ void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex) void CDMRTX::setColorCode(uint8_t colorCode) { - ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); + if(m_trunking) + ::memcpy(m_idle, TERMINATOR_DATA, DMR_FRAME_LENGTH_BYTES); + else + ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); CDMRSlotType slotType; - slotType.encode(colorCode, DT_IDLE, m_idle); + if(m_trunking) { + slotType.encode(colorCode, DT_TERMINATOR_WITH_LC, m_idle); + slotType.encode(colorCode, DT_CSBK, m_aloha); + } + else { + slotType.encode(colorCode, DT_IDLE, m_idle); + } } void CDMRTX::resetFifo1() @@ -418,5 +449,11 @@ uint32_t CDMRTX::getFrameCount() return m_frameCount; } +void CDMRTX::setTrunking(bool trunking) +{ + m_trunking = trunking; +} + + #endif diff --git a/DMRTX.h b/DMRTX.h index 8555f13..d7f3e28 100644 --- a/DMRTX.h +++ b/DMRTX.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX * Copyright (C) 2016 by Colin Durbridge G4EML + * Copyright (C) 2026 by Adrian Musceac YO8RZZ * * 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 @@ -45,10 +46,12 @@ public: uint8_t writeData2(const uint8_t* data, uint16_t length); uint8_t writeShortLC(const uint8_t* data, uint16_t length); + uint8_t writeAloha(const uint8_t* data, uint16_t length); uint8_t writeAbort(const uint8_t* data, uint16_t length); void setStart(bool start); void setCal(bool start); + void setTrunking(bool trunking); void process(); @@ -67,6 +70,7 @@ private: q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare DMRTXSTATE m_state; uint8_t m_idle[DMR_FRAME_LENGTH_BYTES]; + uint8_t m_aloha[DMR_FRAME_LENGTH_BYTES]; uint8_t m_cachPtr; uint8_t m_shortLC[12U]; uint8_t m_newShortLC[12U]; @@ -77,6 +81,8 @@ private: uint32_t m_frameCount; uint32_t m_abortCount[2U]; bool m_abort[2U]; + bool m_controlChannel; + bool m_trunking; void createData(uint8_t slotIndex); void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex); diff --git a/SerialPort.cpp b/SerialPort.cpp index d2bf7a8..302acc1 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -50,6 +50,7 @@ const uint8_t MMDVM_DMR_LOST1 = 0x19U; const uint8_t MMDVM_DMR_DATA2 = 0x1AU; const uint8_t MMDVM_DMR_LOST2 = 0x1BU; const uint8_t MMDVM_DMR_SHORTLC = 0x1CU; +const uint8_t MMDVM_DMR_ALOHA = 0x14U; const uint8_t MMDVM_DMR_START = 0x1DU; const uint8_t MMDVM_DMR_ABORT = 0x1EU; @@ -466,6 +467,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) #endif #if defined(MODE_DMR) + bool trunking = (data[25U] & 128U) == 128U; uint8_t colorCode = data[26U]; if (colorCode > 15U) return 4U; @@ -484,7 +486,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length) #if defined(MODE_DMR) m_dmrEnable = dmrEnable; dmrDMOTX.setTXDelay(txDelay); - + dmrTX.setTrunking(trunking); dmrTX.setColorCode(colorCode); dmrRX.setColorCode(colorCode); dmrRX.setDelay(dmrDelay); @@ -1123,6 +1125,15 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l } break; + case MMDVM_DMR_ALOHA: + if (m_dmrEnable) + err = dmrTX.writeAloha(buffer, length); + if (err != 0U) { + DEBUG2("Received invalid DMR ALOHA", err); + sendNAK(type, err); + } + break; + case MMDVM_DMR_ABORT: if (m_dmrEnable) err = dmrTX.writeAbort(buffer, length);