update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / ui / qt / lte_mac_statistics_dialog.cpp
blob7485c226cc3bdd5a2fcab063028ba4a9d1c7e69c
1 /* lte_mac_statistics_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include "lte_mac_statistics_dialog.h"
12 #include <epan/packet.h>
13 #include <epan/strutil.h>
14 #include <epan/tap.h>
16 #include <epan/dissectors/packet-mac-lte.h>
18 #include <QFormLayout>
19 #include <QTreeWidgetItem>
21 #include <ui/qt/models/percent_bar_delegate.h>
22 #include "main_application.h"
24 // TODO: have never tested in a live capture.
26 // Whole-UE headings.
27 enum {
28 col_rat_,
29 col_rnti_,
30 col_type_,
31 col_ueid_,
32 // UL-specific
33 col_ul_frames_,
34 col_ul_bytes_,
35 col_ul_mb_s_,
36 col_ul_padding_percent_,
37 /* col_ul_crc_failed_, */
38 col_ul_retx_,
39 // DL-specific
40 col_dl_frames_,
41 col_dl_bytes_,
42 col_dl_mb_s_,
43 col_dl_padding_percent_,
44 col_dl_crc_failed_,
45 col_dl_retx_
49 // Type of tree item, so can set column headings properly.
50 enum {
51 mac_whole_ue_row_type_ = 1000,
52 mac_ulsch_packet_count_row_type,
53 mac_ulsch_byte_count_row_type,
54 mac_dlsch_packet_count_row_type,
55 mac_dlsch_byte_count_row_type
58 // Calculate and return a bandwidth figure, in Mbs
59 static double calculate_bw(const nstime_t *start_time, const nstime_t *stop_time,
60 uint32_t bytes)
62 // Can only calculate bandwidth if have time delta
63 if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
64 double elapsed_ms = (((double)stop_time->secs - start_time->secs) * 1000) +
65 (((double)stop_time->nsecs - start_time->nsecs) / 1000000);
67 // Only really meaningful if have a few frames spread over time...
68 // For now at least avoid dividing by something very close to 0.0
69 if (elapsed_ms < 2.0) {
70 return 0.0f;
73 // N.B. very small values will display as scientific notation, but rather that than show 0
74 // when there is some traffic..
75 return ((bytes * 8) / elapsed_ms) / 1000;
77 else {
78 return 0.0f;
83 // Channels (by LCID) data node. Used for UL/DL frames/bytes.
84 class MacULDLTreeWidgetItem : public QTreeWidgetItem
86 public:
87 MacULDLTreeWidgetItem(QTreeWidgetItem *parent, unsigned ueid, unsigned rnti, unsigned rat, int row_type) :
88 QTreeWidgetItem (parent, row_type),
89 ueid_(ueid),
90 rnti_(rnti),
91 rat_(rat)
93 // Init values held for all lcids to 0.
94 for (int n=0; n < MAC_3GPP_DATA_LCID_COUNT_MAX; n++) {
95 lcids[n] = 0;
98 // Set first column to show what counts in this row mean.
99 switch (row_type) {
100 case mac_ulsch_packet_count_row_type:
101 setText(col_rnti_, "UL Packets");
102 break;
103 case mac_ulsch_byte_count_row_type:
104 setText(col_rnti_, "UL Bytes");
105 break;
106 case mac_dlsch_packet_count_row_type:
107 setText(col_rnti_, "DL Packets");
108 break;
109 case mac_dlsch_byte_count_row_type:
110 setText(col_rnti_, "DL Bytes");
111 break;
112 default:
113 // Should never get here...
114 break;
118 bool operator< (const QTreeWidgetItem &other) const
120 // We want rows with a UE to appear in the order they appear in the row_type enum.
121 return type() < other.type();
124 void draw()
126 // Show current value of counter for each LCID.
127 // N.B. fields that are set as % using percent_bar_delegate.h
128 // for UE headings don't display here...
129 for (int n=0; n < MAC_3GPP_DATA_LCID_COUNT_MAX; n++) {
130 setText(col_type_+n, QString::number((uint)lcids[n]));
134 // Increase value held for lcid by given value.
135 void updateLCID(uint8_t lcid, unsigned value)
137 lcids[lcid] += value;
140 // Generate expression for this UE and direction, also filter for SRs and RACH if indicated.
141 const QString filterExpression(bool showSR, bool showRACH)
143 int direction = (type() == mac_dlsch_packet_count_row_type) ||
144 (type() == mac_dlsch_byte_count_row_type);
146 QString filter_expr;
148 if (showSR) {
149 // Only applies to LTE.
150 if (rat_ == MAC_RAT_LTE) {
151 filter_expr = QStringLiteral("(mac-lte.sr-req and mac-lte.ueid == %1) or (").arg(ueid_);
155 if (showRACH) {
156 if (rat_ == MAC_RAT_LTE) {
157 filter_expr += QStringLiteral("(mac-lte.rar or (mac-lte.preamble-sent and mac-lte.ueid == %1)) or (").arg(ueid_);
159 else {
160 filter_expr += QStringLiteral("mac-nr.rar or ");
164 // Main expression matching this UE and direction
165 if (rat_ == MAC_RAT_LTE) {
166 filter_expr += QStringLiteral("mac-lte.ueid==%1 && mac-lte.rnti==%2 && mac-lte.direction==%3").
167 arg(ueid_).arg(rnti_).arg(direction);
169 else {
170 filter_expr += QStringLiteral("mac-nr.ueid==%1 && mac-nr.rnti==%2 && mac-nr.direction==%3").
171 arg(ueid_).arg(rnti_).arg(direction);
174 // Close () if open because of SR
175 if (showSR) {
176 if (rat_ == MAC_RAT_LTE) {
177 filter_expr += QStringLiteral(")");
180 // Close () if open because of RACH
181 if (showRACH) {
182 if (rat_ == MAC_RAT_LTE) {
183 filter_expr += QStringLiteral(")");
187 return filter_expr;
190 // Not showing anything for individual channels. Headings are different than from UEs, and
191 // trying to show both would be too confusing.
192 QList<QVariant> rowData() const
194 return QList<QVariant>();
197 private:
198 unsigned ueid_;
199 unsigned rnti_;
200 unsigned rat_;
201 int lcids[MAC_3GPP_DATA_LCID_COUNT_MAX]; /* For LTE, mapped to 0 to 10 and 32 to 38 */
206 // Whole UE tree item
207 class MacUETreeWidgetItem : public QTreeWidgetItem
209 public:
210 MacUETreeWidgetItem(QTreeWidget *parent, const mac_3gpp_tap_info *mlt_info) :
211 QTreeWidgetItem (parent, mac_whole_ue_row_type_),
212 rnti_(0),
213 type_(0),
214 ueid_(0),
215 ul_frames_(0),
216 ul_bytes_(0),
217 ul_raw_bytes_(0),
218 ul_padding_bytes_(0),
219 ul_retx_(0),
220 dl_frames_(0),
221 dl_bytes_(0),
222 dl_raw_bytes_(0),
223 dl_padding_bytes_(0),
224 dl_crc_failed_(0),
225 dl_retx_(0)
227 // Set fixed fields.
228 rnti_ = mlt_info->rnti;
229 type_ = mlt_info->rntiType;
230 ueid_ = mlt_info->ueid;
231 rat_ = mlt_info->rat;
232 setText(col_rat_, (mlt_info->rat == MAC_RAT_LTE) ?
233 QObject::tr("LTE") :
234 QObject::tr("NR"));
235 setText(col_rnti_, QString::number(rnti_));
236 setText(col_type_, type_ == C_RNTI ? QObject::tr("C-RNTI") : QObject::tr("SPS-RNTI"));
237 setText(col_ueid_, QString::number(ueid_));
239 // Add UL/DL packet/byte count subitems.
240 addDetails();
243 // Does this tap-info match this existing UE item?
244 bool isMatch(const mac_3gpp_tap_info *mlt_info) {
245 return ((rnti_ == mlt_info->rnti) &&
246 (type_ == mlt_info->rntiType) &&
247 (ueid_ == mlt_info->ueid) &&
248 (rat_ == mlt_info->rat));
251 // Update this UE according to the tap info
252 void update(const mac_3gpp_tap_info *mlt_info) {
254 // Uplink.
255 if (mlt_info->direction == DIRECTION_UPLINK) {
256 if (mlt_info->isPHYRetx) {
257 ul_retx_++;
258 return;
261 if (mlt_info->crcStatusValid && (mlt_info->crcStatus != crc_success)) {
262 // TODO: there is not a column for this...
263 //ul_crc_errors_++;
264 return;
267 // Update time range
268 if (ul_frames_ == 0) {
269 ul_time_start_ = mlt_info->mac_time;
271 ul_time_stop_ = mlt_info->mac_time;
273 ul_frames_++;
275 // These values needed for padding % calculation.
276 ul_raw_bytes_ += mlt_info->raw_length;
277 ul_padding_bytes_ += mlt_info->padding_bytes;
279 // N.B. Not going to support predefined data in Qt version..
280 if (!mlt_info->isPredefinedData) {
281 for (int n=0; n < MAC_3GPP_DATA_LCID_COUNT_MAX; n++) {
282 // Update UL child items
283 ul_frames_item_->updateLCID(n, mlt_info->sdus_for_lcid[n]);
284 ul_bytes_item_->updateLCID(n, mlt_info->bytes_for_lcid[n]);
286 ul_bytes_ += mlt_info->bytes_for_lcid[n];
291 // Downlink
292 else {
293 if (mlt_info->isPHYRetx) {
294 dl_retx_++;
295 return;
298 if (mlt_info->crcStatusValid && (mlt_info->crcStatus != crc_success)) {
299 switch (mlt_info->crcStatus) {
300 case crc_fail:
301 dl_crc_failed_++;
302 break;
304 default:
305 // Not a reason we currently care about.
306 break;
308 return;
311 // Update time range
312 if (dl_frames_ == 0) {
313 dl_time_start_ = mlt_info->mac_time;
315 dl_time_stop_ = mlt_info->mac_time;
317 dl_frames_++;
319 // These values needed for padding % calculation.
320 dl_raw_bytes_ += mlt_info->raw_length;
321 dl_padding_bytes_ += mlt_info->padding_bytes;
323 // N.B. Not going to support predefined data in Qt version..
324 if (!mlt_info->isPredefinedData) {
325 for (int n=0; n < MAC_3GPP_DATA_LCID_COUNT_MAX; n++) {
326 // Update DL child items
327 dl_frames_item_->updateLCID(n, mlt_info->sdus_for_lcid[n]);
328 dl_bytes_item_->updateLCID(n, mlt_info->bytes_for_lcid[n]);
330 dl_bytes_ += mlt_info->bytes_for_lcid[n];
336 void addDetails() {
337 // Add UL/DL packet and byte counts.
338 ul_frames_item_ = new MacULDLTreeWidgetItem(this, ueid_, rnti_, rat_, mac_ulsch_packet_count_row_type);
339 ul_bytes_item_ = new MacULDLTreeWidgetItem(this, ueid_, rnti_, rat_, mac_ulsch_byte_count_row_type);
340 dl_frames_item_ = new MacULDLTreeWidgetItem(this, ueid_, rnti_, rat_, mac_dlsch_packet_count_row_type);
341 dl_bytes_item_ = new MacULDLTreeWidgetItem(this, ueid_, rnti_, rat_, mac_dlsch_byte_count_row_type);
343 setExpanded(false);
346 // Draw this UE.
347 void draw() {
348 // Fixed fields (rnti, type, ueid) won't change during lifetime of UE entry.
350 // Calculate bw now.
351 double UL_bw = calculate_bw(&ul_time_start_,
352 &ul_time_stop_,
353 ul_bytes_);
354 double DL_bw = calculate_bw(&dl_time_start_,
355 &dl_time_stop_,
356 dl_bytes_);
358 // Set columns with current values.
359 setText(col_ul_frames_, QString::number(ul_frames_));
360 setText(col_ul_bytes_, QString::number(ul_bytes_));
361 setText(col_ul_mb_s_, QString::number(UL_bw));
362 setData(col_ul_padding_percent_, Qt::UserRole,
363 QVariant::fromValue<double>(ul_raw_bytes_ ?
364 (((double)ul_padding_bytes_ / (double)ul_raw_bytes_) * 100.0) :
365 0.0));
366 setText(col_ul_retx_, QString::number(ul_retx_));
368 setText(col_dl_frames_, QString::number(dl_frames_));
369 setText(col_dl_bytes_, QString::number(dl_bytes_));
370 setText(col_dl_mb_s_, QString::number(DL_bw));
372 setData(col_dl_padding_percent_, Qt::UserRole,
373 QVariant::fromValue<double>(dl_raw_bytes_ ?
374 (((double)dl_padding_bytes_ / (double)dl_raw_bytes_) * 100.0) :
375 0.0));
376 setText(col_dl_crc_failed_, QString::number(dl_crc_failed_));
377 setText(col_dl_retx_, QString::number(dl_retx_));
379 // Draw child items with per-channel counts.
380 ul_frames_item_->draw();
381 ul_bytes_item_->draw();
382 dl_frames_item_->draw();
383 dl_bytes_item_->draw();
386 // < operator. Compare this item with another item, using the column we are currently sorting on.
387 bool operator< (const QTreeWidgetItem &other) const
389 if (other.type() != mac_whole_ue_row_type_) return QTreeWidgetItem::operator< (other);
390 const MacUETreeWidgetItem *other_row = static_cast<const MacUETreeWidgetItem *>(&other);
392 switch (treeWidget()->sortColumn()) {
393 case col_rnti_:
394 return rnti_ < other_row->rnti_;
395 case col_type_:
396 return type_ < other_row->type_;
397 case col_ueid_:
398 return ueid_ < other_row->ueid_;
399 // TODO: other fields?
400 default:
401 break;
404 return QTreeWidgetItem::operator< (other);
407 // Generate expression for this UE, also filter for SRs and RACH if indicated.
408 const QString filterExpression(bool showSR, bool showRACH) {
409 QString filter_expr;
411 if (showSR) {
412 if (rat_ == MAC_RAT_LTE) {
413 filter_expr = QStringLiteral("(mac-lte.sr-req and mac-lte.ueid == %1) or (").arg(ueid_);
417 if (showRACH) {
418 if (rat_ == MAC_RAT_LTE) {
419 filter_expr += QStringLiteral("(mac-lte.rar or (mac-lte.preamble-sent and mac-lte.ueid == %1)) or (").arg(ueid_);
421 else {
422 filter_expr += QStringLiteral("mac-nr.rar or ");
426 // Main expression matching this UE
427 if (rat_ == MAC_RAT_LTE) {
428 filter_expr += QStringLiteral("mac-lte.ueid==%1 && mac-lte.rnti==%2").arg(ueid_).arg(rnti_);
430 else {
431 filter_expr += QStringLiteral("mac-nr.ueid==%1 && mac-nr.rnti==%2").arg(ueid_).arg(rnti_);
434 // Close () if open because of SR
435 if (showSR) {
436 if (rat_ == MAC_RAT_LTE) {
437 filter_expr += QStringLiteral(")");
440 // Close () if open because of RACH
441 if (showRACH) {
442 if (rat_ == MAC_RAT_LTE) {
443 filter_expr += QStringLiteral(")");
447 return filter_expr;
450 // Return the UE-specific fields.
451 QList<QVariant> rowData() const
453 QList<QVariant> row_data;
455 // Key fields
456 row_data << rnti_ << (type_ == C_RNTI ? QObject::tr("C-RNTI") : QObject::tr("SPS-RNTI")) << ueid_;
458 // UL
459 row_data << ul_frames_ << ul_bytes_
460 << calculate_bw(&ul_time_start_, &ul_time_stop_, ul_bytes_)
461 << QVariant::fromValue<double>(ul_raw_bytes_ ?
462 (((double)ul_padding_bytes_ / (double)ul_raw_bytes_) * 100.0) :
463 0.0)
464 << ul_retx_;
466 // DL
467 row_data << dl_frames_ << dl_bytes_
468 << calculate_bw(&dl_time_start_, &dl_time_stop_, dl_bytes_)
469 << QVariant::fromValue<double>(dl_raw_bytes_ ?
470 (((double)dl_padding_bytes_ / (double)dl_raw_bytes_) * 100.0) :
471 0.0)
472 << dl_crc_failed_ << dl_retx_;
473 return row_data;
476 private:
477 // Unchanging (key) fields.
478 uint8_t rat_;
479 unsigned rnti_;
480 unsigned type_;
481 unsigned ueid_;
483 // UL-specific.
484 unsigned ul_frames_;
485 unsigned ul_bytes_;
486 unsigned ul_raw_bytes_;
487 unsigned ul_padding_bytes_;
488 nstime_t ul_time_start_;
489 nstime_t ul_time_stop_;
490 unsigned ul_retx_;
492 // DL-specific.
493 unsigned dl_frames_;
494 unsigned dl_bytes_;
495 unsigned dl_raw_bytes_;
496 unsigned dl_padding_bytes_;
497 nstime_t dl_time_start_;
498 nstime_t dl_time_stop_;
499 unsigned dl_crc_failed_;
500 unsigned dl_retx_;
502 // Child nodes storing per-lcid counts.
503 MacULDLTreeWidgetItem *ul_frames_item_;
504 MacULDLTreeWidgetItem *ul_bytes_item_;
505 MacULDLTreeWidgetItem *dl_frames_item_;
506 MacULDLTreeWidgetItem *dl_bytes_item_;
512 // Label headings. Show according to which type of tree item is currently selected.
513 static const QStringList mac_whole_ue_row_labels = QStringList()
514 << QObject::tr("RAT") << QObject::tr("RNTI") << QObject::tr("Type") << QObject::tr("UEId")
515 << QObject::tr("UL Frames") << QObject::tr("UL Bytes") << QObject::tr("UL MB/s")
516 << QObject::tr("UL Padding %") << QObject::tr("UL Re TX")
517 << QObject::tr("DL Frames") << QObject::tr("DL Bytes") << QObject::tr("DL MB/s")
518 << QObject::tr("DL Padding %") << QObject::tr("DL CRC Failed")
519 << QObject::tr("DL ReTX")
520 // 'Blank out' Channel-level fields
521 << QObject::tr("") << QObject::tr("") << QObject::tr("") << QObject::tr("") << QObject::tr("");
523 static const QStringList mac_channel_counts_labels = QStringList()
524 << QObject::tr("") << QObject::tr("") << QObject::tr("CCCH")
525 << QObject::tr("LCID 1") << QObject::tr("LCID 2") << QObject::tr("LCID 3")
526 << QObject::tr("LCID 4") << QObject::tr("LCID 5") << QObject::tr("LCID 6")
527 << QObject::tr("LCID 7") << QObject::tr("LCID 8") << QObject::tr("LCID 9")
528 << QObject::tr("LCID 10") << QObject::tr("LCID 32") << QObject::tr("LCID 33")
529 << QObject::tr("LCID 34") << QObject::tr("LCID 35") << QObject::tr("LCID 36")
530 << QObject::tr("LCID 37") << QObject::tr("LCID 38");
534 //------------------------------------------------------------------------------------------
535 // Dialog
537 // Constructor.
538 LteMacStatisticsDialog::LteMacStatisticsDialog(QWidget &parent, CaptureFile &cf, const char *filter) :
539 TapParameterDialog(parent, cf, HELP_STATS_LTE_MAC_TRAFFIC_DIALOG),
540 commonStatsCurrent_(false)
542 setWindowSubtitle(tr("LTE/NR Mac Statistics"));
543 loadGeometry(parent.width() * 1, parent.height() * 3 / 4, "LTEMacStatisticsDialog");
545 clearCommonStats();
547 // Create common_stats_grid to appear just above the filter area.
548 int statstree_layout_idx = verticalLayout()->indexOf(filterLayout()->widget());
549 QGridLayout *common_stats_grid = new QGridLayout();
550 // Insert into the vertical layout
551 verticalLayout()->insertLayout(statstree_layout_idx, common_stats_grid);
552 int one_em = fontMetrics().height();
553 common_stats_grid->setColumnMinimumWidth(2, one_em * 2);
554 common_stats_grid->setColumnStretch(2, 1);
555 common_stats_grid->setColumnMinimumWidth(5, one_em * 2);
556 common_stats_grid->setColumnStretch(5, 1);
558 // Create statistics label.
559 commonStatsLabel_ = new QLabel(this);
560 commonStatsLabel_->setObjectName("statisticsLabel");
561 commonStatsLabel_->setTextFormat(Qt::RichText);
562 commonStatsLabel_->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
563 common_stats_grid->addWidget(commonStatsLabel_);
566 // Create a grid for filtering-related widgetsto also appear in layout.
567 int filter_controls_layout_idx = verticalLayout()->indexOf(filterLayout()->widget());
568 QGridLayout *filter_controls_grid = new QGridLayout();
569 // Insert into the vertical layout
570 verticalLayout()->insertLayout(filter_controls_layout_idx, filter_controls_grid);
571 filter_controls_grid->setColumnMinimumWidth(2, one_em * 2);
572 filter_controls_grid->setColumnStretch(2, 1);
573 filter_controls_grid->setColumnMinimumWidth(5, one_em * 2);
574 filter_controls_grid->setColumnStretch(5, 1);
576 // Add individual controls into the grid
577 showSRFilterCheckBox_ = new QCheckBox(tr("Include SR frames in filter"));
578 filter_controls_grid->addWidget(showSRFilterCheckBox_);
579 showRACHFilterCheckBox_ = new QCheckBox(tr("Include RACH frames in filter"));
580 filter_controls_grid->addWidget(showRACHFilterCheckBox_);
582 // Will set whole-UE headings originally.
583 updateHeaderLabels();
585 ul_delegate_ = new PercentBarDelegate();
586 statsTreeWidget()->setItemDelegateForColumn(col_ul_padding_percent_, ul_delegate_);
587 dl_delegate_ = new PercentBarDelegate();
588 statsTreeWidget()->setItemDelegateForColumn(col_dl_padding_percent_, dl_delegate_);
590 statsTreeWidget()->sortByColumn(col_rnti_, Qt::AscendingOrder);
592 // Set up column widths.
593 // resizeColumnToContents doesn't work well here, so set sizes manually.
594 for (int col = 0; col < statsTreeWidget()->columnCount() - 1; col++) {
595 switch (col) {
596 case col_rnti_:
597 statsTreeWidget()->setColumnWidth(col, one_em * 8);
598 break;
599 case col_ul_frames_:
600 statsTreeWidget()->setColumnWidth(col, one_em * 5);
601 break;
602 case col_ul_bytes_:
603 statsTreeWidget()->setColumnWidth(col, one_em * 5);
604 break;
605 case col_ul_mb_s_:
606 statsTreeWidget()->setColumnWidth(col, one_em * 4);
607 break;
608 case col_ul_padding_percent_:
609 statsTreeWidget()->setColumnWidth(col, one_em * 6);
610 break;
611 case col_ul_retx_:
612 statsTreeWidget()->setColumnWidth(col, one_em * 6);
613 break;
614 case col_dl_frames_:
615 statsTreeWidget()->setColumnWidth(col, one_em * 5);
616 break;
617 case col_dl_bytes_:
618 statsTreeWidget()->setColumnWidth(col, one_em * 5);
619 break;
620 case col_dl_mb_s_:
621 statsTreeWidget()->setColumnWidth(col, one_em * 4);
622 break;
623 case col_dl_padding_percent_:
624 statsTreeWidget()->setColumnWidth(col, one_em * 6);
625 break;
626 case col_dl_crc_failed_:
627 statsTreeWidget()->setColumnWidth(col, one_em * 6);
628 break;
629 case col_dl_retx_:
630 statsTreeWidget()->setColumnWidth(col, one_em * 6);
631 break;
633 default:
634 // The rest are numeric
635 statsTreeWidget()->setColumnWidth(col, one_em * 4);
636 statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
637 break;
641 addFilterActions();
643 if (filter) {
644 setDisplayFilter(filter);
647 // Set handler for when the tree item changes to set the appropriate labels.
648 connect(statsTreeWidget(), &QTreeWidget::itemSelectionChanged,
649 this, &LteMacStatisticsDialog::updateHeaderLabels);
651 // Set handler for when display filter string is changed.
652 connect(this, &LteMacStatisticsDialog::updateFilter,
653 this, &LteMacStatisticsDialog::filterUpdated);
656 // Destructor.
657 LteMacStatisticsDialog::~LteMacStatisticsDialog()
659 delete ul_delegate_;
660 delete dl_delegate_;
663 // Update system/common counters, and redraw if changed.
664 void LteMacStatisticsDialog::updateCommonStats(const mac_3gpp_tap_info *tap_info)
666 commonStats_.all_frames++;
668 // For common channels, just update global counters
669 switch (tap_info->rntiType) {
670 case P_RNTI:
671 commonStats_.pch_frames++;
672 commonStats_.pch_bytes += tap_info->single_number_of_bytes;
673 commonStats_.pch_paging_ids += tap_info->number_of_paging_ids;
674 commonStatsCurrent_ = false;
675 break;
676 case SI_RNTI:
677 commonStats_.sib_frames++;
678 commonStats_.sib_bytes += tap_info->single_number_of_bytes;
679 commonStatsCurrent_ = false;
680 break;
681 case NO_RNTI:
682 commonStats_.mib_frames++;
683 commonStatsCurrent_ = false;
684 break;
685 case RA_RNTI:
686 commonStats_.rar_frames++;
687 commonStats_.rar_entries += tap_info->number_of_rars;
688 commonStatsCurrent_ = false;
689 break;
690 case C_RNTI:
691 case SPS_RNTI:
692 // UE-specific.
693 break;
695 default:
696 // Error...
697 return;
700 // Check max UEs/tti counter
701 switch (tap_info->direction) {
702 case DIRECTION_UPLINK:
703 if (tap_info->ueInTTI > commonStats_.max_ul_ues_in_tti) {
704 commonStats_.max_ul_ues_in_tti = tap_info->ueInTTI;
705 commonStatsCurrent_ = false;
707 break;
708 case DIRECTION_DOWNLINK:
709 if (tap_info->ueInTTI > commonStats_.max_dl_ues_in_tti) {
710 commonStats_.max_dl_ues_in_tti = tap_info->ueInTTI;
711 commonStatsCurrent_ = false;
713 break;
717 // Draw current common statistics by regenerating label with current values.
718 void LteMacStatisticsDialog::drawCommonStats()
720 if (!commonStatsCurrent_) {
721 QString stats_tables = "<html><head></head><body>\n";
722 stats_tables += QStringLiteral("<table>\n");
723 stats_tables += QStringLiteral("<tr><th align=\"left\">System</th> <td align=\"left\"> Max UL UEs/TTI=%1</td>").arg(commonStats_.max_ul_ues_in_tti);
724 stats_tables += QStringLiteral("<td align=\"left\">Max DL UEs/TTI=%1</td></tr>\n").arg(commonStats_.max_dl_ues_in_tti);
726 stats_tables += QStringLiteral("<tr><th align=\"left\">System broadcast</th><td align=\"left\">MIBs=%1</td>").arg(commonStats_.mib_frames);
727 stats_tables += QStringLiteral("<td align=\"left\">SIBs=%1 (%2 bytes)</td></tr>\n").arg(commonStats_.sib_frames).arg(commonStats_.sib_bytes);
729 stats_tables += QStringLiteral("<tr><th align=\"left\">RACH</th><td align=\"left\">RARs=%1 frames (%2 RARs)</td></tr>\n").
730 arg(commonStats_.rar_frames).
731 arg(commonStats_.rar_entries);
733 stats_tables += QStringLiteral("<tr><th align=\"left\">Paging</th><td align=\"left\">PCH=%1 (%2 bytes, %3 IDs)</td></tr>\n").
734 arg(commonStats_.pch_frames).
735 arg(commonStats_.pch_bytes).
736 arg(commonStats_.pch_paging_ids);
738 stats_tables += QStringLiteral("</table>\n");
739 stats_tables += "</body>\n";
741 commonStatsLabel_->setText(stats_tables);
743 commonStatsCurrent_ = true;
747 void LteMacStatisticsDialog::clearCommonStats()
749 memset(&commonStats_, 0, sizeof(commonStats_));
752 void LteMacStatisticsDialog::tapReset(void *ws_dlg_ptr)
754 LteMacStatisticsDialog *ws_dlg = static_cast<LteMacStatisticsDialog *>(ws_dlg_ptr);
755 if (!ws_dlg) {
756 return;
759 ws_dlg->statsTreeWidget()->clear();
760 ws_dlg->clearCommonStats();
763 //---------------------------------------------------------------------------------------
764 // Process tap info from a new packet.
765 // Returns TAP_PACKET_REDRAW if a redraw is needed, TAP_PACKET_DONT_REDRAW otherwise.
766 tap_packet_status LteMacStatisticsDialog::tapPacket(void *ws_dlg_ptr, struct _packet_info *, epan_dissect *, const void *mac_3gpp_tap_info_ptr, tap_flags_t)
768 // Look up dialog and tap info.
769 LteMacStatisticsDialog *ws_dlg = static_cast<LteMacStatisticsDialog *>(ws_dlg_ptr);
770 const mac_3gpp_tap_info *mlt_info = (const mac_3gpp_tap_info *)mac_3gpp_tap_info_ptr;
771 if (!ws_dlg || !mlt_info) {
772 return TAP_PACKET_DONT_REDRAW;
775 // Update common stats.
776 ws_dlg->updateCommonStats(mlt_info);
778 // Nothing more to do if tap entry isn't for a UE.
779 if ((mlt_info->rntiType != C_RNTI) && (mlt_info->rntiType != SPS_RNTI)) {
780 return TAP_PACKET_DONT_REDRAW;
783 // Look for an existing UE to match this tap info.
784 MacUETreeWidgetItem *mac_ue_ti = NULL;
785 for (int i = 0; i < ws_dlg->statsTreeWidget()->topLevelItemCount(); i++) {
786 QTreeWidgetItem *ti = ws_dlg->statsTreeWidget()->topLevelItem(i);
787 // Make sure we're looking at a UE entry
788 if (ti->type() != mac_whole_ue_row_type_) {
789 continue;
792 // See if current item matches tap.
793 MacUETreeWidgetItem *cur_muds_ti = static_cast<MacUETreeWidgetItem*>(ti);
794 if (cur_muds_ti->isMatch(mlt_info)) {
795 mac_ue_ti = cur_muds_ti;
796 break;
800 // If don't find matching UE, create a new one.
801 if (!mac_ue_ti) {
802 mac_ue_ti = new MacUETreeWidgetItem(ws_dlg->statsTreeWidget(), mlt_info);
803 for (int col = 0; col < ws_dlg->statsTreeWidget()->columnCount(); col++) {
804 // int QTreeWidgetItem::textAlignment(int column) const
805 // Returns the text alignment for the label in the given column.
806 // Note: This function returns an int for historical reasons. It will be corrected to return Qt::Alignment in Qt 7.
807 mac_ue_ti->setTextAlignment(col, static_cast<Qt::Alignment>(ws_dlg->statsTreeWidget()->headerItem()->textAlignment(col)));
811 // Update the UE item with info from tap!
812 mac_ue_ti->update(mlt_info);
813 return TAP_PACKET_REDRAW;
816 // Return total number of frames tapped.
817 unsigned LteMacStatisticsDialog::getFrameCount()
819 return commonStats_.all_frames;
822 void LteMacStatisticsDialog::tapDraw(void *ws_dlg_ptr)
824 // Look up dialog.
825 LteMacStatisticsDialog *ws_dlg = static_cast<LteMacStatisticsDialog *>(ws_dlg_ptr);
826 if (!ws_dlg) {
827 return;
830 // Go over all of the top-level items.
831 for (int i = 0; i < ws_dlg->statsTreeWidget()->topLevelItemCount(); i++) {
832 // Get item, make sure its of the whole-UE type.
833 QTreeWidgetItem *ti = ws_dlg->statsTreeWidget()->topLevelItem(i);
834 if (ti->type() != mac_whole_ue_row_type_) {
835 continue;
838 // Tell the UE item to draw itself.
839 MacUETreeWidgetItem *mac_ue_ti = static_cast<MacUETreeWidgetItem*>(ti);
840 mac_ue_ti->draw();
843 ws_dlg->drawCommonStats();
845 // Update title
846 ws_dlg->setWindowSubtitle(QStringLiteral("3GPP Mac Statistics (%1 UEs, %2 frames)").
847 arg(ws_dlg->statsTreeWidget()->topLevelItemCount()).arg(ws_dlg->getFrameCount()));
850 const QString LteMacStatisticsDialog::filterExpression()
852 QString filter_expr;
854 if (statsTreeWidget()->selectedItems().count() > 0) {
855 QTreeWidgetItem *ti = statsTreeWidget()->selectedItems()[0];
857 if (ti->type() == mac_whole_ue_row_type_) {
858 MacUETreeWidgetItem *mac_ue_ti = static_cast<MacUETreeWidgetItem*>(ti);
859 filter_expr = mac_ue_ti->filterExpression(showSRFilterCheckBox_->checkState() > Qt::Unchecked,
860 showRACHFilterCheckBox_->checkState() > Qt::Unchecked);
861 } else {
862 MacULDLTreeWidgetItem *mac_channels_ti = static_cast<MacULDLTreeWidgetItem*>(ti);
863 filter_expr = mac_channels_ti->filterExpression(showSRFilterCheckBox_->checkState() > Qt::Unchecked,
864 showRACHFilterCheckBox_->checkState() > Qt::Unchecked);
867 return filter_expr;
870 void LteMacStatisticsDialog::fillTree()
872 if (!registerTapListener("mac-3gpp",
873 this,
874 displayFilter_.toLatin1().data(),
875 TL_REQUIRES_NOTHING,
876 tapReset,
877 tapPacket,
878 tapDraw)) {
879 reject();
880 return;
883 cap_file_.retapPackets();
884 tapDraw(this);
885 removeTapListeners();
888 void LteMacStatisticsDialog::updateHeaderLabels()
890 if (statsTreeWidget()->selectedItems().count() > 0 && statsTreeWidget()->selectedItems()[0]->type() == mac_whole_ue_row_type_) {
891 // Whole-UE labels
892 statsTreeWidget()->setHeaderLabels(mac_whole_ue_row_labels);
893 } else if (statsTreeWidget()->selectedItems().count() > 0) {
894 // ULDL labels
895 switch (statsTreeWidget()->selectedItems()[0]->type()) {
896 case mac_ulsch_packet_count_row_type:
897 case mac_ulsch_byte_count_row_type:
898 case mac_dlsch_packet_count_row_type:
899 case mac_dlsch_byte_count_row_type:
900 statsTreeWidget()->setHeaderLabels(mac_channel_counts_labels);
901 break;
903 default:
904 break;
907 else {
908 // Nothing selected yet, but set whole-UE labels.
909 statsTreeWidget()->setHeaderLabels(mac_whole_ue_row_labels);
913 void LteMacStatisticsDialog::captureFileClosing()
915 remove_tap_listener(this);
917 WiresharkDialog::captureFileClosing();
920 // Store filter from signal.
921 void LteMacStatisticsDialog::filterUpdated(QString filter)
923 displayFilter_ = filter;
926 // Get the item for the row, depending upon the type of tree item.
927 QList<QVariant> LteMacStatisticsDialog::treeItemData(QTreeWidgetItem *item) const
929 // Cast up to our type.
930 MacULDLTreeWidgetItem *channel_item = dynamic_cast<MacULDLTreeWidgetItem*>(item);
931 if (channel_item) {
932 return channel_item->rowData();
934 MacUETreeWidgetItem *ue_item = dynamic_cast<MacUETreeWidgetItem*>(item);
935 if (ue_item) {
936 return ue_item->rowData();
939 // Need to return something..
940 return QList<QVariant>();
944 // Stat command + args
946 static void
947 lte_mac_statistics_init(const char *args, void*) {
948 QStringList args_l = QString(args).split(',');
949 QByteArray filter;
950 if (args_l.length() > 2) {
951 filter = QStringList(args_l.mid(2)).join(",").toUtf8();
953 mainApp->emitStatCommandSignal("LteMacStatistics", filter.constData(), NULL);
956 static stat_tap_ui lte_mac_statistics_ui = {
957 REGISTER_TELEPHONY_GROUP_3GPP_UU,
958 QT_TRANSLATE_NOOP("LteMacStatisticsDialog", "MAC Statistics"),
959 "mac-3gpp,stat", // cli_string
960 lte_mac_statistics_init,
961 0, // nparams
962 NULL // params
965 extern "C" {
967 void register_tap_listener_qt_lte_mac_statistics(void);
969 void
970 register_tap_listener_qt_lte_mac_statistics(void)
972 register_stat_tap_ui(&lte_mac_statistics_ui, NULL);