[EXPERIMENTAL] add support to configure voice channel iden table IDs;

3.5-maint
Bryan Biedenkapp 2 years ago
parent eaa6a60aac
commit 4a764f67df

@ -365,8 +365,10 @@ system:
# Voice Channels # Voice Channels
# #
voiceChNo: voiceChNo:
# Channel Identity (corresponds to the appropriate entry in the iden_table file).
- channelId: 2
# Channel Number (used to calculate actual host frequency based on the identity table). # Channel Number (used to calculate actual host frequency based on the identity table).
- channelNo: 1 channelNo: 1
# REST API IP Address for voice channel. # REST API IP Address for voice channel.
restAddress: 127.0.0.1 restAddress: 127.0.0.1
# REST API Port number for voice channel. # REST API Port number for voice channel.

@ -1837,7 +1837,7 @@ bool Host::readParams()
uint16_t restApiPort = (uint16_t)controlCh["restPort"].as<uint32_t>(REST_API_DEFAULT_PORT); uint16_t restApiPort = (uint16_t)controlCh["restPort"].as<uint32_t>(REST_API_DEFAULT_PORT);
std::string restApiPassword = controlCh["restPassword"].as<std::string>(); std::string restApiPassword = controlCh["restPassword"].as<std::string>();
VoiceChData data = VoiceChData(0U, restApiAddress, restApiPort, restApiPassword); VoiceChData data = VoiceChData(m_channelId, m_channelNo, restApiAddress, restApiPort, restApiPassword);
m_controlChData = data; m_controlChData = data;
if (!m_controlChData.address().empty() && m_controlChData.port() > 0) { if (!m_controlChData.address().empty() && m_controlChData.port() > 0) {
@ -1860,6 +1860,18 @@ bool Host::readParams()
for (size_t i = 0; i < voiceChList.size(); i++) { for (size_t i = 0; i < voiceChList.size(); i++) {
yaml::Node& channel = voiceChList[i]; yaml::Node& channel = voiceChList[i];
uint8_t chId = (uint8_t)channel["channelId"].as<uint32_t>(255U);
// special case default handling for if the channelId field is missing from the
// configuration
if (chId == 255U) {
chId = m_channelId;
}
if (chId > 15U) { // clamp to 15
chId = 15U;
}
uint32_t chNo = (uint32_t)::strtoul(channel["channelNo"].as<std::string>("1").c_str(), NULL, 16); uint32_t chNo = (uint32_t)::strtoul(channel["channelNo"].as<std::string>("1").c_str(), NULL, 16);
if (chNo == 0U) { // clamp to 1 if (chNo == 0U) { // clamp to 1
chNo = 1U; chNo = 1U;
@ -1872,19 +1884,21 @@ bool Host::readParams()
uint16_t restApiPort = (uint16_t)channel["restPort"].as<uint32_t>(REST_API_DEFAULT_PORT); uint16_t restApiPort = (uint16_t)channel["restPort"].as<uint32_t>(REST_API_DEFAULT_PORT);
std::string restApiPassword = channel["restPassword"].as<std::string>(); std::string restApiPassword = channel["restPassword"].as<std::string>();
::LogInfoEx(LOG_HOST, "Voice Channel Id %u Channel No $%04X REST API Address %s:%u", m_channelId, chNo, restApiAddress.c_str(), restApiPort); ::LogInfoEx(LOG_HOST, "Voice Channel Id %u Channel No $%04X REST API Address %s:%u", chId, chNo, restApiAddress.c_str(), restApiPort);
VoiceChData data = VoiceChData(chNo, restApiAddress, restApiPort, restApiPassword); VoiceChData data = VoiceChData(chId, chNo, restApiAddress, restApiPort, restApiPassword);
m_voiceChData[chNo] = data; m_voiceChData[chNo] = data;
m_voiceChNo.push_back(chNo); m_voiceChNo.push_back(chNo);
} }
std::string strVoiceChNo = ""; std::string strVoiceChNo = "";
for (auto it = m_voiceChNo.begin(); it != m_voiceChNo.end(); ++it) { for (auto it = m_voiceChNo.begin(); it != m_voiceChNo.end(); ++it) {
int decVal = ::atoi(std::to_string(*it).c_str()); uint32_t chNo = ::atoi(std::to_string(*it).c_str());
char hexStr[23]; ::lookups::VoiceChData voiceChData = m_voiceChData[chNo];
char hexStr[29];
::sprintf(hexStr, "$%04X (%u)", decVal, decVal); ::sprintf(hexStr, "$%01X.%01X (%u.%u)", voiceChData.chId(), chNo, voiceChData.chId(), chNo);
strVoiceChNo.append(std::string(hexStr)); strVoiceChNo.append(std::string(hexStr));
strVoiceChNo.append(","); strVoiceChNo.append(",");

@ -46,6 +46,7 @@ namespace lookups
public: public:
/// <summary>Initializes a new instance of the VoiceChData class.</summary> /// <summary>Initializes a new instance of the VoiceChData class.</summary>
VoiceChData() : VoiceChData() :
m_chId(0U),
m_chNo(0U), m_chNo(0U),
m_address(), m_address(),
m_port(), m_port(),
@ -54,11 +55,13 @@ namespace lookups
/* stub */ /* stub */
} }
/// <summary>Initializes a new instance of the VoiceChData class.</summary> /// <summary>Initializes a new instance of the VoiceChData class.</summary>
/// <param name="chId">Voice Channel Identity.</param>
/// <param name="chNo">Voice Channel Number.</param> /// <param name="chNo">Voice Channel Number.</param>
/// <param name="address">REST API Address.</param> /// <param name="address">REST API Address.</param>
/// <param name="port">REST API Port.</param> /// <param name="port">REST API Port.</param>
/// <param name="password">REST API Password.</param> /// <param name="password">REST API Password.</param>
VoiceChData(uint32_t chNo, std::string address, uint16_t port, std::string password) : VoiceChData(uint8_t chId, uint32_t chNo, std::string address, uint16_t port, std::string password) :
m_chId(chId),
m_chNo(chNo), m_chNo(chNo),
m_address(address), m_address(address),
m_port(port), m_port(port),
@ -73,6 +76,7 @@ namespace lookups
VoiceChData & operator=(const VoiceChData & data) VoiceChData & operator=(const VoiceChData & data)
{ {
if (this != &data) { if (this != &data) {
m_chId = data.m_chId;
m_chNo = data.m_chNo; m_chNo = data.m_chNo;
m_address = data.m_address; m_address = data.m_address;
m_port = data.m_port; m_port = data.m_port;
@ -82,10 +86,14 @@ namespace lookups
return *this; return *this;
} }
/// <summary>Helper to determine if the channel identity is valid.</summary>
bool isValidChId() { return m_chId != 0U; }
/// <summary>Helper to determine if the channel is valid.</summary> /// <summary>Helper to determine if the channel is valid.</summary>
bool isValidCh() { return m_chNo != 0U; } bool isValidCh() { return m_chNo != 0U; }
public: public:
/// <summary>Voice Channel Identity.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, chId, chId);
/// <summary>Voice Channel Number.</summary> /// <summary>Voice Channel Number.</summary>
__READONLY_PROPERTY_PLAIN(uint32_t, chNo, chNo); __READONLY_PROPERTY_PLAIN(uint32_t, chNo, chNo);
/// <summary>REST API Address.</summary> /// <summary>REST API Address.</summary>

@ -183,7 +183,7 @@ private:
::LogInfoEx(LOG_HOST, "Channel REST API Adddress %s:%u", restApiAddress.c_str(), restApiPort); ::LogInfoEx(LOG_HOST, "Channel REST API Adddress %s:%u", restApiAddress.c_str(), restApiPort);
VoiceChData data = VoiceChData(0U, restApiAddress, restApiPort, restApiPassword); VoiceChData data = VoiceChData(0U, 0U, restApiAddress, restApiPort, restApiPassword);
NodeStatusWnd* wnd = new NodeStatusWnd(this); NodeStatusWnd* wnd = new NodeStatusWnd(this);
wnd->setChData(data); wnd->setChData(data);

@ -126,7 +126,7 @@ namespace p25
__PROTECTED_READONLY_PROPERTY(uint32_t, sysId, SysId); __PROTECTED_READONLY_PROPERTY(uint32_t, sysId, SysId);
/// <summary>Voice channel ID.</summary> /// <summary>Voice channel ID.</summary>
__PROTECTED_PROPERTY(uint32_t, grpVchId, GrpVchId); __PROTECTED_PROPERTY(uint8_t, grpVchId, GrpVchId);
/// <summary>Voice channel number.</summary> /// <summary>Voice channel number.</summary>
__PROTECTED_PROPERTY(uint32_t, grpVchNo, GrpVchNo); __PROTECTED_PROPERTY(uint32_t, grpVchNo, GrpVchNo);

@ -93,7 +93,12 @@ void IOSP_GRP_VCH::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
(m_emergency ? 0x80U : 0x00U) + // Emergency Flag (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_encrypted ? 0x40U : 0x00U) + // Encrypted Flag (m_encrypted ? 0x40U : 0x00U) + // Encrypted Flag
(m_priority & 0x07U); // Priority (m_priority & 0x07U); // Priority
if (m_grpVchId != 0U) {
tsbkValue = (tsbkValue << 4) + m_grpVchId; // Channel ID
}
else {
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID
}
tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number
tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address
tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address

@ -93,7 +93,12 @@ void IOSP_UU_VCH::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
(m_emergency ? 0x80U : 0x00U) + // Emergency Flag (m_emergency ? 0x80U : 0x00U) + // Emergency Flag
(m_encrypted ? 0x40U : 0x00U) + // Encrypted Flag (m_encrypted ? 0x40U : 0x00U) + // Encrypted Flag
(m_priority & 0x07U); // Priority (m_priority & 0x07U); // Priority
if (m_grpVchId != 0U) {
tsbkValue = (tsbkValue << 4) + m_grpVchId; // Channel ID
}
else {
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel ID
}
tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number
tsbkValue = (tsbkValue << 24) + m_dstId; // Target ID tsbkValue = (tsbkValue << 24) + m_dstId; // Target ID
tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address tsbkValue = (tsbkValue << 24) + m_srcId; // Source Radio Address

@ -74,7 +74,12 @@ void OSP_GRP_VCH_GRANT_UPD::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
ulong64_t tsbkValue = 0U; ulong64_t tsbkValue = 0U;
if (m_grpVchId != 0U) {
tsbkValue = m_grpVchId; // Channel ID
}
else {
tsbkValue = m_siteData.channelId(); // Channel ID tsbkValue = m_siteData.channelId(); // Channel ID
}
tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number
tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address tsbkValue = (tsbkValue << 16) + m_dstId; // Talkgroup Address
tsbkValue = (tsbkValue << 32) + 0; tsbkValue = (tsbkValue << 32) + 0;

@ -87,9 +87,19 @@ void OSP_SNDCP_CH_GNT::encode(uint8_t* data, bool rawTSBK, bool noTrellis)
tsbkValue = 0U; tsbkValue = 0U;
tsbkValue = (tsbkValue << 8) + m_dataServiceOptions; // Data Service Options tsbkValue = (tsbkValue << 8) + m_dataServiceOptions; // Data Service Options
if (m_grpVchId != 0U) {
tsbkValue = (tsbkValue << 4) + m_grpVchId; // Channel (T) ID
}
else {
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel (T) ID tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel (T) ID
}
tsbkValue = (tsbkValue << 12) + m_dataChannelNo; // Channel (T) Number tsbkValue = (tsbkValue << 12) + m_dataChannelNo; // Channel (T) Number
if (m_grpVchId != 0U) {
tsbkValue = (tsbkValue << 4) + m_grpVchId; // Channel (R) ID
}
else {
tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel (R) ID tsbkValue = (tsbkValue << 4) + m_siteData.channelId(); // Channel (R) ID
}
tsbkValue = (tsbkValue << 12) + (rxChNo & 0xFFFU); // Channel (R) Number tsbkValue = (tsbkValue << 12) + (rxChNo & 0xFFFU); // Channel (R) Number
tsbkValue = (tsbkValue << 24) + m_dstId; // Target Radio Address tsbkValue = (tsbkValue << 24) + m_dstId; // Target Radio Address

@ -2235,6 +2235,8 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_
} }
if (chNo > 0U) { if (chNo > 0U) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (grp) { if (grp) {
if (!net) { if (!net) {
::ActivityLog("P25", true, "group grant request from %u to TG %u", srcId, dstId); ::ActivityLog("P25", true, "group grant request from %u to TG %u", srcId, dstId);
@ -2242,7 +2244,6 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_
// callback REST API to permit the granted TG on the specified voice channel // callback REST API to permit the granted TG on the specified voice channel
if (m_p25->m_authoritative && m_p25->m_supervisor) { if (m_p25->m_authoritative && m_p25->m_supervisor) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 && if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) { chNo != m_p25->m_siteData.channelNo()) {
json::object req = json::object(); json::object req = json::object();
@ -2272,6 +2273,7 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_
iosp->setMFId(m_lastMFID); iosp->setMFId(m_lastMFID);
iosp->setSrcId(srcId); iosp->setSrcId(srcId);
iosp->setDstId(dstId); iosp->setDstId(dstId);
iosp->setGrpVchId(voiceChData.chId());
iosp->setGrpVchNo(chNo); iosp->setGrpVchNo(chNo);
iosp->setEmergency(emergency); iosp->setEmergency(emergency);
iosp->setEncrypted(encryption); iosp->setEncrypted(encryption);
@ -2298,7 +2300,6 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_
// callback REST API to permit the granted TG on the specified voice channel // callback REST API to permit the granted TG on the specified voice channel
if (m_p25->m_authoritative && m_p25->m_supervisor) { if (m_p25->m_authoritative && m_p25->m_supervisor) {
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 && if (voiceChData.isValidCh() && !voiceChData.address().empty() && voiceChData.port() > 0 &&
chNo != m_p25->m_siteData.channelNo()) { chNo != m_p25->m_siteData.channelNo()) {
json::object req = json::object(); json::object req = json::object();
@ -2328,6 +2329,7 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_
iosp->setMFId(m_lastMFID); iosp->setMFId(m_lastMFID);
iosp->setSrcId(srcId); iosp->setSrcId(srcId);
iosp->setDstId(dstId); iosp->setDstId(dstId);
iosp->setGrpVchId(voiceChData.chId());
iosp->setGrpVchNo(chNo); iosp->setGrpVchNo(chNo);
iosp->setEmergency(emergency); iosp->setEmergency(emergency);
iosp->setEncrypted(encryption); iosp->setEncrypted(encryption);
@ -2378,6 +2380,8 @@ void ControlSignaling::writeRF_TSDU_Grant_Update()
uint32_t dstId = entry.first; uint32_t dstId = entry.first;
uint32_t chNo = entry.second; uint32_t chNo = entry.second;
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
if (chNo == 0U) { if (chNo == 0U) {
noData = true; noData = true;
m_mbfGrpGrntCnt++; m_mbfGrpGrntCnt++;
@ -2387,6 +2391,7 @@ void ControlSignaling::writeRF_TSDU_Grant_Update()
// transmit group voice grant update // transmit group voice grant update
osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD);
osp->setDstId(dstId); osp->setDstId(dstId);
osp->setGrpVchId(voiceChData.chId());
osp->setGrpVchNo(chNo); osp->setGrpVchNo(chNo);
m_mbfGrpGrntCnt++; m_mbfGrpGrntCnt++;
@ -2454,6 +2459,9 @@ bool ControlSignaling::writeRF_TSDU_SNDCP_Grant(uint32_t srcId, uint32_t dstId,
else { else {
if (m_p25->m_affiliations.grantCh(srcId, srcId, GRANT_TIMER_TIMEOUT, net)) { if (m_p25->m_affiliations.grantCh(srcId, srcId, GRANT_TIMER_TIMEOUT, net)) {
uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId); uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId);
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
osp->setGrpVchId(voiceChData.chId());
osp->setGrpVchNo(chNo); osp->setGrpVchNo(chNo);
osp->setDataChnNo(chNo); osp->setDataChnNo(chNo);
m_p25->m_siteData.setChCnt(m_p25->m_affiliations.getRFChCnt() + m_p25->m_affiliations.getGrantedRFChCnt()); m_p25->m_siteData.setChCnt(m_p25->m_affiliations.getRFChCnt() + m_p25->m_affiliations.getGrantedRFChCnt());
@ -2462,6 +2470,9 @@ bool ControlSignaling::writeRF_TSDU_SNDCP_Grant(uint32_t srcId, uint32_t dstId,
} }
else { else {
uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId); uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId);
::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);
osp->setGrpVchId(voiceChData.chId());
osp->setGrpVchNo(chNo); osp->setGrpVchNo(chNo);
osp->setDataChnNo(chNo); osp->setDataChnNo(chNo);

Loading…
Cancel
Save

Powered by TurnKey Linux.