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