Trivial formatting changes
[obnox/wireshark/wip.git] / gtk / mac_lte_stat_dlg.c
1 /* mac_lte_stat_dlg.c
2  * Copyright 2009 Martin Mathieson
3  * (originally based upon wlan_stat_dlg.c)
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 /* TODO:
28    - limit by display filter?
29    - Break down traffic by cell?
30    - CSV export?
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40
41 #include <string.h>
42
43 #include <gtk/gtk.h>
44
45 #include <epan/packet.h>
46 #include <epan/packet_info.h>
47 #include <epan/tap.h>
48 #include <epan/dissectors/packet-mac-lte.h>
49
50 #include "../register.h"
51 #include "../simple_dialog.h"
52 #include "../stat_menu.h"
53
54 #include "gtk/dlg_utils.h"
55 #include "gtk/gui_stat_menu.h"
56 #include "gtk/gui_utils.h"
57 #include "gtk/help_dlg.h"
58 #include "gtk/main.h"
59
60 /**********************************************/
61 /* Table column identifiers and title strings */
62
63 enum {
64     RNTI_COLUMN,
65     UL_FRAMES_COLUMN,
66     UL_BYTES_COLUMN,
67     UL_CRC_ERRORS_COLUMN,
68     UL_RETX_FRAMES_COLUMN,
69     DL_FRAMES_COLUMN,
70     DL_BYTES_COLUMN,
71     DL_CRC_ERRORS_COLUMN,
72     DL_RETX_FRAMES_COLUMN,
73     TABLE_COLUMN,
74     NUM_UE_COLUMNS
75 };
76
77 enum {
78     CCCH_COLUMN=1,
79     LCID1_COLUMN,
80     LCID2_COLUMN,
81     LCID3_COLUMN,
82     LCID4_COLUMN,
83     LCID5_COLUMN,
84     LCID6_COLUMN,
85     LCID7_COLUMN,
86     LCID8_COLUMN,
87     LCID9_COLUMN,
88     LCID10_COLUMN,
89     PREDEFINED_COLUMN,
90     NUM_CHANNEL_COLUMNS
91 };
92
93 static const gchar *ue_titles[] = { "RNTI",
94                                  "UL Frames", "UL Bytes", "UL CRC Errors", "UL ReTX Frames",
95                                  "DL Frames", "DL Bytes", "DL CRC Errors", "DL ReTX Frames"};
96
97 static const gchar *channel_titles[] = { "CCCH",
98                                          "LCID 1", "LCID 2", "LCID 3", "LCID 4", "LCID 5",
99                                          "LCID 6", "LCID 7", "LCID 8", "LCID 9", "LCID 10",
100                                          "Predefined"};
101
102
103 /* Stats for one UE */
104 typedef struct mac_lte_row_data {
105     /* Key for matching this row */
106     guint16 rnti;
107
108     gboolean is_predefined_data;
109
110     guint32 UL_frames;
111     guint32 UL_total_bytes;
112     guint32 UL_CRC_errors;
113     guint32 UL_retx_frames;
114
115     guint32 DL_frames;
116     guint32 DL_total_bytes;
117     guint32 DL_CRC_errors;
118     guint32 DL_retx_frames;
119
120     guint32 UL_bytes_for_lcid[11];
121     guint32 UL_sdus_for_lcid[11];
122     guint32 DL_bytes_for_lcid[11];
123     guint32 DL_sdus_for_lcid[11];
124 } mac_lte_row_data;
125
126
127 /* One row/UE in the UE table */
128 typedef struct mac_lte_ep {
129     struct mac_lte_ep* next;
130     struct mac_lte_row_data stats;
131     GtkTreeIter iter;
132     gboolean iter_valid;
133 } mac_lte_ep_t;
134
135
136 /* Common channel stats */
137 typedef struct mac_lte_common_stats {
138     guint32 all_frames;
139     guint32 bch_frames;
140     guint32 bch_bytes;
141     guint32 pch_frames;
142     guint32 pch_bytes;
143     guint32 rar_frames;
144     guint32 rar_entries;
145 } mac_lte_common_stats;
146
147 static const char * selected_ue_row_names[] = {"UL SDUs", "UL Bytes", "DL SDUs", "DL Bytes"};
148
149 static mac_lte_common_stats common_stats;
150
151 static GtkWidget *mac_lte_common_bch_frames;
152 static GtkWidget *mac_lte_common_bch_bytes;
153 static GtkWidget *mac_lte_common_pch_frames;
154 static GtkWidget *mac_lte_common_pch_bytes;
155 static GtkWidget *mac_lte_common_rar_frames;
156 static GtkWidget *mac_lte_common_rar_entries;
157
158 /* Labels in selected UE 'table' */
159 static GtkWidget *selected_ue_column_entry[NUM_CHANNEL_COLUMNS][5];
160
161
162 /* Top-level dialog and labels */
163 static GtkWidget  *mac_lte_stat_dlg_w = NULL;
164 static GtkWidget  *mac_lte_stat_common_channel_lb = NULL;
165 static GtkWidget  *mac_lte_stat_ues_lb = NULL;
166 static GtkWidget  *mac_lte_stat_selected_ue_lb = NULL;
167
168
169 /* Used to keep track of whole MAC LTE statistics window */
170 typedef struct mac_lte_stat_t {
171     GtkTreeView   *ue_table;
172     mac_lte_ep_t* ep_list;
173 } mac_lte_stat_t;
174
175
176 /* Reset the statistics window */
177 static void
178 mac_lte_stat_reset(void *phs)
179 {
180     mac_lte_stat_t* mac_lte_stat = (mac_lte_stat_t *)phs;
181     mac_lte_ep_t* list = mac_lte_stat->ep_list;
182     gchar title[256];
183     GtkListStore *store;
184     gint i, n;
185
186     /* Set the title */
187     if (mac_lte_stat_dlg_w != NULL) {
188         g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s",
189                    cf_get_display_name(&cfile));
190         gtk_window_set_title(GTK_WINDOW(mac_lte_stat_dlg_w), title);
191     }
192
193     g_snprintf(title, sizeof(title), "UL/DL-SCH data (0 UEs)");
194     gtk_frame_set_label(GTK_FRAME(mac_lte_stat_ues_lb), title);
195
196     memset(&common_stats, 0, sizeof(common_stats));
197
198     /* Remove all entries from the UE list */
199     store = GTK_LIST_STORE(gtk_tree_view_get_model(mac_lte_stat->ue_table));
200     gtk_list_store_clear(store);
201
202     if (!list) {
203         return;
204     }
205
206     mac_lte_stat->ep_list = NULL;
207
208     /* Set all of the channel counters to 0 */
209     for (n=1; n <=4; n++) {
210         for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
211              gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[i][n]), "0");
212         }
213     }
214 }
215
216
217 /* Allocate a mac_lte_ep_t struct to store info for new UE */
218 static mac_lte_ep_t* alloc_mac_lte_ep(struct mac_lte_tap_info *si, packet_info *pinfo _U_)
219 {
220     mac_lte_ep_t* ep;
221     int n;
222
223     if (!si) {
224         return NULL;
225     }
226
227     if (!(ep = g_malloc(sizeof(mac_lte_ep_t)))) {
228         return NULL;
229     }
230
231     /* Copy SI data into ep->stats */
232     ep->stats.rnti = si->rnti;
233
234     /* Counts for new UE are all 0 */
235     ep->stats.UL_frames = 0;
236     ep->stats.DL_frames = 0;
237     ep->stats.UL_total_bytes = 0;
238     ep->stats.DL_total_bytes = 0;
239     ep->stats.UL_CRC_errors = 0;
240     ep->stats.DL_CRC_errors = 0;
241     ep->stats.UL_retx_frames = 0;
242     ep->stats.DL_retx_frames = 0;
243
244     for (n=0; n < 11; n++) {
245         ep->stats.UL_sdus_for_lcid[n] = 0;
246         ep->stats.UL_bytes_for_lcid[n] = 0;
247     }
248     ep->stats.DL_total_bytes = 0;
249     for (n=0; n < 11; n++) {
250         ep->stats.DL_sdus_for_lcid[n] = 0;
251         ep->stats.DL_bytes_for_lcid[n] = 0;
252     }
253
254     ep->next = NULL;
255
256     ep->iter_valid = FALSE;
257
258     return ep;
259 }
260
261
262 /* Process stat struct for a MAC LTE frame */
263 static int
264 mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
265                     const void *phi)
266 {
267     int n;
268
269     /* Get reference to stat window instance */
270     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
271     mac_lte_ep_t *tmp = NULL, *te = NULL;
272
273     /* Cast tap info struct */
274     struct mac_lte_tap_info *si = (struct mac_lte_tap_info *)phi;
275
276     if (!hs) {
277         return 0;
278     }
279
280     common_stats.all_frames++;
281
282     /* For common channels, just update global counters */
283     switch (si->rntiType) {
284         case P_RNTI:
285             common_stats.pch_frames++;
286             common_stats.pch_bytes += si->single_number_of_bytes;
287             return 1;
288         case SI_RNTI:
289         case NO_RNTI:
290             common_stats.bch_frames++;
291             common_stats.bch_bytes += si->single_number_of_bytes;
292             return 1;
293         case RA_RNTI:
294             common_stats.rar_frames++;
295             common_stats.rar_entries += si->number_of_rars;
296             return 1;
297         case C_RNTI:
298             /* Drop through for per-UE update */
299             break;
300
301         default:
302             return 0;
303     }
304
305     /* For per-UE data, must create a new row if none already existing */
306     if (!hs->ep_list) {
307         /* Allocate new list */
308         hs->ep_list = alloc_mac_lte_ep(si, pinfo);
309         /* Make it the first/only entry */
310         te = hs->ep_list;
311     } else {
312         /* Look among existing rows for this RNTI */
313         for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
314             if (tmp->stats.rnti == si->rnti) {
315                 te = tmp;
316                 break;
317             }
318         }
319
320         /* Not found among existing, so create a new one anyway */
321         if (te == NULL) {
322             if ((te = alloc_mac_lte_ep(si, pinfo))) {
323                 /* New item is head of list */
324                 te->next = hs->ep_list;
325                 hs->ep_list = te;
326             }
327         }
328     }
329
330     /* Really should have a row pointer by now */
331     if (!te) {
332         return 0;
333     }
334
335     /* Update entry with details from si */
336     te->stats.rnti = si->rnti;
337     te->stats.is_predefined_data = si->isPredefinedData;
338     if (si->crcStatusValid && !si->crcStatus) {
339         if (si->direction == DIRECTION_UPLINK) {
340             te->stats.UL_CRC_errors++;
341             return 1;
342         }
343         else {
344             te->stats.DL_CRC_errors++;
345             return 1;
346         }
347     }
348
349     /* Uplink */
350     if (si->direction == DIRECTION_UPLINK) {
351         if (si->reTxCount >= 1) {
352             te->stats.UL_retx_frames++;
353             return 1;
354         }
355         te->stats.UL_frames++;
356
357         if (si->isPredefinedData) {
358             te->stats.UL_total_bytes += si->single_number_of_bytes;
359         }
360         else {
361             for (n=0; n < 11; n++) {
362                 if (si->bytes_for_lcid[n]) {
363                     te->stats.UL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
364                 }
365                 te->stats.UL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
366                 te->stats.UL_total_bytes += si->bytes_for_lcid[n];
367             }
368         }
369     }
370
371     /* Downlink */
372     else {
373         if (si->reTxCount >= 1) {
374             te->stats.DL_retx_frames++;
375             return 1;
376         }
377
378         te->stats.DL_frames++;
379
380         if (si->isPredefinedData) {
381             te->stats.DL_total_bytes += si->single_number_of_bytes;
382         }
383         else {
384             for (n=0; n < 11; n++) {
385                 if (si->bytes_for_lcid[n]) {
386                     te->stats.DL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
387                 }
388                 te->stats.DL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
389                 te->stats.DL_total_bytes += si->bytes_for_lcid[n];
390             }
391         }
392     }
393
394     return 1;
395 }
396
397
398 /* Draw the UE details table according to the current UE selection */
399 static void
400 mac_lte_ue_details(mac_lte_ep_t *mac_stat_ep)
401 {
402     int n;
403     gchar buff[32];
404
405     /**********************************/
406     /* Set data one row at a time     */
407
408     /* UL SDUs */
409     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
410         g_snprintf(buff, sizeof(buff), "%u",
411                    mac_stat_ep ? mac_stat_ep->stats.UL_sdus_for_lcid[n] : 0);
412          gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][1]), buff);
413     }
414
415     /* Predefined */
416     if (mac_stat_ep) {
417         g_snprintf(buff, sizeof(buff), "%u",
418                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.UL_frames : 0);
419     }
420     else {
421         g_snprintf(buff, sizeof(buff), "%u", 0);
422     }
423     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][1]), buff);
424
425
426     /* UL Bytes */
427     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
428         g_snprintf(buff, sizeof(buff), "%u",
429                    (mac_stat_ep) ? mac_stat_ep->stats.UL_bytes_for_lcid[n] : 0);
430         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][2]), buff);
431     }
432
433     /* Predefined */
434     if (mac_stat_ep) {
435         g_snprintf(buff, sizeof(buff), "%u",
436                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.UL_total_bytes : 0);
437     }
438     else {
439         g_snprintf(buff, sizeof(buff), "%u", 0);
440     }
441     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][2]), buff);
442
443
444     /* DL SDUs */
445     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
446         g_snprintf(buff, sizeof(buff), "%u",
447                    mac_stat_ep ? mac_stat_ep->stats.DL_sdus_for_lcid[n] : 0);
448         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][3]), buff);
449     }
450     /* Predefined */
451     if (mac_stat_ep) {
452         g_snprintf(buff, sizeof(buff), "%u",
453                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.DL_frames : 0);
454     }
455     else {
456         g_snprintf(buff, sizeof(buff), "%u", 0);
457     }
458     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][3]), buff);
459
460
461     /* DL Bytes */
462     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
463         g_snprintf(buff, sizeof(buff), "%u",
464                    mac_stat_ep ? mac_stat_ep->stats.DL_bytes_for_lcid[n] : 0);
465         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][4]), buff);
466     }
467     /* Predefined */
468     if (mac_stat_ep) {
469         g_snprintf(buff, sizeof(buff), "%u",
470                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.DL_total_bytes : 0);
471     }
472     else {
473         g_snprintf(buff, sizeof(buff), "%u", 0);
474     }
475     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][4]), buff);
476 }
477
478
479
480 /* (Re)draw the whole dialog window */
481 static void
482 mac_lte_stat_draw(void *phs)
483 {
484     gchar   buff[32];
485     guint16 number_of_ues = 0;
486     gchar title[256];
487
488     /* Look up the statistics window */
489     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
490     mac_lte_ep_t* list = hs->ep_list, *tmp = 0;
491
492     GtkListStore *ues_store;
493     GtkTreeSelection *sel;
494     GtkTreeModel *model;
495     GtkTreeIter iter;
496
497     /* Common channel data */
498     g_snprintf(buff, sizeof(buff), "BCH Frames: %u", common_stats.bch_frames);
499     gtk_label_set_text(GTK_LABEL(mac_lte_common_bch_frames), buff);
500     g_snprintf(buff, sizeof(buff), "BCH Bytes: %u", common_stats.bch_bytes);
501     gtk_label_set_text(GTK_LABEL(mac_lte_common_bch_bytes), buff);
502     g_snprintf(buff, sizeof(buff), "PCH Frames: %u", common_stats.pch_frames);
503     gtk_label_set_text(GTK_LABEL(mac_lte_common_pch_frames), buff);
504     g_snprintf(buff, sizeof(buff), "PCH Bytes: %u", common_stats.pch_bytes);
505     gtk_label_set_text(GTK_LABEL(mac_lte_common_pch_bytes), buff);
506     g_snprintf(buff, sizeof(buff), "RAR Frames: %u", common_stats.rar_frames);
507     gtk_label_set_text(GTK_LABEL(mac_lte_common_rar_frames), buff);
508     g_snprintf(buff, sizeof(buff), "RAR Entries: %u", common_stats.rar_entries);
509     gtk_label_set_text(GTK_LABEL(mac_lte_common_rar_entries), buff);
510
511
512     /* Per-UE table entries */
513     ues_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->ue_table));
514
515     /* Set title that shows how many UEs currently in table */
516     for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
517     g_snprintf(title, sizeof(title), "UL/DL-SCH data (%u UEs)", number_of_ues);
518     gtk_frame_set_label(GTK_FRAME(mac_lte_stat_ues_lb), title);
519
520     /* Update title to include number of UEs and frames */
521     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s (%u UEs, %u frames)",
522                cf_get_display_name(&cfile),
523                number_of_ues,
524                common_stats.all_frames);
525     gtk_window_set_title(GTK_WINDOW(mac_lte_stat_dlg_w), title);
526
527
528
529     /* For each row/UE/C-RNTI in the model */
530     for (tmp = list; tmp; tmp=tmp->next) {
531         if (tmp->iter_valid != TRUE) {
532             /* Add to list control if not drawn this UE before */
533             gtk_list_store_append(ues_store, &tmp->iter);
534             tmp->iter_valid = TRUE;
535         }
536
537         /* Set each column for this row */
538         gtk_list_store_set(ues_store, &tmp->iter,
539                            RNTI_COLUMN, tmp->stats.rnti,
540                            UL_FRAMES_COLUMN, tmp->stats.UL_frames,
541                            UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
542                            UL_CRC_ERRORS_COLUMN, tmp->stats.UL_CRC_errors,
543                            UL_RETX_FRAMES_COLUMN, tmp->stats.UL_retx_frames,
544                            DL_FRAMES_COLUMN, tmp->stats.DL_frames,
545                            DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
546                            DL_CRC_ERRORS_COLUMN, tmp->stats.DL_CRC_errors,
547                            DL_RETX_FRAMES_COLUMN, tmp->stats.DL_retx_frames,
548                            TABLE_COLUMN, tmp,
549                            -1);
550     }
551
552     /* If there is a UE selected, update its counters in details window */
553     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
554     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
555         mac_lte_ep_t *ep;
556
557         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
558         mac_lte_ue_details(ep);
559     }
560 }
561
562
563 /* What to do when a list item is selected/unselected */
564 static void mac_lte_select_cb(GtkTreeSelection *sel, gpointer data _U_)
565 {
566     mac_lte_ep_t   *ep;
567     GtkTreeModel   *model;
568     GtkTreeIter    iter;
569
570     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
571         /* Show details of selected UE */
572         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
573         mac_lte_ue_details(ep);
574     }
575     else {
576         mac_lte_ue_details(NULL);
577     }
578 }
579
580
581
582 /* Destroy the stats window */
583 static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
584 {
585     mac_lte_stat_t *hs = (mac_lte_stat_t *)data;
586
587     protect_thread_critical_region();
588     remove_tap_listener(hs);
589     unprotect_thread_critical_region();
590
591     if (mac_lte_stat_dlg_w != NULL) {
592         window_destroy(mac_lte_stat_dlg_w);
593         mac_lte_stat_dlg_w = NULL;
594     }
595     mac_lte_stat_reset(hs);
596     g_free(hs);
597 }
598
599
600 /* Create a new MAC LTE stats dialog */
601 static void mac_lte_stat_dlg_create(void)
602 {
603     mac_lte_stat_t    *hs;
604     GString       *error_string;
605     GtkWidget     *ues_scrolled_window;
606     GtkWidget     *bbox;
607     GtkWidget     *top_level_vbox;
608
609     GtkWidget     *common_row_hbox;
610     GtkWidget     *ues_vb;
611     GtkWidget     *selected_ue_hb;
612
613     GtkWidget     *selected_ue_vbox[NUM_CHANNEL_COLUMNS];
614     GtkWidget     *selected_ue_column_titles[5];
615
616     GtkWidget     *close_bt;
617     GtkWidget     *help_bt;
618
619     GtkListStore  *store;
620
621     GtkTreeView       *tree_view;
622     GtkCellRenderer   *renderer;
623     GtkTreeViewColumn *column;
624     GtkTreeSelection  *sel;
625     gchar title[256];
626     gint i, n;
627
628     /* Create dialog */
629     hs = g_malloc(sizeof(mac_lte_stat_t));
630     hs->ep_list = NULL;
631
632     /* Set title */
633     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Statistics: %s",
634                cf_get_display_name(&cfile));
635     mac_lte_stat_dlg_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, title, "LTE MAC Statistics");
636
637     /* Window size */
638     gtk_window_set_default_size(GTK_WINDOW(mac_lte_stat_dlg_w), 750, 300);
639
640     /* Will stack widgets vertically inside dlg */
641     top_level_vbox = gtk_vbox_new(FALSE, 3);       /* FALSE = not homogeneous */
642     gtk_container_add(GTK_CONTAINER(mac_lte_stat_dlg_w), top_level_vbox);
643
644     gtk_container_set_border_width(GTK_CONTAINER(top_level_vbox), 6);
645     gtk_widget_show(top_level_vbox);
646
647
648     /**********************************************/
649     /* Common Channel data                        */
650     /**********************************************/
651     mac_lte_stat_common_channel_lb = gtk_frame_new("Common Channel Data");
652
653     /* Will add BCH and PCH counters into one row */
654     common_row_hbox = gtk_hbox_new(FALSE, 0);
655     gtk_container_add(GTK_CONTAINER(mac_lte_stat_common_channel_lb), common_row_hbox);
656     gtk_container_set_border_width(GTK_CONTAINER(common_row_hbox), 5);
657
658     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_common_channel_lb, FALSE, FALSE, 0);
659
660     /* Create labels (that will hold label and counter value) */
661     mac_lte_common_bch_frames = gtk_label_new("BCH Frames:");
662     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_bch_frames), 0.0f, .5f);
663     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_bch_frames);
664     gtk_widget_show(mac_lte_common_bch_frames);
665
666     mac_lte_common_bch_bytes = gtk_label_new("BCH Bytes:");
667     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_bch_bytes), 0.0f, .5f);
668     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_bch_bytes);
669     gtk_widget_show(mac_lte_common_bch_bytes);
670
671     mac_lte_common_pch_frames = gtk_label_new("PCH Frames:");
672     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_pch_frames), 0.0f, .5f);
673     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_pch_frames);
674     gtk_widget_show(mac_lte_common_pch_frames);
675
676     mac_lte_common_pch_bytes = gtk_label_new("PCH Bytes:");
677     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_pch_bytes), 0.0f, .5f);
678     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_pch_bytes);
679     gtk_widget_show(mac_lte_common_pch_bytes);
680
681     mac_lte_common_rar_frames = gtk_label_new("RAR Frames:");
682     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_rar_frames), 0.0f, .5f);
683     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_rar_frames);
684     gtk_widget_show(mac_lte_common_rar_frames);
685
686     mac_lte_common_rar_entries = gtk_label_new("RAR Entries:");
687     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_rar_entries), 0.0f, .5f);
688     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_rar_entries);
689     gtk_widget_show(mac_lte_common_rar_entries);
690
691     /**********************************************/
692     /* UL/DL-SCH data                             */
693     /**********************************************/
694
695     mac_lte_stat_ues_lb = gtk_frame_new("UL/DL-SCH Data (0 UEs)");
696     ues_vb = gtk_vbox_new(FALSE, 0);
697     gtk_container_add(GTK_CONTAINER(mac_lte_stat_ues_lb), ues_vb);
698     gtk_container_set_border_width(GTK_CONTAINER(ues_vb), 5);
699
700     ues_scrolled_window = scrolled_window_new(NULL, NULL);
701     gtk_box_pack_start(GTK_BOX(ues_vb), ues_scrolled_window, TRUE, TRUE, 0);
702     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ues_scrolled_window),
703                                         GTK_SHADOW_IN);
704
705     /* Create the table of UE data */
706     store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT,
707                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,  /* UL */
708                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,  /* DL */
709                                G_TYPE_POINTER);
710     hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
711     gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
712     g_object_unref(G_OBJECT(store));
713
714     tree_view = hs->ue_table;
715     gtk_tree_view_set_headers_visible(tree_view, TRUE);
716     gtk_tree_view_set_headers_clickable(tree_view, TRUE);
717
718     /* Create the titles for each column of the per-UE table */
719     for (i = 0; i < TABLE_COLUMN; i++) {
720         renderer = gtk_cell_renderer_text_new();
721         column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
722                                                           "text", i, NULL);
723         gtk_tree_view_column_set_sort_column_id(column, i);
724
725         if (i == 0) {
726             /* Expand first column (RNTI, which is Key) */
727             gtk_tree_view_column_set_expand(column, TRUE);
728         } else {
729             /* For other columns, set all of the free space to be on the left */
730             g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
731         }
732         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
733         gtk_tree_view_column_set_resizable(column, TRUE);
734         gtk_tree_view_append_column(tree_view, column);
735     }
736
737     /* Set callback function for selecting a row in the UE table */
738     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
739     gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
740     g_signal_connect(sel, "changed", G_CALLBACK(mac_lte_select_cb), hs);
741
742     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_ues_lb, TRUE, TRUE, 0);
743
744
745     /**********************************************/
746     /* Details of selected UE                     */
747     /**********************************************/
748
749     mac_lte_stat_selected_ue_lb = gtk_frame_new("Selected UE details");
750
751     selected_ue_hb = gtk_hbox_new(FALSE, 6);
752     gtk_container_add(GTK_CONTAINER(mac_lte_stat_selected_ue_lb), selected_ue_hb);
753     gtk_container_set_border_width(GTK_CONTAINER(selected_ue_hb), 5);
754
755     /********************************/
756     /* First (row titles) column    */
757     selected_ue_vbox[0] = gtk_vbox_new(FALSE, 0);
758     gtk_container_add(GTK_CONTAINER(selected_ue_hb), selected_ue_vbox[0]);
759
760     selected_ue_column_titles[0] = gtk_label_new("");
761     gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[0]), 0.0f, 0.0f);
762     gtk_container_add(GTK_CONTAINER(selected_ue_vbox[0]), selected_ue_column_titles[0]);
763
764     for (n=1; n < 5; n++) {
765         selected_ue_column_titles[n] = gtk_label_new(selected_ue_row_names[n-1]);
766         gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[n]), 0.0f, 0.0f);
767         gtk_container_add(GTK_CONTAINER(selected_ue_vbox[0]), selected_ue_column_titles[n]);
768         gtk_widget_show(selected_ue_column_titles[n]);
769     }
770
771
772     /*************************/
773     /* Other columns         */
774     for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
775         selected_ue_vbox[i] = gtk_vbox_new(FALSE, 0);
776         gtk_container_add(GTK_CONTAINER(selected_ue_hb), selected_ue_vbox[i]);
777
778         /* Channel title */
779         selected_ue_column_entry[i][0] = gtk_label_new(channel_titles[i-1]);
780         gtk_misc_set_alignment(GTK_MISC(selected_ue_column_entry[i][0]), 0.5f, 0.0f);
781         gtk_container_add(GTK_CONTAINER(selected_ue_vbox[i]), selected_ue_column_entry[i][0]);
782
783
784         /* Counts for this channel */
785         for (n=1; n < 5; n++) {
786             selected_ue_column_entry[i][n] = gtk_label_new("0");
787             gtk_misc_set_alignment(GTK_MISC(selected_ue_column_entry[i][n]), 1.0f, 0.0f);
788             gtk_container_add(GTK_CONTAINER(selected_ue_vbox[i]), selected_ue_column_entry[i][n]);
789             gtk_widget_show(selected_ue_column_entry[i][n]);
790         }
791     }
792
793     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_selected_ue_lb, FALSE, FALSE, 0);
794
795
796     /**********************************************/
797     /* Register the tap listener                  */
798     /**********************************************/
799
800     error_string = register_tap_listener("mac-lte", hs, NULL, 0,
801                                          mac_lte_stat_reset,
802                                          mac_lte_stat_packet,
803                                          mac_lte_stat_draw);
804     if (error_string) {
805         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
806         g_string_free(error_string, TRUE);
807         g_free(hs);
808         return;
809     }
810
811
812     /************************************/
813     /* Button row.                      */
814     /************************************/
815
816     bbox = dlg_button_row_new (GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
817     gtk_box_pack_end (GTK_BOX(top_level_vbox), bbox, FALSE, FALSE, 0);
818
819     /* Add the close button */
820     close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
821     window_set_cancel_button(mac_lte_stat_dlg_w, close_bt, window_cancel_button_cb);
822
823     help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
824     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_LTE_MAC_TRAFFIC_DIALOG);
825
826     /* Set callbacks */
827     g_signal_connect(mac_lte_stat_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
828     g_signal_connect(mac_lte_stat_dlg_w, "destroy", G_CALLBACK(win_destroy_cb), hs);
829
830     /* Show the window */
831     gtk_widget_show_all(mac_lte_stat_dlg_w);
832     window_present(mac_lte_stat_dlg_w);
833
834     /* Retap */
835     cf_retap_packets(&cfile);
836     gdk_window_raise(mac_lte_stat_dlg_w->window);
837 }
838
839
840 /* Show window, creating if necessary */
841 static void mac_lte_stat_launch(GtkWidget *w _U_, gpointer data _U_)
842 {
843     if (mac_lte_stat_dlg_w) {
844         reactivate_window(mac_lte_stat_dlg_w);
845     } else {
846         mac_lte_stat_dlg_create();
847     }
848 }
849
850 /* Register this tap listener (need void on own so line register function found) */
851 void
852 register_tap_listener_mac_lte_stat(void)
853 {
854     register_stat_menu_item("_LTE MAC...", REGISTER_STAT_GROUP_TELEPHONY,
855                             mac_lte_stat_launch, NULL, NULL, NULL);
856 }
857