diff --git a/Defines.h b/Defines.h index 23e59101..719d2528 100644 --- a/Defines.h +++ b/Defines.h @@ -93,10 +93,17 @@ typedef unsigned long long ulong64_t; // Constants // --------------------------------------------------------------------------- +#ifndef __GIT_VER__ +#define __GIT_VER__ "00000000" +#endif +#ifndef __GIT_VER_HASH__ +#define __GIT_VER_HASH__ "00000000" +#endif + #define __PROG_NAME__ "Digital Voice Modem Host" #define __NET_NAME__ "DVM_DMR_P25" #define __EXE_NAME__ "dvmhost" -#define __VER__ "R01.00.00" +#define __VER__ "R01.00.00 (" __GIT_VER__ ")" #define __BUILD__ __DATE__ " " __TIME__ #define HOST_SW_API @@ -201,23 +208,23 @@ inline std::string __IP_FROM_ULONG(const ulong64_t& value) { #define WRITE_BIT(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_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7]) -#define __SET_UINT32(val, buffer, offset) \ - buffer[0U + offset] = val >> 24; \ - buffer[1U + offset] = val >> 16; \ - buffer[2U + offset] = val >> 8; \ - buffer[3U + offset] = val >> 0; -#define __GET_UINT32(buffer, offset) \ - (buffer[offset + 0U] << 24) | \ - (buffer[offset + 1U] << 16) | \ - (buffer[offset + 2U] << 8) | \ +#define __SET_UINT32(val, buffer, offset) \ + buffer[0U + offset] = (val >> 24) & 0xFFU; \ + buffer[1U + offset] = (val >> 16) & 0xFFU; \ + buffer[2U + offset] = (val >> 8) & 0xFFU; \ + buffer[3U + offset] = (val >> 0) & 0xFFU; +#define __GET_UINT32(buffer, offset) \ + (buffer[offset + 0U] << 24) | \ + (buffer[offset + 1U] << 16) | \ + (buffer[offset + 2U] << 8) | \ (buffer[offset + 3U] << 0); -#define __SET_UINT16(val, buffer, offset) \ - buffer[0U + offset] = val >> 16; \ - buffer[1U + offset] = val >> 8; \ - buffer[2U + offset] = val >> 0; -#define __GET_UINT16(buffer, offset) \ - (buffer[offset + 0U] << 16) | \ - (buffer[offset + 1U] << 8) | \ +#define __SET_UINT16(val, buffer, offset) \ + buffer[0U + offset] = (val >> 16) & 0xFFU; \ + buffer[1U + offset] = (val >> 8) & 0xFFU; \ + buffer[2U + offset] = (val >> 0) & 0xFFU; +#define __GET_UINT16(buffer, offset) \ + (buffer[offset + 0U] << 16) | \ + (buffer[offset + 1U] << 8) | \ (buffer[offset + 2U] << 0); /** diff --git a/HostMain.cpp b/HostMain.cpp index 537161ea..6d5ce36f 100644 --- a/HostMain.cpp +++ b/HostMain.cpp @@ -74,6 +74,8 @@ bool g_killed = false; bool g_fireDMRBeacon = false; bool g_fireP25Control = false; +uint8_t* g_gitHashBytes = NULL; + // --------------------------------------------------------------------------- // Global Functions // --------------------------------------------------------------------------- @@ -188,6 +190,12 @@ int checkArgs(int argc, char* argv[]) int main(int argc, char** argv) { + g_gitHashBytes = new uint8_t[4U]; + ::memset(g_gitHashBytes, 0x00U, 4U); + + uint32_t hash = ::strtoul(__GIT_VER_HASH__, 0, 16); + __SET_UINT32(hash, g_gitHashBytes, 0U); + if (argv[0] != NULL && *argv[0] != 0) g_progExe = std::string(argv[0]); diff --git a/HostMain.h b/HostMain.h index 8b7e5568..d0566318 100644 --- a/HostMain.h +++ b/HostMain.h @@ -50,6 +50,8 @@ extern bool g_killed; extern bool g_fireDMRBeacon; extern bool g_fireP25Control; +extern uint8_t* g_gitHashBytes; + extern HOST_SW_API void fatal(const char* msg, ...); #endif // __HOST_MAIN_H__ diff --git a/Makefile b/Makefile index bc2a6731..ebb1b91d 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,15 @@ ifneq ($(ARCH),) TAR_ARCH = "_$(ARCH)" endif +GITFLAGS= +GIT_VER = +GIT_VER_HASH = +ifneq ("$(wildcard .git)",) + GIT_VER = \"$(shell git describe --abbrev=8 --dirty --always --tags)\" + GIT_VER_HASH = \"$(shell git describe --abbrev=8 --always --tags)\" + GITFLAGS= -D__GIT_VER__=$(GIT_VER) -D__GIT_VER_HASH__=$(GIT_VER_HASH) +endif + HOST_BIN = dvmhost HOST_OBJECTS = \ edac/AMBEFEC.o \ @@ -107,13 +116,13 @@ CMD_OBJECTS = \ all: dvmhost dvmcmd dvmhost: $(HOST_OBJECTS) - $($(ARCH)CXX) $(HOST_OBJECTS) $(CFLAGS) $(EXTFLAGS) $(LIBS) -o $(HOST_BIN) + $($(ARCH)CXX) $(HOST_OBJECTS) $(CFLAGS) $(GITFLAGS) $(EXTFLAGS) $(LIBS) -o $(HOST_BIN) dvmcmd: $(CMD_OBJECTS) - $($(ARCH)CXX) $(CMD_OBJECTS) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) $(LIBS) -o $(CMD_BIN) + $($(ARCH)CXX) $(CMD_OBJECTS) $(GITFLAGS) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) $(LIBS) -o $(CMD_BIN) %.o: %.cpp - $($(ARCH)CXX) $(CFLAGS) $(EXTFLAGS) -c -o $@ $< + $($(ARCH)CXX) $(CFLAGS) $(GITFLAGS) $(EXTFLAGS) -c -o $@ $< %.cmd.o: %.cpp - $($(ARCH)CXX) $(CFLAGS) $(CCFLAGS) $(EXTFLAGS) -c -o $@ $< + $($(ARCH)CXX) $(CFLAGS) $(CCFLAGS) $(GITFLAGS) $(EXTFLAGS) -c -o $@ $< strip: -$($(ARCH)STRIP) $(HOST_BIN) -$($(ARCH)STRIP) $(CMD_BIN) @@ -122,7 +131,7 @@ clean: $(RM) -r dpkg_build tar_build $(RM) dvmhost_1.0.0* dvmhost-dbgsym*.deb -install:all +install: all mkdir -p /opt/dvm/bin || true install -m 755 $(HOST_BIN) /opt/dvm/bin/ install -m 755 $(CMD_BIN) /opt/dvm/bin/ diff --git a/RingBuffer.h b/RingBuffer.h index 482532a6..499af455 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -80,14 +80,18 @@ public: clear(); return false; } - +#if DEBUG_RINGBUFFER + uint32_t iPtr_BeforeWrite = m_iPtr; +#endif for (uint32_t i = 0U; i < length; i++) { m_buffer[m_iPtr++] = buffer[i]; if (m_iPtr == m_length) m_iPtr = 0U; } - +#if DEBUG_RINGBUFFER + LogDebug(LOG_HOST, "RingBuffer::addData(%s): iPtr_Before = %u, iPtr_After = %u, oPtr = %u, len = %u, len_Written = %u", m_name, iPtr_BeforeWrite, m_iPtr, m_oPtr, m_length, (m_iPtr - iPtr_BeforeWrite)); +#endif return true; } @@ -101,14 +105,18 @@ public: LogError(LOG_HOST, "**** Underflow in %s ring buffer, %u < %u", m_name, dataSize(), length); return false; } - +#if DEBUG_RINGBUFFER + uint32_t oPtr_BeforeRead = m_oPtr; +#endif for (uint32_t i = 0U; i < length; i++) { buffer[i] = m_buffer[m_oPtr++]; if (m_oPtr == m_length) m_oPtr = 0U; } - +#if DEBUG_RINGBUFFER + LogDebug(LOG_HOST, "RingBuffer::getData(%s): iPtr = %u, oPtr_Before = %u, oPtr_After = %u, len = %u, len_Read = %u", m_name, m_iPtr, oPtr_BeforeRead, m_oPtr, m_length, (m_oPtr - oPtr_BeforeRead)); +#endif return true; } diff --git a/dmr/Control.cpp b/dmr/Control.cpp index 639763ca..d6193a9a 100644 --- a/dmr/Control.cpp +++ b/dmr/Control.cpp @@ -76,6 +76,7 @@ Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool m_tidLookup(tidLookup), m_tsccSlotNo(0U), m_ccRunning(false), + m_ccHalted(false), m_dumpCSBKData(dumpCSBKData), m_verbose(verbose), m_debug(debug) @@ -176,6 +177,26 @@ void Control::setCCRunning(bool ccRunning) } } +/// +/// Sets a flag indicating whether the DMR control channel is halted. +/// +/// +void Control::setCCHalted(bool ccHalted) +{ + m_ccHalted = ccHalted; + switch (m_tsccSlotNo) { + case 1U: + m_slot1->setCCHalted(ccHalted); + break; + case 2U: + m_slot2->setCCHalted(ccHalted); + break; + default: + LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo); + break; + } +} + /// /// Helper to process wakeup frames from the RF interface. /// diff --git a/dmr/Control.h b/dmr/Control.h index 04c4e8c0..f484d62e 100644 --- a/dmr/Control.h +++ b/dmr/Control.h @@ -68,10 +68,15 @@ namespace dmr /// Helper to set DMR configuration options. void setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8_t channelId, uint32_t channelNo, bool printOptions); + /// Gets a flag indicating whether the DMR control channel is running. bool getCCRunning() { return m_ccRunning; } /// Sets a flag indicating whether the DMR control channel is running. void setCCRunning(bool ccRunning); + /// Gets a flag indicating whether the DMR control channel is running. + bool getCCHalted() { return m_ccHalted; } + /// Sets a flag indicating whether the DMR control channel is halted. + void setCCHalted(bool ccHalted); /// Helper to process wakeup frames from the RF interface. bool processWakeup(const uint8_t* data); @@ -107,6 +112,7 @@ namespace dmr uint8_t m_tsccSlotNo; bool m_ccRunning; + bool m_ccHalted; bool m_dumpCSBKData; bool m_verbose; diff --git a/dmr/DMRDefines.h b/dmr/DMRDefines.h index afbc5ab5..52dd8d71 100644 --- a/dmr/DMRDefines.h +++ b/dmr/DMRDefines.h @@ -160,6 +160,7 @@ namespace dmr // Feature IDs const uint8_t FID_ETSI = 0x00U; // ETSI Standard Feature Set const uint8_t FID_DMRA = 0x10U; // + const uint8_t FID_DVM = 0xFEU; // internal DMR FID used for internal signalling // LC Service Options const uint8_t LC_SVC_OPT_EMERGENCY = 0x80U; @@ -248,6 +249,8 @@ namespace dmr const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK + const uint8_t CSBKO_DVM_GIT_HASH = 0xFBU; // + const uint8_t TALKER_ID_NONE = 0x00U; const uint8_t TALKER_ID_HEADER = 0x01U; const uint8_t TALKER_ID_BLOCK1 = 0x02U; diff --git a/dmr/Slot.cpp b/dmr/Slot.cpp index b1cc8f67..6e0849e3 100644 --- a/dmr/Slot.cpp +++ b/dmr/Slot.cpp @@ -148,6 +148,8 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD), m_ccSeq(0U), m_ccRunning(false), + m_ccPrevRunning(false), + m_ccHalted(false), m_enableTSCC(false), m_dumpCSBKData(dumpCSBKData), m_verbose(verbose), @@ -170,15 +172,6 @@ Slot::~Slot() delete m_control; } -/// -/// Sets a flag indicating whether the DMR control channel is running. -/// -/// -void Slot::setCCRunning(bool ccRunning) -{ - m_ccRunning = ccRunning; -} - /// /// Process DMR data frame from the RF interface. /// @@ -332,7 +325,6 @@ uint32_t Slot::getFrame(uint8_t* data) uint8_t len = 0U; m_queue.getData(&len, 1U); - m_queue.getData(data, len); return len; @@ -404,37 +396,50 @@ void Slot::clock() } } + // if we have control enabled; do clocking to generate a CC data stream if (m_enableTSCC) { - m_ccPacketInterval.clock(ms); - if (!m_ccPacketInterval.isRunning()) { + if (m_ccRunning && !m_ccPacketInterval.isRunning()) { m_ccPacketInterval.start(); } - if (m_ccPacketInterval.isRunning() && m_ccPacketInterval.hasExpired()) { - // increment the TSCC counter on every slot 1 clock - m_tsccCnt++; - if (m_tsccCnt == TSCC_MAX_CNT) { - m_tsccCnt = 0U; + if (m_ccHalted) { + if (!m_ccRunning) { + m_ccHalted = false; + m_ccPrevRunning = m_ccRunning; + m_queue.clear(); // clear the frame buffer } - - if (m_ccSeq == 3U) { - m_ccSeq = 0U; + } + else { + m_ccPacketInterval.clock(ms); + if (!m_ccPacketInterval.isRunning()) { + m_ccPacketInterval.start(); } - if (m_dedicatedTSCC) { - setShortLC_TSCC(m_siteData, m_tsccCnt); - writeRF_ControlData(m_tsccCnt, m_ccSeq); - } - else { + if (m_ccPacketInterval.isRunning() && m_ccPacketInterval.hasExpired()) { if (m_ccRunning) { + // increment the TSCC counter on every slot 1 clock + m_tsccCnt++; + if (m_tsccCnt == TSCC_MAX_CNT) { + m_tsccCnt = 0U; + } + + if (m_ccSeq == 3U) { + m_ccSeq = 0U; + } + setShortLC_TSCC(m_siteData, m_tsccCnt); writeRF_ControlData(m_tsccCnt, m_ccSeq); + + m_ccSeq++; } - } - m_ccSeq++; + m_ccPacketInterval.start(); + } + } - m_ccPacketInterval.start(); + if (m_ccPrevRunning && !m_ccRunning) { + m_queue.clear(); // clear the frame buffer + m_ccPrevRunning = m_ccRunning; } } @@ -872,11 +877,22 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) return; } - // loop to generate 2 control sequences + // loop to generate 3 control sequences if (frameCnt == 511U) { seqCnt = 3U; } + // shuld we insert the Git Hash burst? + bool hash = (frameCnt % 256U) == 0U; + if (hash) { + m_control->writeRF_TSCC_Git_Hash(); + + if (seqCnt > 0U) + n++; + + return; + } + do { if (m_debug) { diff --git a/dmr/Slot.h b/dmr/Slot.h index 09882b0d..a35e1f55 100644 --- a/dmr/Slot.h +++ b/dmr/Slot.h @@ -72,8 +72,14 @@ namespace dmr /// Finalizes a instance of the Slot class. ~Slot(); - /// Sets a flag indicating whether the DMR control channel is running. - void setCCRunning(bool ccRunning); + /// Gets a flag indicating whether the P25 control channel is running. + bool getCCRunning() { return m_ccRunning; } + /// Sets a flag indicating whether the P25 control channel is running. + void setCCRunning(bool ccRunning) { m_ccPrevRunning = m_ccRunning; m_ccRunning = ccRunning; } + /// Gets a flag indicating whether the DMR control channel is running. + bool getCCHalted() { return m_ccHalted; } + /// Sets a flag indicating whether the DMR control channel is halted. + void setCCHalted(bool ccHalted) { m_ccHalted = ccHalted; } /// Process a data frame from the RF interface. bool processFrame(uint8_t* data, uint32_t len); @@ -165,6 +171,8 @@ namespace dmr uint8_t m_ccSeq; bool m_ccRunning; + bool m_ccPrevRunning; + bool m_ccHalted; bool m_enableTSCC; bool m_dedicatedTSCC; diff --git a/dmr/lc/CSBK.cpp b/dmr/lc/CSBK.cpp index f7de04f5..46587280 100644 --- a/dmr/lc/CSBK.cpp +++ b/dmr/lc/CSBK.cpp @@ -32,6 +32,7 @@ #include "dmr/lc/CSBK.h" #include "edac/BPTC19696.h" #include "edac/CRC.h" +#include "HostMain.h" #include "Log.h" #include "Utils.h" @@ -427,7 +428,6 @@ void CSBK::encode(uint8_t* bytes) csbkValue = (csbkValue << 1) + ((m_hibernating) ? 1U : 0U); // TSCC Hibernating csbkValue = (csbkValue << 22) + 0U; // Broadcast Parms 2 (Reserved) } - break; } // split value into bytes @@ -460,10 +460,60 @@ void CSBK::encode(uint8_t* bytes) m_data[7U] = (m_srcId >> 16) & 0xFFU; // Source ID m_data[8U] = (m_srcId >> 8) & 0xFFU; m_data[9U] = (m_srcId >> 0) & 0xFFU; - LogError(LOG_DMR, "CSBK::encode(), unknown CSBK type, csbko = $%02X", m_CSBKO); + if ((m_FID == FID_ETSI) || (m_FID == FID_DMRA)) { + LogError(LOG_DMR, "CSBK::encode(), unknown CSBK type, csbko = $%02X", m_CSBKO); + } break; } + // internal DMR vendor opcodes + if (m_FID == FID_DVM) { + switch (m_CSBKO) { + case CSBKO_DVM_GIT_HASH: + { + ulong64_t csbkValue = 0U; + csbkValue = g_gitHashBytes[0]; // ... + csbkValue = (csbkValue << 8) + (g_gitHashBytes[1U]); // ... + csbkValue = (csbkValue << 8) + (g_gitHashBytes[2U]); // ... + csbkValue = (csbkValue << 8) + (g_gitHashBytes[3U]); // ... + csbkValue = (csbkValue << 16) + 0U; + csbkValue = (csbkValue << 4) + m_siteIdenEntry.channelId(); // Channel ID + csbkValue = (csbkValue << 12) + m_logicalCh1; // Channel Number + + // split value into bytes + m_data[2U] = (uint8_t)((csbkValue >> 56) & 0xFFU); + m_data[3U] = (uint8_t)((csbkValue >> 48) & 0xFFU); + m_data[4U] = (uint8_t)((csbkValue >> 40) & 0xFFU); + m_data[5U] = (uint8_t)((csbkValue >> 32) & 0xFFU); + m_data[6U] = (uint8_t)((csbkValue >> 24) & 0xFFU); + m_data[7U] = (uint8_t)((csbkValue >> 16) & 0xFFU); + m_data[8U] = (uint8_t)((csbkValue >> 8) & 0xFFU); + m_data[9U] = (uint8_t)((csbkValue >> 0) & 0xFFU); + } + break; + default: + if (m_GI) { + m_data[2U] |= 0x40U; // Group or Individual + } + + if (m_dataContent) { + m_data[2U] |= 0x80U; // + } + + m_data[3U] = m_CBF; // + + m_data[4U] = (m_dstId >> 16) & 0xFFU; // Destination ID + m_data[5U] = (m_dstId >> 8) & 0xFFU; + m_data[6U] = (m_dstId >> 0) & 0xFFU; + + m_data[7U] = (m_srcId >> 16) & 0xFFU; // Source ID + m_data[8U] = (m_srcId >> 8) & 0xFFU; + m_data[9U] = (m_srcId >> 0) & 0xFFU; + LogError(LOG_DMR, "CSBK::encode(), unknown CSBK type, csbko = $%02X", m_CSBKO); + break; + } + } + m_data[10U] ^= CSBK_CRC_MASK[0U]; m_data[11U] ^= CSBK_CRC_MASK[1U]; diff --git a/dmr/packet/ControlSignaling.cpp b/dmr/packet/ControlSignaling.cpp index a4c11480..3b311a78 100644 --- a/dmr/packet/ControlSignaling.cpp +++ b/dmr/packet/ControlSignaling.cpp @@ -633,3 +633,42 @@ void ControlSignaling::writeRF_TSCC_Bcast_Sys_Parm() if (m_slot->m_duplex) m_slot->addFrame(data); } + +/// +/// Helper to write a TSCC Git Hash broadcast packet on the RF interface. +/// +void ControlSignaling::writeRF_TSCC_Git_Hash() +{ + if (m_debug) { + LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_DVM_GIT_HASH (DVM Git Hash)", m_slot->m_slotNo); + } + + uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES); + + SlotType slotType; + slotType.setColorCode(m_slot->m_colorCode); + slotType.setDataType(DT_CSBK); + + lc::CSBK csbk = lc::CSBK(m_slot->m_siteData, m_slot->m_idenEntry, m_slot->m_dumpCSBKData); + csbk.setVerbose(m_dumpCSBKData); + csbk.setCSBKO(CSBKO_DVM_GIT_HASH); + csbk.setFID(FID_DVM); + + // Regenerate the CSBK data + csbk.encode(data + 2U); + + // Regenerate the Slot Type + slotType.encode(data + 2U); + + // Convert the Data Sync to be from the BS or MS as needed + Sync::addDMRDataSync(data + 2U, m_slot->m_duplex); + + m_slot->m_rfSeqNo = 0U; + + data[0U] = modem::TAG_DATA; + data[1U] = 0x00U; + + if (m_slot->m_duplex) + m_slot->addFrame(data); +} diff --git a/dmr/packet/ControlSignaling.h b/dmr/packet/ControlSignaling.h index 7bc512c7..8a788179 100644 --- a/dmr/packet/ControlSignaling.h +++ b/dmr/packet/ControlSignaling.h @@ -93,6 +93,8 @@ namespace dmr void writeRF_TSCC_Bcast_Ann_Wd(uint32_t channelNo, bool annWd); /// Helper to write a TSCC Sys_Parm broadcast packet on the RF interface. void writeRF_TSCC_Bcast_Sys_Parm(); + /// Helper to write a TSCC Git Hash broadcast packet on the RF interface. + void writeRF_TSCC_Git_Hash(); }; } // namespace packet } // namespace dmr diff --git a/host/Host.cpp b/host/Host.cpp index 4295c79d..9379a293 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -662,8 +662,10 @@ int Host::run() #define INTERRUPT_DMR_BEACON \ if (dmr != NULL) { \ if (dmrBeaconDurationTimer.isRunning() && !dmrBeaconDurationTimer.hasExpired()) { \ - if (m_dmrTSCCData && !m_dmrCtrlChannel) \ + if (m_dmrTSCCData && !m_dmrCtrlChannel) { \ + dmr->setCCHalted(true); \ dmr->setCCRunning(false); \ + } \ } \ dmrBeaconDurationTimer.stop(); \ } @@ -727,6 +729,8 @@ int Host::run() if (ret) { len = dmr->getFrame(1U, data); if (len > 0U) { + LogDebug(LOG_HOST, "found DMR frame, len = %u", len); + // if the state is idle; set to DMR, start mode timer and start DMR idle frames if (m_state == STATE_IDLE) { m_modeTimer.setTimeout(m_netModeHang); @@ -1274,6 +1278,7 @@ int Host::run() } dmr->setCCRunning(false); + dmr->setCCHalted(true); dmrBeaconDurationTimer.stop(); dmrBeaconIntervalTimer.stop(); @@ -2041,7 +2046,11 @@ void Host::setState(uint8_t state) } m_modem->setState(STATE_IDLE); - + + m_modem->clearDMRData1(); + m_modem->clearDMRData2(); + m_modem->clearP25Data(); + if (m_state == HOST_STATE_ERROR) { m_modem->sendCWId(m_cwCallsign); diff --git a/p25/P25Defines.h b/p25/P25Defines.h index 5b0ec532..f5e637dc 100644 --- a/p25/P25Defines.h +++ b/p25/P25Defines.h @@ -113,7 +113,7 @@ namespace p25 const uint8_t P25_MFG_STANDARD = 0x00U; const uint8_t P25_MFG_MOT = 0x90U; - const uint8_t P25_MFG_DVM = 0xFEU; // internal P25 MFId used for internal signalling (shouldn't be air transmitted!) + const uint8_t P25_MFG_DVM = 0xFEU; // internal P25 MFId used for internal signalling const uint8_t P25_MOT_CALLSIGN_LENGTH_BYTES = 8U; @@ -333,6 +333,9 @@ namespace p25 const uint8_t TSBK_OSP_MOT_CC_BSI = 0x0BU; // MOT CC BSI - Motorola / Control Channel Base Station Identifier const uint8_t TSBK_OSP_MOT_PSH_CCH = 0x0EU; // MOT PSH CCH - Motorola / Planned Control Channel Shutdown + // TSBK Motorola Outbound Signalling Packet (OSP) Opcode(s) + const uint8_t TSBK_OSP_DVM_GIT_HASH = 0xFBU; // + // Data Unit ID(s) const uint8_t P25_DUID_HDU = 0x00U; // Header Data Unit const uint8_t P25_DUID_TDU = 0x03U; // Simple Terminator Data Unit diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp index 4e1f6f49..b4745a75 100644 --- a/p25/lc/TSBK.cpp +++ b/p25/lc/TSBK.cpp @@ -28,6 +28,7 @@ #include "p25/lc/TSBK.h" #include "p25/P25Utils.h" #include "edac/CRC.h" +#include "HostMain.h" #include "Log.h" #include "Utils.h" @@ -975,7 +976,7 @@ void TSBK::encode(uint8_t* data, bool rawTSBK, bool noTrellis) break; case TSBK_OSP_MOT_CC_BSI: tsbkValue = (m_siteCallsign[0] - 43U) & 0x3F; // Character 0 - for (int i = 1; i < P25_MOT_CALLSIGN_LENGTH_BYTES; i++) { + for (uint8_t i = 1; i < P25_MOT_CALLSIGN_LENGTH_BYTES; i++) { tsbkValue = (tsbkValue << 6) + ((m_siteCallsign[i] - 43U) & 0x3F); // Character 1 - 7 } tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID @@ -1008,11 +1009,20 @@ void TSBK::encode(uint8_t* data, bool rawTSBK, bool noTrellis) // internal P25 vendor opcodes if (m_mfId == P25_MFG_DVM) { switch (m_lco) { + case TSBK_OSP_DVM_GIT_HASH: + tsbkValue = g_gitHashBytes[0]; // ... + tsbkValue = (tsbkValue << 8) + (g_gitHashBytes[1U]); // ... + tsbkValue = (tsbkValue << 8) + (g_gitHashBytes[2U]); // ... + tsbkValue = (tsbkValue << 8) + (g_gitHashBytes[3U]); // ... + tsbkValue = (tsbkValue << 16) + 0U; + tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID + tsbkValue = (tsbkValue << 12) + m_siteData.channelNo(); // Channel Number + break; case LC_CALL_TERM: - tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID - tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number - tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address - tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address + tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID + tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number + tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address + tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address break; default: LogError(LOG_P25, "TSBK::encode(), unknown TSBK LCO value, mfId = $%02X, lco = $%02X", m_mfId, m_lco); diff --git a/p25/packet/Trunk.cpp b/p25/packet/Trunk.cpp index 27cbb7e5..3fd8fbb8 100644 --- a/p25/packet/Trunk.cpp +++ b/p25/packet/Trunk.cpp @@ -1521,6 +1521,12 @@ void Trunk::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS) queueRF_TSBK_Ctrl(TSBK_OSP_MOT_CC_BSI); } + // shuld we insert the Git Hash burst? + bool hash = (frameCnt % 125U) == 0U; + if (hash && n > 3U) { + queueRF_TSBK_Ctrl(TSBK_OSP_DVM_GIT_HASH); + } + // add padding after the last sequence or if forced; and only // if we're doing multiblock frames (MBF) if ((n >= 4U || forcePad) && m_ctrlTSDUMBF) @@ -2057,6 +2063,17 @@ void Trunk::queueRF_TSBK_Ctrl(uint8_t lco) m_rfTSBK.setLCO(TSBK_OSP_MOT_CC_BSI); m_rfTSBK.setMFId(P25_MFG_MOT); break; + + /** DVM CC data */ + case TSBK_OSP_DVM_GIT_HASH: + if (m_debug) { + LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_DVM_GIT_HASH (DVM Git Hash)"); + } + + // transmit git hash burst + m_rfTSBK.setLCO(TSBK_OSP_DVM_GIT_HASH); + m_rfTSBK.setMFId(P25_MFG_DVM); + break; } m_rfTSBK.setLastBlock(true); // always set last block