# 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. import os from tkinter import BooleanVar, filedialog, messagebox from tkinter.ttk import Button, Checkbutton, Combobox, Label, LabelFrame from ...utils.common import update_period from ...utils.datalogger import data_logger from ...utils.dataplotter import data_plotter from ...utils.layoutmanager import fill_parent, grid_span, padding from ...utils.subjectobserver import Observer from .channelwindow import ChannelWindow class RecordFrame(LabelFrame, Observer): def __init__(self, master=None, **kwargs): super().__init__(master, text="Record", **kwargs) self.curr_capture_count = 0 self.file_path = None self.user_specified_duration = 0 self.create_widgets() self.manage_layout() fill_parent(self) def create_widgets(self): hrs = [h for h in range(0, 24)] mins = [m for m in range(0, 60)] secs = [s for s in range(0, 60)] self.hr_c = Combobox(self, values=hrs, state="readonly", width=3) self.min_c = Combobox(self, values=mins, state="readonly", width=3) self.sec_c = Combobox(self, values=secs, state="readonly", width=3) self.hr_c.current(0) self.min_c.current(0) self.sec_c.current(0) self.hr_l = Label(self, text="hr") self.min_l = Label(self, text="min") self.sec_l = Label(self, text="sec") self.bg_v = BooleanVar() self.bg_cb = Checkbutton(self, text='background', var=self.bg_v) self.start_stop_b = Button(self, text="capture log...", command=self.start_stop_capturing) self.graph_b = Button(self, text="plot graph...", command=self.new_channel_window) def manage_layout(self): self.hr_c.grid(row=0, column=0, sticky="E", **grid_span) self.hr_l.grid(row=0, column=1, sticky="W", **grid_span) self.min_c.grid(row=0, column=2, sticky="E", **grid_span) self.min_l.grid(row=0, column=3, sticky="W", **grid_span) self.sec_c.grid(row=0, column=4, sticky="E", **grid_span) self.sec_l.grid(row=0, column=5, sticky="W", **grid_span) self.bg_cb.grid(row=0, column=6, **grid_span, **padding) self.start_stop_b.grid(row=0, column=7, **grid_span, **padding) self.graph_b.grid(row=0, column=8, **grid_span, **padding) def new_channel_window(self): self.channel_window = ChannelWindow() def is_capturing(self): return self.user_specified_duration > 0 and self.file_path def start_stop_capturing(self): if not self.is_capturing(): h_in_sec = int(self.hr_c.get()) * 3600 m_in_sec = int(self.min_c.get()) * 60 s_in_sec = int(self.sec_c.get()) self.user_specified_duration = h_in_sec + m_in_sec + s_in_sec # Early return if the user didn't provide capture duration if self.user_specified_duration <= 0: mb_title = "Unable to capture log" mb_message = "Please select capture duration." messagebox.showwarning(mb_title, mb_message) return # Early return if the user didn't provide the file path self.file_path = self.save_log() if not self.file_path: return # Iconify the entire window if "background" checkbutton checked if self.bg_v.get(): window = self.winfo_toplevel() window.iconify() else: self.finish_capturing() self.update_widgets() def finish_capturing(self): mb_title = "Finish capturing log" mb_message = f"Save captured log to {self.file_path}" messagebox.showinfo(mb_title, mb_message) self.curr_capture_count = 0 self.file_path = None self.user_specified_duration = 0 def save_log(self): # Pop up a file dialog to let user select file path to save log filedialog_title = "Select path to store captured log" file_path = filedialog.asksaveasfilename( title=filedialog_title, filetypes=data_logger.supported_file_types) # Early return if the user didn't provide the file path if not file_path: mb_title = "Unable to capture log" mb_message = "Please select file path to store captured log." messagebox.showwarning(mb_title, mb_message) return None # If the provided path already exist, tkinter will prompt a messagebox # to ask if the user want to override the file. Override oridinary file # with user's permission. if os.path.exists(file_path): os.remove(file_path) return file_path def update_widgets(self): widget_state = "readonly" start_stop_text = "capture log..." if self.is_capturing(): widget_state = "disabled" start_stop_text = "stop capturing" self.hr_c.configure(state=widget_state) self.min_c.configure(state=widget_state) self.sec_c.configure(state=widget_state) self.start_stop_b.configure(text=start_stop_text) def update_data(self, data): # Data plotter holds a copy of power data in order to plot dynamic # graph, so its data should be updated periodically. data_plotter.set_dyn_data(data) if not self.is_capturing() or not self.file_path: return if 0 == self.curr_capture_count: data_logger.dump_heading(data, self.file_path) # Append new data to the log file data_logger.append_data(data, self.file_path) target_count = self.user_specified_duration * 1000 / update_period self.curr_capture_count += 1 if self.curr_capture_count == target_count: self.finish_capturing() self.update_widgets()