qt/ledset/mainwin.cpp
2023-09-05 10:02:20 +08:00

322 lines
14 KiB
C++
Raw Permalink 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 "pcap.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, [=] {
auto item = table->selectedItem();
if(item) (new ExpertWin(this, (enum_rcvCardType) item->data("type").toInt()))->show();
else if(QMessageBox::question(this, "Info", tr("未选择卡, 是否继续?"))==QMessageBox::Yes) (new ExpertWin(this, NoCard))->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 TreeWidget{
{"_num_", "", 20},
{"type", "控制系统类型"},
{"name", "名称"},
{"link", "连接方式"},
{"vcsNum", "接收卡数量"},
{"netPorts", "网口统计P1~Pn"},
{"info", "其他信息", QHeaderView::Stretch},
};
table->setDefs();
table->setSortingEnabled(true);
table->sortItems("name");
table->setStyleSheet("TreeWidget::item{height: 26px;}");
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() : "";
if(data.startsWith("{\"")) {
QString error;
auto json = JFrom(gram.data(), &error);
if(! error.isEmpty()) {
qDebug()<<"Json Error: "+error;
continue;
}
auto cardId = json["cardId"].toStr();
TreeWidgetItem *item;
for(int rr=0; rr<table->topLevelItemCount(); rr++) if((item = table->item(rr))->text("name")==cardId) {
item->setText("link", addr);
goto end;
}
item = new TreeWidgetItem(table);
item->setText("type", tr("异步卡"), enum_xixun_async);
item->setText("name", cardId);
item->setText("link", addr);
} else {
auto bytes = gram.data();
auto packet = (UDPPacket *)bytes.data();
TreeWidgetItem *item;
for(int rr=0; rr<table->topLevelItemCount(); rr++) if((item = table->item(rr))->text("name")==packet->serialCode) {
item->setText("link", addr);
goto end;
}
item = new TreeWidgetItem(table);
item->setText("type", tr("异步卡"), enum_xixun_async);
item->setText("name", packet->serialCode);
item->setText("link", addr);
}
end:;
}
});
reThd->addMultiCallback(0x105B14, [=](int, const QByteArray data) {
unsigned short ver = *(quint16_be *)(data.data()+headMap_zrf.protcolFlag);
unsigned char pkgType = *(quint8 *)(data.data()+headMap_zrf.pkgType);
if(ver!=0x105B || pkgType != 0x14) return;
auto strDeviceName = QString(QLatin1String(data.data()+headMap_zrf.paramStart+st_zrf_rb_param.deviceName, 9));
TreeWidgetItem *item;
for(int i=0; i<table->topLevelItemCount(); i++) if((item = table->item(i))->text("name")==strDeviceName) goto end;
item = new TreeWidgetItem(table);
end:
int virtualVCM = *(quint8*)(data.data()+headMap_zrf.netPort) + 1;
int rcvIdex = *(quint8*)(data.data()+headMap_zrf.rcvIndex) + 1;
if(rcvIdex > maxNetPort_zrf) maxNetPort_zrf = rcvIdex;
item->setText("type", tr("PC虚拟卡V1.0"), enum_zrf);
item->setText("name", strDeviceName);
item->setText("link", "千兆网直连");
item->setText("vcsNum", QString::number(maxNetPort_zrf));
item->setText("netPorts", "P: "+QString::number(virtualVCM));
item->setText("info", "版本: "+QLatin1String(data.data()+headMap_zrf.paramStart+st_zrf_rb_param.deviceVer, 8)+" [备注:可直接配屏,无需发送卡]");
if(table->selectedItem()==0) item->setSelected(true);
});
getCard();
}
MainWin::~MainWin() {
mUdpSocket.close();
QSettings config;
config.setValue("FileHome", gFileHome);
}
void MainWin::getCard() {
table->clear();
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 item = new TreeWidgetItem(table);
int virtualVCM = *(quint16_be*)(data.data()+headMap.srcAddr);
//modified by alahover -s 20230822
auto ver = *(byte*)(data.data()+headMap.ver);
if(ver==0x01) item->setText("type", tr("PC虚拟卡V0.0"), enum_xixun_sync);
else if(ver==0x58) item->setText("type", tr("PC虚拟卡V1.0"), enum_zrf);
item->setText("name", QString::number(virtualVCM)+" (网口)");
item->setText("link", "千兆网直连");
item->setText("vcsNum", QString::number(*(quint32_be*)(data.data()+headMap.body)));
item->setText("netPorts", "P: "+QString::number(virtualVCM));
item->setText("info", "备注: 可直接配屏,无需发送卡");
if(table->selectedItem()==0) item->setSelected(true);
});
if(res) {
QString err = pcap_geterr(pcapSend);
if(! err.endsWith("(2150891551)")) QMessageBox::critical(this, "Error", QString(tr("发送失败: "))+QString::fromLocal8Bit(pcap_geterr(pcapSend)));
}
//modified by alahover -s 20230822
//查询105B协议类型ZRF版本fpga的接收卡, 0x105B1400 表示是zrf协议类型并且是回读数据包
msg = QByteArray::fromHex("5555 001122334455 001122334455 105A 13 00 00 00 00 e0 ff ff 00 f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00");
res = pcap_sendpacket(pcapSend, (const u_char *)msg.data(), msg.size());
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();
}
}
}