# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: LicenseRef-NvidiaProprietary # # NVIDIA CORPORATION, its affiliates and licensors retain all intellectual # property and proprietary rights in and to this material, related # documentation and any modifications thereto. Any use, reproduction, # disclosure or distribution of this material and related documentation # without an express license agreement from NVIDIA CORPORATION or # its affiliates is strictly prohibited. from tkinter import BooleanVar, Toplevel, filedialog, messagebox from tkinter.ttk import Button, Checkbutton from ...utils.common import str_to_val from ...utils.datacenter import data_center from ...utils.datalogger import data_logger from ...utils.dataplotter import data_plotter from ...utils.layoutmanager import fill_parent, grid_span, padding class ChannelWindow(Toplevel): def __init__(self, master=None, **kwargs): super().__init__(master, **kwargs) self.title("Power channels") self.data = data_center.get_data() self.history_selected_channels = [] # 2d-list self.selecting_all = False self.is_alive = True self.is_plotting = False self.plottable_channel_nums = 0 self.count_plottable_channel_nums() self.create_widgets() self.manage_layout() self.bind("", lambda event: self.on_channel_window_destroy(event)) fill_parent(self) def count_plottable_channel_nums(self): for v in self.data.values(): val = str_to_val(str(v)) if val != None: # Do not use `if(val)` since 0 is valid value self.plottable_channel_nums += 1 def create_widgets(self): self.channel_v = [None] * self.plottable_channel_nums self.channel_cb = [None] * self.plottable_channel_nums self.select_b = Button(self, text="select all", command=self.select_deselect_all) self.plot_log_b = Button(self, text="plot from log...", command=self.plot_log) self.plot_dyn_b = Button(self, text="plot dynamically", command=self.plot_dynamic) i = 0 for key in self.data.keys(): val = str_to_val(str(self.data[key])) if val != None: # Do not use `if(val)` since 0 is valid value self.channel_v[i] = BooleanVar() self.channel_cb[i] = Checkbutton(self, text=f"{key[0]}-{key[1]}", var=self.channel_v[i]) i += 1 def manage_layout(self): max_r = 20 last_c = 0 for i in range(self.plottable_channel_nums): self.channel_cb[i].grid(row=i % max_r, column=i // max_r, **grid_span, **padding) last_c = row = i // max_r new_c = last_c + 1 self.select_b.grid(row=max_r - 3, column=new_c, **grid_span, **padding) self.plot_log_b.grid(row=max_r - 2, column=new_c, **grid_span, **padding) self.plot_dyn_b.grid(row=max_r - 1, column=new_c, **grid_span, **padding) def select_deselect_all(self): self.selecting_all = not(self.selecting_all) for i in range(self.plottable_channel_nums): self.channel_v[i].set(self.selecting_all) btn_text = "deselect all" if self.selecting_all else "select all" self.select_b.configure(text=btn_text) def store_selected_channels(self): curr_selected_channels = [] for i in range(self.plottable_channel_nums): if self.channel_v[i].get(): curr_selected_channels.append(self.channel_cb[i]["text"]) if not curr_selected_channels: mb_title = "Unable to submit channels" mb_message = "Channels cannot be empty!" \ " Please select interested channels." messagebox.showwarning(mb_title, mb_message) return False self.history_selected_channels.append(curr_selected_channels) return True def upload_log(self): # Pop up a file dialog to let user select file path to upload log filedialog_title = "Select path to upload captured log" file_path = filedialog.askopenfilename( title=filedialog_title, filetypes=data_logger.supported_file_types) # Early return if user did not provide file path if not file_path: mb_title = "Unable to upload captured log" mb_message = "Please select file path to upload captured log." messagebox.showwarning(mb_title, mb_message) return file_path def plot_log(self): is_channel_selected = self.store_selected_channels() if not is_channel_selected: return log_path = self.upload_log() if not log_path: return if not self.history_selected_channels[-1]: mb_title = "Unable to plot captured log" mb_message = "Please select channels to plot log first." messagebox.showwarning(mb_title, mb_message) return # Plot the log with the selected channels selected_data = [None] * len(self.history_selected_channels[-1]) for i, channel in enumerate(self.history_selected_channels[-1]): extracted_data = data_logger.read_one_column(log_path, channel) if extracted_data: selected_data[i] = extracted_data # Handle unknown or corrupted log file if not any(selected_data): mb_title = "Unknown or incorrectly formatted log file" mb_message = "Please check if the uploaded log file is right." messagebox.showwarning(mb_title, mb_message) return data_plotter.plot_static(selected_data, self.history_selected_channels[-1]) def plot_dynamic(self): if not self.is_plotting: self.start_plotting_dyn() else: self.stop_plotting_dyn() def start_plotting_dyn(self): is_channel_selected = self.store_selected_channels() if is_channel_selected: self.is_plotting = True self.plot_dyn_b.configure(text="stop plotting") # Pass stop_plotting_dyn as a argument to handle the situation # where the user closes the graph window before pressing the "stop # plotting" button data_plotter.plot_dynamic(self.history_selected_channels[-1], self.stop_plotting_dyn) def stop_plotting_dyn(self): if self.is_alive: self.is_plotting = False self.plot_dyn_b.configure(text="plot dynamically") data_plotter.stop_dyn_plot() def on_channel_window_destroy(self, event): if event.widget == self: self.is_alive = False