qt/ledset/mainwin.cpp
2023-08-21 11:21:00 +08:00

284 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mainwin.h"
#include "gutil/qjson.h"
#include "pcaprethread.h"
#include "fast.h"
#include "expertwin.h"
#include "brightwin.h"
#include "testwin.h"
#include "videowin.h"
#include <QLabel>
#include <QPushButton>
#include <QToolButton>
#include <QComboBox>
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <QMessageBox>
#include "globalfunc.h"
#include "basewin.h"
#include <QSettings>
#include <QDir>
#include <QApplication>
#include <QtEndian>
#include <QStandardPaths>
#include <QNetworkDatagram>
#include <QNetworkInterface>
class ImgBtn : public QToolButton {
public:
ImgBtn() {
setStyleSheet("QToolButton{border: none; padding-top: 4px;}");
}
bool isEnter{false};
protected:
void resizeEvent(QResizeEvent *event) override {
QToolButton::resizeEvent(event);
if(isEnter) setIconSize(QSize(width(), width()));
else setIconSize(QSize(width()-8, width()-8));
}
void enterEvent(QEvent *event) override {
QToolButton::enterEvent(event);
setStyleSheet("QToolButton{border: none;}");
setIconSize(QSize(width(), width()));
}
void leaveEvent(QEvent *event) override {
QToolButton::leaveEvent(event);
setIconSize(QSize(width()-8, width()-8));
setStyleSheet("QToolButton{border: none; padding-top: 4px;}");
}
};
inline QLabel *newImgLabel(QPixmap pixmap){
QLabel *lb = new QLabel();
lb->setPixmap(pixmap);
return lb;
}
inline QLabel *newSubLabel(QString txt){
QLabel *lb = new QLabel(txt);
lb->setAlignment(Qt::AlignCenter);
return lb;
}
ImgBtn *addImg(QHBoxLayout *parent, const QIcon &icon, const QString &text) {
auto imgBtn = new ImgBtn();
auto ft = imgBtn->font();
ft.setPixelSize(14);
imgBtn->setFont(ft);
imgBtn->setIcon(icon);
imgBtn->setText(text);
imgBtn->setFixedSize(76, 100);
imgBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
parent->addWidget(imgBtn);
return imgBtn;
}
MainWin::MainWin() {
setWindowTitle("LedSet Express");
resize(900, 600);
auto ft = font();
ft.setPixelSize(14);
setFont(ft);
auto vBox = new QVBoxLayout(center);
vBox->setContentsMargins(0,0,0,0);
vBox->addLayout(addBtns(new QHBoxLayout()));
QHBoxLayout *imgsBar = new QHBoxLayout();
auto btnImg = addImg(imgsBar, QPixmap(":/imgs/fast.png").scaledToWidth(128, Qt::SmoothTransformation), "快速调屏");
connect(btnImg, &ImgBtn::clicked, this, [=] {
(new Fast(this))->show();
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/expert.png").scaledToWidth(128, Qt::SmoothTransformation), tr("专家调屏"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
(new ExpertWin(this))->show();
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/bright.png").scaledToWidth(128, Qt::SmoothTransformation), tr("亮度控制"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
(new BrightWin(this))->show();
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/correct.png").scaledToWidth(128, Qt::SmoothTransformation), tr("相机矫正"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/monitor.png").scaledToWidth(128, Qt::SmoothTransformation), tr("屏体监控"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/multi.png").scaledToWidth(128, Qt::SmoothTransformation), tr("多功能卡"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
//win->move(win->x()-1, win->y());
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/test.png").scaledToWidth(128, Qt::SmoothTransformation), tr("协议调试"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
if(reThd->status) return;
(new TestWin(this))->show();
});
btnImg = addImg(imgsBar, QPixmap(":/imgs/idea.png").scaledToWidth(128, Qt::SmoothTransformation), tr("模拟同步"));
connect(btnImg, &ImgBtn::clicked, this, [=] {
auto ins = VideoWin::newIns(net_name, this);
if(ins) ins->show();
});
vBox->addLayout(imgsBar);
vBox->addSpacing(9);
vBox->addWidget(new QLabel(" 硬件信息"));
table = new Table{
{"type", "发送卡型号"},
{"name", "名称"},
{"link", "连接方式"},
{"vcsNum", "接收卡数量"},
{"netPorts", "网口统计P1~Pn"},
{"info", "其他信息", QHeaderView::Stretch},
};
table->setDefs();
vBox->addWidget(table);
auto hBox = new HBox(vBox);
hBox->addLabel("V" __VER__" - " __DATE__);
hBox->addStretch();
auto btnNetSelect = new QPushButton("通讯选择");
connect(btnNetSelect, &QPushButton::clicked, this, [this] {
auto name = getNetDev(this, net_name, false);
if(name.isEmpty()) return;
//PCAP_OPENFLAG_DATATX_UDP2它定义了数据传输假如是远程抓包是否用UDP协议来处理。
//PCAP_OPENFLAG_NOCAPTURE_RPCAP4它定义了远程探测器是否捕获它自己产生的数据包。
char errbuf[PCAP_ERRBUF_SIZE]{0};
auto pcapR = pcap_open_live(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS|4|8|16, 50, errbuf);
if(pcapR == 0) {
QMessageBox::critical(this, "Error", QString(tr("打开网卡失败"))+errbuf);
return;
}
auto pcapS = pcap_open_live(name.data(), 65536, 0, 50, errbuf);
if(pcapS == 0) {
QMessageBox::critical(this, "Error", QString(tr("打开网卡失败"))+errbuf);
return;
}
if(reThd) reThd->status = 2;
if(pcapSend) pcap_close(pcapSend);
pcapSend = pcapS;
reThd = new PcapReThread(pcapR);
reThd->start();
QSettings().setValue("net_name", net_name = name);
});
hBox->addWidget(btnNetSelect);
auto btnRefresh = new QPushButton(tr("刷新"));
connect(btnRefresh, &QPushButton::clicked, this, &MainWin::getCard);
hBox->addWidget(btnRefresh);
show();
QSettings config;
gFileHome = config.value("FileHome").toString();
if(gFileHome.isEmpty() || ! QFileInfo(gFileHome).isDir()) gFileHome = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
auto name = config.value("net_name").toByteArray();
name = getNetDev(this, name, true);
if(! name.isEmpty()) {
char errbuf[PCAP_ERRBUF_SIZE]{0};
auto pcapRe = pcap_open_live(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS|4|8|16, 50, errbuf);
if(pcapRe == 0) QMessageBox::critical(this, "Error", QString(tr("打开网卡失败"))+errbuf);
else {
pcapSend = pcap_open_live(name.data(), 65536, 0, 50, errbuf);
if(pcapSend == 0) QMessageBox::critical(this, "Error", QString(tr("打开网卡失败"))+errbuf);
else {
config.setValue("net_name", net_name = name);
reThd = new PcapReThread(pcapRe);
reThd->start();
}
}
}
connect(&mUdpSocket, &QUdpSocket::readyRead, this, [this] {
while(mUdpSocket.hasPendingDatagrams()) {
auto gram = mUdpSocket.receiveDatagram();
auto data = gram.data();
if(data.isEmpty()) continue;
auto senderAddress = gram.senderAddress();
bool ok = true;
if(senderAddress.protocol()==QUdpSocket::IPv6Protocol) senderAddress.setAddress(senderAddress.toIPv4Address(&ok));
auto addr = ok ? senderAddress.toString() : "";
int cnt = table->rowCount();
if(data.startsWith("{\"")) {
QString error;
auto json = JFrom(gram.data(), &error);
if(! error.isEmpty()) {
qDebug()<<"Json Error: "+error;
continue;
}
auto cardId = json["cardId"].toStr();
for(int rr=0; rr<cnt; rr++) if(table->text(rr, "name")==cardId) {
table->setText(rr, "link", addr);
goto end;
}
table->setRowCount(cnt+1);
//table->setText(cnt, "type", tr("虚拟设备"));
table->setText(cnt, "name", cardId);
table->setText(cnt, "link", addr);
//table->setText(cnt, "vcsNum", QString::number(*(quint32_be*)(data.data()+headMap.body)));
//table->setText(cnt, "netPorts", "P:"+QString::number(virtualVCM));
//table->setText(cnt, "info", "备注:可直接配屏,无需发送卡");
} else {
auto bytes = gram.data();
auto packet = (UDPPacket *)bytes.data();
for(int rr=0; rr<cnt; rr++) if(table->text(rr, "name")==packet->serialCode) {
table->setText(rr, "link", addr);
goto end;
}
table->setRowCount(cnt+1);
table->setText(cnt, "name", packet->serialCode);
table->setText(cnt, "link", addr);
}
end:;
}
});
getCard();
}
MainWin::~MainWin() {
mUdpSocket.close();
QSettings config;
config.setValue("FileHome", gFileHome);
}
void MainWin::getCard() {
table->setRowCount(0);
auto msg = QByteArray::fromHex("5555 01 0D 0008 FFFFFFFF 0000ABCD A0000000 0000 38CB847E 00000000 0000ABCD CD040446");
auto res = sendMsg(msg, 0x1E0, 10000, [=](int, const QByteArray data) {
if(*(quint32_be*)(data.data()+headMap.ptr) != 0xA0000000) return;
auto rr = 0;
table->setRowCount(rr+1);
int virtualVCM = *(quint16_be*)(data.data()+headMap.srcAddr);
table->setText(rr, "type", tr("虚拟设备"));
table->setText(rr, "name", tr("网口:")+QString::number(virtualVCM));
table->setText(rr, "link", "千兆网直连");
table->setText(rr, "vcsNum", QString::number(*(quint32_be*)(data.data()+headMap.body)));
table->setText(rr, "netPorts", "P:"+QString::number(virtualVCM));
table->setText(rr, "info", "备注:可直接配屏,无需发送卡");
});
if(res) {
QString err = pcap_geterr(pcapSend);
if(! err.endsWith("(2150891551)")) QMessageBox::critical(this, "Error", QString(tr("发送失败: "))+QString::fromLocal8Bit(pcap_geterr(pcapSend)));
}
auto data = JToBytes(JObj{{"action", "getInfo"}});
uchar ccc[]{0x7E, 0x7E, 0x7E, 0x90, 0x42, 0x72, 0x6F, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x21,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x9F};
if(mUdpSocket.writeDatagram(data, QHostAddress("255.255.255.255"), 22222) != data.length()) qDebug() << "getInfo write to 255.255.255.255 failed";
if(mUdpSocket.writeDatagram((char *)ccc, sizeof(ccc), QHostAddress("255.255.255.255"), 31296) != sizeof(ccc)) qDebug() << "getInfo write to 255.255.255.255 failed";
auto networkinterfaces = QNetworkInterface::allInterfaces();
foreach(auto face, networkinterfaces) {
auto flags = face.flags();
bool can = (flags & QNetworkInterface::IsRunning) && (flags & QNetworkInterface::CanBroadcast) && ! (flags & QNetworkInterface::IsLoopBack);
if(! can) continue;
auto addrEntries = face.addressEntries();
foreach(QNetworkAddressEntry addrEntry, addrEntries) {
auto ip = addrEntry.ip();
if(ip.protocol()!=QAbstractSocket::IPv4Protocol) continue;
auto broadcast = addrEntry.broadcast();
if(mUdpSocket.writeDatagram(data, broadcast, 22222) != data.length()) qDebug() << "getInfo write failed." << ip.toString() << "->" << broadcast.toString();
}
}
}