#include "DeviceListModel.h" #include "BoostLog.h" #include #include #include #include #include DeviceListModel::DeviceListModel(QObject *parent) : QAbstractListModel{parent} { m_broadcastSocket = new QUdpSocket(this); } int DeviceListModel::rowCount(const QModelIndex &parent) const { return m_devices.size(); } QVariant DeviceListModel::data(const QModelIndex &index, int role) const { QVariant ret; auto row = index.row(); if (role == DeviceIdRole) { ret = m_devices.at(row).deviceId; } else if (role == FirmwareVersionRole) { ret = m_devices.at(row).firmwareVersion; } else if (role == SoftwareVersionRole) { ret = m_devices.at(row).softwareVersion; } else if (role == IpRole) { ret = m_devices.at(row).ip; } return ret; } QHash DeviceListModel::roleNames() const { QHash roleNames; roleNames.insert(DeviceIdRole, "deviceId"); roleNames.insert(FirmwareVersionRole, "firmwareVersion"); roleNames.insert(SoftwareVersionRole, "softwareVersion"); roleNames.insert(IpRole, "ip"); return roleNames; } QVariantMap DeviceListModel::get(int index) const { QVariantMap map; if (index >= 0 && index < m_devices.size()) { map["firmwareVersion"] = m_devices[index].firmwareVersion; map["softwareVersion"] = m_devices[index].softwareVersion; map["deviceId"] = m_devices[index].deviceId; map["ip"] = m_devices[index].ip; } return map; } void DeviceListModel::startSearchDevice() { if (m_timerId >= 0) { LOG(error) << "app is searching device."; return; } beginResetModel(); m_devices.clear(); endResetModel(); auto interfaces = QNetworkInterface::allInterfaces(); for (auto &interface : interfaces) { if (interface.flags() & QNetworkInterface::IsLoopBack) continue; if (interface.flags() & QNetworkInterface::IsUp && interface.flags() & QNetworkInterface::IsRunning) { const QList entries = interface.addressEntries(); for (const QNetworkAddressEntry &entry : entries) { if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) continue; QUdpSocket *socket = new QUdpSocket(this); if (socket->bind(entry.ip(), ListenPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) { connect(socket, &QUdpSocket::readyRead, this, &DeviceListModel::onDeviceReplyReadyRead); m_udpSockets.push_back(socket); LOG(info) << "Listening on " << entry.ip().toString().toStdString() << ":" << ListenPort; } else { LOG(error) << "Failed to bind UDP socket on" << entry.ip().toString().toStdString() << ":" << ListenPort; delete socket; } } } } if (!m_udpSockets.empty()) { m_retries = 0; emit searchProgressChanged(); m_timerId = startTimer(1000); emit isSearchingChanged(); } } bool DeviceListModel::isSearching() const { return m_timerId >= 0; } float DeviceListModel::searchProgress() const { return static_cast(m_retries) * 100 / RetryCount; } 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(); DeviceInfomation device; device.deviceId = QString::fromStdString(std::string(reply.at("devid").as_string())); device.firmwareVersion = QString::fromStdString(std::string(reply.at("fw_ver").as_string())); device.softwareVersion = QString::fromStdString(std::string(reply.at("sw_ver").as_string())); device.ip = datagram.senderAddress().toString(); auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(), [&device](const DeviceInfomation &item) { return item.deviceId == device.deviceId; }); if (iterator == m_devices.cend()) { beginInsertRows(QModelIndex(), m_devices.size(), m_devices.size()); m_devices.push_back(device); endInsertRows(); } LOG(info) << "Received datagram from " << datagram.senderAddress().toString().toStdString() << ":" << datagram.senderPort() << ", Data: " << datagram.data().toStdString(); } } void DeviceListModel::broadcast() { if (m_udpSockets.empty()) return; QByteArray datagram = "FACEPASS_V2"; auto interfaces = QNetworkInterface::allInterfaces(); for (auto &interface : interfaces) { if (interface.flags() & QNetworkInterface::IsLoopBack) continue; if (interface.flags() & QNetworkInterface::IsUp && interface.flags() & QNetworkInterface::IsRunning) { const QList entries = interface.addressEntries(); for (const QNetworkAddressEntry &entry : entries) { if (entry.broadcast().toIPv4Address()) { m_broadcastSocket->writeDatagram(datagram, entry.broadcast(), BroadcastPort); LOG(info) << "Broadcasted datagram: " << datagram.toStdString() << " to " << entry.broadcast().toString().toStdString() << ":" << BroadcastPort; } } } } } void DeviceListModel::stopSearchDevice() { if (m_timerId >= 0) { killTimer(m_timerId); m_timerId = -1; } if (!m_udpSockets.empty()) { for (auto &socket : m_udpSockets) { socket->deleteLater(); } m_udpSockets.clear(); } emit isSearchingChanged(); } void DeviceListModel::timerEvent(QTimerEvent *event) { broadcast(); m_retries++; emit searchProgressChanged(); if (m_retries >= RetryCount) { QTimer::singleShot(0, this, &DeviceListModel::stopSearchDevice); } }