适配设备的上线策略。
This commit is contained in:
parent
31aa3d86ac
commit
d822dcda76
@ -145,7 +145,7 @@ void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QS
|
|||||||
if (!m_device.expired()) {
|
if (!m_device.expired()) {
|
||||||
auto device = m_device.lock();
|
auto device = m_device.lock();
|
||||||
device->updateNetworkInfomation(dhcp, ip, netmask, gateway, dns);
|
device->updateNetworkInfomation(dhcp, ip, netmask, gateway, dns);
|
||||||
emit newMessage(1, "网络设置", "设置成功,请重新搜索并连接设备!");
|
emit newMessage(1, "网络设置", "设置成功,请等待设备重新上线!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,15 @@ bool DeviceConnection::isConnected() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::connect(const Infomation &infomation) {
|
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_infomation = infomation;
|
||||||
m_commandSocket = new QTcpSocket(this);
|
m_commandSocket = new QTcpSocket(this);
|
||||||
QObject::connect(m_commandSocket, &QTcpSocket::disconnected, this, &DeviceConnection::onDisconnected);
|
QObject::connect(m_commandSocket, &QTcpSocket::disconnected, this, &DeviceConnection::onDisconnected);
|
||||||
@ -54,6 +63,7 @@ NetworkInfomation DeviceConnection::networkInfomation() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::setLiveStreamEnabled(bool enabled) {
|
void DeviceConnection::setLiveStreamEnabled(bool enabled) {
|
||||||
|
m_videoEnabled = enabled;
|
||||||
boost::json::object request;
|
boost::json::object request;
|
||||||
request["func"] = enabled ? "openlivestream_setdata" : "closelivestream_setdata";
|
request["func"] = enabled ? "openlivestream_setdata" : "closelivestream_setdata";
|
||||||
request["deviceid"] = "0";
|
request["deviceid"] = "0";
|
||||||
@ -365,7 +375,9 @@ void DeviceConnection::transferBinContent() {
|
|||||||
|
|
||||||
auto fileProgress = static_cast<float>(m_sendedSize) / m_uploadBuffer.size();
|
auto fileProgress = static_cast<float>(m_sendedSize) / m_uploadBuffer.size();
|
||||||
m_otaProgress = 2 + 96 * fileProgress;
|
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()) {
|
if (m_sendedSize < m_uploadBuffer.size()) {
|
||||||
QTimer::singleShot(0, this, &DeviceConnection::transferBinContent);
|
QTimer::singleShot(0, this, &DeviceConnection::transferBinContent);
|
||||||
@ -490,6 +502,7 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
|||||||
task->future->reportFinished(&status);
|
task->future->reportFinished(&status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
requestNetworkInfomation();
|
||||||
LOG(info) << replyText;
|
LOG(info) << replyText;
|
||||||
} else if (function == "a22devicefirmware_setdata") {
|
} else if (function == "a22devicefirmware_setdata") {
|
||||||
LOG(warning) << "ota reply: " << replyText;
|
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();
|
auto &value = data.at("value").as_string();
|
||||||
if (value == "1") {
|
if (value == "1") {
|
||||||
m_otaProgress = 1;
|
m_otaProgress = 1;
|
||||||
emit otaProgressChanged(true, m_otaProgress, "设备已进入OTA升级状态......");
|
emit otaProgressChanged(true, m_otaProgress, "设备已进入升级状态......");
|
||||||
QTimer::singleShot(0, this, [this]() { transferBinContent(); });
|
QTimer::singleShot(0, this, [this]() { transferBinContent(); });
|
||||||
} else if (value == "2") {
|
} else if (value == "2") {
|
||||||
LOG(info) << "md5 check finished";
|
LOG(info) << "md5 check finished";
|
||||||
m_otaProgress = 99;
|
m_otaProgress = 99;
|
||||||
emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......");
|
emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......");
|
||||||
QTimer::singleShot(0, this, [this]() {
|
QTimer::singleShot(0, this, [this]() {
|
||||||
m_commandSocket->close();
|
m_commandSocket->close(); // 等待设备重新上线后,发起广播。由搜索服务触发重连
|
||||||
m_h264Socket->close();
|
m_h264Socket->close();
|
||||||
if (m_otaTimer == nullptr) {
|
if (m_otaTimer == nullptr) {
|
||||||
m_otaTimer = new QTimer(this);
|
m_otaTimer = new QTimer(this);
|
||||||
@ -519,12 +532,7 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
|||||||
m_h264Socket->close();
|
m_h264Socket->close();
|
||||||
},
|
},
|
||||||
Qt::SingleShotConnection);
|
Qt::SingleShotConnection);
|
||||||
m_otaTimer->start(60 * 1000);
|
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);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const char *message = nullptr;
|
const char *message = nullptr;
|
||||||
@ -569,7 +577,7 @@ void DeviceConnection::onConnected() {
|
|||||||
m_otaTimer->stop();
|
m_otaTimer->stop();
|
||||||
}
|
}
|
||||||
} else if (socket == m_h264Socket) {
|
} else if (socket == m_h264Socket) {
|
||||||
if (m_otaProgress >= 99) {
|
if (m_videoEnabled) {
|
||||||
setLiveStreamEnabled(true);
|
setLiveStreamEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -640,13 +648,7 @@ void DeviceConnection::onCommandReadyRead() {
|
|||||||
|
|
||||||
void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError) {
|
void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError) {
|
||||||
auto socket = dynamic_cast<QTcpSocket *>(sender());
|
auto socket = dynamic_cast<QTcpSocket *>(sender());
|
||||||
qDebug() << "DeviceConnection::onErrorOccurred" << socketError;
|
LOG(info) << "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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConnection::timerEvent(QTimerEvent *event) {
|
void DeviceConnection::timerEvent(QTimerEvent *event) {
|
||||||
|
@ -18,6 +18,7 @@ class DeviceConnection : public QObject {
|
|||||||
QML_UNCREATABLE("Only created in C++...")
|
QML_UNCREATABLE("Only created in C++...")
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
constexpr static auto WirelessAddress = "192.168.10.2";
|
||||||
enum Resolution {
|
enum Resolution {
|
||||||
Video_360P = 0,
|
Video_360P = 0,
|
||||||
Video_720P,
|
Video_720P,
|
||||||
@ -115,6 +116,7 @@ private:
|
|||||||
QTcpSocket *m_commandSocket = nullptr;
|
QTcpSocket *m_commandSocket = nullptr;
|
||||||
|
|
||||||
QTcpSocket *m_h264Socket = nullptr;
|
QTcpSocket *m_h264Socket = nullptr;
|
||||||
|
bool m_videoEnabled = false;
|
||||||
bool m_receivedFirstJsonReply = false;
|
bool m_receivedFirstJsonReply = false;
|
||||||
|
|
||||||
QByteArray m_commandBuffer;
|
QByteArray m_commandBuffer;
|
||||||
|
@ -7,6 +7,38 @@
|
|||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
#include <boost/json/parse.hpp>
|
#include <boost/json/parse.hpp>
|
||||||
|
|
||||||
|
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<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
|
||||||
|
for (const QNetworkInterface &iface : interfaces) {
|
||||||
|
QList<QNetworkAddressEntry> 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} {
|
DeviceListModel::DeviceListModel(QObject *parent) : QAbstractListModel{parent} {
|
||||||
m_broadcastSocket = new QUdpSocket(this);
|
m_broadcastSocket = new QUdpSocket(this);
|
||||||
}
|
}
|
||||||
@ -72,6 +104,12 @@ void DeviceListModel::startSearchDevice() {
|
|||||||
LOG(error) << "app is searching device.";
|
LOG(error) << "app is searching device.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!m_udpSockets.empty()) {
|
||||||
|
for (auto &socket : m_udpSockets) {
|
||||||
|
socket->deleteLater();
|
||||||
|
}
|
||||||
|
m_udpSockets.clear();
|
||||||
|
}
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_devices.clear();
|
m_devices.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
@ -143,37 +181,56 @@ void DeviceListModel::onDeviceReplyReadyRead() {
|
|||||||
auto udp = dynamic_cast<QUdpSocket *>(sender());
|
auto udp = dynamic_cast<QUdpSocket *>(sender());
|
||||||
while (udp->hasPendingDatagrams()) {
|
while (udp->hasPendingDatagrams()) {
|
||||||
QNetworkDatagram datagram = udp->receiveDatagram();
|
QNetworkDatagram datagram = udp->receiveDatagram();
|
||||||
auto replyVale = boost::json::parse(datagram.data().toStdString());
|
if (isTargetIPInSameNetwork(datagram.senderAddress())) { // 设备开机时可能会广播一个 192.168.2.10 的地址
|
||||||
auto &reply = replyVale.as_object();
|
auto replyVale = boost::json::parse(datagram.data().toStdString());
|
||||||
DeviceConnection::Infomation device;
|
auto &reply = replyVale.as_object();
|
||||||
if (reply.contains("devid")) {
|
DeviceConnection::Infomation device;
|
||||||
device.deviceId = QString::fromStdString(std::string(reply.at("devid").as_string()));
|
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("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 (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 (!device.softwareVersion.startsWith("RD_T009")) continue; // 其它设备不予显示
|
||||||
|
device.ip = datagram.senderAddress().toString();
|
||||||
|
|
||||||
auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(),
|
auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(),
|
||||||
[&device](const std::shared_ptr<DeviceConnection> &item) {
|
[&device](const std::shared_ptr<DeviceConnection> &item) {
|
||||||
return item->infomation().deviceId == device.deviceId;
|
return item->infomation().deviceId == device.deviceId;
|
||||||
});
|
});
|
||||||
if (iterator == m_devices.cend()) {
|
if (iterator == m_devices.cend()) {
|
||||||
auto connection = std::shared_ptr<DeviceConnection>(new DeviceConnection(),
|
if (m_timerId >= 0) { // 只有在搜索设备的过程中,才加入新设备
|
||||||
[](DeviceConnection *self) { self->deleteLater(); });
|
auto connection = std::shared_ptr<DeviceConnection>(
|
||||||
connect(connection.get(), &DeviceConnection::connected, this, &DeviceListModel::onDeviceConnected);
|
new DeviceConnection(), [](DeviceConnection *self) { self->deleteLater(); });
|
||||||
connect(connection.get(), &DeviceConnection::disconnected, this, &DeviceListModel::onDeviceDisconnected);
|
connect(connection.get(), &DeviceConnection::connected, this, &DeviceListModel::onDeviceConnected);
|
||||||
connection->connect(device);
|
connect(connection.get(), &DeviceConnection::disconnected, this,
|
||||||
beginInsertRows(QModelIndex(), m_devices.size(), m_devices.size());
|
&DeviceListModel::onDeviceDisconnected);
|
||||||
m_devices.push_back(connection);
|
connection->connect(device);
|
||||||
endInsertRows();
|
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<int> 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() << ":"
|
LOG(info) << datagram.destinationAddress().toString().toStdString() << ":" << datagram.destinationPort()
|
||||||
<< datagram.senderPort() << ", Data: " << datagram.data().toStdString();
|
<< " 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);
|
killTimer(m_timerId);
|
||||||
m_timerId = -1;
|
m_timerId = -1;
|
||||||
}
|
}
|
||||||
if (!m_udpSockets.empty()) {
|
|
||||||
for (auto &socket : m_udpSockets) {
|
|
||||||
socket->deleteLater();
|
|
||||||
}
|
|
||||||
m_udpSockets.clear();
|
|
||||||
}
|
|
||||||
emit isSearchingChanged();
|
emit isSearchingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ Popup {
|
|||||||
placeholderText: "请选择升级bin文件"
|
placeholderText: "请选择升级bin文件"
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
|
enabled: otaFinished
|
||||||
text: "选择"
|
text: "选择"
|
||||||
onClicked: fileDialog.open()
|
onClicked: fileDialog.open()
|
||||||
}
|
}
|
||||||
@ -76,6 +77,7 @@ Popup {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
|
enabled: otaFinished
|
||||||
text: "开始"
|
text: "开始"
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@ -119,7 +121,10 @@ Popup {
|
|||||||
}
|
}
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if(!visible){
|
if(!visible){
|
||||||
|
progressBar.value = 0
|
||||||
otaMessage.color = "black"
|
otaMessage.color = "black"
|
||||||
|
progressText.text = "0%"
|
||||||
|
otaMessage.text = "请选择升级文件,点击开始按钮升级模组"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user