diff --git a/config.example.yml b/config.example.yml index d5f8fc4a..43a7766c 100644 --- a/config.example.yml +++ b/config.example.yml @@ -58,6 +58,8 @@ protocols: broadcast: true interval: 300 duration: 1 + disableTSDUMBF: false + enableTimeDateAnn: false voiceOnControl: false disableCompositeFlag: false inhibitIllegal: false diff --git a/p25/Control.cpp b/p25/Control.cpp index cc3fdc38..ea13ebf5 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -254,6 +254,7 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s m_voiceOnControl = p25Protocol["voiceOnControl"].as(false); m_ackTSBKRequests = control["ackRequests"].as(true); m_trunk->m_ctrlTSDUMBF = !control["disableTSDUMBF"].as(false); + m_trunk->m_ctrlTimeDateAnn = control["enableTimeDateAnn"].as(false); #if ENABLE_DFSI_SUPPORT if (m_modem->isP25DFSI()) { @@ -326,6 +327,7 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s LogInfo(" Disable Multi-Block TSDUs: yes"); } LogInfo(" Emergency Support Disabled: %s", m_emergDisabled ? "yes" : "no"); + LogInfo(" Time/Date Announcement TSBK: %s", m_trunk->m_ctrlTimeDateAnn ? "yes" : "no"); LogInfo(" Inhibit Illegal: %s", m_inhibitIllegal ? "yes" : "no"); LogInfo(" Legacy Group Grant: %s", m_legacyGroupGrnt ? "yes" : "no"); diff --git a/p25/P25Defines.h b/p25/P25Defines.h index 13fbd59b..03c6e898 100644 --- a/p25/P25Defines.h +++ b/p25/P25Defines.h @@ -333,6 +333,7 @@ namespace p25 const uint8_t TSBK_OSP_AUTH_FNE_RESP = 0x32U; // AUTH FNE RESP - Authentication FNE Response const uint8_t TSBK_OSP_QUE_RSP = 0x33U; // QUE RSP - Queued Response const uint8_t TSBK_OSP_IDEN_UP_VU = 0x34U; // IDEN UP VU - Channel Identifier Update for VHF/UHF Bands + const uint8_t TSBK_OSP_TIME_DATE_ANN = 0x35U; // TIME DATE ANN - Time and Date Announcement const uint8_t TSBK_OSP_SYS_SRV_BCAST = 0x38U; // SYS SRV BCAST - System Service Broadcast const uint8_t TSBK_OSP_SCCB = 0x39U; // SCCB - Secondary Control Channel Broadcast const uint8_t TSBK_OSP_RFSS_STS_BCAST = 0x3AU; // RFSS STS BCAST - RFSS Status Broadcast diff --git a/p25/lc/tsbk/OSP_TIME_DATE_ANN.cpp b/p25/lc/tsbk/OSP_TIME_DATE_ANN.cpp new file mode 100644 index 00000000..88856032 --- /dev/null +++ b/p25/lc/tsbk/OSP_TIME_DATE_ANN.cpp @@ -0,0 +1,129 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2022 by Jason-UWU +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* 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 +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "Defines.h" +#include "p25/lc/tsbk/OSP_TIME_DATE_ANN.h" +#include "Log.h" +#include "Utils.h" + +using namespace p25::lc::tsbk; +using namespace p25::lc; +using namespace p25; + +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the OSP_TIME_DATE_ANN class. +/// +OSP_TIME_DATE_ANN::OSP_TIME_DATE_ANN() : TSBK() +{ + m_lco = TSBK_OSP_TIME_DATE_ANN; +} + +/// +/// Decode a trunking signalling block. +/// +/// +/// +/// True, if TSBK was decoded, otherwise false. +bool OSP_TIME_DATE_ANN::decode(const uint8_t* data, bool rawTSBK) +{ + assert(data != NULL); + + /* stub */ + + return true; +} + +/// +/// Encode a trunking signalling block. +/// +/// +/// +/// +void OSP_TIME_DATE_ANN::encode(uint8_t* data, bool rawTSBK, bool noTrellis) +{ + assert(data != NULL); + + ulong64_t tsbkValue = 0U; + + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + time_t tt = std::chrono::system_clock::to_time_t(now); + tm local_tm = *gmtime(&tt); + + uint32_t tmM = (local_tm.tm_mon + 1); + uint32_t tmY = (local_tm.tm_year - 100); + + uint32_t tmS = 0U; + uint32_t i = local_tm.tm_sec; + if (i > 59U) { + tmS |= 59U; + } else { + tmS |= i; + } + +#if DEBUG_P25_TSBK + LogDebug(LOG_P25, "TSBK_OSP_TIME_DATE_ANN, tmM = %u / %u, tmY = %u / %u", local_tm.tm_mon, tmM, local_tm.tm_year, tmY); +#endif + + uint8_t lto = fabs(m_siteData.lto()) * 2U; // this will cause a bug for half-hour timezone intervals... + + // mark the LTO as valid if its non-zero + bool vl = false; + if (lto > 0U) + vl = true; + + tsbkValue = 0xC0U + // VD and VT flags set + (vl ? 0x20U : 0x00U) + // Valid LTO Flag + ((lto >> 8) & 0x0F); // LTO MSB (Upper 4-bits) + tsbkValue = (tsbkValue << 8) + (lto & 0xFFU); // LTO LSB + + // Date + tsbkValue = (tsbkValue << 4) + (tmM & 0x0FU); // Month + tsbkValue = (tsbkValue << 5) + (local_tm.tm_mday & 0x1FU); // Day of Month + tsbkValue = (tsbkValue << 13) + (tmY & 0x1FFFU); // Year + tsbkValue = (tsbkValue << 2); // Reserved + + // Time + tsbkValue = (tsbkValue << 5) + (local_tm.tm_hour & 0x1FU); // Hour + tsbkValue = (tsbkValue << 6) + (local_tm.tm_min & 0x3FU); // Minute + tsbkValue = (tsbkValue << 6) + (local_tm.tm_sec & 0x3FU); // Seconds + tsbkValue = (tsbkValue << 7); // Reserved + +#if DEBUG_P25_TSBK + LogDebug(LOG_P25, "TSBK_OSP_TIME_DATE_ANN, tmM = %u, tmMDAY = %u, tmY = %u, tmH = %u, tmMin = %u, tmS = %u", tmM, tmMDAY, tmY, tmH, tmMin, tmS); +#endif + + std::unique_ptr tsbk = TSBK::fromValue(tsbkValue); + TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis); +} diff --git a/p25/lc/tsbk/OSP_TIME_DATE_ANN.h b/p25/lc/tsbk/OSP_TIME_DATE_ANN.h new file mode 100644 index 00000000..91e88535 --- /dev/null +++ b/p25/lc/tsbk/OSP_TIME_DATE_ANN.h @@ -0,0 +1,57 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2022 by Bryan Biedenkapp N2PLL +* +* 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 +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__P25_LC_TSBK__OSP_TIME_DATE_ANN_H__) +#define __P25_LC_TSBK__OSP_TIME_DATE_ANN_H__ + +#include "Defines.h" +#include "p25/lc/TSBK.h" + +namespace p25 +{ + namespace lc + { + namespace tsbk + { + // --------------------------------------------------------------------------- + // Class Declaration + // Implements TIME DATE ANN - Time and Date Announcement + // --------------------------------------------------------------------------- + + class HOST_SW_API OSP_TIME_DATE_ANN : public TSBK { + public: + /// Initializes a new instance of the OSP_TIME_DATE_ANN class. + OSP_TIME_DATE_ANN(); + + /// Decode a trunking signalling block. + virtual bool decode(const uint8_t* data, bool rawTSBK = false); + /// Encode a trunking signalling block. + virtual void encode(uint8_t* data, bool rawTSBK = false, bool noTrellis = false); + }; + } // namespace tsbk + } // namespace lc +} // namespace p25 + +#endif // __P25_LC_TSBK__OSP_TIME_DATE_ANN_H__ diff --git a/p25/lc/tsbk/TSBKFactory.h b/p25/lc/tsbk/TSBKFactory.h index 7c704a94..c88ed2cf 100644 --- a/p25/lc/tsbk/TSBKFactory.h +++ b/p25/lc/tsbk/TSBKFactory.h @@ -75,6 +75,7 @@ #include "p25/lc/tsbk/OSP_SNDCP_CH_GNT.h" #include "p25/lc/tsbk/OSP_SYNC_BCAST.h" #include "p25/lc/tsbk/OSP_SYS_SRV_BCAST.h" +#include "p25/lc/tsbk/OSP_TIME_DATE_ANN.h" #include "p25/lc/tsbk/OSP_U_DEREG_ACK.h" #include "p25/lc/tsbk/OSP_U_REG_CMD.h" diff --git a/p25/packet/Trunk.cpp b/p25/packet/Trunk.cpp index d608f67d..6187dad1 100644 --- a/p25/packet/Trunk.cpp +++ b/p25/packet/Trunk.cpp @@ -1193,6 +1193,7 @@ Trunk::Trunk(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, boo m_adjSiteUpdateTimer(1000U), m_adjSiteUpdateInterval(ADJ_SITE_TIMER_TIMEOUT), m_microslotCount(0U), + m_ctrlTimeDateAnn(false), m_ctrlTSDUMBF(true), m_localEmergAlarm(false), m_sndcpChGrant(false), @@ -1377,15 +1378,21 @@ void Trunk::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS) break; } + // are we transmitting the time/date annoucement? + bool timeDateAnn = (frameCnt % 64U) == 0U; + if (m_ctrlTimeDateAnn && timeDateAnn && n > 4U) { + queueRF_TSBK_Ctrl(TSBK_OSP_TIME_DATE_ANN); + } + // should we insert the BSI bursts? bool bsi = (frameCnt % 127U) == 0U; - if (bsi && n > 3U) { + if (bsi && n > 4U) { queueRF_TSBK_Ctrl(TSBK_OSP_MOT_CC_BSI); } - // shuld we insert the Git Hash burst? + // should we insert the Git Hash burst? bool hash = (frameCnt % 125U) == 0U; - if (hash && n > 3U) { + if (hash && n > 4U) { queueRF_TSBK_Ctrl(TSBK_OSP_DVM_GIT_HASH); } @@ -2054,6 +2061,19 @@ void Trunk::queueRF_TSBK_Ctrl(uint8_t lco) tsbk = std::move(osp); } break; + case TSBK_OSP_TIME_DATE_ANN: + { + if (m_ctrlTimeDateAnn) { + if (m_debug) { + LogMessage(LOG_RF , P25_TSDU_STR ", TSBK_OSP_TIME_DATE_ANN (Time and Date Announcement)"); + } + + // transmit time/date announcement + std::unique_ptr osp = new_unique(OSP_TIME_DATE_ANN); + tsbk = std::move(osp); + } + } + break; /** Motorola CC data */ case TSBK_OSP_MOT_PSH_CCH: diff --git a/p25/packet/Trunk.h b/p25/packet/Trunk.h index d939bbda..c7bb9ec3 100644 --- a/p25/packet/Trunk.h +++ b/p25/packet/Trunk.h @@ -144,6 +144,8 @@ namespace p25 uint16_t m_microslotCount; + bool m_ctrlTimeDateAnn; + bool m_ctrlTSDUMBF; bool m_localEmergAlarm;