diff --git a/p25/P25Defines.h b/p25/P25Defines.h
index 08d97b9b..7940848c 100644
--- a/p25/P25Defines.h
+++ b/p25/P25Defines.h
@@ -285,9 +285,10 @@ namespace p25
// TSBK Inbound Signalling Packet (ISP) Opcode(s)
const uint8_t TSBK_ISP_TELE_INT_PSTN_REQ = 0x09U; // TELE INT PSTN REQ - Telephone Interconnect Request - Implicit
- const uint8_t TSBK_ISP_SNDCP_CH_REQ = 0x13U; // SNDCP CH REQ - SNDCP Data Channel Request
+ const uint8_t TSBK_ISP_SNDCP_CH_REQ = 0x12U; // SNDCP CH REQ - SNDCP Data Channel Request
const uint8_t TSBK_ISP_STS_Q_RSP = 0x19U; // STS Q RSP - Status Query Response
const uint8_t TSBK_ISP_CAN_SRV_REQ = 0x23U; // CAN SRV REQ - Cancel Service Request
+ const uint8_t TSBK_ISP_EMERG_ALRM_REQ = 0x27U; // EMERG ALRM REQ - Emergency Alarm Request
const uint8_t TSBK_ISP_GRP_AFF_Q_RSP = 0x29U; // GRP AFF Q RSP - Group Affiliation Query Response
const uint8_t TSBK_ISP_U_DEREG_REQ = 0x2BU; // U DE REG REQ - Unit De-Registration Request
const uint8_t TSBK_ISP_LOC_REG_REQ = 0x2DU; // LOC REG REQ - Location Registration Request
diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp
index ed0fcaa5..6c2eb862 100644
--- a/p25/TrunkPacket.cpp
+++ b/p25/TrunkPacket.cpp
@@ -294,6 +294,22 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
writeRF_TSDU_Queue(P25_QUE_RSN_TGT_UNIT_QUEUED, TSBK_IOSP_TELE_INT_ANS);
}
break;
+ case TSBK_ISP_SNDCP_CH_REQ:
+ // make sure control data is supported
+ IS_SUPPORT_CONTROL_CHECK("TSBK_ISP_SNDCP_CH_REQ (SNDCP Channel Request)", TSBK_ISP_SNDCP_CH_REQ, srcId);
+
+ // validate the source RID
+ VALID_SRCID("TSBK_ISP_SNDCP_CH_REQ (SNDCP Channel Request)", TSBK_ISP_SNDCP_CH_REQ, srcId);
+
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_ISP_SNDCP_CH_REQ (SNDCP Channel Request), dataServiceOptions = $%02X, dataAccessControl = %u, srcId = %u",
+ m_rfTSBK.getDataServiceOptions(), m_rfTSBK.getDataAccessControl(), srcId);
+ }
+
+ // SNDCP data channel requests are currently unsupported -- maybe in the future?
+
+ writeRF_TSDU_Deny(P25_DENY_RSN_SYS_UNSUPPORTED_SVC, TSBK_ISP_SNDCP_CH_REQ);
+ break;
case TSBK_IOSP_STS_UPDT:
// validate the source RID
VALID_SRCID("TSBK_IOSP_STS_UPDT (Status Update)", TSBK_IOSP_STS_UPDT, srcId);
@@ -395,6 +411,18 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
writeRF_TSDU_SBF(true);
break;
+ case TSBK_ISP_EMERG_ALRM_REQ:
+ if (m_rfTSBK.getEmergency()) {
+ if (m_verbose) {
+ LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_ISP_EMERG_ALRM_REQ (Emergency Alarm Request), srcId = %u, dstId = %u",
+ srcId, dstId);
+ }
+
+ ::ActivityLog("P25", true, "emergency alarm request request from %u", srcId);
+
+ writeRF_TSDU_SBF();
+ }
+ break;
case TSBK_IOSP_GRP_AFF:
// make sure control data is supported
IS_SUPPORT_CONTROL_CHECK("TSBK_IOSP_GRP_AFF (Group Affiliation Request)", TSBK_IOSP_GRP_AFF, srcId);
@@ -680,6 +708,20 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
m_netTSBK.getService(), srcId, dstId);
}
break;
+ case TSBK_ISP_EMERG_ALRM_REQ:
+ // non-emergency mode is a TSBK_OSP_DENY_RSP
+ if (!m_netTSBK.getEmergency()) {
+ if (m_verbose) {
+ LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
+ m_netTSBK.getAIV(), m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
+ }
+ } else {
+ if (m_verbose) {
+ LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_ISP_EMERG_ALRM_REQ (Emergency Alarm Request), srcId = %u, dstId = %u",
+ srcId, dstId);
+ }
+ }
+ break;
case TSBK_IOSP_GRP_AFF:
// ignore a network group affiliation command
return true; // don't allow this to write to the air
@@ -689,12 +731,6 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d
case TSBK_OSP_LOC_REG_RSP:
// ignore a network location registration command
return true; // don't allow this to write to the air
- case TSBK_OSP_DENY_RSP:
- if (m_verbose) {
- LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_DENY_RSP (Deny Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
- m_netTSBK.getAIV(), m_netTSBK.getResponse(), m_netTSBK.getSrcId(), m_netTSBK.getDstId());
- }
- break;
case TSBK_OSP_QUE_RSP:
if (m_verbose) {
LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_QUE_RSP (Queue Response), AIV = %u, reason = $%02X, srcId = %u, dstId = %u",
diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp
index 619e9863..93d7f73f 100644
--- a/p25/lc/TSBK.cpp
+++ b/p25/lc/TSBK.cpp
@@ -334,6 +334,11 @@ bool TSBK::decode(const uint8_t* data)
m_response = (uint8_t)((tsbkValue >> 48) & 0xFFU); // Answer Response
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
+ case TSBK_ISP_SNDCP_CH_REQ:
+ m_dataServiceOptions = (uint8_t)((tsbkValue >> 56) & 0xFFU); // Data Service Options
+ m_dataAccessControl = (uint32_t)((tsbkValue >> 40) & 0xFFFFFFFFU); // Data Access Control
+ m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
+ break;
case TSBK_IOSP_STS_UPDT:
m_statusValue = (uint8_t)((tsbkValue >> 56) & 0xFFU); // Status Value
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Target Radio Address
@@ -354,6 +359,23 @@ bool TSBK::decode(const uint8_t* data)
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Target Radio Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
+ case TSBK_ISP_EMERG_ALRM_REQ: // TSBK_OSP_DENY_RSP
+ /*
+ ** these are used by TSBK_OSP_DENY_RSP; best way to check is for m_response > 0
+ */
+ m_aivFlag = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Additional Info. Flag
+ m_service = (uint8_t)((tsbkValue >> 56) & 0x3FU); // Service Type
+ m_response = (uint8_t)((tsbkValue >> 48) & 0xFFU); // Reason
+
+ if (m_response > 0U) {
+ m_emergency = true;
+ } else {
+ m_emergency = false;
+ }
+
+ m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Target Radio Address
+ m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
+ break;
case TSBK_IOSP_EXT_FNCT:
m_extendedFunction = (uint32_t)((tsbkValue >> 48) & 0xFFFFU); // Extended Function
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFFFU); // Argument
@@ -381,7 +403,6 @@ bool TSBK::decode(const uint8_t* data)
m_dstId = (uint32_t)((tsbkValue >> 24) & 0xFFFFU); // Talkgroup Address
m_srcId = (uint32_t)(tsbkValue & 0xFFFFFFU); // Source Radio Address
break;
- case TSBK_OSP_DENY_RSP:
case TSBK_OSP_QUE_RSP:
m_aivFlag = (((tsbkValue >> 56) & 0xFFU) & 0x80U) == 0x80U; // Additional Info. Flag
m_service = (uint8_t)((tsbkValue >> 56) & 0x3FU); // Service Type
diff --git a/p25/lc/TSBK.h b/p25/lc/TSBK.h
index 2ea47769..420f8a8f 100644
--- a/p25/lc/TSBK.h
+++ b/p25/lc/TSBK.h
@@ -132,6 +132,12 @@ namespace p25
/// Extended function opcode.
__PROPERTY(uint32_t, extendedFunction, ExtendedFunction);
+ /** SNDCP Channel Request */
+ /// SNDCP Data Service Options
+ __PROPERTY(uint8_t, dataServiceOptions, DataServiceOptions);
+ /// SNDCP Data Access Control
+ __PROPERTY(uint32_t, dataAccessControl, DataAccessControl);
+
/** Adjacent Site Data */
/// Adjacent site CFVA flags.
__PROPERTY(uint8_t, adjCFVA, AdjSiteCFVA);