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:
parent
295863f9e2
commit
65399cdf14
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue