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
10 #include "lte_mac_statistics_dialog.h"
12 #include <epan/packet.h>
13 #include <epan/strutil.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.
36 col_ul_padding_percent_
,
37 /* col_ul_crc_failed_, */
43 col_dl_padding_percent_
,
49 // Type of tree item, so can set column headings properly.
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
,
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) {
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;
83 // Channels (by LCID) data node. Used for UL/DL frames/bytes.
84 class MacULDLTreeWidgetItem
: public QTreeWidgetItem
87 MacULDLTreeWidgetItem(QTreeWidgetItem
*parent
, unsigned ueid
, unsigned rnti
, unsigned rat
, int row_type
) :
88 QTreeWidgetItem (parent
, row_type
),
93 // Init values held for all lcids to 0.
94 for (int n
=0; n
< MAC_3GPP_DATA_LCID_COUNT_MAX
; n
++) {
98 // Set first column to show what counts in this row mean.
100 case mac_ulsch_packet_count_row_type
:
101 setText(col_rnti_
, "UL Packets");
103 case mac_ulsch_byte_count_row_type
:
104 setText(col_rnti_
, "UL Bytes");
106 case mac_dlsch_packet_count_row_type
:
107 setText(col_rnti_
, "DL Packets");
109 case mac_dlsch_byte_count_row_type
:
110 setText(col_rnti_
, "DL Bytes");
113 // Should never get here...
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();
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
);
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_
);
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_
);
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
);
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
176 if (rat_
== MAC_RAT_LTE
) {
177 filter_expr
+= QStringLiteral(")");
180 // Close () if open because of RACH
182 if (rat_
== MAC_RAT_LTE
) {
183 filter_expr
+= QStringLiteral(")");
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
>();
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
210 MacUETreeWidgetItem(QTreeWidget
*parent
, const mac_3gpp_tap_info
*mlt_info
) :
211 QTreeWidgetItem (parent
, mac_whole_ue_row_type_
),
218 ul_padding_bytes_(0),
223 dl_padding_bytes_(0),
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
) ?
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.
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
) {
255 if (mlt_info
->direction
== DIRECTION_UPLINK
) {
256 if (mlt_info
->isPHYRetx
) {
261 if (mlt_info
->crcStatusValid
&& (mlt_info
->crcStatus
!= crc_success
)) {
262 // TODO: there is not a column for this...
268 if (ul_frames_
== 0) {
269 ul_time_start_
= mlt_info
->mac_time
;
271 ul_time_stop_
= mlt_info
->mac_time
;
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
];
293 if (mlt_info
->isPHYRetx
) {
298 if (mlt_info
->crcStatusValid
&& (mlt_info
->crcStatus
!= crc_success
)) {
299 switch (mlt_info
->crcStatus
) {
305 // Not a reason we currently care about.
312 if (dl_frames_
== 0) {
313 dl_time_start_
= mlt_info
->mac_time
;
315 dl_time_stop_
= mlt_info
->mac_time
;
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
];
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
);
348 // Fixed fields (rnti, type, ueid) won't change during lifetime of UE entry.
351 double UL_bw
= calculate_bw(&ul_time_start_
,
354 double DL_bw
= calculate_bw(&dl_time_start_
,
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) :
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) :
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()) {
394 return rnti_
< other_row
->rnti_
;
396 return type_
< other_row
->type_
;
398 return ueid_
< other_row
->ueid_
;
399 // TODO: other fields?
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
) {
412 if (rat_
== MAC_RAT_LTE
) {
413 filter_expr
= QStringLiteral("(mac-lte.sr-req and mac-lte.ueid == %1) or (").arg(ueid_
);
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_
);
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_
);
431 filter_expr
+= QStringLiteral("mac-nr.ueid==%1 && mac-nr.rnti==%2").arg(ueid_
).arg(rnti_
);
434 // Close () if open because of SR
436 if (rat_
== MAC_RAT_LTE
) {
437 filter_expr
+= QStringLiteral(")");
440 // Close () if open because of RACH
442 if (rat_
== MAC_RAT_LTE
) {
443 filter_expr
+= QStringLiteral(")");
450 // Return the UE-specific fields.
451 QList
<QVariant
> rowData() const
453 QList
<QVariant
> row_data
;
456 row_data
<< rnti_
<< (type_
== C_RNTI
? QObject::tr("C-RNTI") : QObject::tr("SPS-RNTI")) << ueid_
;
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) :
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) :
472 << dl_crc_failed_
<< dl_retx_
;
477 // Unchanging (key) fields.
486 unsigned ul_raw_bytes_
;
487 unsigned ul_padding_bytes_
;
488 nstime_t ul_time_start_
;
489 nstime_t ul_time_stop_
;
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_
;
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 //------------------------------------------------------------------------------------------
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");
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
++) {
597 statsTreeWidget()->setColumnWidth(col
, one_em
* 8);
600 statsTreeWidget()->setColumnWidth(col
, one_em
* 5);
603 statsTreeWidget()->setColumnWidth(col
, one_em
* 5);
606 statsTreeWidget()->setColumnWidth(col
, one_em
* 4);
608 case col_ul_padding_percent_
:
609 statsTreeWidget()->setColumnWidth(col
, one_em
* 6);
612 statsTreeWidget()->setColumnWidth(col
, one_em
* 6);
615 statsTreeWidget()->setColumnWidth(col
, one_em
* 5);
618 statsTreeWidget()->setColumnWidth(col
, one_em
* 5);
621 statsTreeWidget()->setColumnWidth(col
, one_em
* 4);
623 case col_dl_padding_percent_
:
624 statsTreeWidget()->setColumnWidth(col
, one_em
* 6);
626 case col_dl_crc_failed_
:
627 statsTreeWidget()->setColumnWidth(col
, one_em
* 6);
630 statsTreeWidget()->setColumnWidth(col
, one_em
* 6);
634 // The rest are numeric
635 statsTreeWidget()->setColumnWidth(col
, one_em
* 4);
636 statsTreeWidget()->headerItem()->setTextAlignment(col
, Qt::AlignRight
);
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
);
657 LteMacStatisticsDialog::~LteMacStatisticsDialog()
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
) {
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;
677 commonStats_
.sib_frames
++;
678 commonStats_
.sib_bytes
+= tap_info
->single_number_of_bytes
;
679 commonStatsCurrent_
= false;
682 commonStats_
.mib_frames
++;
683 commonStatsCurrent_
= false;
686 commonStats_
.rar_frames
++;
687 commonStats_
.rar_entries
+= tap_info
->number_of_rars
;
688 commonStatsCurrent_
= false;
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;
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;
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
);
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_
) {
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
;
800 // If don't find matching UE, create a new one.
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
)
825 LteMacStatisticsDialog
*ws_dlg
= static_cast<LteMacStatisticsDialog
*>(ws_dlg_ptr
);
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_
) {
838 // Tell the UE item to draw itself.
839 MacUETreeWidgetItem
*mac_ue_ti
= static_cast<MacUETreeWidgetItem
*>(ti
);
843 ws_dlg
->drawCommonStats();
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()
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
);
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
);
870 void LteMacStatisticsDialog::fillTree()
872 if (!registerTapListener("mac-3gpp",
874 displayFilter_
.toLatin1().data(),
883 cap_file_
.retapPackets();
885 removeTapListeners();
888 void LteMacStatisticsDialog::updateHeaderLabels()
890 if (statsTreeWidget()->selectedItems().count() > 0 && statsTreeWidget()->selectedItems()[0]->type() == mac_whole_ue_row_type_
) {
892 statsTreeWidget()->setHeaderLabels(mac_whole_ue_row_labels
);
893 } else if (statsTreeWidget()->selectedItems().count() > 0) {
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
);
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
);
932 return channel_item
->rowData();
934 MacUETreeWidgetItem
*ue_item
= dynamic_cast<MacUETreeWidgetItem
*>(item
);
936 return ue_item
->rowData();
939 // Need to return something..
940 return QList
<QVariant
>();
944 // Stat command + args
947 lte_mac_statistics_init(const char *args
, void*) {
948 QStringList args_l
= QString(args
).split(',');
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
,
967 void register_tap_listener_qt_lte_mac_statistics(void);
970 register_tap_listener_qt_lte_mac_statistics(void)
972 register_stat_tap_ui(<e_mac_statistics_ui
, NULL
);