# power_constant_module.py
# Versão: 2.6 (Com entrada de potência configurável e validação corrigida)
# Data: 18/08/2025
# Descrição: Módulo 100% standalone, com gerenciamento de porta otimizado, método de leitura de RSSI corrigido, 
# potência configurável, plotagem de -70 dBm quando não há tags detectadas e validação de entrada corrigida.

import tkinter as tk
from tkinter import ttk, messagebox
import queue
import threading
import time
import os
import ctypes
import struct
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
from src.core.port_manager import get_port_manager
from .i18n import get_translator, t

try:
    matplotlib.use('TkAgg')
except Exception:
    matplotlib.use('Agg')

# --- BLOCO DE CONTROLE DE HARDWARE EMBUTIDO ---

DLL_NAME = "UHFRFID.dll"
try:
    dll_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), DLL_NAME)
    rfid_sdk = ctypes.CDLL(dll_path)
    rfid_sdk.UHF_RFID_Open.argtypes = [ctypes.c_ubyte, ctypes.c_int]; rfid_sdk.UHF_RFID_Open.restype = ctypes.c_int
    rfid_sdk.UHF_RFID_Close.argtypes = [ctypes.c_ubyte]; rfid_sdk.UHF_RFID_Close.restype = ctypes.c_int
    rfid_sdk.UHF_RFID_Set.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_uint, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint)]; rfid_sdk.UHF_RFID_Set.restype = ctypes.c_int
    HARDWARE_AVAILABLE = True
except (OSError, AttributeError):
    rfid_sdk = None
    HARDWARE_AVAILABLE = False

# COM_PORT = 4 ### ALTERADO: Removido
BAUD_RATE = 115200
RFID_CMD_SET_TXPOWER = 0x10
RFID_CMD_SET_FREQ_TABLE = 0x14
RFID_CMD_INV_TAG = 0x80
RFID_CMD_GET_RSSIVALU = 0x64 # Não mais usado para leitura principal
RFID_CMD_STOP_INVENTORY = 0x8C
RFID_CMD_SET_CW_STATUS = 0x24
RFID_CMD_SET_REGION = 0x2C
RFID_CMD_GET_TEMPERATURE = 0x34
RFID_CMD_GET_PORT_LOSS = 0x32
TEMPERATURE_LIMIT = 50.0
REFLECTED_POWER_LIMIT = 10.0  # dBm - Potência refletida máxima aceitável

# Tabela para conversão ADC -> RSSI
RxAdcTable = [
    0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0005, 0x0007, 0x000B, 0x0010, 0x0116, 0x011D, 0x0126,
    0x0131, 0x013E, 0x024C, 0x0260, 0x0374, 0x048B, 0x05A5, 0x06C3, 0x08E6, 0x09FF, 0x0BFF, 0x0EFF,
    0x10FF, 0x14FF, 0x17FF, 0x1CFF, 0x21FF, 0x26FF, 0x2DFF, 0x34FF, 0x3CFF, 0x46FF, 0x50FF, 0x5DFF,
    0x6AFF, 0x7AFF, 0x8BFF, 0x9EFF, 0xB4FF, 0xCCFF, 0xE7FF, 0xFFFF
]

class TagInfo:
    def __init__(self, epc, rssi):
        self.epc = epc; self.rssi = rssi
    def __repr__(self):
        return f"Tag(EPC={self.epc}, RSSI={self.rssi}dBm)"

# --- FIM DO BLOCO DE CONTROLE DE HARDWARE ---

class PowerConstantModule(tk.Frame):
    ### ALTERADO: Adicionado com_port=4 ###
    def __init__(self, parent, app_shell=None, demo_mode=False, com_port=4):
        print(f"🚀 PowerConstantModule: INICIANDO CONSTRUÇÃO DO MÓDULO")
        print(f"🚀 PowerConstantModule: app_shell: {app_shell}")
        print(f"🚀 PowerConstantModule: demo_mode: {demo_mode}")
        print(f"🚀 PowerConstantModule: com_port: {com_port}")
        super().__init__(parent)
        self.parent = parent
        self.app_shell = app_shell
        self.demo_mode = demo_mode
        self.com_port = com_port ### NOVO: Armazena a porta COM ###
        self.com_port_lock = threading.Lock()
        self.port_manager = get_port_manager()
        self.translator = get_translator()
        self._widget_refs = {}  # Para armazenar referências aos widgets para atualização de idioma

        self.frequency = 915.0
        self.power = 15.0
        self.samples_per_point = 3
        self.pause_between_samples = 0.01
        self.pause_between_points = 0.1
        
        self.test_running = False
        self.test_paused = False  # NOVO: Controle de pausa
        self.data_queue = queue.Queue()
        self.time_data = []
        self.rssi_data = []
        self.test_start_time = None  # NOVO: Tempo de início do teste
        self.paused_time = 0  # NOVO: Tempo total pausado
        self.pause_start_time = None  # NOVO: Momento do início da pausa
        
        # NOVO: Para controle de tags detectadas
        self.previous_epcs = set()  # EPCs do ciclo anterior
        self.current_epcs = set()   # EPCs do ciclo atual
        
        # Inicializa limites da licença com valores padrão (modo browser)
        # CORREÇÃO: Usa valores mais restritivos como padrão para forçar atualização
        self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
        
        # DEBUG: Mostra estado inicial
        
        # CORREÇÃO DEFINITIVA: Força o uso dos limites corretos da licença
        if app_shell:
            try:
                # Tenta obter limites da licença ativa
                if hasattr(app_shell, '_calculate_license_limits'):
                    valid_lics = ["PowerConstant", "FastChecker"]
                    license_limits = app_shell._calculate_license_limits(valid_lics)
                    if license_limits.get('is_licensed', False):
                        self.license_limits = license_limits
                    else:
                        # Se não há licença, usa limites restritivos
                        self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
                elif hasattr(app_shell, 'license_limits'):
                    self.license_limits = app_shell.license_limits
                else:
                    # Fallback: usa limites restritivos
                    self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
            except Exception as e:
                # Em caso de erro, usa limites restritivos
                self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
        else:
            # Sem app_shell, usa limites restritivos
            self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
        
        # DEBUG: Mostra estado final
        
        self.setup_ui()
        
        # NOVO: Atualiza limites de licença após setup da UI
        self._update_license_limits()
        
        if not HARDWARE_AVAILABLE:
            messagebox.showerror(t('constant_power.dll_error'), t('constant_power.dll_error_msg'))
            self.start_button.config(state="disabled")
        else:
            self.after(100, lambda: self._initial_reader_cleanup())
        
        self.process_data_queue()
        
        # Timer para verificar EPCs periodicamente
        self.after(1000, self._check_epc_timeout)
        
        # REQUISITOS: Captura porta + Reset ao entrar
        self._initialize_hardware_on_enter()

    def _initialize_hardware_on_enter(self):
        """REQUISITOS 1+4: Captura porta e reseta hardware - com preparação robusta"""
        if not HARDWARE_AVAILABLE or not rfid_sdk:
            return
        
        try:
            print(f"🔧 Constant Power: Inicializando hardware...")
            
            # CORREÇÃO: Fecha porta primeiro para garantir estado limpo
            try:
                rfid_sdk.UHF_RFID_Close(self.com_port)
                time.sleep(0.1)  # Delay para garantir que a porta foi fechada
            except:
                pass  # Ignora erro se porta já estiver fechada
            
            # CORREÇÃO: Tenta abrir porta com retry (até 3 tentativas)
            port_opened = False
            for attempt in range(3):
                if rfid_sdk.UHF_RFID_Open(self.com_port, BAUD_RATE) == 0:
                    port_opened = True
                    print(f"✅ Constant Power: Porta COM{self.com_port} capturada (tentativa {attempt + 1})")
                    break
                else:
                    if attempt < 2:
                        # Tenta fechar novamente antes da próxima tentativa
                        try:
                            rfid_sdk.UHF_RFID_Close(self.com_port)
                        except:
                            pass
                        time.sleep(0.3)  # Delay entre tentativas
            
            if port_opened:
                # REQUISITO 3: Para comandos ativos
                out_buf = ctypes.create_string_buffer(64)
                out_len = ctypes.c_uint(0)
                rfid_sdk.UHF_RFID_Set(RFID_CMD_STOP_INVENTORY, None, 0, out_buf, ctypes.byref(out_len))
                
                # Fecha porta (será reaberta quando necessário)
                rfid_sdk.UHF_RFID_Close(self.com_port)
                
                print(f"✅ Constant Power: Hardware inicializado (sem bip)")
            else:
                print(f"⚠️ Constant Power: Falha ao capturar porta após 3 tentativas")
                
        except Exception as e:
            print(f"⚠️ Constant Power: Erro ao inicializar hardware: {e}")
    
    def get_temperature(self):
        """Lê a temperatura do hardware RFID"""
        if not HARDWARE_AVAILABLE or not rfid_sdk:
            return None
        try:
            output_buffer = ctypes.create_string_buffer(64)
            output_len = ctypes.c_uint(0)
            status = rfid_sdk.UHF_RFID_Set(RFID_CMD_GET_TEMPERATURE, None, 0, output_buffer, ctypes.byref(output_len))
            if status == 0 and output_len.value >= 3:
                temp_val = struct.unpack('>h', output_buffer.raw[1:3])[0]
                return temp_val / 100.0
        except Exception as e:
            print(f"⚠️ Erro ao ler temperatura: {e}")
        return None

    def get_reflected_power(self):
        """Lê a Potência Refletida (dBm) via RFID_CMD_GET_PORT_LOSS"""
        if not HARDWARE_AVAILABLE or not rfid_sdk:
            print(f"⚠️ Constant Power: Hardware não disponível para ler potência refletida")
            return None
        
        # CRÍTICO: Abre porta antes de ler
        print(f"🔍 Constant Power: Abrindo porta COM{self.com_port} para ler potência refletida...")
        if not self.port_manager.acquire_port("PowerConstant", timeout=2.0):
            print(f"❌ Constant Power: Timeout ao adquirir porta COM{self.com_port}")
            return None
        
        try:
            # CORREÇÃO: Fechar porta primeiro para garantir estado limpo
            try:
                rfid_sdk.UHF_RFID_Close(self.com_port)
                time.sleep(0.05)  # Pequeno delay para garantir que a porta foi fechada
            except:
                pass  # Ignora erro se porta já estiver fechada
            
            # Tentar abrir a porta (com retry)
            port_opened = False
            for attempt in range(3):
                if rfid_sdk.UHF_RFID_Open(self.com_port, BAUD_RATE) == 0:
                    port_opened = True
                    print(f"✅ Constant Power: Porta COM{self.com_port} aberta (tentativa {attempt + 1})")
                    break
                else:
                    if attempt < 2:
                        time.sleep(0.1)  # Aguarda antes de tentar novamente
            
            if not port_opened:
                print(f"❌ Constant Power: Falha ao abrir porta COM{self.com_port} após 3 tentativas")
                self.port_manager.release_port("PowerConstant")
                return None
            
            # Ler potência refletida
            output_buffer = ctypes.create_string_buffer(64)
            output_len = ctypes.c_uint(0)
            status = rfid_sdk.UHF_RFID_Set(RFID_CMD_GET_PORT_LOSS, b'', 0, output_buffer, ctypes.byref(output_len))
            print(f"🔍 Constant Power: Status comando 0x32: {status}, Tamanho resposta: {output_len.value}")
            
            if status == 0 and output_len.value >= 3:
                adc_value = struct.unpack('>H', output_buffer.raw[1:3])[0]
                reflected_power_dbm = -25 + next((i for i, val in enumerate(RxAdcTable) if adc_value <= val), len(RxAdcTable) - 1)
                print(f"📊 Constant Power: ADC={adc_value}, Potência Refletida={reflected_power_dbm:.1f} dBm")
                return reflected_power_dbm
        except Exception as e:
            print(f"⚠️ Constant Power: Erro ao ler Potência Refletida: {e}")
        finally:
            try:
                rfid_sdk.UHF_RFID_Close(self.com_port)
            except:
                pass
            self.port_manager.release_port("PowerConstant")
            print(f"🔍 Constant Power: Porta COM{self.com_port} fechada")
        return None

    def destroy(self):
        """REQUISITOS 2+3+4: Libera porta, para comandos, reseta"""
        try:
            print(f"🔄 Constant Power: Iniciando cleanup...")
            
            if hasattr(self, 'test_running') and self.test_running:
                self.test_running = False
            
            if HARDWARE_AVAILABLE and rfid_sdk:
                try:
                    if self.port_manager.acquire_port("PowerConstant", timeout=2.0):
                        try:
                            # CORREÇÃO: Fechar porta primeiro para garantir estado limpo
                            try:
                                rfid_sdk.UHF_RFID_Close(self.com_port)
                                time.sleep(0.05)  # Pequeno delay para garantir que a porta foi fechada
                            except:
                                pass  # Ignora erro se porta já estiver fechada
                            
                            # Tentar abrir a porta (com retry)
                            port_opened = False
                            for attempt in range(3):
                                if rfid_sdk.UHF_RFID_Open(self.com_port, BAUD_RATE) == 0:
                                    port_opened = True
                                    break
                                else:
                                    if attempt < 2:
                                        time.sleep(0.1)  # Aguarda antes de tentar novamente
                            
                            if port_opened:
                                out_buf = ctypes.create_string_buffer(64)
                                out_len = ctypes.c_uint(0)
                                rfid_sdk.UHF_RFID_Set(RFID_CMD_STOP_INVENTORY, None, 0, out_buf, ctypes.byref(out_len))
                                rfid_sdk.UHF_RFID_Close(self.com_port)
                                print(f"✅ Constant Power: Comandos parados, porta liberada (sem bip)")
                        finally:
                            self.port_manager.release_port("PowerConstant")
                except Exception as e:
                    print(f"⚠️ Constant Power: Erro: {e}")
            
            print(f"✅ Constant Power: Cleanup concluído")
        except:
            pass
        
        try:
            super().destroy()
        except:
            pass
    
    def _update_license_limits(self):
        """Atualiza os limites de licença e a interface visual"""
        if self.app_shell and hasattr(self.app_shell, '_calculate_license_limits'):
            try:
                # Usa o mesmo padrão do Threshold que funciona corretamente
                license_limits = self.app_shell._calculate_license_limits(["PowerConstant", "FastChecker"])
                if license_limits.get('is_licensed', False):
                    self.license_limits = license_limits
                    print(f"🔄 PowerConstant: Limites atualizados - Freq: {license_limits.get('min_freq')}-{license_limits.get('max_freq')}MHz, Power: {license_limits.get('min_power')}-{license_limits.get('max_power')}dBm")
                    print(f"🔄 PowerConstant: Licença ativa atualizada: '{license_limits.get('license_name', 'N/A')}'")
                    
                    # Atualiza labels visuais se existirem
                    if hasattr(self, 'freq_limits_label'):
                        min_freq = self.license_limits.get('min_freq', 800)
                        max_freq = self.license_limits.get('max_freq', 1000)
                        self.freq_limits_label.config(text=f"({min_freq}-{max_freq})")
                        
                    if hasattr(self, 'limits_label'):
                        min_power = self.license_limits.get('min_power', 5)
                        max_power = self.license_limits.get('max_power', 20)
                        self.limits_label.config(text=f"({min_power}-{max_power})")
                        
                else:
                    print("🔄 PowerConstant: Nenhuma licença ativa encontrada durante atualização")
            except Exception as e:
                pass
    
    def _update_license_limits_from_app_shell(self):
        """CORREÇÃO DEFINITIVA: Atualiza limites de licença a partir do app_shell"""
        try:
            if not hasattr(self, 'app_shell') or self.app_shell is None:
                self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
                self._update_ui_limits()
                return
            
            # SEMPRE tenta obter limites da licença ativa
            valid_lics = ["PowerConstant", "FastChecker"]
            license_limits = self.app_shell._calculate_license_limits(valid_lics)
            
            if license_limits.get('is_licensed', False):
                self.license_limits = license_limits
            else:
                # Se não há licença, usa limites restritivos
                self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
            
            self._update_ui_limits()
            
        except Exception as e:
            # Em caso de erro, usa limites restritivos
            self.license_limits = {'min_freq': 800, 'max_freq': 1000, 'min_power': 5, 'max_power': 20, 'is_licensed': False}
            self._update_ui_limits()
    
    def _update_ui_limits(self):
        """Atualiza os limites na interface visual"""
        try:
            # Atualiza labels visuais se existirem
            if hasattr(self, 'freq_limits_label'):
                min_freq = self.license_limits.get('min_freq', 800)
                max_freq = self.license_limits.get('max_freq', 1000)
                self.freq_limits_label.config(text=f"({min_freq}-{max_freq})")
                
            if hasattr(self, 'limits_label'):
                min_power = self.license_limits.get('min_power', 5)
                max_power = self.license_limits.get('max_power', 20)
                self.limits_label.config(text=f"({min_power}-{max_power})")
                
        except Exception as e:
            pass
        
    def setup_ui(self):
        # Layout principal: barra lateral + área principal
        main_container = tk.Frame(self)
        main_container.pack(fill="both", expand=True, padx=5, pady=5)
        
        # Configuração do grid
        main_container.columnconfigure(1, weight=1)  # Área principal ocupa espaço restante
        main_container.rowconfigure(0, weight=1)
        
        # BARRA LATERAL (esquerda)
        self.sidebar = tk.Frame(main_container, width=300, bg='#f0f0f0')
        self.sidebar.grid(row=0, column=0, sticky="nsew", padx=(0, 5))
        self.sidebar.grid_propagate(False)  # Mantém largura fixa
        
        # ÁREA PRINCIPAL (direita)
        self.main_area = tk.Frame(main_container)
        self.main_area.grid(row=0, column=1, sticky="nsew")
        self.main_area.columnconfigure(0, weight=1)
        self.main_area.rowconfigure(0, weight=1)
        
        # Construir componentes da barra lateral
        self._build_sidebar()
        
        # Construir área principal
        self._build_main_area()

    def _build_sidebar(self):
        """Constrói a barra lateral com todas as seções"""
        # 1. Configuração do Teste
        self._build_test_config_section()
        
        # 2. Controles
        self._build_controls_section()

    def _build_test_config_section(self):
        """Seção de configuração do teste"""
        config_frame = tk.LabelFrame(self.sidebar, text=t('constant_power.test_config'), padx=10, pady=10, font=("Helvetica", 10))
        config_frame.pack(fill="x", padx=5, pady=5)
        self._widget_refs['config_frame'] = config_frame
        
        # Mensagem de modo browser dentro da Configuração do Teste
        try:
            if not hasattr(self, 'browser_frame'):
                self.browser_frame = tk.Frame(config_frame, bg='#f0f8ff')
                tk.Label(self.browser_frame, text="•", fg="blue", font=("Helvetica", 10), bg='#f0f8ff').pack(side='left', anchor='w')
                browser_mode_label = tk.Label(self.browser_frame, text=f" {t('constant_power.browser_mode')}", fg="blue", font=("Helvetica", 10), bg='#f0f8ff')
                browser_mode_label.pack(side='left', anchor='w')
                self._widget_refs['browser_mode_label'] = browser_mode_label
            if self.license_limits.get('is_licensed', False):
                self.browser_frame.pack_forget()
            else:
                self.browser_frame.pack(fill='x', pady=(0, 5))
        except Exception:
            pass
        
        # Frequência
        freq_frame = tk.Frame(config_frame)
        freq_frame.pack(fill="x", pady=2)
        freq_label = tk.Label(freq_frame, text=t('constant_power.frequency_mhz'))
        freq_label.pack(anchor="w")
        self._widget_refs['freq_label'] = freq_label
        
        freq_input_frame = tk.Frame(freq_frame)
        freq_input_frame.pack(fill="x", pady=(2, 0))
        
        self.freq_var = tk.StringVar(value=str(self.frequency))
        self.freq_entry = tk.Entry(freq_input_frame, textvariable=self.freq_var, width=10)
        self.freq_entry.pack(side="left")
        
        # Label dos limites da licença para frequência
        min_freq = self.license_limits.get('min_freq', 800)
        max_freq = self.license_limits.get('max_freq', 1000)
        self.freq_limits_label = tk.Label(freq_input_frame, text=f"({min_freq}-{max_freq})", 
                                         font=("Arial", 8), fg="blue")
        self.freq_limits_label.pack(side="left", padx=(2, 0))
        
        # Potência
        power_frame = tk.Frame(config_frame)
        power_frame.pack(fill="x", pady=2)
        power_label = tk.Label(power_frame, text=t('constant_power.power_dbm'))
        power_label.pack(anchor="w")
        self._widget_refs['power_label'] = power_label
        
        power_input_frame = tk.Frame(power_frame)
        power_input_frame.pack(fill="x", pady=(2, 0))
        
        self.power_var = tk.DoubleVar(value=self.power)
        self.power_entry = tk.Entry(power_input_frame, textvariable=self.power_var, width=10)
        self.power_entry.pack(side="left")
        
        # Label dos limites da licença para potência
        min_power = self.license_limits.get('min_power', 5)
        max_power = self.license_limits.get('max_power', 20)
        self.power_limits_label = tk.Label(power_input_frame, text=f"({min_power}-{max_power})", 
                                          font=("Arial", 8), fg="blue")
        self.power_limits_label.pack(side="left", padx=(2, 0))
        
        # Campos removidos - não são utilizados no código

    def _build_controls_section(self):
        """Seção de controles"""
        controls_frame = tk.LabelFrame(self.sidebar, text=t('constant_power.controls'), padx=10, pady=10, font=("Helvetica", 10))
        controls_frame.pack(fill="x", padx=5, pady=5)
        self._widget_refs['controls_frame'] = controls_frame
        
        # Botão de teste
        self.start_button = tk.Button(controls_frame, text=t('constant_power.test'), command=self.start_test, font=("Arial", 10))
        self.start_button.pack(fill="x", pady=2)
        self._widget_refs['start_button'] = self.start_button
        
        # Botão de parar
        self.stop_button = tk.Button(controls_frame, text=t('constant_power.stop'), command=self.stop_test, font=("Arial", 10, "bold"), state="disabled")
        self.stop_button.pack(fill="x", pady=2)
        self._widget_refs['stop_button'] = self.stop_button
        
        # Botão de limpar
        self.clear_button = tk.Button(controls_frame, text=t('constant_power.clear_graph'), command=self.clear_graph, font=("Arial", 10))
        self.clear_button.pack(fill="x", pady=2)
        self._widget_refs['clear_button'] = self.clear_button
    
    def refresh_language(self):
        """Atualiza todos os textos da interface quando o idioma é alterado"""
        try:
            # Atualiza títulos de frames
            if 'config_frame' in self._widget_refs:
                self._widget_refs['config_frame'].config(text=t('constant_power.test_config'))
            if 'controls_frame' in self._widget_refs:
                self._widget_refs['controls_frame'].config(text=t('constant_power.controls'))
            if 'graph_frame' in self._widget_refs:
                self._widget_refs['graph_frame'].config(text=t('constant_power.graph_title'))
            
            # Atualiza labels
            if 'freq_label' in self._widget_refs:
                self._widget_refs['freq_label'].config(text=t('constant_power.frequency_mhz'))
            if 'power_label' in self._widget_refs:
                self._widget_refs['power_label'].config(text=t('constant_power.power_dbm'))
            if 'browser_mode_label' in self._widget_refs:
                self._widget_refs['browser_mode_label'].config(text=f" {t('constant_power.browser_mode')}")
            
            # Atualiza botões
            if 'start_button' in self._widget_refs:
                # Só atualiza se não estiver desabilitado e em teste
                if self.start_button.cget('state') != 'disabled':
                    self._widget_refs['start_button'].config(text=t('constant_power.test'))
            if 'stop_button' in self._widget_refs:
                # Atualiza baseado no estado do botão
                current_text = self.stop_button.cget('text')
                if 'Pausar' in current_text or 'Pause' in current_text:
                    self.stop_button.config(text=t('constant_power.pause'))
                elif 'Continuar' in current_text or 'Resume' in current_text:
                    self.stop_button.config(text=t('constant_power.resume'))
                elif 'Parar' in current_text or 'Stop' in current_text:
                    self.stop_button.config(text=t('constant_power.stop'))
            if 'clear_button' in self._widget_refs:
                self._widget_refs['clear_button'].config(text=t('constant_power.clear_graph'))
        except Exception as e:
            print(f"⚠️ Erro ao atualizar idioma no Constant Power: {e}")

    def _build_main_area(self):
        """Constrói a área principal com gráfico"""
        # Área do gráfico
        self._build_graph_area()

    def _build_graph_area(self):
        """Constrói a área do gráfico"""
        graph_frame = tk.LabelFrame(self.main_area, text=t('constant_power.graph_title'), padx=10, pady=10, font=("Helvetica", 10))
        graph_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
        self._widget_refs['graph_frame'] = graph_frame
        graph_frame.columnconfigure(0, weight=1)
        graph_frame.rowconfigure(0, weight=1)
        
        self.fig = Figure(figsize=(10, 6), dpi=100)
        self.ax = self.fig.add_subplot(111)
        self.ax.set_xlabel("Tempo (s)")
        self.ax.set_ylabel("RSSI (dBm)")
        self.ax.grid(True, alpha=0.3)
        
        self.canvas = FigureCanvasTkAgg(self.fig, master=graph_frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky="nsew")

    def _initial_reader_cleanup(self):
        def cleanup_worker():
            print("PowerConstantModule: Executando limpeza silenciosa inicial...")
            with self.com_port_lock:
                ### ALTERADO: usa self.com_port ###
                if self.port_manager.acquire_port("PowerConstant", timeout=2.0):
                    acquired = True
                else:
                    acquired = False
                
                if acquired:
                    # CORREÇÃO: Fechar porta primeiro para garantir estado limpo
                    try:
                        rfid_sdk.UHF_RFID_Close(self.com_port)
                        time.sleep(0.05)  # Pequeno delay para garantir que a porta foi fechada
                    except:
                        pass  # Ignora erro se porta já estiver fechada
                    
                    # Tentar abrir a porta (com retry)
                    port_opened = False
                    for attempt in range(3):
                        if rfid_sdk.UHF_RFID_Open(self.com_port, BAUD_RATE) == 0:
                            port_opened = True
                            break
                        else:
                            if attempt < 2:
                                time.sleep(0.1)  # Aguarda antes de tentar novamente
                    
                    if port_opened:
                        try:
                            out_buf = ctypes.create_string_buffer(64)
                            out_len = ctypes.c_uint(0)
                            rfid_sdk.UHF_RFID_Set(RFID_CMD_STOP_INVENTORY, None, 0, out_buf, ctypes.byref(out_len))
                            rfid_sdk.UHF_RFID_Set(RFID_CMD_SET_CW_STATUS, ctypes.c_char_p(b'\x00'), 1, out_buf, ctypes.byref(out_len))
                            # CORREÇÃO: Status contextual baseado na licença
                            is_licensed = self.license_limits.get('is_licensed', False)
                            if is_licensed:
                                print("PowerConstantModule: Limpeza inicial concluída.")
                            else:
                                print("PowerConstantModule: Modo browser ativo.")
                        finally:
                            ### ALTERADO: usa self.com_port ###
                            try:
                                rfid_sdk.UHF_RFID_Close(self.com_port)
                            except:
                                pass
                            if acquired:
                                self.port_manager.release_port("PowerConstant")
                    else:
                        # Falha ao abrir porta - libera o port_manager
                        if acquired:
                            self.port_manager.release_port("PowerConstant")
        threading.Thread(target=cleanup_worker, daemon=True).start()

        

        
    def _update_power_entry_state(self):
        """Atualiza o estado da caixa de entrada de potência baseado no estado do teste"""
        if hasattr(self, 'power_entry'):
            if self.test_paused:
                # Quando pausado, permite edição
                self.power_entry.config(state='normal')
            else:
                # Quando rodando, bloqueia edição
                self.power_entry.config(state='disabled')
    
    def update_ui_state(self):
        """Atualiza o estado da UI baseado na licença"""
        try:
            is_licensed = self.license_limits.get('is_licensed', False)
            
            # Status baseado na licença
            
            if is_licensed:
                # Com licença, botões ficam habilitados (respeitando outras condições)
                if not self.test_running:
                    self.start_button.config(state='normal')
                self.clear_button.config(state='normal')
                
                # Campos de entrada habilitados com licença
                self.freq_entry.config(state='normal')
                if not self.test_running or self.test_paused:
                    self.power_entry.config(state='normal')
                    
            else:
                # Sem licença (modo browser): bloquear apenas ações que acionam o reader
                self.start_button.config(state='disabled')
                self.stop_button.config(state='disabled')
                self.clear_button.config(state='normal')  # Sempre permite limpar
                
                # Permitir edição de campos em modo browser
                self.freq_entry.config(state='normal')
                if not self.test_running or self.test_paused:
                    self.power_entry.config(state='normal')
                else:
                    self.power_entry.config(state='disabled')
                
        except Exception as e:
            pass
        

    
    def _update_epc_display(self, epcs):
        """Atualiza a caixa de exibição do EPC com as tags detectadas"""
        
        if hasattr(self, 'epc_text'):
            self.epc_text.config(state='normal')
            self.epc_text.delete(1.0, tk.END)
            
            if epcs:
                # Formata os EPCs detectados
                epc_text = f"Tags detectadas ({len(epcs)}):\n"
                for i, epc in enumerate(epcs, 1):
                    epc_text += f"{i}. {epc}\n"
                
                # Insere o texto
                self.epc_text.insert(tk.END, epc_text)
                
                # Aplica cor baseada no número de tags
                if len(epcs) > 1:
                    # Múltiplas tags = VERMELHO
                    self.epc_text.tag_add("multiple_tags", "1.0", "end")
                    self.epc_text.tag_config("multiple_tags", foreground="red")
                    print(f"🔴 Múltiplas tags detectadas ({len(epcs)}) - texto em VERMELHO")
                else:
                    # Uma tag ou sem tags = AZUL
                    self.epc_text.tag_add("single_tag", "1.0", "end")
                    self.epc_text.tag_config("single_tag", foreground="blue")
                    print(f"🔵 {len(epcs)} tag(s) detectada(s) - texto em AZUL")
            else:
                # Mostra mensagem quando não há tags
                self.epc_text.insert(tk.END, "Nenhuma tag detectada (-70 dBm plotado)")
            
            self.epc_text.config(state='disabled')
    
    def _sync_power_entry(self):
        """Sincroniza a caixa de entrada de potência com o valor atual"""
        if hasattr(self, 'power_var') and hasattr(self, 'power'):
            self.power_var.set(self.power)
        
        
    def start_test(self):
        if self.demo_mode:
            messagebox.showinfo(t('constant_power.demo_mode'), t('constant_power.demo_mode_msg'))
            return
        
        # PROTEÇÃO DE TEMPERATURA: Verifica antes de iniciar
        temp = self.get_temperature()
        if temp is not None and temp >= TEMPERATURE_LIMIT:
            messagebox.showerror(t('constant_power.safety_stop_temp'), t('constant_power.safety_stop_temp_msg').format(temp=temp, limit=TEMPERATURE_LIMIT), parent=self)
            return
        
        # PROTEÇÃO DE POTÊNCIA REFLETIDA: Verifica antes de iniciar
        print(f"🔍 Constant Power: Verificando potência refletida...")
        reflected_power = self.get_reflected_power()
        print(f"🔍 Constant Power: Potência Refletida lida = {reflected_power} dBm (Limite: {REFLECTED_POWER_LIMIT} dBm)")
        if reflected_power is not None and reflected_power > REFLECTED_POWER_LIMIT:
            messagebox.showerror(t('constant_power.reflected_power_high'), t('constant_power.reflected_power_high_msg').format(power=reflected_power, limit=REFLECTED_POWER_LIMIT), parent=self)
            print(f"❌ Constant Power: TESTE BLOQUEADO - Potência Refletida muito alta!")
            return
        else:
            print(f"✅ Constant Power: Potência Refletida OK - Teste permitido")
        
        # NOVO: Validação dos limites da licença
        if not self.license_limits.get('is_licensed', False):
            messagebox.showerror(t('constant_power.invalid_license'), t('constant_power.invalid_license_msg'), parent=self)
            return
            
        if not HARDWARE_AVAILABLE:
            messagebox.showerror(t('constant_power.hardware_unavailable'), t('constant_power.hardware_unavailable_msg'))
            return
        try:
            if self.test_running and not self.test_paused:
                # Se está rodando, pausa
                self.toggle_test()
                return
            
            self.frequency = float(self.freq_var.get())
            # SEMPRE usa a potência da caixa de entrada
            self.power = float(self.power_var.get())
            
            # DEBUG: Log dos valores lidos
            
            # CORREÇÃO: Validação da frequência contra múltiplas faixas da licença
            min_freq = self.license_limits.get('min_freq', 800)
            max_freq = self.license_limits.get('max_freq', 1000)
            
            # DEBUG: Mostra os limites atuais da licença para frequência
            
            # Validação contra múltiplas faixas
            freq_valid = False
            freq_ranges = self.license_limits.get('freq_ranges', [])
            excluded_ranges = self.license_limits.get('excluded_ranges', [])
            
            if freq_ranges:
                # Valida contra faixas específicas
                for i, (range_min, range_max) in enumerate(freq_ranges):
                    if range_min <= self.frequency <= range_max:
                        # Verifica se não está em uma faixa excluída
                        in_excluded = False
                        for excl_min, excl_max in excluded_ranges:
                            if excl_min <= self.frequency <= excl_max:
                                in_excluded = True
                                break
                        
                        if not in_excluded:
                            freq_valid = True
                            break
                        else:
                            pass
                    else:
                        pass
            else:
                # Fallback para validação simples
                freq_valid = (min_freq <= self.frequency <= max_freq)
            
            if not freq_valid:
                ranges_str = " ou ".join([f"{r[0]}-{r[1]} MHz" for r in freq_ranges]) if freq_ranges else f"{min_freq}-{max_freq} MHz"
                excluded_str = " e ".join([f"{r[0]}-{r[1]} MHz" for r in excluded_ranges]) if excluded_ranges else "nenhuma"
                messagebox.showerror(t('constant_power.freq_outside_license'), t('constant_power.freq_outside_license_msg').format(freq=self.frequency, allowed=ranges_str, excluded=excluded_str))
                return
            
            # CORREÇÃO: Validação da potência contra limites da licença
            min_power = self.license_limits.get('min_power', 5)
            max_power = self.license_limits.get('max_power', 20)  # CORREÇÃO: 20 em vez de 25
            
            # DEBUG: Mostra os limites atuais da licença
            
            if not (min_power <= self.power <= max_power):
                messagebox.showerror(t('constant_power.power_outside_license'), t('constant_power.power_outside_license_msg').format(power=self.power, min_power=min_power, max_power=max_power), parent=self)
                return
            else:
                pass
            
            # Se não está pausado, limpa os dados (novo teste)
            if not self.test_paused:
                self.time_data.clear(); self.rssi_data.clear()
                while not self.data_queue.empty(): self.data_queue.get()
                self.test_start_time = time.time()
                self.paused_time = 0
            
            self.test_running = True
            self.test_paused = False
            self.start_button.config(state="disabled")
            self.stop_button.config(state="normal", text=t('constant_power.pause'), command=self.toggle_test)
            
            # Desabilita edição da potência quando o teste inicia
            self._update_power_entry_state()
            
            self.reading_thread = threading.Thread(target=self.rfid_interrogation_worker, daemon=True)
            self.reading_thread.start()
            
        except ValueError: messagebox.showerror(t('constant_power.invalid_values'), t('constant_power.invalid_values_msg'))
        except Exception as e: messagebox.showerror(t('constant_power.error_starting'), t('constant_power.error_starting_msg').format(error=str(e)))
            
    def toggle_test(self):
        """Alterna entre pausar e continuar o teste"""
        if self.test_running:
            # Pausar teste
            self.test_running = False
            self.test_paused = True
            self.pause_start_time = time.time()  # Marca início da pausa
            self.data_queue.put({'type': 'pause'})
            self.stop_button.config(text=t('constant_power.resume'), command=self.continue_test)
            
            # NOVO: Não sincroniza automaticamente - deixa o usuário controlar
            
            # Habilita edição da potência quando pausado
            self._update_power_entry_state()
        elif self.test_paused:
            # Se está pausado e clica em "Continuar", continua o teste
            self.continue_test()
    
    def continue_test(self):
        """Continua o teste pausado"""
        if self.test_paused:
            # SEMPRE lê a nova potência da caixa de entrada e aplica
            try:
                new_power = float(self.power_var.get())
                self.power = new_power
                
                # Aplica a nova potência ao hardware imediatamente
                if hasattr(self, '_set_power'):
                    self._set_power(new_power)
            except ValueError:
                pass
            
            # Adiciona tempo pausado ao total
            self.paused_time += time.time() - self.pause_start_time
            self.test_paused = False
            self.test_running = True
            self.stop_button.config(text=t('constant_power.pause'), command=self.toggle_test)
            
            # Desabilita edição da potência quando rodando
            self._update_power_entry_state()
            
            # Reinicia o thread de leitura
            self.reading_thread = threading.Thread(target=self.rfid_interrogation_worker, daemon=True)
            self.reading_thread.start()
    
    def stop_test(self):
        """Para o teste completamente e reseta tudo"""
        self.test_running = False
        self.test_paused = False
        self.data_queue.put({'type': 'stop'})
        
        # CORREÇÃO: Status contextual baseado na licença
        is_licensed = self.license_limits.get('is_licensed', False)
        status_text = "Status: Aguardando..." if is_licensed else "• modo browser"
        
        self.after(100, lambda: [
            self.start_button.config(state="normal", text=t('constant_power.test')), 
            self.stop_button.config(state="disabled", text=t('constant_power.pause'), command=self.toggle_test),
            self._update_power_entry_state()  # Reabilita edição da potência
        ])
        
    def clear_graph(self):
        if self.test_running or self.test_paused: 
            self.stop_test()
        self.time_data.clear(); self.rssi_data.clear()
        
        # Limpa o gráfico e reconfigura
        self.ax.clear()
        self.ax.set_xlabel("Tempo (s)")
        self.ax.set_ylabel("RSSI (dBm)")
        self.ax.grid(True, alpha=0.3)
        self.ax.set_xlim(0, 60)
        self.ax.set_ylim(-70, -20)
        self.canvas.draw()
        
        # Limpa também a caixa de EPC
        if hasattr(self, 'epc_text'):
            self.epc_text.config(state='normal')
            self.epc_text.delete(1.0, tk.END)
            self.epc_text.insert(tk.END, "Nenhuma tag detectada")
            # Remove todas as tags de cor
            self.epc_text.tag_remove("multiple_tags", "1.0", "end")
            self.epc_text.tag_remove("single_tag", "1.0", "end")
            self.epc_text.config(state='disabled')
        
        # Limpa os conjuntos de EPC
        self.previous_epcs.clear()
        self.current_epcs.clear()
        
        # Habilita entrada de potência (força habilitação)
        if hasattr(self, 'power_entry'):
            self.power_entry.config(state='normal')
    
    def _check_epc_timeout(self):
        """Verifica periodicamente se os EPCs ainda estão válidos"""
        if hasattr(self, 'epc_text') and self.test_running:
            # Se não há EPCs atuais mas a caixa ainda mostra tags, força limpeza
            if not self.current_epcs:
                self._update_epc_display([])
        
        # Agenda próxima verificação
        if self.test_running:
            self.after(1000, self._check_epc_timeout)
        
    def rfid_interrogation_worker(self):
        """Worker thread que executa o teste - com retry robusto para garantir abertura da porta"""
        try:
            # CORREÇÃO: Tenta fechar a porta silenciosamente antes de abrir (garante estado limpo)
            # Isso ajuda quando você vai direto para o módulo sem passar por outros módulos
            try:
                rfid_sdk.UHF_RFID_Close(self.com_port)
                time.sleep(0.1)  # Delay maior para garantir que a porta foi fechada
            except:
                pass  # Ignora erro se porta já estiver fechada ou não estiver aberta
            
            # CORREÇÃO: Retry robusto para abrir a porta (até 3 tentativas com delay)
            # Isso garante que a porta seja aberta mesmo se houver algum problema temporário
            port_opened = False
            for attempt in range(3):
                if rfid_sdk.UHF_RFID_Open(self.com_port, BAUD_RATE) == 0:
                    port_opened = True
                    print(f"✅ Constant Power: Porta COM{self.com_port} aberta para teste (tentativa {attempt + 1})")
                    break
                else:
                    if attempt < 2:
                        # Se falhou, tenta fechar novamente antes da próxima tentativa
                        try:
                            rfid_sdk.UHF_RFID_Close(self.com_port)
                        except:
                            pass
                        time.sleep(0.3)  # Delay maior entre tentativas
            
            if not port_opened:
                self.data_queue.put({'error': f'Falha ao abrir a porta COM{self.com_port} após 3 tentativas'})
                return
            
            try:
                if not self._set_region_brazil():
                    print("AVISO: Falha ao configurar região Brasil.")
                
                if not self._set_frequency(self.frequency) or not self._set_power(self.power):
                    self.data_queue.put({'error': 'Falha ao configurar freq/potência'}); return
                
                # Usa o tempo de início já definido ou define um novo
                if self.test_start_time is None:
                    self.test_start_time = time.time()
                
                while self.test_running:
                    # Calcula tempo considerando pausas
                    current_time = time.time()
                    elapsed_time = current_time - self.test_start_time - self.paused_time
                    rssi_values = []
                    
                    # NOVO: Atualiza EPCs do ciclo anterior
                    self.previous_epcs = self.current_epcs.copy()
                    self.current_epcs.clear()
                    
                    for _ in range(self.samples_per_point):
                        if not self.test_running: break
                        tags = self._scan_for_tags_internal()
                        for tag in tags:
                            if hasattr(tag, 'rssi') and tag.rssi is not None:
                                rssi_values.append(tag.rssi)
                            # Captura o EPC da tag
                            if hasattr(tag, 'epc') and tag.epc:
                                self.current_epcs.add(tag.epc)
                                # print(f"🔍 DEBUG: EPC adicionado: {tag.epc}")
                        time.sleep(self.pause_between_samples)
                    
                    # print(f"🔍 DEBUG: EPCs coletados neste ciclo: {self.current_epcs}")
                    
                    # SEMPRE envia dados, com RSSI real ou valor padrão
                    if rssi_values:
                        avg_rssi = sum(rssi_values) / len(rssi_values)
                        print(f"📊 RSSI real detectado: {avg_rssi:.1f} dBm")
                    else:
                        # Quando não há tags detectadas, usa -70 dBm
                        avg_rssi = -70.0
                        print(f"📊 Sem tags - plotando: {avg_rssi} dBm")
                    
                    # Envia dados incluindo EPCs detectados e status de mudança
                    epc_list = list(self.current_epcs) if self.current_epcs else []
                    epcs_changed = self.current_epcs != self.previous_epcs
                    # print(f"🔍 DEBUG: epc_list: {epc_list}")
                    # print(f"🔍 DEBUG: epcs_changed: {epcs_changed}")
                    # print(f"🔍 DEBUG: previous_epcs: {list(self.previous_epcs)}")
                    
                    self.data_queue.put({
                        'type': 'update', 
                        'time': elapsed_time, 
                        'rssi': avg_rssi,
                        'epcs': epc_list,
                        'epcs_changed': epcs_changed,
                        'previous_epcs': list(self.previous_epcs)
                    })
                    
                    time.sleep(self.pause_between_points)
            finally:
                print("Fechando porta COM no final do worker.")
                ### ALTERADO: usa self.com_port ###
                try:
                    rfid_sdk.UHF_RFID_Close(self.com_port)
                except:
                    pass
        except Exception as e:
            self.data_queue.put({'error': f'Erro no teste: {str(e)}'})
        
    def process_data_queue(self):
        try:
            message = self.data_queue.get_nowait()
            msg_type = message.get('type')
            
            if msg_type == 'update':
                # SEMPRE adiciona dados (RSSI real ou -70 dBm)
                self.time_data.append(message['time'])
                self.rssi_data.append(message['rssi'])
                self.update_plot()
                
                # Atualiza a caixa de EPC com as tags detectadas
                if 'epcs' in message:
                    epcs = message['epcs']
                    epcs_changed = message.get('epcs_changed', False)
                    
                    # Atualiza a caixa de EPC com as tags detectadas
                    
                    # SEMPRE atualiza a exibição quando há mudança ou quando não há tags
                    if epcs_changed or not epcs:
                        self._update_epc_display(epcs)
                        
                        # Log das mudanças para debug
                        if epcs:
                            print(f"🔍 EPCs detectados: {epcs}")
                        else:
                            print("🔍 EPC limpo - nenhuma tag detectada")
                    
                    # Força atualização se não há tags (mesmo sem mudança)
                    if not epcs and epcs != []:
                        self._update_epc_display([])
            elif msg_type == 'pause':
                # Teste pausado - não faz nada, apenas para sair do loop
                pass
            elif msg_type == 'stop':
                self.test_running = False
                self.test_paused = False
            elif 'error' in message:
                self.test_running = False
                self.test_paused = False
                messagebox.showerror("Erro no Teste", message['error'])
        except queue.Empty:
            pass
        self.after(50, self.process_data_queue)
            
    def update_plot(self):
        if not self.time_data or not self.rssi_data: return
        self.ax.clear()
        self.ax.set_xlabel('Tempo (s)'); self.ax.set_ylabel('RSSI (dBm)')
        self.ax.grid(True, alpha=0.3); self.ax.set_ylim(-70, -20)
        
        # Se o teste está pausado, não atualiza a janela de tempo
        if self.test_paused:
            current_time = max(self.time_data) if self.time_data else 0
            window_start = max(0, current_time - 60)
        else:
            # Teste rodando - janela de tempo se move
            current_time = max(self.time_data) if self.time_data else 0
            window_start = max(0, current_time - 60)
        
        valid_data = [(t, r) for t, r in zip(self.time_data, self.rssi_data) if r is not None and t >= window_start]
        
        if valid_data:
            times, rssis = zip(*valid_data)
            adjusted_times = [t - window_start for t in times]
            self.ax.set_xlim(0, 60)
            self.ax.plot(adjusted_times, rssis, 'b-o', linewidth=0.8, markersize=2, label='RSSI')
        else:
            self.ax.set_xlim(0, 60)

        self.canvas.draw()
        
    def _set_power(self, power_dbm):
        print(f"🔧 DEBUG: _set_power chamado com: {power_dbm} dBm")
        try:
            # Implementação corrigida - usa a mesma implementação do rssi_power_module
            power_val = int(power_dbm * 100)
            power_data = bytes([0, 0]) + power_val.to_bytes(2, 'big') * 2
            out_buf = ctypes.create_string_buffer(32)
            out_len = ctypes.c_uint(0)
            status = rfid_sdk.UHF_RFID_Set(RFID_CMD_SET_TXPOWER, ctypes.c_char_p(power_data), 6, out_buf, ctypes.byref(out_len))
            print(f"🔧 DEBUG: _set_power resultado: {'✅ Sucesso' if status == 0 else '❌ Falha'}")
            print(f"🔧 DEBUG: power_val calculado: {power_val}, power_data: {power_data.hex()}")
            return status == 0
        except Exception as e:
            print(f"🔧 DEBUG: _set_power erro: {e}")
            return False

    def _set_frequency(self, freq_mhz):
        freq_data = (1).to_bytes(1, 'big') + int(freq_mhz * 1000).to_bytes(3, 'big')
        out_buf = ctypes.create_string_buffer(32)
        out_len = ctypes.c_uint(0)
        status = rfid_sdk.UHF_RFID_Set(RFID_CMD_SET_FREQ_TABLE, ctypes.c_char_p(freq_data), 4, out_buf, ctypes.byref(out_len))
        return status == 0

    def _set_region_brazil(self):
        region_data = bytes([0x01, 0x06])
        out_buf = ctypes.create_string_buffer(32)
        out_len = ctypes.c_uint(0)
        status = rfid_sdk.UHF_RFID_Set(RFID_CMD_SET_REGION, ctypes.c_char_p(region_data), len(region_data), out_buf, ctypes.byref(out_len))
        return status == 0

    def _scan_for_tags_internal(self):
        tags_found = []
        out_buf = ctypes.create_string_buffer(256)
        out_len = ctypes.c_uint(0)
        status = rfid_sdk.UHF_RFID_Set(RFID_CMD_INV_TAG, bytes([0x00, 0x64]), 2, out_buf, ctypes.byref(out_len))
        
        if status == 0 and out_len.value > 5:
            try:
                epc = out_buf.raw[2:out_len.value - 3].hex().upper()
                rssi_bytes = out_buf.raw[out_len.value - 3:out_len.value - 1]
                rssi = struct.unpack('>h', rssi_bytes)[0] / 10.0
                
                if -100 <= rssi <= 0:
                    tags_found.append(TagInfo(epc, rssi))
            except (struct.error, IndexError) as e:
                print(f"Erro ao decodificar resposta da tag: {e}")
                
        return tags_found

if __name__ == '__main__':
    root = tk.Tk()
    root.title("Teste de Constant Power (Standalone)")
    root.geometry("800x600")

    from port_manager import get_com_port_number
    com_port = get_com_port_number()
    if com_port is None:
        messagebox.showerror(t('constant_power.hardware_unavailable'), t('constant_power.hardware_unavailable_msg'))
        root.destroy()
    else:
        app = PowerConstantModule(root, com_port=com_port)
        app.pack(fill="both", expand=True)
        root.mainloop()