2024-08-13 20:06:10 +08:00
|
|
|
#include "DeviceConnection.h"
|
|
|
|
#include "BoostLog.h"
|
2024-08-19 09:33:04 +08:00
|
|
|
#include "StringUtility.h"
|
2024-08-13 20:06:10 +08:00
|
|
|
#include <QPointF>
|
|
|
|
#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-16 16:24:15 +08:00
|
|
|
void DeviceConnection::connect(const QString &address) {
|
2024-08-13 20:06:10 +08:00
|
|
|
m_commandSocket = new QTcpSocket(this);
|
|
|
|
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-16 16:24:15 +08:00
|
|
|
m_commandSocket->connectToHost(address, 8000);
|
|
|
|
m_h264Socket->connectToHost(address, 8000);
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::start() {
|
|
|
|
boost::json::object request;
|
|
|
|
request["func"] = "openlivestream_setdata";
|
|
|
|
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-14 20:01:38 +08:00
|
|
|
auto task = [this]() {
|
|
|
|
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());
|
|
|
|
LOG(info) << "requestOpenDoorArea";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
2024-08-16 16:24:15 +08:00
|
|
|
void DeviceConnection::updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points) {
|
|
|
|
auto 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());
|
|
|
|
LOG(info) << "updateOpenDoorAreaPoints";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::requestShieldedArea() {
|
|
|
|
auto task = [this]() {
|
|
|
|
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());
|
|
|
|
LOG(info) << "requestShieldedArea";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::updateShieldedAreaPoints(bool enabled, const QList<QPointF> &points) {
|
|
|
|
auto task = [this, enabled, points]() {
|
|
|
|
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());
|
|
|
|
LOG(info) << "updateShieldedAreaPoints";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::requestAntiClipArea() {
|
|
|
|
auto task = [this]() {
|
|
|
|
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());
|
|
|
|
LOG(info) << "requestAntiClipArea";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points) {
|
|
|
|
auto task = [this, enabled, points]() {
|
|
|
|
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()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::requestResolution(Resolution resolution) {
|
|
|
|
auto task = [this, resolution]() {
|
|
|
|
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());
|
|
|
|
LOG(info) << "requestShieldedArea";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
|
2024-08-16 16:24:15 +08:00
|
|
|
void DeviceConnection::requestNetworkInfomation() {
|
|
|
|
auto task = [this]() {
|
|
|
|
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()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask,
|
|
|
|
const QString &gateway) {
|
|
|
|
auto task = [this, dhcp, ip, netmask, gateway]() {
|
|
|
|
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();
|
|
|
|
|
|
|
|
request["data"] = std::move(data);
|
|
|
|
auto text = boost::json::serialize(request);
|
|
|
|
m_commandSocket->write(text.data(), text.size());
|
|
|
|
LOG(info) << "requestUpdateNetworkInfomation";
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
2024-08-19 09:33:04 +08:00
|
|
|
void DeviceConnection::requestOta(const QString &file) {
|
|
|
|
LOG(info) << file.toStdString();
|
|
|
|
|
|
|
|
auto task = [this, file]() {
|
|
|
|
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>());
|
|
|
|
|
|
|
|
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;
|
|
|
|
data["target_linux04_firmware"] = "RD_T009_V21R003B001";
|
|
|
|
data["datasize"] = std::filesystem::file_size(file.toStdString());
|
|
|
|
data["md5"] = oss.str();
|
|
|
|
request["data"] = std::move(data);
|
|
|
|
auto text = boost::json::serialize(request);
|
|
|
|
m_commandSocket->write(text.data(), text.size());
|
|
|
|
LOG(info) << "requestOta: " << text;
|
|
|
|
};
|
|
|
|
if (m_requests.empty()) {
|
|
|
|
task();
|
|
|
|
}
|
|
|
|
m_requests.push(task);
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:06:10 +08:00
|
|
|
void DeviceConnection::handleCommand(const std::string_view &replyText) {
|
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();
|
|
|
|
return;
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
emit currentOpenDoorAreaChanged(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);
|
|
|
|
}
|
2024-08-14 20:01:38 +08:00
|
|
|
emit currentShieldedAreaChanged(value == "1", points);
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
emit currentAntiClipAreaChanged(value == "1", points);
|
2024-08-16 16:24:15 +08:00
|
|
|
} else if (function == "netconfig_getdata") {
|
|
|
|
auto &data = reply.at("data").as_object();
|
|
|
|
NetworkInfomation info;
|
|
|
|
info.dhcp = data.at("type").as_string() == "dhcp";
|
|
|
|
info.ip = data.at("ip").as_string().c_str();
|
|
|
|
info.gateway = data.at("gateway").as_string().c_str();
|
|
|
|
info.netmask = data.at("netmask").as_string().c_str();
|
|
|
|
emit currentNetworkInfomationChanged(info);
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceConnection::onConnected() {
|
|
|
|
LOG(info) << "onConnected";
|
|
|
|
auto socket = dynamic_cast<QTcpSocket *>(sender());
|
|
|
|
if (socket == m_commandSocket) {
|
|
|
|
requestOpenDoorArea();
|
2024-08-14 20:01:38 +08:00
|
|
|
requestShieldedArea();
|
|
|
|
requestAntiClipArea();
|
2024-08-16 16:24:15 +08:00
|
|
|
requestNetworkInfomation();
|
|
|
|
} else if (socket == m_h264Socket) {
|
|
|
|
start();
|
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;
|
|
|
|
LOG(info) << "h264 reply: " << m_commandBuffer.data() + sizeof(uint32_t);
|
|
|
|
handleCommand(std::string_view(m_commandBuffer.data() + sizeof(uint32_t), packageSize));
|
|
|
|
m_commandBuffer.remove(0, packageSize + sizeof(uint32_t));
|
2024-08-14 20:01:38 +08:00
|
|
|
m_requests.pop();
|
|
|
|
if (!m_requests.empty()) {
|
|
|
|
m_requests.front()();
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
}
|