#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 #include #include #include #include #include #include #include #include #include "globalfunc.h" #include "basewin.h" #include #include #include #include #include #include #include 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_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。 //PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。 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; rrtopLevelItemCount(); 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; rrtopLevelItemCount(); 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; itopLevelItemCount(); 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(); } } }