AntiClipSettings/DeviceConnection.cpp

815 lines
30 KiB
C++
Raw Permalink Normal View History

2024-08-26 16:46:41 +08:00
#include "DeviceConnection.h"
2024-08-13 20:06:10 +08:00
#include "BoostLog.h"
2024-08-19 09:33:04 +08:00
#include "StringUtility.h"
#include <QFileInfo>
2024-08-13 20:06:10 +08:00
#include <QPointF>
2024-08-21 09:26:06 +08:00
#include <QTimer>
#include <QTimerEvent>
2024-08-13 20:06:10 +08:00
#include <WinSock2.h>
#include <boost/json/object.hpp>
#include <boost/json/parse.hpp>
#include <boost/json/serialize.hpp>
2024-08-19 09:33:04 +08:00
#include <filesystem>
#include <fstream>
#include <mbedtls/md5.h>
2024-08-13 20:06:10 +08:00
DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} {
}
2024-08-27 11:14:36 +08:00
DeviceConnection::~DeviceConnection() {
close();
}
void DeviceConnection::close() {
if (m_otaTimer != nullptr) {
m_otaTimer->deleteLater();
m_otaTimer = nullptr;
}
if (m_heartbeatTimerId > 0) {
killTimer(m_heartbeatTimerId);
m_heartbeatTimerId = -1;
2024-08-27 11:14:36 +08:00
}
if (m_commandSocket != nullptr) {
m_commandSocket->deleteLater();
m_commandSocket = nullptr;
}
if (m_h264Socket != nullptr) {
m_h264Socket->deleteLater();
m_h264Socket = nullptr;
}
while (!m_requests.empty()) {
m_requests.pop();
}
}
2024-08-21 09:26:06 +08:00
DeviceConnection::Infomation DeviceConnection::infomation() const {
return m_infomation;
}
bool DeviceConnection::isConnected() const {
bool ret = false;
if (m_commandSocket != nullptr) {
// LOG(info) << "DeviceConnection::isConnected " << m_commandSocket->isValid();
ret = m_commandSocket->isValid() && (m_commandSocket->state() == QTcpSocket::ConnectedState);
}
return ret;
}
void DeviceConnection::connect(const Infomation &infomation) {
2024-08-27 11:14:36 +08:00
close();
2024-08-21 09:26:06 +08:00
m_infomation = infomation;
2024-08-13 20:06:10 +08:00
m_commandSocket = new QTcpSocket(this);
2024-08-21 16:03:49 +08:00
QObject::connect(m_commandSocket, &QTcpSocket::disconnected, this, &DeviceConnection::onDisconnected);
2024-08-21 09:26:06 +08:00
QObject::connect(m_commandSocket, &QTcpSocket::errorOccurred, this, &DeviceConnection::onErrorOccurred);
2024-08-13 20:06:10 +08:00
m_h264Socket = new QTcpSocket(this);
QObject::connect(m_commandSocket, &QTcpSocket::connected, this, &DeviceConnection::onConnected);
QObject::connect(m_h264Socket, &QTcpSocket::connected, this, &DeviceConnection::onConnected);
QObject::connect(m_h264Socket, &QTcpSocket::readyRead, this, &DeviceConnection::onH264ReadyRead);
QObject::connect(m_commandSocket, &QTcpSocket::readyRead, this, &DeviceConnection::onCommandReadyRead);
2024-08-21 09:26:06 +08:00
LOG(info) << "connect to " << infomation.ip.toStdString();
m_commandSocket->connectToHost(infomation.ip, 8000);
m_h264Socket->connectToHost(infomation.ip, 8000);
}
NetworkInfomation DeviceConnection::networkInfomation() const {
return m_networkInfomation;
2024-08-13 20:06:10 +08:00
}
2024-08-21 09:26:06 +08:00
void DeviceConnection::setLiveStreamEnabled(bool enabled) {
2024-08-22 18:12:11 +08:00
m_videoEnabled = enabled;
2024-08-13 20:06:10 +08:00
boost::json::object request;
2024-08-21 09:26:06 +08:00
request["func"] = enabled ? "openlivestream_setdata" : "closelivestream_setdata";
2024-08-13 20:06:10 +08:00
request["deviceid"] = "0";
boost::json::object data;
data["value"] = "1";
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_h264Socket->write(text.data(), text.size());
}
void DeviceConnection::requestOpenDoorArea() {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor1_getdata";
task.task = [this]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor1_getdata";
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
}
2024-08-22 10:48:28 +08:00
QFuture<bool> DeviceConnection::updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points) {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor1_setdata";
task.task = [this, way, points]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor1_setdata";
request["deviceid"] = "0";
boost::json::object data;
2024-08-16 16:24:15 +08:00
const char *value = "0";
if (way == FullArea) {
value = "1";
} else if (way == Quadrangle) {
value = "2";
}
data["value"] = value;
2024-08-14 20:01:38 +08:00
boost::json::array pointArray;
for (auto &p : points) {
boost::json::object point;
point["x"] = p.x();
point["y"] = p.y();
pointArray.push_back(std::move(point));
}
data["points"] = std::move(pointArray);
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
2024-08-22 10:48:28 +08:00
task.future = std::make_shared<QFutureInterface<bool>>();
2024-08-14 20:01:38 +08:00
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
2024-08-22 10:48:28 +08:00
auto ret = task.future->future();
2024-08-14 20:01:38 +08:00
m_requests.push(task);
2024-08-22 10:48:28 +08:00
return ret;
2024-08-14 20:01:38 +08:00
}
void DeviceConnection::requestShieldedArea() {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor4_getdata";
task.task = [this]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor4_getdata";
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
}
void DeviceConnection::updateShieldedAreaPoints(bool enabled, const QList<QPointF> &points) {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor4_setdata";
task.task = [this, enabled, points]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor4_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = enabled ? "1" : "0";
boost::json::array pointArray;
for (auto &p : points) {
boost::json::object point;
point["x"] = p.x();
point["y"] = p.y();
pointArray.push_back(std::move(point));
}
data["points"] = std::move(pointArray);
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
}
void DeviceConnection::requestAntiClipArea() {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor5_getdata";
task.task = [this]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor5_getdata";
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
}
void DeviceConnection::updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points) {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a03opendoor5_setdata";
task.task = [this, enabled, points]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "a03opendoor5_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = enabled ? "1" : "0";
boost::json::array pointArray;
for (auto &p : points) {
boost::json::object point;
point["x"] = p.x();
point["y"] = p.y();
pointArray.push_back(std::move(point));
}
data["points"] = std::move(pointArray);
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "updateAntiClipAreaPoints";
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
}
void DeviceConnection::requestResolution(Resolution resolution) {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "quality_setdata";
task.task = [this, resolution]() {
2024-08-14 20:01:38 +08:00
boost::json::object request;
request["func"] = "quality_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = static_cast<int>(resolution);
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
2024-08-21 16:03:49 +08:00
LOG(info) << "requestResolution";
2024-08-14 20:01:38 +08:00
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
}
m_requests.push(task);
}
void DeviceConnection::updateRotation(int rotation) {
Task task;
task.command = "a23imagerotate_setdata";
task.task = [this, rotation]() {
boost::json::object request;
request["func"] = "a23imagerotate_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = std::to_string(rotation);
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "updateRotation: " << text;
};
if (m_requests.empty()) {
task.task();
}
m_requests.push(task);
}
void DeviceConnection::updateFlip(bool flip) {
Task task;
task.command = "a04imageflipping_setdata";
task.task = [this, flip]() {
boost::json::object request;
request["func"] = "a04imageflipping_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = flip ? "2" : "1";
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
task.task();
}
m_requests.push(task);
}
2024-08-21 16:03:49 +08:00
void DeviceConnection::requestVersion() {
Task task;
task.command = "a15devicedetail_getdata";
task.task = [this]() {
boost::json::object request;
request["func"] = "a15devicedetail_getdata";
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "requestVersion";
};
if (m_requests.empty()) {
task.task();
2024-08-14 20:01:38 +08:00
}
m_requests.push(task);
2024-08-13 20:06:10 +08:00
}
void DeviceConnection::requestVideoInformation() {
constexpr const char *commands[] = {"a23imagerotate_getdata", "a04imageflipping_getdata"};
for (auto command : commands) {
Task task;
task.command = command;
task.task = [this, command]() {
boost::json::object request;
request["func"] = command;
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
};
if (m_requests.empty()) {
task.task();
}
m_requests.push(task);
}
}
2024-08-16 16:24:15 +08:00
void DeviceConnection::requestNetworkInfomation() {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "netconfig_getdata";
task.task = [this]() {
2024-08-16 16:24:15 +08:00
boost::json::object request;
request["func"] = "netconfig_getdata";
request["deviceid"] = "0";
boost::json::object data;
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "requestNetworkInfomation";
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-16 16:24:15 +08:00
}
m_requests.push(task);
}
2024-08-22 10:48:28 +08:00
QFuture<bool> DeviceConnection::updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask,
const QString &gateway, const QString &dns) {
2024-08-21 16:03:49 +08:00
Task task;
task.command = "netconfig_setdata";
2024-08-22 10:48:28 +08:00
task.task = [this, dhcp, ip, netmask, gateway, dns]() {
2024-08-16 16:24:15 +08:00
boost::json::object request;
request["func"] = "netconfig_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["type"] = dhcp ? "dhcp" : "static";
data["ip"] = ip.toStdString();
data["netmask"] = netmask.toStdString();
data["gateway"] = gateway.toStdString();
2024-08-22 10:48:28 +08:00
data["dns"] = dns.toStdString();
2024-08-16 16:24:15 +08:00
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "requestUpdateNetworkInfomation";
};
2024-08-22 10:48:28 +08:00
task.future = std::make_shared<QFutureInterface<bool>>();
2024-08-16 16:24:15 +08:00
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-16 16:24:15 +08:00
}
2024-08-22 10:48:28 +08:00
auto ret = task.future->future();
2024-08-16 16:24:15 +08:00
m_requests.push(task);
2024-08-22 10:48:28 +08:00
return ret;
2024-08-16 16:24:15 +08:00
}
2024-08-22 15:32:58 +08:00
void DeviceConnection::requestOta(const QString &firmware, const QString &file) {
2024-08-21 09:26:06 +08:00
m_otaProgress = 0;
emit otaProgressChanged(true, m_otaProgress, "正在向设备发起OTA请求......");
if (m_heartbeatTimerId > 0) {
killTimer(m_heartbeatTimerId);
m_heartbeatTimerId = -1;
2024-08-21 16:03:49 +08:00
}
while (!m_requests.empty()) { // 清除之前的命令
2024-08-27 11:14:36 +08:00
m_requests.pop();
}
2024-08-21 16:03:49 +08:00
Task task;
task.command = "a22devicefirmware_setdata";
2024-08-22 15:32:58 +08:00
task.task = [this, file, firmware]() {
2024-08-19 09:33:04 +08:00
std::ifstream ifs(Amass::StringUtility::UTF8ToGBK(file.toStdString()), std::ifstream::binary);
m_uploadBuffer = std::vector<uint8_t>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
2024-08-21 09:26:06 +08:00
m_sendedSize = 0;
2024-08-19 09:33:04 +08:00
unsigned char md5[16];
mbedtls_md5_context context;
mbedtls_md5_init(&context);
mbedtls_md5_starts(&context);
mbedtls_md5_update(&context, m_uploadBuffer.data(), m_uploadBuffer.size());
mbedtls_md5_finish(&context, md5);
mbedtls_md5_free(&context);
std::stringstream oss;
oss << std::hex << std::setfill('0');
for (int i = 0; i < 16; i++) {
oss << std::setw(2) << static_cast<int>(md5[i]);
}
boost::json::object request;
request["func"] = "a22devicefirmware_setdata";
request["deviceid"] = "0";
boost::json::object data;
2024-08-22 15:32:58 +08:00
data["target_linux04_firmware"] = firmware.toStdString();
QFileInfo fileInfo(file);
data["datasize"] = fileInfo.size();
2024-08-19 09:33:04 +08:00
data["md5"] = oss.str();
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
2024-08-22 15:32:58 +08:00
LOG(info) << "requestOta: " << text;
2024-08-19 09:33:04 +08:00
};
if (m_requests.empty()) {
2024-08-21 16:03:49 +08:00
task.task();
2024-08-19 09:33:04 +08:00
}
m_requests.push(task);
}
2024-08-21 09:26:06 +08:00
void DeviceConnection::transferBinContent() {
constexpr int SliceSize = 1024;
constexpr int WaitMd5CheckTime = 3000; // ms
if (m_sendedSize >= m_uploadBuffer.size()) return;
char buffer[1 + sizeof(int32_t) + 1024];
int sendSize = SliceSize;
if ((m_sendedSize + SliceSize) > m_uploadBuffer.size()) {
sendSize = m_uploadBuffer.size() - m_sendedSize;
}
memcpy(buffer + 1 + sizeof(int32_t), m_uploadBuffer.data() + m_sendedSize, sendSize);
buffer[0] = ':';
auto contentSize = reinterpret_cast<int32_t *>(&buffer[1]);
*contentSize = htonl(sendSize);
m_commandSocket->write(buffer, sendSize + 1 + sizeof(uint32_t));
m_sendedSize += sendSize;
auto fileProgress = static_cast<float>(m_sendedSize) / m_uploadBuffer.size();
2024-08-22 10:48:28 +08:00
m_otaProgress = 2 + 96 * fileProgress;
2024-08-22 18:12:11 +08:00
emit otaProgressChanged(true, m_otaProgress,
m_otaProgress < 98 ? "向设备发送升级固件......"
: "升级固件发送完成,等待设备校验升级固件......");
2024-08-21 09:26:06 +08:00
2024-08-27 11:14:36 +08:00
if ((m_sendedSize < m_uploadBuffer.size()) && isConnected()) {
2024-08-21 09:26:06 +08:00
QTimer::singleShot(0, this, &DeviceConnection::transferBinContent);
} else if (m_sendedSize >= m_uploadBuffer.size()) {
LOG(info) << "transfer ota file finished, wait " << WaitMd5CheckTime
<< " ms for send check, total sended size: " << m_sendedSize;
2024-08-27 11:14:36 +08:00
if (m_otaTimer == nullptr) {
m_otaTimer = new QTimer(this);
m_otaTimer->setSingleShot(true);
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Qt::ConnectionType type = Qt::SingleShotConnection;
#else
Qt::ConnectionType type = Qt::UniqueConnection;
#endif
m_otaTimer->callOnTimeout(
this,
[this]() {
emit otaProgressChanged(false, m_otaProgress, "升级超时,请检查设备并重新尝试...");
m_otaProgress = -1;
m_commandSocket->close();
m_h264Socket->close();
},
type);
m_otaTimer->start(5 * 60 * 1000); // 固件升级五分钟正常升级2.5分钟左右(包含算法模型)
2024-08-21 09:26:06 +08:00
}
}
2024-08-22 10:48:28 +08:00
QString DeviceConnection::handleCommand(const std::string_view &replyText, const Task *task) {
2024-08-21 16:03:49 +08:00
QString ret;
2024-08-14 20:01:38 +08:00
boost::system::error_code error;
auto replyValue = boost::json::parse(replyText, error);
if (error) {
LOG(error) << "prase [" << replyText << "] failed, message: " << error.message();
2024-08-21 16:03:49 +08:00
return ret;
2024-08-14 20:01:38 +08:00
}
2024-08-13 20:06:10 +08:00
auto &reply = replyValue.as_object();
auto &function = reply.at("func").as_string();
if (function == "a03opendoor1_getdata") {
auto &data = reply.at("data").as_object();
2024-08-14 20:01:38 +08:00
auto &value = data.at("value").as_string();
auto &pointArray = data.at("points").as_array();
QList<QPointF> points;
for (auto &p : pointArray) {
QPointF point;
auto &obj = p.as_object();
point.setX(obj.at("x").as_double());
point.setY(obj.at("y").as_double());
points.push_back(point);
}
2024-08-16 16:24:15 +08:00
AreaWay way = Diabled;
if (value == "1") {
way = FullArea;
} else if (value == "2") {
way = Quadrangle;
}
m_infomation.openDoorAreaWay = way;
m_infomation.openDoorArea = points;
2024-08-21 09:26:06 +08:00
emit openDoorAreaChanged(way, points);
2024-08-14 20:01:38 +08:00
} else if (function == "a03opendoor4_getdata") {
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
2024-08-13 20:06:10 +08:00
auto &pointArray = data.at("points").as_array();
QList<QPointF> points;
for (auto &p : pointArray) {
QPointF point;
auto &obj = p.as_object();
point.setX(obj.at("x").as_double());
point.setY(obj.at("y").as_double());
points.push_back(point);
}
m_infomation.shieldedAreaEnabled = value == "1";
m_infomation.shieldedArea = points;
2024-08-21 09:26:06 +08:00
emit shieldedAreaChanged(value == "1", points);
2024-08-14 20:01:38 +08:00
} else if (function == "a03opendoor5_getdata") {
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
auto &pointArray = data.at("points").as_array();
QList<QPointF> points;
for (auto &p : pointArray) {
QPointF point;
auto &obj = p.as_object();
point.setX(obj.at("x").as_double());
point.setY(obj.at("y").as_double());
points.push_back(point);
}
m_infomation.antiClipAreaEnabled = value == "1";
m_infomation.antiClipArea = points;
2024-08-21 09:26:06 +08:00
emit antiClipAreaChanged(value == "1", points);
2024-08-16 16:24:15 +08:00
} else if (function == "netconfig_getdata") {
auto &data = reply.at("data").as_object();
2024-08-21 09:26:06 +08:00
m_networkInfomation.dhcp = data.at("type").as_string() == "dhcp";
m_networkInfomation.ip = data.at("ip").as_string().c_str();
m_networkInfomation.gateway = data.at("gateway").as_string().c_str();
m_networkInfomation.netmask = data.at("netmask").as_string().c_str();
2024-08-22 10:48:28 +08:00
if (data.contains("dns")) {
m_networkInfomation.dns = data.at("dns").as_string().c_str();
}
2024-08-21 09:26:06 +08:00
emit networkInfomationChanged(m_networkInfomation);
2024-08-22 10:48:28 +08:00
LOG(info) << replyText;
2024-08-21 16:03:49 +08:00
} else if (function == "a15devicedetail_getdata") {
auto &data = reply.at("data").as_object();
auto firmware = QString::fromStdString(std::string(data.at("linux04_firmware").as_string()));
if (m_infomation.firmwareVersion != firmware) {
m_infomation.firmwareVersion = firmware;
emit firmwareChanged(m_infomation.firmwareVersion);
}
2024-08-21 09:26:06 +08:00
} else if (function == "a03opendoor5_setdata") {
requestAntiClipArea();
} else if (function == "a03opendoor4_setdata") {
requestShieldedArea();
} else if (function == "a03opendoor1_setdata") {
2024-08-22 10:48:28 +08:00
if ((task != nullptr) && (task->command.toStdString() == function)) {
if (task->timeoutTimer) {
task->timeoutTimer->stop();
}
bool status = true;
if (task->future) {
task->future->reportFinished(&status);
}
}
2024-08-21 09:26:06 +08:00
requestOpenDoorArea();
2024-08-22 10:48:28 +08:00
} else if (function == "netconfig_setdata") {
if ((task != nullptr) && (task->command.toStdString() == function)) {
if (task->timeoutTimer) {
task->timeoutTimer->stop();
}
bool status = true;
if (task->future) {
task->future->reportFinished(&status);
}
}
2024-08-22 18:12:11 +08:00
requestNetworkInfomation();
2024-08-22 10:48:28 +08:00
LOG(info) << replyText;
2024-08-21 09:26:06 +08:00
} else if (function == "a22devicefirmware_setdata") {
LOG(warning) << "ota reply: " << replyText;
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
if (value == "1") {
m_otaProgress = 1;
2024-08-22 18:12:11 +08:00
emit otaProgressChanged(true, m_otaProgress, "设备已进入升级状态......");
2024-08-21 09:26:06 +08:00
QTimer::singleShot(0, this, [this]() { transferBinContent(); });
} else if (value == "2") {
2024-08-30 17:25:31 +08:00
bool isWireConnect = true;
if (data.contains("is_eth")) {
isWireConnect = data.at("is_eth").as_int64() >= 1;
}
2024-08-21 09:26:06 +08:00
LOG(info) << "md5 check finished";
2024-08-22 10:48:28 +08:00
m_otaProgress = 99;
2024-08-21 09:26:06 +08:00
QTimer::singleShot(0, this, [this]() {
2024-08-22 18:12:11 +08:00
m_commandSocket->close(); // 等待设备重新上线后,发起广播。由搜索服务触发重连
2024-08-21 09:26:06 +08:00
m_h264Socket->close();
});
2024-08-30 17:25:31 +08:00
if (isWireConnect) {
emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......");
} else {
m_otaTimer->stop(); // 这里不需要再超时了
emit otaProgressChanged(true, 100, "设备正在升级中请于五分钟后重新连接wifi搜索设备");
2024-08-30 17:25:31 +08:00
}
2024-08-22 10:48:28 +08:00
} else {
2024-08-22 15:32:58 +08:00
const char *message = nullptr;
if (value == "3") {
message = "升级固件MD5校验错误(3)";
} else if (value == "4") {
message = "升级固件大小错误(4)";
} else if (value == "5") {
message = "升级固件太大(5)";
} else if (value == "6") {
message = "升级固件版本不匹配(6)";
}
QString tip;
if (message == nullptr) {
tip = QString("升级失败,错误码: %1").arg(value.c_str());
} else {
tip = QString("升级失败: %1").arg(message);
}
emit otaProgressChanged(false, m_otaProgress, tip);
2024-08-21 09:26:06 +08:00
}
} else if (function == "a23imagerotate_getdata") {
// {"data":{"value":"2"},"deviceid":"0","flag":"ok","func":"a23imagerotate_getdata"}
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
m_infomation.rotation = std::stoi(static_cast<std::string>(value));
emit rotationChanged(m_infomation.rotation);
} else if (function == "a04imageflipping_getdata") {
// {"data":{"value":"1"},"deviceid":"0","flag":"ok","func":"a04imageflipping_getdata"}
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
m_infomation.flip = value == "2";
emit flipChanged(m_infomation.flip);
} else if (function == "a04imageflipping_setdata") {
if ((task != nullptr) && (task->command.toStdString() == function)) {
if (task->timeoutTimer) {
task->timeoutTimer->stop();
}
bool status = true;
if (task->future) {
task->future->reportFinished(&status);
}
}
requestVideoInformation();
} else if (function == "a23imagerotate_setdata") {
if ((task != nullptr) && (task->command.toStdString() == function)) {
if (task->timeoutTimer) {
task->timeoutTimer->stop();
}
bool status = true;
if (task->future) {
task->future->reportFinished(&status);
}
}
requestVideoInformation();
2024-08-21 09:26:06 +08:00
} else {
LOG(warning) << "unknown reply: " << replyText;
2024-08-13 20:06:10 +08:00
}
return QString::fromStdString(std::string(function));
2024-08-13 20:06:10 +08:00
}
void DeviceConnection::onConnected() {
auto socket = dynamic_cast<QTcpSocket *>(sender());
if (socket == m_commandSocket) {
2024-08-21 16:03:49 +08:00
requestVersion();
2024-08-13 20:06:10 +08:00
requestOpenDoorArea();
2024-08-14 20:01:38 +08:00
requestShieldedArea();
requestAntiClipArea();
2024-08-16 16:24:15 +08:00
requestNetworkInfomation();
requestVideoInformation();
2024-08-21 09:26:06 +08:00
emit connected();
m_heartbeatTimerId = startTimer(2500);
2024-08-22 10:48:28 +08:00
if (m_otaProgress == 99) {
m_otaProgress = -1;
emit otaProgressChanged(true, 100, "设备升级成功!");
}
if (m_otaTimer != nullptr) {
m_otaTimer->stop();
2024-08-21 09:26:06 +08:00
}
if (m_requestTimerId < 0) {
m_requestTimerId = startTimer(HeartbeatInterval);
}
2024-08-16 16:24:15 +08:00
} else if (socket == m_h264Socket) {
2024-08-22 18:12:11 +08:00
if (m_videoEnabled) {
2024-08-21 09:26:06 +08:00
setLiveStreamEnabled(true);
}
2024-08-13 20:06:10 +08:00
}
}
2024-08-21 16:03:49 +08:00
void DeviceConnection::onDisconnected() {
auto socket = dynamic_cast<QTcpSocket *>(sender());
if (socket == m_commandSocket) {
if (m_requestTimerId > 0) {
killTimer(m_requestTimerId);
m_requestTimerId = -1;
}
if (m_heartbeatTimerId > 0) {
killTimer(m_heartbeatTimerId);
m_heartbeatTimerId = -1;
2024-08-21 16:03:49 +08:00
}
emit disconnected();
2024-08-22 10:48:28 +08:00
if ((m_otaProgress >= 0) && (m_otaProgress <= 98)) {
m_otaProgress = -1;
emit otaProgressChanged(false, m_otaProgress, "网络断开,设备升级失败!");
}
2024-08-26 14:55:15 +08:00
m_h264Socket->close();
2024-08-21 16:03:49 +08:00
}
}
2024-08-13 20:06:10 +08:00
void DeviceConnection::setH264FrameCallback(H264FrameCallback &&callback) {
m_frameCallback = std::move(callback);
}
void DeviceConnection::onH264ReadyRead() {
auto data = m_h264Socket->readAll();
m_h264Buffer.push_back(data);
while (!m_h264Buffer.isEmpty()) {
auto packageSize = ntohl(*reinterpret_cast<uint32_t *>(m_h264Buffer.data()));
if (m_h264Buffer.size() < (packageSize + sizeof(uint32_t))) break;
// LOG(info) << "onH264ReadyRead " << data.size() << " " << packageSize;
if (m_receivedFirstJsonReply) {
if (m_frameCallback) {
m_frameCallback(m_h264Buffer.data() + sizeof(uint32_t), packageSize);
}
} else {
LOG(info) << "h264 reply: " << m_h264Buffer.data() + sizeof(uint32_t);
m_receivedFirstJsonReply = true;
}
m_h264Buffer.remove(0, packageSize + sizeof(uint32_t));
}
}
void DeviceConnection::onCommandReadyRead() {
auto data = m_commandSocket->readAll();
m_commandBuffer.push_back(data);
while (!m_commandBuffer.isEmpty()) {
auto packageSize = ntohl(*reinterpret_cast<uint32_t *>(m_commandBuffer.data()));
if (m_commandBuffer.size() < (packageSize + sizeof(uint32_t))) break;
2024-08-22 10:48:28 +08:00
auto command = handleCommand(std::string_view(m_commandBuffer.data() + sizeof(uint32_t), packageSize),
m_requests.empty() ? nullptr : &m_requests.front());
2024-08-13 20:06:10 +08:00
m_commandBuffer.remove(0, packageSize + sizeof(uint32_t));
2024-08-21 09:26:06 +08:00
2024-08-14 20:01:38 +08:00
if (!m_requests.empty()) {
2024-08-21 16:03:49 +08:00
auto &task = m_requests.front();
if (task.command == command) {
m_requests.pop();
} else {
LOG(warning) << "current command[" << command.toStdString() << "] is no the task queue's head["
<< task.command.toStdString() << "]";
2024-08-21 16:03:49 +08:00
}
2024-08-21 09:26:06 +08:00
if (!m_requests.empty()) {
auto &command = m_requests.front();
command.task();
2024-08-21 09:26:06 +08:00
}
2024-08-14 20:01:38 +08:00
}
2024-08-13 20:06:10 +08:00
}
}
2024-08-21 09:26:06 +08:00
void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError) {
auto socket = dynamic_cast<QTcpSocket *>(sender());
2024-08-22 18:12:11 +08:00
LOG(info) << "DeviceConnection::onErrorOccurred" << socketError;
2024-08-21 09:26:06 +08:00
}
void DeviceConnection::timerEvent(QTimerEvent *event) {
using namespace std::chrono;
if (event->timerId() == m_heartbeatTimerId) {
if (isConnected()) {
int index = heartbeats % 3;
if (index == 0) {
requestOpenDoorArea();
} else if (index == 1) {
requestShieldedArea();
} else if (index == 2) {
requestAntiClipArea();
}
heartbeats++;
}
} else if (event->timerId() == m_requestTimerId) {
if (!m_requests.empty()) {
auto &command = m_requests.front();
auto elapsed = duration_cast<milliseconds>(system_clock::now() - command.time);
if (elapsed > (HeartbeatInterval * 2)) {
LOG(info) << "not received command[" << command.command.toStdString() << "] more than "
<< (HeartbeatInterval * 2).count() << " ms, consider it failed, send next command.";
m_requests.pop();
if (!m_requests.empty()) {
m_requests.front().task();
}
} else if (elapsed > HeartbeatInterval) {
LOG(info) << "not received command[" << command.command.toStdString() << "] more than "
<< HeartbeatInterval.count() << " ms, resend it.";
command.task();
}
2024-08-21 16:03:49 +08:00
}
2024-08-21 09:26:06 +08:00
}
}