diff --git a/Application.cpp b/Application.cpp index 1845d8b..48ae276 100644 --- a/Application.cpp +++ b/Application.cpp @@ -145,7 +145,7 @@ void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QS if (!m_device.expired()) { auto device = m_device.lock(); device->updateNetworkInfomation(dhcp, ip, netmask, gateway, dns); - emit newMessage(1, "网络设置", "设置成功,请重新搜索并连接设备!"); + emit newMessage(1, "网络设置", "设置成功,请等待设备重新上线!"); } } diff --git a/DeviceConnection.cpp b/DeviceConnection.cpp index 7eac525..1db6fa4 100644 --- a/DeviceConnection.cpp +++ b/DeviceConnection.cpp @@ -28,6 +28,15 @@ bool DeviceConnection::isConnected() const { } void DeviceConnection::connect(const Infomation &infomation) { + while (!m_requests.empty()) { + m_requests.pop(); + } + if (m_commandSocket != nullptr) { + m_commandSocket->deleteLater(); + } + if (m_h264Socket != nullptr) { + m_h264Socket->deleteLater(); + } m_infomation = infomation; m_commandSocket = new QTcpSocket(this); QObject::connect(m_commandSocket, &QTcpSocket::disconnected, this, &DeviceConnection::onDisconnected); @@ -54,6 +63,7 @@ NetworkInfomation DeviceConnection::networkInfomation() const { } void DeviceConnection::setLiveStreamEnabled(bool enabled) { + m_videoEnabled = enabled; boost::json::object request; request["func"] = enabled ? "openlivestream_setdata" : "closelivestream_setdata"; request["deviceid"] = "0"; @@ -365,7 +375,9 @@ void DeviceConnection::transferBinContent() { auto fileProgress = static_cast(m_sendedSize) / m_uploadBuffer.size(); m_otaProgress = 2 + 96 * fileProgress; - emit otaProgressChanged(true, m_otaProgress, "向设备发送OTA升级文件......"); + emit otaProgressChanged(true, m_otaProgress, + m_otaProgress < 98 ? "向设备发送升级固件......" + : "升级固件发送完成,等待设备校验升级固件......"); if (m_sendedSize < m_uploadBuffer.size()) { QTimer::singleShot(0, this, &DeviceConnection::transferBinContent); @@ -490,6 +502,7 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const task->future->reportFinished(&status); } } + requestNetworkInfomation(); LOG(info) << replyText; } else if (function == "a22devicefirmware_setdata") { LOG(warning) << "ota reply: " << replyText; @@ -497,14 +510,14 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const auto &value = data.at("value").as_string(); if (value == "1") { m_otaProgress = 1; - emit otaProgressChanged(true, m_otaProgress, "设备已进入OTA升级状态......"); + emit otaProgressChanged(true, m_otaProgress, "设备已进入升级状态......"); QTimer::singleShot(0, this, [this]() { transferBinContent(); }); } else if (value == "2") { LOG(info) << "md5 check finished"; m_otaProgress = 99; emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......"); QTimer::singleShot(0, this, [this]() { - m_commandSocket->close(); + m_commandSocket->close(); // 等待设备重新上线后,发起广播。由搜索服务触发重连 m_h264Socket->close(); if (m_otaTimer == nullptr) { m_otaTimer = new QTimer(this); @@ -519,12 +532,7 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const m_h264Socket->close(); }, Qt::SingleShotConnection); - m_otaTimer->start(60 * 1000); - }); - QTimer::singleShot(25000, this, [this]() { - LOG(info) << "try connect after ota."; - m_commandSocket->connectToHost(m_infomation.ip, 8000); - m_h264Socket->connectToHost(m_infomation.ip, 8000); + m_otaTimer->start(60 * 1000); }); } else { const char *message = nullptr; @@ -569,7 +577,7 @@ void DeviceConnection::onConnected() { m_otaTimer->stop(); } } else if (socket == m_h264Socket) { - if (m_otaProgress >= 99) { + if (m_videoEnabled) { setLiveStreamEnabled(true); } } @@ -640,13 +648,7 @@ void DeviceConnection::onCommandReadyRead() { void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError) { auto socket = dynamic_cast(sender()); - qDebug() << "DeviceConnection::onErrorOccurred" << socketError; - if (m_otaProgress == 99) { // 99 表示设备正在OTA重启,需要重连 - if (socket->state() == QTcpSocket::UnconnectedState) { - LOG(info) << "try reconnect after ota."; - socket->connectToHost(m_infomation.ip, 8000); - } - } + LOG(info) << "DeviceConnection::onErrorOccurred" << socketError; } void DeviceConnection::timerEvent(QTimerEvent *event) { diff --git a/DeviceConnection.h b/DeviceConnection.h index 792d93b..7059820 100644 --- a/DeviceConnection.h +++ b/DeviceConnection.h @@ -18,6 +18,7 @@ class DeviceConnection : public QObject { QML_UNCREATABLE("Only created in C++...") public: + constexpr static auto WirelessAddress = "192.168.10.2"; enum Resolution { Video_360P = 0, Video_720P, @@ -115,6 +116,7 @@ private: QTcpSocket *m_commandSocket = nullptr; QTcpSocket *m_h264Socket = nullptr; + bool m_videoEnabled = false; bool m_receivedFirstJsonReply = false; QByteArray m_commandBuffer; diff --git a/DeviceListModel.cpp b/DeviceListModel.cpp index fc9c7aa..62aba52 100644 --- a/DeviceListModel.cpp +++ b/DeviceListModel.cpp @@ -7,6 +7,38 @@ #include #include +static QHostAddress calculateNetworkAddress(const QHostAddress &ip, const QHostAddress &netmask) { + quint32 ipInt = ip.toIPv4Address(); + quint32 netmaskInt = netmask.toIPv4Address(); + quint32 networkInt = ipInt & netmaskInt; + return QHostAddress(networkInt); +} + +static bool isSameNetwork(const QHostAddress &ip1, const QHostAddress &netmask1, const QHostAddress &ip2) { + QHostAddress network1 = calculateNetworkAddress(ip1, netmask1); + QHostAddress network2 = calculateNetworkAddress(ip2, netmask1); // Using the same netmask for the target IP + return network1 == network2; +} + +static bool isTargetIPInSameNetwork(const QHostAddress &targetIP) { + QList interfaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : interfaces) { + QList entries = iface.addressEntries(); + for (const QNetworkAddressEntry &entry : entries) { + QHostAddress ip = entry.ip(); + QHostAddress netmask = entry.netmask(); + + if (ip.protocol() == QAbstractSocket::IPv4Protocol) { + bool sameNetwork = isSameNetwork(ip, netmask, targetIP); + if (sameNetwork) { + return true; + } + } + } + } + return false; +} + DeviceListModel::DeviceListModel(QObject *parent) : QAbstractListModel{parent} { m_broadcastSocket = new QUdpSocket(this); } @@ -72,6 +104,12 @@ void DeviceListModel::startSearchDevice() { LOG(error) << "app is searching device."; return; } + if (!m_udpSockets.empty()) { + for (auto &socket : m_udpSockets) { + socket->deleteLater(); + } + m_udpSockets.clear(); + } beginResetModel(); m_devices.clear(); endResetModel(); @@ -143,37 +181,56 @@ void DeviceListModel::onDeviceReplyReadyRead() { auto udp = dynamic_cast(sender()); while (udp->hasPendingDatagrams()) { QNetworkDatagram datagram = udp->receiveDatagram(); - auto replyVale = boost::json::parse(datagram.data().toStdString()); - auto &reply = replyVale.as_object(); - DeviceConnection::Infomation device; - if (reply.contains("devid")) { - device.deviceId = QString::fromStdString(std::string(reply.at("devid").as_string())); - } - if (reply.contains("fw_ver")) { - device.firmwareVersion = QString::fromStdString(std::string(reply.at("fw_ver").as_string())); - } - if (reply.contains("sw_ver")) { - device.softwareVersion = QString::fromStdString(std::string(reply.at("sw_ver").as_string())); - } - if (!device.softwareVersion.startsWith("RD_T009")) continue; // 其它设备不予显示 - device.ip = datagram.senderAddress().toString(); + if (isTargetIPInSameNetwork(datagram.senderAddress())) { // 设备开机时可能会广播一个 192.168.2.10 的地址 + auto replyVale = boost::json::parse(datagram.data().toStdString()); + auto &reply = replyVale.as_object(); + DeviceConnection::Infomation device; + if (reply.contains("devid")) { + device.deviceId = QString::fromStdString(std::string(reply.at("devid").as_string())); + } + if (reply.contains("fw_ver")) { + device.firmwareVersion = QString::fromStdString(std::string(reply.at("fw_ver").as_string())); + } + if (reply.contains("sw_ver")) { + device.softwareVersion = QString::fromStdString(std::string(reply.at("sw_ver").as_string())); + } + if (!device.softwareVersion.startsWith("RD_T009")) continue; // 其它设备不予显示 + device.ip = datagram.senderAddress().toString(); - auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(), - [&device](const std::shared_ptr &item) { - return item->infomation().deviceId == device.deviceId; - }); - if (iterator == m_devices.cend()) { - auto connection = std::shared_ptr(new DeviceConnection(), - [](DeviceConnection *self) { self->deleteLater(); }); - connect(connection.get(), &DeviceConnection::connected, this, &DeviceListModel::onDeviceConnected); - connect(connection.get(), &DeviceConnection::disconnected, this, &DeviceListModel::onDeviceDisconnected); - connection->connect(device); - beginInsertRows(QModelIndex(), m_devices.size(), m_devices.size()); - m_devices.push_back(connection); - endInsertRows(); + auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(), + [&device](const std::shared_ptr &item) { + return item->infomation().deviceId == device.deviceId; + }); + if (iterator == m_devices.cend()) { + if (m_timerId >= 0) { // 只有在搜索设备的过程中,才加入新设备 + auto connection = std::shared_ptr( + new DeviceConnection(), [](DeviceConnection *self) { self->deleteLater(); }); + connect(connection.get(), &DeviceConnection::connected, this, &DeviceListModel::onDeviceConnected); + connect(connection.get(), &DeviceConnection::disconnected, this, + &DeviceListModel::onDeviceDisconnected); + connection->connect(device); + beginInsertRows(QModelIndex(), m_devices.size(), m_devices.size()); + m_devices.push_back(connection); + endInsertRows(); + } + } else { + auto info = (*iterator)->infomation(); + if ((m_timerId < 0) || + ((info.ip == DeviceConnection::WirelessAddress) && (device.ip != DeviceConnection::WirelessAddress)) || + ((device.ip != DeviceConnection::WirelessAddress) && (device.ip != info.ip))) { + QList roles; + roles << OnlineStatusRole << IpRole; + int row = std::distance(m_devices.cbegin(), iterator); + emit dataChanged(index(row), index(row), roles); + (*iterator)->connect(device); + LOG(info) << "device: " << device.deviceId.toStdString() << " back online"; + } + } } - LOG(info) << "Received datagram from " << datagram.senderAddress().toString().toStdString() << ":" - << datagram.senderPort() << ", Data: " << datagram.data().toStdString(); + LOG(info) << datagram.destinationAddress().toString().toStdString() << ":" << datagram.destinationPort() + << " received datagram from " << datagram.senderAddress().toString().toStdString() << ":" + << datagram.senderPort() << ", Data: " << datagram.data().toStdString() + << ", same network: " << isTargetIPInSameNetwork(datagram.senderAddress()); } } @@ -201,12 +258,6 @@ void DeviceListModel::stopSearchDevice() { killTimer(m_timerId); m_timerId = -1; } - if (!m_udpSockets.empty()) { - for (auto &socket : m_udpSockets) { - socket->deleteLater(); - } - m_udpSockets.clear(); - } emit isSearchingChanged(); } diff --git a/qml/OtaPopup.qml b/qml/OtaPopup.qml index 6a23c2f..a805ec3 100644 --- a/qml/OtaPopup.qml +++ b/qml/OtaPopup.qml @@ -45,6 +45,7 @@ Popup { placeholderText: "请选择升级bin文件" } Button { + enabled: otaFinished text: "选择" onClicked: fileDialog.open() } @@ -76,6 +77,7 @@ Popup { Layout.fillWidth: true } Button { + enabled: otaFinished text: "开始" Layout.alignment: Qt.AlignRight onClicked: { @@ -119,7 +121,10 @@ Popup { } onVisibleChanged: { if(!visible){ + progressBar.value = 0 otaMessage.color = "black" + progressText.text = "0%" + otaMessage.text = "请选择升级文件,点击开始按钮升级模组" } } }