Compare commits

..

6 Commits

8 changed files with 206 additions and 58 deletions

View File

@@ -105,8 +105,8 @@
cinc: { cinc: {
mode: null, // 'positional' | 'delay' mode: null, // 'positional' | 'delay'
searchBandwidth: 0, // полоса поиска в кГц searchBandwidth: 0, // полоса поиска в кГц
position: { position: {
station: { station: {
latitude: 0, latitude: 0,
longitude: 0 longitude: 0

View File

@@ -84,6 +84,8 @@ class ServerResources {
std::unique_ptr<api_driver::ApiDriver> api; std::unique_ptr<api_driver::ApiDriver> api;
http::auth::AuthProvider auth{}; http::auth::AuthProvider auth{};
bool upgradeOrRebootRunning = false;
static void onUploadFirmware(const http::server::Request& req) { static void onUploadFirmware(const http::server::Request& req) {
std::ofstream f("/tmp/firmware.zip", std::ios::binary); std::ofstream f("/tmp/firmware.zip", std::ios::binary);
@@ -204,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());
})); }));
@@ -415,7 +419,7 @@ public:
} }
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/reboot", this->auth, 0, [](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/reboot", this->auth, 0, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
} }
@@ -424,6 +428,7 @@ 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)});
const std::string result = R"({"status":"ok"})"; const std::string result = R"({"status":"ok"})";
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());
this->upgradeOrRebootRunning = true;
system(REBOOT_COMMAND); system(REBOOT_COMMAND);
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetSettings", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetSettings", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
@@ -439,10 +444,11 @@ public:
system(REBOOT_COMMAND); system(REBOOT_COMMAND);
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
if (req.method != "PUT") { if (req.method != "PUT") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
} }
this->upgradeOrRebootRunning = true;
onUploadFirmware(req); onUploadFirmware(req);
rep.status = http::server::ok; rep.status = http::server::ok;
@@ -454,12 +460,14 @@ public:
result += http::utils::sha256(req.payload.data(), req.payload.size()); result += http::utils::sha256(req.payload.data(), req.payload.size());
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());
this->upgradeOrRebootRunning = false;
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/doFirmwareUpgrade", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/doFirmwareUpgrade", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
} }
this->upgradeOrRebootRunning = true;
doTerminalUpgrade(); doTerminalUpgrade();
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.clear(); rep.headers.clear();
@@ -467,6 +475,19 @@ public:
const auto result = api->loadFirmwareVersion(); const auto result = api->loadFirmwareVersion();
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());
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
boost::ignore_unused(req);
sf->serve(INTERNET_JPG, rep);
}));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/fetchParams", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
std::string result = R"({"status":"ok","fwsize":)";
result += std::to_string(req.payload.size());
result += R"(,"sha256":")";
result += "\"}";
}));
} }
~ServerResources() = default; ~ServerResources() = default;

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:

16
static/dev-params.json Normal file
View File

@@ -0,0 +1,16 @@
{
"params": [
{
"label": "Запись пакетов",
"name": "log_bool",
"widget": "checkbox",
"function": "DmaDebug"
},
{
"label": "Unused test",
"name": "log_bool",
"widget": "checkbox",
"function": "DmaDebug"
}
]
}

10
static/dev.html Normal file
View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>

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>
@@ -540,8 +541,8 @@
</template> </template>
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatus.qos"></span></button> <button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatus.qos"></span></button>
<h2 hidden>Настройки TCP-акселерации</h2> <h2>Настройки TCP-акселерации</h2>
<div hidden class="settings-set-container"> <div class="settings-set-container">
<label> <label>
<span>Активировать акселерацию</span> <span>Активировать акселерацию</span>
<span class="toggle-input"><input type="checkbox" v-model="param.tcpAccel.en" /><span class="slider"></span></span> <span class="toggle-input"><input type="checkbox" v-model="param.tcpAccel.en" /><span class="slider"></span></span>
@@ -551,7 +552,7 @@
<input type="number" v-model="param.tcpAccel.maxConnections" min="1" max="10000" /> <input type="number" v-model="param.tcpAccel.maxConnections" min="1" max="10000" />
</label> </label>
</div> </div>
<button hidden class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button> <button class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button>
</div> </div>
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete"> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
<h2>Настройки сети</h2> <h2>Настройки сети</h2>
@@ -667,15 +668,13 @@
function modcodToStr(modcod) { function modcodToStr(modcod) {
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf // модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
// NOTE модкоды со скоростью хода 3/5 не работают
const modcods = [ const modcods = [
"DUMMY", "DUMMY",
"QPSK 1/4", "QPSK 1/4",
"QPSK 1/3", "QPSK 1/3",
"QPSK 2/5", "QPSK 2/5",
"QPSK 1/2", "QPSK 1/2",
"QPSK 3/5", // отключено "QPSK 3/5",
"QPSK 2/3", "QPSK 2/3",
"QPSK 3/4", "QPSK 3/4",
"QPSK 4/5", "QPSK 4/5",
@@ -683,7 +682,7 @@
"QPSK 8/9", "QPSK 8/9",
"QPSK 9/10", "QPSK 9/10",
"8PSK 3/5", // отключено "8PSK 3/5",
"8PSK 2/3", "8PSK 2/3",
"8PSK 3/4", "8PSK 3/4",
"8PSK 5/6", "8PSK 5/6",
@@ -717,7 +716,7 @@
case '1/3': return 2 case '1/3': return 2
case '2/5': return 3 case '2/5': return 3
case '1/2': return 4 case '1/2': return 4
case '3/5': return 5 // отключено case '3/5': return 5
case '2/3': return 6 case '2/3': return 6
case '3/4': return 7 case '3/4': return 7
case '4/5': return 8 case '4/5': return 8
@@ -728,7 +727,7 @@
} }
case '8psk': case '8psk':
switch (speed) { switch (speed) {
case '3/5': return 12 // отключено case '3/5': return 12
case '2/3': return 13 case '2/3': return 13
case '3/4': return 14 case '3/4': return 14
case '5/6': return 15 case '5/6': return 15
@@ -851,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: {
@@ -981,9 +981,9 @@
// NOTE модкоды со скоростью хода 3/5 не работают // NOTE модкоды со скоростью хода 3/5 не работают
switch (modulation) { switch (modulation) {
case 'qpsk': case 'qpsk':
return ['1/4', '1/3', '2/5', '1/2', /* '3/5',*/ '2/3', '3/4', '4/5', '5/6', '8/9', '9/10'] return ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
case '8psk': case '8psk':
return [/* '3/5',*/ '2/3', '3/4', '5/6', '8/9', '9/10'] return ['3/5', '2/3', '3/4', '5/6', '8/9', '9/10']
case '16apsk': case '16apsk':
return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10'] return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
case '32apsk': case '32apsk':
@@ -1039,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() {