import tkinter as tk from tkinter import filedialog, messagebox, ttk, scrolledtext from view_parameters import ViewParametersDialog import struct import os import logging from logger import logger # Use the centralized logger # Create a logger # logger = logging.getLogger(__name__) class FlashWindow: def __init__(self, master, main_window): try: logger.info("Initializing FlashWindow") # Validate input if master is None: raise ValueError("Master window cannot be None") # Store references self.parent = master self.main_window = main_window # Referência à janela principal # Create window self.window = tk.Toplevel(master) self.window.title("Flash File - EDC15") self.window.geometry("800x600") # Minimizar janela principal quando abrir Flash self.main_window.iconify() # Configurar para restaurar janela principal quando fechar self.window.protocol("WM_DELETE_WINDOW", self.on_close) # Add a frame to the new window self.flash_frame = ttk.Frame(self.window) self.flash_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) # Create buttons frame self.buttons_frame = ttk.Frame(self.flash_frame) self.buttons_frame.pack(fill=tk.X, pady=(0, 10)) # Add Open and Save buttons ttk.Button(self.buttons_frame, text="Open File", command=self.open_file).pack(side=tk.LEFT, padx=5) ttk.Button(self.buttons_frame, text="Save File", command=self.save_file).pack(side=tk.LEFT, padx=5) ttk.Button(self.buttons_frame, text="Parâmetros", command=self.show_parameters).pack(side=tk.LEFT, padx=5) # Botão para alternar entre Hexa e Decimal self.btn_view_mode = ttk.Button(self.buttons_frame, text="Hexa", command=self.toggle_view_mode) self.btn_view_mode.pack(side=tk.LEFT, padx=5) # Botão 2D self.btn_2d_view = ttk.Button(self.buttons_frame, text="2D", command=self.open_2d_graph) self.btn_2d_view.pack(side=tk.LEFT, padx=5) # File path label self.file_path = tk.StringVar() self.file_path_label = ttk.Label(self.flash_frame, textvariable=self.file_path, wraplength=780) self.file_path_label.pack(fill=tk.X, pady=5) # Create text area for binary content self.content_frame = ttk.LabelFrame(self.flash_frame, text="Binary Content") self.content_frame.pack(fill=tk.BOTH, expand=True, pady=5) self.text_area = scrolledtext.ScrolledText(self.content_frame, wrap=tk.WORD, width=80, height=20) self.text_area.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.text_area.config(font=('Courier', 10)) # Store binary data and view parameters self.binary_data = None self.view_params = { 'first_cell': '0000F0', 'offset': 0, 'columns': 16, 'hex_view': False, 'show_diff': True, 'value_type': '8bit', 'address_type': '8bit' } logger.info("FlashWindow initialized successfully") except Exception as e: logger.error(f"Error initializing FlashWindow: {e}", exc_info=True) messagebox.showerror("Initialization Error", str(e)) if hasattr(self, 'window'): self.window.destroy() def format_value(self, data, start_idx, value_type, hex_view): try: # Primeiro, garantir que temos bytes suficientes if value_type == '8bit' and len(data) < 1: return "?" * (2 if hex_view else 3) elif value_type == '16bit' and len(data) < 2: return "?" * (4 if hex_view else 5) elif (value_type == '32bit' or value_type == 'float') and len(data) < 4: return "?" * (8 if hex_view else 10) # Agora processar o valor if value_type == '8bit': value = data[0] if hex_view: return f"{value:02X}" return f"{value:03d}" elif value_type == '16bit': value = struct.unpack('>H', data[:2])[0] # big-endian if hex_view: return f"{value:04X}" return f"{value:05d}" elif value_type == '32bit': value = struct.unpack('>I', data[:4])[0] # big-endian if hex_view: return f"{value:08X}" return f"{value:010d}" elif value_type == 'float': value = struct.unpack('>f', data[:4])[0] # big-endian return f"{value:10.4f}" except (IndexError, struct.error) as e: return "?" * (2 if hex_view else 3) def get_value_size(self, value_type): if value_type == '8bit': return 1 elif value_type == '16bit': return 2 else: # 32bit ou float return 4 def show_parameters(self): dialog = ViewParametersDialog(self.window, self.view_params) result = dialog.show() if result: self.view_params = result self.display_binary_data() def open_file(self): file_path = filedialog.askopenfilename( title="Select Binary File", filetypes=[ ("Binary files", "*.bin"), ("All files", "*.*") ] ) if file_path: self.file_path.set(f"Selected file: {file_path}") try: with open(file_path, 'rb') as f: self.binary_data = f.read() self.display_binary_data() except Exception as e: messagebox.showerror("Error", f"Error reading file: {str(e)}") def display_binary_data(self): if self.binary_data: self.text_area.delete('1.0', tk.END) # Get parameters bytes_per_row = self.view_params['columns'] start_offset = self.view_params['offset'] hex_view = self.view_params['hex_view'] value_type = self.view_params['value_type'] # Update frame title mode_text = "Hexadecimal" if hex_view else "Decimal" value_text = f"{value_type} values" if value_type == 'float': value_text = "Floating point values" self.content_frame.configure(text=f"Binary Content - {mode_text} ({value_text})") # Calculate display range display_data = self.binary_data[start_offset:] # Get the size of each value based on type value_size = self.get_value_size(value_type) values_per_row = bytes_per_row // value_size for i in range(0, len(display_data), bytes_per_row): # Format offset (from the first_cell value) base_offset = int(self.view_params['first_cell'], 16) current_offset = base_offset + i offset = f"{current_offset:08X}" # Get row data row_data = display_data[i:i + bytes_per_row] # Format values values = [] ascii_values = [] # Process each value in the row for j in range(0, len(row_data), value_size): value_data = row_data[j:j + value_size] if len(value_data) == value_size: # Format the value according to type value_str = self.format_value(value_data, j, value_type, hex_view) values.append(value_str) # ASCII representation (only for 8-bit values) if value_type == '8bit': b = value_data[0] ascii_values.append(chr(b) if 32 <= b <= 126 else '.') else: ascii_values.extend(['.' for _ in range(value_size)]) # Join values and ASCII values_part = " ".join(values) ascii_part = "".join(ascii_values) # Add the line to display line = f"{offset}: {values_part} | {ascii_part}\n" self.text_area.insert(tk.END, line) self.text_area.see('1.0') # Scroll to top def save_file(self): if not self.binary_data: messagebox.showwarning("Warning", "No data to save. Please open a file first.") return file_path = filedialog.asksaveasfilename( title="Save Binary File", defaultextension=".bin", filetypes=[ ("Binary files", "*.bin"), ("All files", "*.*") ] ) if file_path: try: with open(file_path, 'wb') as f: f.write(self.binary_data) self.file_path.set(f"File saved to: {file_path}") except Exception as e: messagebox.showerror("Error", f"Error saving file: {str(e)}") def open_2d_graph(self): try: # Ensure binary data is available if not hasattr(self, 'binary_data') or self.binary_data is None: logger.warning("No binary data available to plot graph") messagebox.showwarning("Graph Error", "No binary data available to plot.") return # Import BinaryGraphWindow dynamically to avoid circular imports from binary_graph import BinaryGraphWindow # Convert binary data to byte values if not already done # Ensure we're passing a list of integers byte_values = [int(byte) for byte in self.binary_data] # Open binary graph window graph_window = BinaryGraphWindow(self.window, byte_values) logger.info("Binary graph window opened successfully") except ImportError as e: logger.error(f"Failed to import BinaryGraphWindow: {e}") messagebox.showerror("Import Error", "Could not load graph module.") except Exception as e: logger.error(f"Error opening binary graph: {e}", exc_info=True) messagebox.showerror("Graph Error", f"Could not open graph: {e}") def toggle_view_mode(self): # Alternar entre hexadecimal e decimal current_mode = self.view_params.get('hex_view', False) self.view_params['hex_view'] = not current_mode # Atualizar texto do botão self.btn_view_mode.config(text="Decimal" if current_mode else "Hexa") # Redesenhar dados self.display_binary_data() def on_close(self): # Restaurar janela principal self.main_window.deiconify() # Fechar janela Flash self.window.destroy()