#include "DeviceConnection.h" #include "BoostLog.h" #include "StringUtility.h" #include #include #include #include #include #include #include #include DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} { } void DeviceConnection::connect(const QString &address) { 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); m_commandSocket->connectToHost(address, 8000); m_h264Socket->connectToHost(address, 8000); } 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() { 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); } void DeviceConnection::updateOpenDoorAreaPoints(AreaWay way, const QList &points) { auto task = [this, way, points]() { boost::json::object request; request["func"] = "a03opendoor1_setdata"; request["deviceid"] = "0"; boost::json::object data; const char *value = "0"; if (way == FullArea) { value = "1"; } else if (way == Quadrangle) { value = "2"; } data["value"] = value; 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 &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 &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(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); } 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); } 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((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 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(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); } void DeviceConnection::handleCommand(const std::string_view &replyText) { boost::system::error_code error; auto replyValue = boost::json::parse(replyText, error); if (error) { LOG(error) << "prase [" << replyText << "] failed, message: " << error.message(); return; } auto &reply = replyValue.as_object(); auto &function = reply.at("func").as_string(); if (function == "a03opendoor1_getdata") { auto &data = reply.at("data").as_object(); auto &value = data.at("value").as_string(); auto &pointArray = data.at("points").as_array(); QList 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); } AreaWay way = Diabled; if (value == "1") { way = FullArea; } else if (value == "2") { way = Quadrangle; } emit currentOpenDoorAreaChanged(way, points); } else if (function == "a03opendoor4_getdata") { auto &data = reply.at("data").as_object(); auto &value = data.at("value").as_string(); auto &pointArray = data.at("points").as_array(); QList 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 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 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); } 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); } } void DeviceConnection::onConnected() { LOG(info) << "onConnected"; auto socket = dynamic_cast(sender()); if (socket == m_commandSocket) { requestOpenDoorArea(); requestShieldedArea(); requestAntiClipArea(); requestNetworkInfomation(); } else if (socket == m_h264Socket) { start(); } } 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(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(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)); m_requests.pop(); if (!m_requests.empty()) { m_requests.front()(); } } }