From d3a7cd2207bed92ec81b18410c860a987089b611 Mon Sep 17 00:00:00 2001 From: gangphon Date: Fri, 24 Mar 2023 18:41:48 +0800 Subject: [PATCH] =?UTF-8?q?ledset=E5=A2=9E=E5=8A=A0=E6=97=A7=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ledset/globalfunc.cpp | 6 +- ledset/globalfunc.h | 2 +- ledset/mainwin.cpp | 6 +- ledset/pcaprethread.cpp | 2 +- ledset/videowin.cpp | 187 +++++++++++++++++++++++++++++----------- ledset/videowin.h | 13 ++- 6 files changed, 156 insertions(+), 60 deletions(-) diff --git a/ledset/globalfunc.cpp b/ledset/globalfunc.cpp index 974b8bb..868d90d 100644 --- a/ledset/globalfunc.cpp +++ b/ledset/globalfunc.cpp @@ -9,7 +9,7 @@ pcap_t *pcapSend{0}; PcapReThread *reThd{0}; -QByteArray getNetDev(QWidget *parent, QByteArray def) { +QByteArray getNetDev(QWidget *parent, QByteArray def, bool justReturnIfHave) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *devs; if(pcap_findalldevs(&devs, errbuf) == -1) { @@ -32,7 +32,7 @@ QByteArray getNetDev(QWidget *parent, QByteArray def) { for(a=dev->addresses; a; a=a->next) { auto sa_family = a->addr->sa_family; if(sa_family==AF_INET) { - if(! def.isEmpty() && dev->name == def) { + if(justReturnIfHave && ! def.isEmpty() && dev->name == def) { pcap_freealldevs(devs); table->deleteLater(); return def; @@ -84,7 +84,7 @@ QByteArray getNetDev(QWidget *parent, QByteArray def) { table->setDefs(); table->setSelectionMode(QAbstractItemView::SingleSelection); table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - table->selectRow(0); + if(! def.isEmpty()) for(int r=0; rrowCount(); r++) if(table->item(r, "name")->text()==def) table->selectRow(r); QByteArray name; dlg->connect(table, &Table::cellDoubleClicked, dlg, [dlg, table, &name](int row) { name = table->item(row, "name")->text().toLocal8Bit(); diff --git a/ledset/globalfunc.h b/ledset/globalfunc.h index fe0efd1..61dbd44 100644 --- a/ledset/globalfunc.h +++ b/ledset/globalfunc.h @@ -10,7 +10,7 @@ extern pcap_t *pcapSend; extern PcapReThread *reThd; -QByteArray getNetDev(QWidget *parent, QByteArray); +QByteArray getNetDev(QWidget *parent, QByteArray, bool); int sendMsg(QByteArray, const Resp &resp); int sendMsgNet(QByteArray, const Resp &resp); diff --git a/ledset/mainwin.cpp b/ledset/mainwin.cpp index 72ae1ab..742aba9 100644 --- a/ledset/mainwin.cpp +++ b/ledset/mainwin.cpp @@ -131,7 +131,7 @@ MainWin::MainWin() { auto btnNetSelect = new QPushButton("通讯选择"); btnNetSelect->setMinimumWidth(80); connect(btnNetSelect, &QPushButton::clicked, this, [this] { - auto name = getNetDev(this, ""); + auto name = getNetDev(this, net_name, false); if(name.isEmpty()) return; //PCAP_OPENFLAG_DATATX_UDP:2,它定义了数据传输(假如是远程抓包)是否用UDP协议来处理。 //PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定义了远程探测器是否捕获它自己产生的数据包。 @@ -168,7 +168,7 @@ MainWin::MainWin() { QSettings config(QApplication::applicationDirPath()+"/ledset.config", QSettings::IniFormat); config.beginGroup("GLOBAL");//保存数据 auto name = config.value("net_name").toByteArray(); - name = getNetDev(this, name); + 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); @@ -190,7 +190,7 @@ MainWin::MainWin() { void MainWin::getCard() { auto msg = QByteArray::fromHex("55 55 01 0D 00 08 FF FF FF FF 00 00 AB CD A0 00 00 00 00 00 38 CB 84 7E 00 00 00 00 00 00 AB CD CD 04 04 46"); - auto res = sendMsg(msg, {0x10d, [=](const QByteArray data) { + auto res = sendMsg(msg, {0x1E0, [=](const QByteArray data) { if(((u_char)data[10])==0xA0 && data[11]==0 && data[12]==0 && data[13]==0) { auto rr = 0; table->setRowCount(rr+1); diff --git a/ledset/pcaprethread.cpp b/ledset/pcaprethread.cpp index 2f1976d..df9d1c3 100644 --- a/ledset/pcaprethread.cpp +++ b/ledset/pcaprethread.cpp @@ -21,7 +21,7 @@ void PcapReThread::run() { std::lock_guard lock(mtx); for(int i=0; icaplen)); + emit onMsg(resp, QByteArray((char*)(data+4), header->caplen-4)); break; } } diff --git a/ledset/videowin.cpp b/ledset/videowin.cpp index 11ab6c1..802b680 100644 --- a/ledset/videowin.cpp +++ b/ledset/videowin.cpp @@ -61,13 +61,22 @@ VideoWin::VideoWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWi fdMsecCapScr->setRange(1, 1000); fdMsecCapScr->setValue(17); hBox->addWidget(fdMsecCapScr); - hBox->addSpacing(20); + hBox->addSpacing(10); fdNoReview = new QCheckBox("关闭显示"); fdNoReview->setChecked(noReview); hBox->addWidget(fdNoReview); - hBox->addSpacing(20); + hBox->addSpacing(10); + auto fdUseOldProtocol = new QCheckBox("用旧协议"); + connect(fdUseOldProtocol, &QRadioButton::toggled, [=](bool checked) { + useOldProto = checked; + if(thdSend) thdSend->useOldProto = checked; + if(thdRece) thdRece->useOldProto = checked; + }); + hBox->addWidget(fdUseOldProtocol); + + hBox->addSpacing(10); hBox->addWidget(new QLabel("接收线程优先级")); fdYxj = new QSpinBox; @@ -135,7 +144,30 @@ VideoWin::VideoWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWi connect(thdRece, &QThread::finished, this, [this] { thdRece = 0; }); - connect(thdRece, &VideoRecThread::onMsg, fdCanvas, [this, fdCanvas](QImage img, int lostTimes, int lostPkts) { + connect(thdRece, &VideoRecThread::onMsg, fdCanvas, [this, fdCanvas](const QByteArray chars) { + if(noReview) return; + auto data = (uchar *)chars.data(); + if(data[14]==0x12) { + imgLines.append(chars); + int i = (data[18]<<8 | data[19]) + 1; + if(i > imgHeight) imgHeight = i; + i = (data[20]<<8 | data[21]) + (data[22]<<8 | data[23]); + if(i > imgWidth) imgWidth = i; + } else if(data[14]==0x11 && imgWidth && imgHeight) { + //qDebug()<<"imgWidth"<img = img; + fdCanvas->update(); + } + }); + connect(thdRece, &VideoRecThread::onImg, fdCanvas, [this, fdCanvas](QImage img, int lostTimes, int lostPkts) { if(noReview) return; fdCanvas->img = img; fdCanvas->update(); @@ -147,16 +179,16 @@ VideoWin::VideoWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWi }); thdRece->start(QThread::Priority(fdYxj->value()));//HighestPriority //InheritPriority //TimeCriticalPriority - sendThd = new VideoSendThread(pcapSend); - connect(sendThd, &QThread::finished, this, [this] { + thdSend = new VideoSendThread(pcapSend); + connect(thdSend, &QThread::finished, this, [this] { fdEnd->setChecked(true); - sendThd = 0; + thdSend = 0; }); - connect(sendThd, &VideoSendThread::onErr, this, [this](QString err) { + connect(thdSend, &VideoSendThread::onErr, this, [this](QString err) { fdEnd->setChecked(true); QMessageBox::critical(this, "Error", err); }); - sendThd->start(); + thdSend->start(); } void VideoWin::timerEvent(QTimerEvent *event) { @@ -170,14 +202,14 @@ void VideoWin::timerEvent(QTimerEvent *event) { auto img = pixmap.toImage(); img.convertTo(QImage::Format_RGB888); { - std::lock_guard lock(sendThd->mtx); - if(sendThd->imgs.size()>2) return; - sendThd->imgs.append(img); + std::lock_guard lock(thdSend->mtx); + if(thdSend->imgs.size()>2) return; + thdSend->imgs.append(img); } auto now_epoch = chrono::duration_cast(chrono::steady_clock::now().time_since_epoch()).count(); int dur = now_epoch - last_epoch; last_epoch = now_epoch; - fdInfo->setText(info = "帧间隔: "+QString::number(dur)+" 帧缓存: "+QString::number(sendThd ? sendThd->imgs.size() : 0)); + fdInfo->setText(info = "帧间隔: "+QString::number(dur)+" 帧缓存: "+QString::number(thdSend ? thdSend->imgs.size() : 0)); } } @@ -197,21 +229,73 @@ void VideoSendThread::run() { QThread::msleep(15); continue; } - QByteArray bytes; - bytes.append("\x55\x55\x9a\x3d"); //前导, 版本号, 服务类型 - bytes.append("\0\x4", 2); //数据长度 - bytes.append(4, '\xff'); //目的地址 - bytes.append(4, 0); //源地址 - bytes.append("\x35\0\xc\xbb", 4); //内存指针 - bytes.append(2, 0); //应答填充项 - auto crc32 = crc32_calc((uint8_t*)bytes.data()+2, bytes.length()-2); - bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); - bytes.append(img.width()>>8).append(img.width()).append(img.height()>>8).append(img.height()); - crc32 = crc32_calc((uint8_t*)bytes.data()+bytes.length()-4, 4); - bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); - //发送帧开始指令包 auto queue = pcap_sendqueue_alloc(img.width()*img.height()*4); - { + if(useOldProto) { + QByteArray bytes; + bytes.append("\x00\x11\x22\x33\x44\x55", 6); //目的地址 + bytes.append("\x00\x11\x22\x33\x44\x55", 6); //源地址 + bytes.append("\x10\x5A"); //协议标识 + bytes.append("\x11\0\0\0", 4); //包类型标识 保留 网口标识 接收卡标识 + bytes.append(frameIdx>>8).append(frameIdx);//帧循环计数 + frameIdx++; + bytes.append(2, 0); //帧保持计数 + bytes.append("\x0\xff\x0\x0\x0", 5); //自动亮度模式 整屏亮度 实时参数模式 测试模式 保留 + auto crc32 = crc32_calc((uint8_t*)bytes.data(), bytes.length()); + bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); + //发送帧开始指令包 + struct pcap_pkthdr pktheader; + pktheader.len = pktheader.caplen = bytes.size(); + if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) { + onErr(QString("添加开始失败: ")+pcap_geterr(pcap)); + goto end; + } + auto lineLen = img.width() * 3; + int once; + if(lineLen > MAX_ONCE) { + int cnt = (lineLen + MAX_ONCE - 1) / MAX_ONCE; + once = (lineLen + cnt - 1) / cnt; + } else once = lineLen; + auto bytesPerLine = img.bytesPerLine(); + auto bits = img.constBits(); + //按行发送图像数据包 + for(int i=0; i once) dataLen = once; + bytes.clear(); + bytes.append("\x00\x11\x22\x33\x44\x55", 6); //目的地址 + bytes.append("\x00\x11\x22\x33\x44\x55", 6); //源地址 + bytes.append("\x10\x5A"); //协议标识 + bytes.append("\x12\0\0\0", 4); //包类型标识 保留 网口标识 接收卡标识 + bytes.append(i>>8).append(i).append(j/3>>8).append(j/3); //行列起始位置 + bytes.append(dataLen/3>>8).append(dataLen/3); //包像素计数 + bytes.append((const char*)bits + i * bytesPerLine + j, dataLen); //图像数据 + crc32 = crc32_calc((uint8_t*)bytes.data(), bytes.length()); + bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); + pktheader.len = pktheader.caplen = bytes.size(); + if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) { + onErr(QString("添加数据失败: ")+pcap_geterr(pcap)); + goto end; + } + } + u_int res; + if((res = pcap_sendqueue_transmit(pcap, queue, 0)) < queue->len) { + onErr(QString::asprintf("发送包出错: %s. 仅发了 %d / %d bytes", pcap_geterr(pcap), res, queue->len)); + goto end; + } + } else { + QByteArray bytes; + bytes.append("\x55\x55\x9a\x3d"); //前导, 版本号, 服务类型 + bytes.append("\0\x4", 2); //数据长度 + bytes.append(4, '\xff'); //目的地址 + bytes.append(4, 0); //源地址 + bytes.append("\x35\0\xc\xbb", 4); //内存指针 + bytes.append(2, 0); //应答填充项 + auto crc32 = crc32_calc((uint8_t*)bytes.data()+2, bytes.length()-2); + bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); + bytes.append(img.width()>>8).append(img.width()).append(img.height()>>8).append(img.height()); + crc32 = crc32_calc((uint8_t*)bytes.data()+bytes.length()-4, 4); + bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32); + //发送帧开始指令包 struct pcap_pkthdr pktheader; pktheader.len = pktheader.caplen = bytes.size(); if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) { @@ -296,29 +380,34 @@ void VideoRecThread::run() { if(status==2) return; if(status==1 || res == 0 || noReview) continue; //超时 if(header->caplen<24) continue; - if(data[0]!=0x55 || data[1]!=0x55) continue; - if(data[2]==0x9a && data[3]==0x3d) { - if(data[17]==0xBB) { - img = QImage(((int)data[24] << 8) + data[25], ((int)data[26] << 8) + data[27], QImage::Format_RGB888); - lastIdx = -1; - lostTimes = 0; - lostPkts = 0; - } else if(data[17]==0xCC) emit onMsg(img, lostTimes, lostPkts); - continue; - } - if(data[2]!=0x1 || data[3]!=0x33) continue; - int len = ((int)data[4] << 8) + data[5]; - int row = ((int)data[14] << 8) + data[15]; - int col = ((int)data[16] << 8) + data[17]; - quint32 idx = ((quint32)data[24] << 24) + ((quint32)data[25] << 16) + ((quint32)data[26] << 8) + data[27]; - //auto epoch = chrono::duration_cast(chrono::steady_clock::now().time_since_epoch()).count(); - memcpy(img.bits()+row*img.bytesPerLine()+col, &data[28], len-4); - int diff = idx - lastIdx - 1; - lastIdx = idx; - if(diff > 0) { - //qDebug()<<"丢包"<caplen)); + } else { + if(data[0]!=0x55 || data[1]!=0x55) continue; + if(data[2]==0x9a && data[3]==0x3d) { + if(data[17]==0xBB) { + img = QImage(((int)data[24] << 8) + data[25], ((int)data[26] << 8) + data[27], QImage::Format_RGB888); + lastIdx = -1; + lostTimes = 0; + lostPkts = 0; + } else if(data[17]==0xCC) emit onImg(img, lostTimes, lostPkts); + continue; + } + if(data[2]!=0x1 || data[3]!=0x33) continue; + int len = ((int)data[4] << 8) + data[5]; + int row = ((int)data[14] << 8) + data[15]; + int col = ((int)data[16] << 8) + data[17]; + quint32 idx = ((quint32)data[24] << 24) + ((quint32)data[25] << 16) + ((quint32)data[26] << 8) + data[27]; + //auto epoch = chrono::duration_cast(chrono::steady_clock::now().time_since_epoch()).count(); + memcpy(img.bits()+row*img.bytesPerLine()+col, &data[28], len-4); + int diff = idx - lastIdx - 1; + lastIdx = idx; + if(diff > 0) { + //qDebug()<<"丢包"< status{0}; QList imgs; std::mutex mtx; + quint16 frameIdx{0}; + bool useOldProto{false}; protected: void run(); signals: @@ -38,10 +40,12 @@ public: pcap *pcap; std::atomic status{0}; bool noReview{false}; + bool useOldProto{false}; protected: void run(); signals: - void onMsg(QImage, int, int); + void onMsg(const QByteArray data); + void onImg(QImage, int, int); void onErr(char *); }; @@ -59,16 +63,19 @@ public: ~VideoWin() { if(thdRece) thdRece->status = 2; - if(sendThd) sendThd->status = 2; + if(thdSend) thdSend->status = 2; if(timerId) killTimer(timerId); } VideoRecThread *thdRece{0}; - VideoSendThread *sendThd{0}; + VideoSendThread *thdSend{0}; + QList imgLines; + int imgWidth{0}, imgHeight{0}; QScreen *screen; int timerId{0}; QSpinBox *fdWidth, *fdHeight, *fdMsecCapScr,*fdYxj; QCheckBox *fdNoReview; bool noReview{false}; + bool useOldProto{false}; QRadioButton *fdEnd; QLabel *fdInfo, *fdLostTimes, *fdLostPkts; QString info;