New param TETRA_USER_INFOFILE reads the data of the tetra users from a new json file and not from a svxlink.conf section anymore. Please move all tetra user data (normally configured in svxlink.conf-section [Tetra_Users]) to the new json file. The param TETRA_USERS should not be used anymore! An example of the new json file can be found here src/svxlink/svxlink/tetra_users.json). Better handling if TSI‘s are shorter than expected (09011638300023456 || 901999900023456). Extended data transmission between node and reflector to support the work of the dashboard developers. Very important: You have to update all nodes and reflectors!

This commit is contained in:
Adi Bier / DL1HRC 2021-09-24 23:34:12 +02:00
parent 295863f9e2
commit 65399cdf14
9 changed files with 336 additions and 102 deletions

View File

@ -263,13 +263,13 @@ void Reflector::updateUserdata(Json::Value user_arr)
m_user.issi = t_userdata.get("tsi", "").asString();
m_user.name = t_userdata.get("name","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
m_user.aprs_sym = static_cast<char>(t_userdata.get("sym","").asInt());
m_user.aprs_tab = static_cast<char>(t_userdata.get("tab","").asInt());
m_user.comment = t_userdata.get("comment","").asString();
if (t_userdata.get("last_activity","").asString().length() > 0)
if (t_userdata.get("last_activity","").asUInt() > 0)
{
m_user.last_activity = (time_t) strtol(
t_userdata.get("last_activity","").asString().c_str(), NULL, 10);
m_user.last_activity = (time_t) t_userdata.get("last_activity","").asUInt();
}
std::map<std::string, User>::iterator iu;
@ -280,6 +280,7 @@ void Reflector::updateUserdata(Json::Value user_arr)
iu->second.aprs_sym = m_user.aprs_sym;
iu->second.aprs_tab = m_user.aprs_tab;
iu->second.comment = m_user.comment;
iu->second.location = m_user.location;
if (m_user.last_activity)
{
iu->second.last_activity = m_user.last_activity;
@ -288,8 +289,8 @@ void Reflector::updateUserdata(Json::Value user_arr)
if (debug)
{
cout << "UPDATE: call=" << m_user.call << ", issi=" << m_user.issi
<< ", name=" << m_user.name << " (" << m_user.comment << ")"
<< endl;
<< ", name=" << m_user.name << ", location=" << m_user.location
<< " (" << m_user.comment << ")" << endl;
}
}
else
@ -298,8 +299,8 @@ void Reflector::updateUserdata(Json::Value user_arr)
if (debug)
{
cout << "New user: call=" << m_user.call << ", issi=" << m_user.issi
<< ", name=" << m_user.name << " (" << m_user.comment << ")"
<< endl;
<< ", name=" << m_user.name << ", location=" << m_user.location
<< " (" << m_user.comment << ")" << endl;
}
}
}
@ -908,11 +909,11 @@ bool Reflector::getUserData(void)
m_user.issi = t_userdata.get("tsi", "").asString();
m_user.name = t_userdata.get("name","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
m_user.aprs_sym = static_cast<char>(t_userdata.get("sym","").asInt());
m_user.aprs_tab = static_cast<char>(t_userdata.get("tab","").asInt());
m_user.comment = t_userdata.get("comment","").asString();
m_user.last_activity = (time_t) strtol(
t_userdata.get("last_activity","").asString().c_str(), NULL, 10);
m_user.last_activity = (time_t) t_userdata.get("last_activity","").asUInt();
userdata[m_user.issi] = m_user;
}
cout << "+++ " << cfg_root.size() << " users loaded from '"
@ -933,15 +934,11 @@ void Reflector::writeUserData(std::map<std::string, User> userdata)
t_userinfo["tsi"] = iu->second.issi;
t_userinfo["call"] = iu->second.call;
t_userinfo["name"] = iu->second.name;
t_userinfo["location"] = iu->second.location;
t_userinfo["sym"] = iu->second.aprs_sym;
t_userinfo["tab"] = iu->second.aprs_tab;
t_userinfo["comment"] = iu->second.comment;
if (iu->second.last_activity)
{
stringstream la;
la << iu->second.last_activity;
t_userinfo["last_activity"] = la.str();
}
t_userinfo["last_activity"] = static_cast<uint32_t>(iu->second.last_activity);
event.append(t_userinfo);
}

View File

@ -224,6 +224,7 @@ class Reflector : public sigc::trackable
std::string issi;
std::string call;
std::string name;
std::string location;
std::string comment;
float lat;
float lon;

View File

@ -99,6 +99,7 @@ install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/gpio.conf
${SVX_SYSCONF_INSTALL_DIR}
)
install_if_not_exists(node_info.json ${SVX_SYSCONF_INSTALL_DIR})
install_if_not_exists(tetra_users.json ${SVX_SYSCONF_INSTALL_DIR})
install(FILES events.tcl DESTINATION ${SVX_SHARE_INSTALL_DIR})
install(FILES RepeaterLogic.tcl SimplexLogic.tcl ReflectorLogic.tcl Module.tcl
Logic.tcl CW.tcl SelCall.tcl TetraLogic.tcl locale.tcl

View File

@ -670,8 +670,19 @@ void ReflectorLogic::remoteReceivedPublishStateEvent(
}
sendMsg(msg);
}
else if (event_name == "Sds:info" || event_name == "TetraUsers:info" ||
event_name == "QsoInfo:state")
else if (event_name == "QsoInfo:state")
{
std::istringstream is(data);
Json::Value user_info;
is >> user_info;
user_info["TG"] = m_selected_tg;
string ud =jsonToString(user_info);
// cout << "sende: " << event_name << "," << ud << endl;
MsgStateEvent msg(logic->name(), event_name, ud);
sendMsg(msg);
}
else if (event_name == "Sds:info" || event_name == "TetraUsers:info")
{
// cout << "sende: " << event_name << "," << data << endl;
MsgStateEvent msg(logic->name(), event_name, data);
@ -1789,6 +1800,15 @@ void ReflectorLogic::handlePlayDtmf(const std::string& digit, int amp,
} /* ReflectorLogic::handlePlayDtmf */
string ReflectorLogic::jsonToString(Json::Value eventmessage)
{
Json::FastWriter jsontoString;
std::string message = jsontoString.write(eventmessage);
message.erase(std::remove_if(message.begin(), message.end(),
[](unsigned char x){return std::iscntrl(x);}));
return message;
} /* ReflectorLogic::jsonToString */
/*
* This file has not been truncated
*/

View File

@ -305,7 +305,7 @@ class ReflectorLogic : public LogicBase
void handlePlaySilence(int duration);
void handlePlayTone(int fq, int amp, int duration);
void handlePlayDtmf(const std::string& digit, int amp, int duration);
std::string jsonToString(Json::Value eventmessage);
}; /* class ReflectorLogic */

View File

@ -718,6 +718,47 @@ std::string getISSI(std::string tsi)
} /* getISSI */
bool splitTsi(std::string tsi, int &mcc, int &mnc, int &issi)
{
bool ret = false;
size_t len = tsi.length();
if (len < 9)
{
issi = atoi(tsi.c_str());
mcc = 0;
mnc = 0;
ret = true;
}
else
{
issi = atoi(tsi.substr(len-8,8).c_str());
std::string t = tsi.substr(0, len-8);
if (t.length() == 7)
{
mcc = atoi(t.substr(0,3).c_str());
mnc = atoi(t.substr(3,4).c_str());
ret = true;
}
else if (t.length() == 8)
{
mcc = atoi(t.substr(0,3).c_str());
mnc = atoi(t.substr(3,5).c_str());
ret = true;
}
else if (t.length() == 9)
{
mcc = atoi(t.substr(0,4).c_str());
mnc = atoi(t.substr(4,5).c_str());
ret = true;
}
else ret = false;
}
return ret;
} /* splitTsi */
unsigned int hex2int(std::string sds)
{
unsigned int t;

View File

@ -39,6 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdio.h>
#include <iostream>
#include <regex.h>
#include <fstream>
/****************************************************************************
@ -127,6 +128,7 @@ using namespace SvxLink;
#define LOGINFO 2
#define LOGDEBUG 3
#define TETRA_LOGIC_VERSION "24092021"
/****************************************************************************
*
@ -197,7 +199,8 @@ TetraLogic::TetraLogic(Async::Config& cfg, const string& name)
peiBreakCommandTimer(3000, Timer::TYPE_ONESHOT, false),
proximity_warning(3.1), time_between_sds(3600), own_lat(0.0),
own_lon(0.0), endCmd(""), new_sds(false), inTransmission(false),
cmgs_received(true), share_userinfo(true), current_cci(0)
cmgs_received(true), share_userinfo(true), current_cci(0), dmnc(0),
dmcc(0)
{
peiComTimer.expired.connect(mem_fun(*this, &TetraLogic::onComTimeout));
peiActivityTimer.expired.connect(mem_fun(*this,
@ -277,6 +280,8 @@ bool TetraLogic::initialize(void)
value += mcc;
mcc = value.substr(value.length()-4,4);
}
dmcc = atoi(mcc.c_str());
if (!cfg().getValue(name(), "APRSPATH", aprspath))
{
aprspath = "APRS,qAR,";
@ -299,6 +304,8 @@ bool TetraLogic::initialize(void)
value += mnc;
mnc = value.substr(value.length()-5,5);
}
dmnc = atoi(mnc.c_str());
// Welcome message to new users
if (!cfg().getValue(name(), "INFO_SDS", infosds))
{
@ -359,6 +366,14 @@ bool TetraLogic::initialize(void)
string user_section;
if (cfg().getValue(name(), "TETRA_USERS", user_section))
{
cout
<< "***************************************************************\n"
<< "* WARNING: The parameter TETRA_USERS is outdated and will be *\n"
<< "* removed soon. Use TETRA_USER_INFOFILE=tetra_users.json in- *\n"
<< "* stead and transfer your tetra user data into the json file. *\n"
<< "* You will find an example of tetra_users.json in *\n"
<< "* src/svxlink/svxlink directory *\n"
<< "***************************************************************\n";
list<string> user_list = cfg().listSection(user_section);
User m_user;
@ -399,6 +414,80 @@ bool TetraLogic::initialize(void)
}
}
std::string user_info_file;
if (cfg().getValue(name(), "TETRA_USER_INFOFILE", user_info_file))
{
std::ifstream user_info_is(user_info_file.c_str(), std::ios::in);
if (user_info_is.good())
{
try
{
if (!(user_info_is >> m_user_info))
{
std::cerr << "*** ERROR: Failure while reading user information file "
"\"" << user_info_file << "\""
<< std::endl;
isok = false;
}
}
catch (const Json::Exception& e)
{
std::cerr << "*** ERROR: Failure while reading user information "
"file \"" << user_info_file << "\": "
<< e.what()
<< std::endl;
isok = false;
}
}
else
{
std::cerr << "*** ERROR: Could not open user information file "
"\"" << user_info_file << "\""
<< std::endl;
isok = false;
}
User m_user;
for (Json::Value::ArrayIndex i = 0; i < m_user_info.size(); i++)
{
Json::Value& t_userdata = m_user_info[i];
m_user.issi = t_userdata.get("tsi", "").asString();
if (m_user.issi.length() != 17)
{
cout << "*** ERROR: The TSI must have a length of 17 digits.\n"
<< "\" Check dataset " << i + 1 << " in \"" << user_info_file
<< "\"" << endl;
isok = false;
}
m_user.name = t_userdata.get("name","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
if (t_userdata.get("symbol","").asString().length() != 2)
{
cout << "*** ERROR: Aprs symbol in \"" << user_info_file
<< "\" dataset " << i + 1 << " is not correct, must have 2 digits!"
<< endl;
isok = false;
}
else
{
m_user.aprs_sym = t_userdata.get("symbol","").asString()[0];
m_user.aprs_tab = t_userdata.get("symbol","").asString()[1];
}
m_user.comment = t_userdata.get("comment","").asString();
struct tm mtime = {0}; // set default date/time 31.12.1899
m_user.last_activity = mktime(&mtime);
m_user.sent_last_sds = mktime(&mtime);
userdata[m_user.issi] = m_user;
if (debug >= LOGINFO)
{
cout << "tsi=" << m_user.issi << ",call=" << m_user.call << ",name="
<< m_user.name << ",location=" << m_user.location << ",comment="
<< m_user.comment << endl;
}
}
}
// define sds messages send to user when received Sds's from him due to
// state changes
std::string sds_useractivity;
@ -582,6 +671,12 @@ bool TetraLogic::initialize(void)
processEvent("startup");
cout << ">>> Started SvxLink with special TetraLogic extension (v"
<< TETRA_LOGIC_VERSION << ")" << endl;
cout << ">>> No guarantee! Please send a bug report to\n"
<< ">>> Adi/DL1HRC <dl1hrc@gmx.de> or use the groups.io mailing list"
<< endl;
return isok;
} /* TetraLogic::initialize */
@ -748,6 +843,8 @@ void TetraLogic::sendUserInfo(void)
t_userinfo["tab"] = iu->second.aprs_tab;
t_userinfo["sym"] = iu->second.aprs_sym;
t_userinfo["comment"] = iu->second.comment;
t_userinfo["location"] = iu->second.location;
t_userinfo["last_activity"] = 0;
event.append(t_userinfo);
}
publishInfo("TetraUsers:info", event);
@ -830,14 +927,14 @@ void TetraLogic::handlePeiAnswer(std::string m_message)
case SDS:
handleSds(m_message);
break;
case ACK_SDS:
break;
case TEXT_SDS:
handleSdsMsg(m_message);
break;
case SIMPLE_TEXT_SDS:
case STATE_SDS:
handleSdsMsg(m_message);
@ -854,7 +951,7 @@ void TetraLogic::handlePeiAnswer(std::string m_message)
// sds state send be MS
handleCmgs(m_message);
break;
case TX_DEMAND:
break;
@ -873,11 +970,11 @@ void TetraLogic::handlePeiAnswer(std::string m_message)
case CTGS:
handleCtgs(m_message);
break;
case CTDGR:
cout << handleCtdgr(m_message);
break;
case CLVL:
handleClvl(m_message);
break;
@ -909,7 +1006,7 @@ void TetraLogic::initGroupCall(int gc_gssi)
cmd = "ATD";
cmd += to_string(gc_gssi);
sendPei(cmd);
stringstream ss;
ss << "init_group_call " << to_string(gc_gssi);
processEvent(ss.str());
@ -928,19 +1025,22 @@ TETRA Incoming Call Notification +CTICN
Example: MCC| MNC| ISSI | MCC| MNC| GSSI |
+CTICN: 1,0,0,5,09011638300023404,1,1,0,1,1,5,09011638300000001,0
OR ISSI GSSI
+CTICN: 1,0,0,5,23404,1,1,0,1,1,5,1000,0
*/
void TetraLogic::handleCallBegin(std::string message)
{
if (message.length() < 65)
// +CTICN: 1, 0, 0, 4, 1002, 1, 1, 0, 1, 1, 0, 1000, 1
std::string reg = "\\+CTICN: [0-9],[0-9],[0-9],[0-9],[0-9]{1,17},[0-9],[0-9],[0-9],[0-9],[0-9],[0-9],[0-9]{1,17},[0-9]";
if (!rmatch(message, reg))
{
if (debug >= LOGWARN)
{
cout << "*** No valid +CTICN response, message to short" << endl;
cout << "*** Wrong +CTICN response (wrong format)" << endl;
}
return;
}
}
squelchOpen(true); // open the Squelch
Callinfo t_ci;
@ -956,9 +1056,21 @@ void TetraLogic::handleCallBegin(std::string message)
t_ci.origin_cpit = getNextVal(h);
std::string o_tsi = getNextStr(h);
t_ci.o_mcc = atoi(o_tsi.substr(0,4).c_str());
t_ci.o_mnc = atoi(o_tsi.substr(4,5).c_str());
t_ci.o_issi = atoi(o_tsi.substr(9,8).c_str());
if (o_tsi.length() < 9)
{
t_ci.o_issi = atoi(o_tsi.c_str());
string t = mcc;
t += mnc;
t += getISSI(o_tsi);
o_tsi = t;
t_ci.o_mnc = dmnc;
t_ci.o_mcc = dmcc;
}
else
{
splitTsi(o_tsi, t_ci.o_mcc, t_ci.o_mnc, t_ci.o_issi);
}
t_ci.hook = getNextVal(h);
t_ci.simplex = getNextVal(h);
@ -968,13 +1080,26 @@ void TetraLogic::handleCallBegin(std::string message)
t_ci.dest_cpit = getNextVal(h);
std::string d_tsi = getNextStr(h);
t_ci.d_mcc = atoi(d_tsi.substr(0,4).c_str());
t_ci.d_mnc = atoi(d_tsi.substr(4,5).c_str());
t_ci.d_issi = atoi(d_tsi.substr(9,8).c_str());
if (d_tsi.length() < 9)
{
t_ci.d_issi = atoi(d_tsi.c_str());
string t = mcc;
t += mnc;
t += getISSI(d_tsi);
d_tsi = t;
t_ci.d_mnc = dmnc;
t_ci.d_mcc = dmcc;
}
else
{
splitTsi(d_tsi, t_ci.d_mcc, t_ci.d_mnc, t_ci.d_issi);
}
t_ci.prio = atoi(h.c_str());
// store call specific data into a Callinfo struct
callinfo[t_ci.o_issi] = t_ci;
callinfo[t_ci.instance] = t_ci;
// check if the user is stored? no -> default
std::map<std::string, User>::iterator iu = userdata.find(o_tsi);
@ -1007,29 +1132,28 @@ void TetraLogic::handleCallBegin(std::string message)
Qso.tsi = o_tsi;
Qso.start = time(NULL);
// prepare array for tetra users to be send over the network
Json::Value event(Json::arrayValue);
// prepare event for tetra users to be send over the network
Json::Value qsoinfo(Json::objectValue);
qsoinfo["active"] = true;
qsoinfo["qso_active"] = true;
qsoinfo["gateway"] = callsign();
qsoinfo["dest_mcc"] = t_ci.d_mcc;
qsoinfo["dest_mnc"] = t_ci.d_mnc;
qsoinfo["dest_issi"] = t_ci.d_issi;
qsoinfo["aimode"] = t_ci.aistatus;
qsoinfo["cci"] = t_ci.instance;
uint32_t ti = time(NULL);
qsoinfo["last_activity"] = ti;
std::list<std::string>::iterator it;
it = find(Qso.members.begin(), Qso.members.end(), iu->second.call);
if (it == Qso.members.end())
{
qsoinfo["call"] = iu->second.call;
qsoinfo["tsi"] = Qso.tsi;
stringstream la;
la << userdata[o_tsi].last_activity;
qsoinfo["last_activity"] = la.str();
event.append(qsoinfo);
Qso.members.push_back(iu->second.call);
}
publishInfo("QsoInfo:state", event);
qsoinfo["qso_members"] = joinList(Qso.members);
publishInfo("QsoInfo:state", qsoinfo);
// end of publish messages
// callup tcl event
@ -1059,15 +1183,14 @@ void TetraLogic::handleCallBegin(std::string message)
void TetraLogic::handleSds(std::string sds)
{
sds.erase(0,9); // remove "+CTSDSR: "
// store header of sds for further handling
//pSDS.sdstype = getNextVal(sds); // type of SDS (12)
pSDS.aiservice = getNextVal(sds); // type of SDS (TypeOfService 0-12)
pSDS.aiservice = getNextVal(sds); // type of SDS (TypeOfService 0-12)
pSDS.fromtsi = getTSI(getNextStr(sds)); // sender Tsi (23404)
getNextVal(sds); // (0)
pSDS.totsi = getNextVal(sds); // destination Issi
getNextVal(sds); // (0)
getNextVal(sds); // Sds length (112)
getNextVal(sds); // (0)
pSDS.totsi = getTSI(getNextStr(sds)); // destination Issi
getNextVal(sds); // (0)
getNextVal(sds); // Sds length (112)
pSDS.last_activity = time(NULL);
} /* TetraLogic::handleSds */
@ -1221,12 +1344,13 @@ void TetraLogic::handleSdsMsg(std::string sds)
return;
}
stringstream la;
la << userdata[t_sds.tsi].last_activity;
sdsinfo["last_activity"] = la.str();
sdsinfo["tsi"] = t_sds.tsi;
uint32_t ti = time(NULL);
sdsinfo["last_activity"] = ti;
sdsinfo["sendertsi"] = t_sds.tsi;
sdsinfo["type"] = m_sdstype;
sdsinfo["call"] = userdata[t_sds.tsi].call;
sdsinfo["from"] = userdata[t_sds.tsi].call;
sdsinfo["to"] = userdata[pSDS.totsi].call;
sdsinfo["receivertsi"] = pSDS.totsi;
sdsinfo["gateway"] = callsign();
event.append(sdsinfo);
publishInfo("Sds:info", event);
@ -1263,11 +1387,12 @@ std::string TetraLogic::handleCtgs(std::string m_message)
} /* TetraLogic::handleCtgs */
// 6.14.10 TETRA DMO visible gateways/repeaters
// +CTDGR: [<DM communication type>], [<gateway/repeater address>], [<MNI>],
// [<presence information>]
// TETRA DMO visible gateways/repeaters +CTDGR
// +CTDGR: 2,1001,90116383,0
/* 6.14.10 TETRA DMO visible gateways/repeaters
* +CTDGR: [<DM communication type>], [<gateway/repeater address>], [<MNI>],
* [<presence information>]
* TETRA DMO visible gateways/repeaters +CTDGR
* +CTDGR: 2,1001,90116383,0
*/
std::string TetraLogic::handleCtdgr(std::string m_message)
{
m_message.erase(0,8);
@ -1479,9 +1604,10 @@ void TetraLogic::handleStateSds(unsigned int isds)
} /* TetraLogic::handleStateSds */
// 6.15.11 Down Transmission Ceased +CDTXC
// +CDTXC: <CC instance>, <TxRqPrmsn>
// +CDTXC: 1,0
/* 6.15.11 Down Transmission Ceased +CDTXC
* +CDTXC: <CC instance>, <TxRqPrmsn>
* +CDTXC: 1,0
*/
void TetraLogic::handleTransmissionEnd(std::string message)
{
squelchOpen(false); // close Squelch
@ -1500,7 +1626,8 @@ void TetraLogic::handleCallReleased(std::string message)
Qso.stop = time(NULL);
stringstream ss;
getNextStr(message);
message.erase(0,7);
int cci = getNextVal(message);
if (tetra_modem_sql->isOpen())
{
@ -1513,32 +1640,28 @@ void TetraLogic::handleCallReleased(std::string message)
}
processEvent(ss.str());
// prepare array for tetra users to be send over the network
Json::Value event(Json::arrayValue);
std::list<std::string>::iterator it;
// send call/qso end to aprs network
std::string m_aprsmesg = aprspath;
if (!Qso.members.empty())
{
m_aprsmesg += ">Qso ended (";
for (const auto &it : Qso.members)
{
m_aprsmesg += it;
m_aprsmesg += ",";
}
m_aprsmesg.pop_back();
m_aprsmesg += joinList(Qso.members);
m_aprsmesg += ")";
// send userinfo to SvxReflector when
for (it=Qso.members.begin(); it!=Qso.members.end(); it++)
{
Json::Value qsoinfo(Json::objectValue);
qsoinfo["qso_active"] = false;
qsoinfo["members"] = *it;
event.append(qsoinfo);
}
publishInfo("QsoInfo:state", event);
// prepare event for tetra users to be send over the network
Json::Value qsoinfo(Json::objectValue);
uint32_t ti = time(NULL);
qsoinfo["last_activity"] = ti;
qsoinfo["qso_active"] = false;
qsoinfo["qso_members"] = joinList(Qso.members);
qsoinfo["gateway"] = callsign();
qsoinfo["cci"] = cci;
qsoinfo["aimode"] = callinfo[cci].aistatus;
qsoinfo["dest_mcc"] = callinfo[cci].d_mcc;
qsoinfo["dest_mnc"] = callinfo[cci].d_mnc;
qsoinfo["dest_issi"] = callinfo[cci].d_issi;
publishInfo("QsoInfo:state", qsoinfo);
}
else
{
@ -1555,6 +1678,18 @@ void TetraLogic::handleCallReleased(std::string message)
} /* TetraLogic::handleCallReleased */
std::string TetraLogic::joinList(std::list<std::string> members)
{
std::string qi;
for (const auto &it : members)
{
qi += it;
qi += ",";
}
return qi.substr(0,qi.length()-1);
} /* TetraLogic::joinList */
void TetraLogic::sendPei(std::string cmd)
{
// a sdsmsg must end with 0x1a
@ -1639,33 +1774,53 @@ void TetraLogic::cfmTxtSdsReceived(std::string message, std::string tsi)
void TetraLogic::handleCnumf(std::string m_message)
{
size_t f = m_message.find("+CNUMF: ");
if (f != string::npos)
{
m_message.erase(0,8);
}
// e.g. +CNUMF: 6,09011638300023401
// e.g. +CNUMF: 6,09011638300023401
int t_mnc, t_mcc, t_issi;
short m_numtype = getNextVal(m_message);
if (debug >= LOGINFO) cout << "<num type> is " << m_numtype << " ("
<< NumType[m_numtype] << ")" << endl;
if (m_numtype == 6)
if (m_numtype == 6 || m_numtype == 0)
{
if (mcc != m_message.substr(0,4) && debug >= LOGWARN)
// get the tsi and split it into mcc,mnc,issi
splitTsi(m_message, t_mcc, t_mnc, t_issi);
// check if the configured MCC fits to MCC in MS
if (t_mcc != atoi(mcc.c_str()))
{
cout << "*** ERROR: wrong MCC in MS, will not work! " << mcc << "!="
<< m_message.substr(0,4) << endl;
if (debug >= LOGWARN)
{
cout << "*** ERROR: wrong MCC in MS, will not work! "
<< mcc << "!=" << t_mcc << endl;
}
}
if (mnc != m_message.substr(4,5) && debug >= LOGWARN)
// check if the configured MNC fits to MNC in MS
if (t_mnc != atoi(mnc.c_str()))
{
cout << "*** ERROR: wrong MNC in MS, will not work! " << mnc << "!="
<< m_message.substr(4,5) << endl;
if (debug >= LOGWARN)
{
cout << "*** ERROR: wrong MNC in MS, will not work! "
<< mnc << "!=" << t_mnc << endl;
}
}
if (atoi(issi.c_str()) != atoi(m_message.substr(9,8).c_str()) && debug >= LOGWARN)
dmcc = t_mcc;
dmnc = t_mnc;
if (atoi(issi.c_str()) != t_issi)
{
cout << "*** ERROR: wrong ISSI in MS, will not work! " << issi <<"!="
<< atoi(m_message.substr(9,8).c_str()) << endl;
if (debug >= LOGWARN)
{
cout << "*** ERROR: wrong ISSI in MS, will not work! "
<< issi <<"!=" << t_issi << endl;
}
}
}
@ -1889,7 +2044,10 @@ void TetraLogic::onPublishStateEvent(const string &event_name, const string &msg
if (event_name == "TetraUsers:info")
{
if (debug >= LOGINFO) cout << "Download userdata from Reflector (TetraUsers:info):" << endl;
if (debug >= LOGINFO)
{
cout << "Download userdata from Reflector (TetraUsers:info):" << endl;
}
for (Json::Value::ArrayIndex i = 0; i != user_arr.size(); i++)
{
User m_user;
@ -1897,14 +2055,18 @@ void TetraLogic::onPublishStateEvent(const string &event_name, const string &msg
m_user.issi = t_userdata.get("tsi", "").asString();
m_user.name = t_userdata.get("name","").asString();
m_user.call = t_userdata.get("call","").asString();
m_user.location = t_userdata.get("location","").asString();
m_user.aprs_sym = static_cast<char>(t_userdata.get("sym","").asInt());
m_user.aprs_tab = static_cast<char>(t_userdata.get("tab","").asInt());
m_user.comment = t_userdata.get("comment","").asString();
m_user.last_activity = t_userdata.get("last_activity","").asUInt();
userdata[m_user.issi] = m_user;
if (debug >= LOGINFO)
{
cout << "tsi:" << m_user.issi << ",call=" << m_user.call << ",name="
<< m_user.name << ",comment=" << m_user.comment << endl;
<< m_user.name << ",location=" << m_user.location
<< ", comment=" << m_user.comment << endl;
}
}
}
@ -2034,6 +2196,10 @@ void TetraLogic::sendWelcomeSds(string tsi, short r4s)
} /* TetraLogic::sendWelcomeSds */
/*
* @param: a message, e.g. +CTCC: 1,1,1,0,0,1,1
* @return: the current caller identifier
*/
int TetraLogic::handleCci(std::string m_message)
{
size_t f = m_message.find("+CTCC: ");

View File

@ -269,6 +269,7 @@ class TetraLogic : public Logic
std::string call;
std::string name;
std::string comment;
std::string location;
float lat;
float lon;
std::string state;
@ -365,7 +366,10 @@ class TetraLogic : public Logic
bool inTransmission;
bool cmgs_received;
bool share_userinfo;
Json::Value m_user_info;
int current_cci;
int dmnc;
int dmcc;
void initPei(void);
void onCharactersReceived(char *buf, int count);
@ -409,6 +413,7 @@ class TetraLogic : public Logic
void onDapnetMessage(std::string, std::string message);
void sendAprs(std::string call, std::string aprsmessage);
bool checkIfDapmessage(std::string message);
std::string joinList(std::list<std::string> members);
}; /* class TetraLogic */

View File

@ -137,12 +137,13 @@ PROXIMITY_WARNING=3.1
TIME_BETWEEN_SDS=3600
INFO_SDS=Welcome new user
TETRA_USERS=Tetra_Users
TETRA_USER_INFOFILE=@SVX_SYSCONF_INSTALL_DIR@/tetra_users.json
TETRA_STATUS=Tetra_Status
SDS_ON_USERACTIVITY=SdsOnUserActivity
SDS_TO_OTHERS_ON_ACTIVITY=DMO_ON,DMO_OFF,PROXIMITY
SDS_TO_COMMAND=SdsToCommand
END_CMD=ATH
SHARE_USERINFO=1
#SHARE_USERINFO=0
DAPNET_SERVER=dapnet.afu.rwth-aachen.de
DAPNET_PORT=43434
DAPNET_CALLSIGN=MYCALL
@ -165,6 +166,8 @@ DAPNET_RUBRIC_REGISTRATION=RicRegistration
1234=1024,1051
23451=1028,1051
# please move the next section to
# @SVX_SYSCONF_INSTALL_DIR@/tetra_users.json
[Tetra_Users]
# ISSI = Call,Name,comment
09011638300023401=DM0SVX,DMO-Repeater,\\r,Halle/Saale