适配设备的上线策略。

This commit is contained in:
luocai 2024-08-22 18:12:11 +08:00
parent 31aa3d86ac
commit d822dcda76
5 changed files with 113 additions and 53 deletions

View File

@ -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, "网络设置", "设置成功,请等待设备重新上线!");
}
}

View File

@ -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<float>(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<QTcpSocket *>(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) {

View File

@ -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;

View File

@ -7,6 +7,38 @@
#include <QUdpSocket>
#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} {
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<QUdpSocket *>(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<DeviceConnection> &item) {
return item->infomation().deviceId == device.deviceId;
});
if (iterator == m_devices.cend()) {
auto connection = std::shared_ptr<DeviceConnection>(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<DeviceConnection> &item) {
return item->infomation().deviceId == device.deviceId;
});
if (iterator == m_devices.cend()) {
if (m_timerId >= 0) { // 只有在搜索设备的过程中,才加入新设备
auto connection = std::shared_ptr<DeviceConnection>(
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<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() << ":"
<< 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();
}

View File

@ -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 = "请选择升级文件,点击开始按钮升级模组"
}
}
}