Compare commits

..

3 Commits

5 changed files with 148 additions and 43 deletions

View File

@ -206,6 +206,8 @@ public:
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
std::string result = R"({"mainState":)"; std::string result = R"({"mainState":)";
result += api->loadTerminalState(); result += api->loadTerminalState();
result += R"(,"sysinfo":)";
result += api->loadSysInfo();
result += "}"; result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));

View File

@ -8,6 +8,8 @@
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <sys/sysinfo.h>
typedef boost::property_tree::ptree::path_type json_path; typedef boost::property_tree::ptree::path_type json_path;
@ -107,17 +109,19 @@ static std::ostream& operator<<(std::ostream& out, CP_Result result) {
return out; return out;
} }
static void logCpApiError(const char* desc, CP_Result err) {
if (err != OK) {
BOOST_LOG_TRIVIAL(error) << "CP API error in " << desc << ": " << err;
}
}
/** /**
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки * Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
*/ */
class api_driver::TerminalApiDaemon { class api_driver::TerminalApiDaemon {
private: private:
CP_Result lastCpError = OK;
void logCpApiError(const char* desc, CP_Result err) {
if (err != OK) {
BOOST_LOG_TRIVIAL(error) << "CP API error in " << desc << ": " << err;
this->lastCpError = err;
}
}
void updateState() { void updateState() {
modulator_state modulator{}; modulator_state modulator{};
demodulator_state demodulator{}; demodulator_state demodulator{};
@ -224,38 +228,52 @@ private:
} }
} }
void connectToApi() {
{
std::lock_guard _lock(this->stateMutex);
this->deviceInitState = "Not connected to API";
}
unsigned int access{};
for (int connectAttempt = 0;; connectAttempt++) {
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Try to connect api (attempt " << connectAttempt << ")...";
auto res = CP_Login("admin", "pass", &sid, &access);
logCpApiError(R"(api_driver::TerminalApiDaemon::connectToApi()->CP_Login("admin", "pass"))", res);
if (res != OK) {
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(1000)));
} else {
break;
}
}
std::string tmp;
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetDmaDebug(status_init)", CP_GetDmaDebug(sid, "status_init", &tmp));
{
std::lock_guard _lock(this->stateMutex);
this->deviceInitState = tmp;
}
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Success connect!";
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): API status: " << tmp;
TerminalFirmwareVersion f;
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(version)", CP_GetNetwork(sid, "version", &f.version));
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(chip_id)", CP_GetNetwork(sid, "chip_id", &f.modemId));
rtrim(f.modemId);
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(serial)", CP_GetNetwork(sid, "serial", &f.modemSn));
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(mac_eth0)", CP_GetNetwork(sid, "mac_eth0", &f.macMang));
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(mac_eth1)", CP_GetNetwork(sid, "mac_eth1", &f.macData));
{
std::lock_guard _lock(this->firmwareMutex);
this->firmware = f;
}
this->lastCpError = OK;
}
void run() { void run() {
// это демон, который в бесконечном цикле опрашивает API // это демон, который в бесконечном цикле опрашивает API
{ this->connectToApi();
TSID sid{};
unsigned int access{};
for (int connectAttempt = 0;; connectAttempt++) {
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::run(): Try to connect api (attempt " << connectAttempt << ")...";
auto res = CP_Login("admin", "pass", &sid, &access);
logCpApiError(R"(api_driver::TerminalApiDaemon::run()->CP_Login("admin", "pass"))", res);
if (res != OK) {
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(1000)));
} else {
break;
}
}
std::string tmp;
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetDmaDebug(status_init)", CP_GetDmaDebug(sid, "status_init", &tmp));
{
std::lock_guard _lock(this->stateMutex);
this->deviceInitState = tmp;
}
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::run(): Success connect!";
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::run(): API status: " << tmp;
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetNetwork(version)", CP_GetNetwork(sid, "version", &firmware.version));
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetNetwork(chip_id)", CP_GetNetwork(sid, "chip_id", &firmware.modemId));
rtrim(firmware.modemId);
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetNetwork(serial)", CP_GetNetwork(sid, "serial", &firmware.modemSn));
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetNetwork(mac_eth0)", CP_GetNetwork(sid, "mac_eth0", &firmware.macMang));
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetNetwork(mac_eth1)", CP_GetNetwork(sid, "mac_eth1", &firmware.macData));
}
struct IntervalUpdate_t { struct IntervalUpdate_t {
int64_t lastUpdate; int64_t lastUpdate;
@ -317,6 +335,12 @@ private:
}; };
while (true) { while (true) {
if (this->lastCpError == ERROR || this->lastCpError == TIMEOUT) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run(): close current daemon session caused error " << this->lastCpError;
CP_Logout(this->sid);
this->connectToApi();
}
int64_t sleepTime = 60000; // минута по-умолчанию int64_t sleepTime = 60000; // минута по-умолчанию
auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count(); auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
for (auto& u: updaters) { for (auto& u: updaters) {
@ -360,13 +384,14 @@ private:
bool qosEnabled; bool qosEnabled;
std::string qosClassesJson; std::string qosClassesJson;
std::shared_mutex firmwareMutex;
TerminalFirmwareVersion firmware;
public: public:
std::mutex cpApiMutex; std::mutex cpApiMutex;
TSID sid; TSID sid;
boost::thread daemon; boost::thread daemon;
TerminalFirmwareVersion firmware;
explicit TerminalApiDaemon(): deviceInitState("Not connected to API"), qosEnabled(false), sid(0), daemon([this]() { this->run(); }) { explicit TerminalApiDaemon(): deviceInitState("Not connected to API"), qosEnabled(false), sid(0), daemon([this]() { this->run(); }) {
this->qosClassesJson = DEFAULT_QOS_CLASSES; this->qosClassesJson = DEFAULT_QOS_CLASSES;
} }
@ -584,6 +609,11 @@ public:
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", "")); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
} }
TerminalFirmwareVersion getFirmware() {
std::shared_lock lock(this->firmwareMutex);
return firmware;
}
void resetPacketStatistics() { void resetPacketStatistics() {
std::string tmp; std::string tmp;
std::lock_guard lock(this->cpApiMutex); std::lock_guard lock(this->cpApiMutex);
@ -884,11 +914,12 @@ std::string api_driver::ApiDriver::loadFirmwareVersion() const {
} }
std::stringstream result; std::stringstream result;
result << "{\n\"fw.version\":" << buildEscapedString(daemon->firmware.version); auto firmware = daemon->getFirmware();
result << ",\"fw.modemId\":" << buildEscapedString(daemon->firmware.modemId); result << "{\n\"fw.version\":" << buildEscapedString(firmware.version);
result << ",\"fw.modemSn\":" << buildEscapedString(daemon->firmware.modemSn); result << ",\"fw.modemId\":" << buildEscapedString(firmware.modemId);
result << ",\"fw.macMang\":" << buildEscapedString(daemon->firmware.macMang); result << ",\"fw.modemSn\":" << buildEscapedString(firmware.modemSn);
result << ",\"fw.macData\":" << buildEscapedString(daemon->firmware.macData); result << ",\"fw.macMang\":" << buildEscapedString(firmware.macMang);
result << ",\"fw.macData\":" << buildEscapedString(firmware.macData);
result << "\n}"; result << "\n}";
return result.str(); return result.str();
} }
@ -1062,4 +1093,42 @@ void api_driver::ApiDriver::executeInApi(const std::function<void(TSID sid)>& ca
} }
} }
std::string api_driver::ApiDriver::loadSysInfo() {
std::stringstream result;
struct sysinfo info{};
sysinfo(&info);
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* Swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
};
result << "{\n\"uptime\":" << info.uptime;
result << ",\"load1min\":" << info.loads[0];
result << ",\"load5min\":" << info.loads[1];
result << ",\"load15min\":" << info.loads[2];
result << ",\"totalram\":" << info.totalram;
result << ",\"freeram\":" << info.freeram;
result << ",\"sharedram\":" << info.sharedram;
result << ",\"bufferram\":" << info.bufferram;
result << ",\"totalswap\":" << info.totalswap;
result << ",\"freeswap\":" << info.freeswap;
result << ",\"procs\":" << static_cast<long>(info.procs);
result << ",\"totalhigh\":" << info.totalhigh;
result << ",\"freehigh\":" << info.freehigh;
result << ",\"mem_unit\":" << info.mem_unit;
result << "\n}";
return result.str();
}
api_driver::ApiDriver::~ApiDriver() = default; api_driver::ApiDriver::~ApiDriver() = default;

View File

@ -70,6 +70,8 @@ namespace api_driver {
void executeInApi(const std::function<void(TSID sid)>& callback); void executeInApi(const std::function<void(TSID sid)>& callback);
static std::string loadSysInfo();
~ApiDriver(); ~ApiDriver();
private: private:

View File

@ -118,6 +118,7 @@
<tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr> <tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr>
<tr><th>Температура ZYNQ</th><td>{{ stat_device.zynq }} °C</td></tr> <tr><th>Температура ZYNQ</th><td>{{ stat_device.zynq }} °C</td></tr>
<tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr> <tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr>
<tr><th>Uptime</th><td>{{ stat_os.uptime }}</td></tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -849,6 +850,7 @@
stat_device: { // температурные датчики stat_device: { // температурные датчики
adrv: 0, zynq: 0, fpga: 0 adrv: 0, zynq: 0, fpga: 0
}, },
stat_os: {uptime: '?'},
param: { param: {
general: { general: {
@ -1037,6 +1039,20 @@
this.stat_device.fpga = vals["mainState"]["device.fpga"] this.stat_device.fpga = vals["mainState"]["device.fpga"]
this.testState = vals["mainState"]["testState"] this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"]
if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
let hours = uptime % 24
uptime = Math.floor( uptime / 24)
let res = `${hours}:${mins}:${secs}`
if (uptime > 0) { res = `${uptime} days, ` + res }
this.stat_os.uptime = res
} else {
this.stat_os.uptime = '?'
}
}, },
resetPacketsStatistics() { resetPacketsStatistics() {

View File

@ -105,6 +105,7 @@
<tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr> <tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr>
<tr><th>Температура ZYNQ</th><td>{{ stat_device.zynq }} °C</td></tr> <tr><th>Температура ZYNQ</th><td>{{ stat_device.zynq }} °C</td></tr>
<tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr> <tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr>
<tr><th>Uptime</th><td>{{ stat_os.uptime }}</td></tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -641,6 +642,7 @@
stat_device: { // температурные датчики stat_device: { // температурные датчики
adrv: 0, zynq: 0, fpga: 0 adrv: 0, zynq: 0, fpga: 0
}, },
stat_os: {uptime: '?'},
param: { param: {
tx: { tx: {
@ -775,6 +777,20 @@
this.stat_device.fpga = vals["mainState"]["device.fpga"] this.stat_device.fpga = vals["mainState"]["device.fpga"]
this.testState = vals["mainState"]["testState"] this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"]
if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
let hours = uptime % 24
uptime = Math.floor( uptime / 24)
let res = `${hours}:${mins}:${secs}`
if (uptime > 0) { res = `${uptime} days, ` + res }
this.stat_os.uptime = res
} else {
this.stat_os.uptime = '?'
}
}, },
resetPacketsStatistics() { resetPacketsStatistics() {