diff --git a/config_manager.py b/config_manager.py index afca2c3..9c1a18f 100644 --- a/config_manager.py +++ b/config_manager.py @@ -18,11 +18,19 @@ class ConfigManager: 'function_type': 'Sinusoidal', 'min_brix_map': '0', 'max_brix_map': '80', - 'cycle_time': '0.5', # Cambiado de 'period' a 'cycle_time' para tiempo de ciclo completo - 'manual_brix': '10.0', + 'cycle_time': '0.5', + 'manual_input_type': 'Brix', # Nuevo: 'Brix', 'mA', 'Voltaje' + 'manual_value': '10.0', # Nuevo: valor correspondiente al manual_input_type # Configuración para NetCom 'netcom_com_port': 'COM3', - 'netcom_baud_rate': '115200' + 'netcom_baud_rate': '115200', + 'netcom_bytesize': 8, # Data bits (5, 6, 7, 8) + 'netcom_parity': 'N', # Parity ('N', 'E', 'O', 'M', 'S') + 'netcom_stopbits': 1, # Stop bits (1, 1.5, 2) + 'netcom_rtscts': False, # Hardware flow control RTS/CTS + 'netcom_dsrdtr': False, # Hardware flow control DSR/DTR + 'netcom_xonxoff': False, # Software flow control XON/XOFF + 'netcom_bridge_delay': 0.001 # Delay in seconds for the bridge polling loop } def save_config(self, config_data): @@ -54,6 +62,12 @@ class ConfigManager: config['cycle_time'] = config['period'] del config['period'] + # Migrar 'manual_brix' a 'manual_input_type' y 'manual_value' + if 'manual_brix' in config and 'manual_value' not in config: + config['manual_value'] = config['manual_brix'] + config['manual_input_type'] = config.get('manual_input_type', 'Brix') # Asumir Brix si no existe + del config['manual_brix'] + return config except Exception as e: @@ -108,6 +122,13 @@ class ConfigManager: except ValueError: errors.append("El tiempo de ciclo debe ser un número válido") + # Validar valor manual + try: + manual_value = float(config.get('manual_value', '0')) + # Aquí se podrían añadir validaciones de rango según el manual_input_type + except ValueError: + errors.append("El valor manual debe ser un número válido") + # Validar puerto serie if config.get('connection_type') == 'Serial': com_port = config.get('com_port', '') diff --git a/connection_manager.py b/connection_manager.py index 3f112d4..64e633b 100644 --- a/connection_manager.py +++ b/connection_manager.py @@ -17,9 +17,15 @@ class ConnectionManager: try: if conn_type == "Serial": self.connection = serial.Serial( - conn_params['port'], - conn_params['baud'], - timeout=1 + port=conn_params['port'], + baudrate=conn_params['baudrate'], # Standard pyserial parameter name + timeout=conn_params.get('timeout', 1), + bytesize=conn_params.get('bytesize', serial.EIGHTBITS), # Use provided or default + parity=conn_params.get('parity', serial.PARITY_NONE), # Use provided or default + stopbits=conn_params.get('stopbits', serial.STOPBITS_ONE), # Use provided or default + xonxoff=conn_params.get('xonxoff', False), + rtscts=conn_params.get('rtscts', False), + dsrdtr=conn_params.get('dsrdtr', False) ) self.connection_type = "Serial" @@ -58,21 +64,39 @@ class ConnectionManager: self.connection_type = None self.dest_address = None - def send_data(self, data): + def send_data(self, data_bytes): """Envía datos por la conexión actual""" if not self.connection: raise Exception("No hay conexión activa") - + + data_to_send = None + if isinstance(data_bytes, str): + # Esto no debería suceder si el llamador (NetComTab, SimulatorTab) funciona como se espera. + # Loguear una advertencia e intentar codificar como último recurso. + print(f"ADVERTENCIA: ConnectionManager.send_data recibió str, se esperaba bytes. Intentando codificar a ASCII. Datos: {data_bytes!r}") + try: + data_to_send = data_bytes.encode('ascii') + except UnicodeEncodeError as uee: + print(f"ERROR CRÍTICO: No se pudo codificar la cadena (str) a ASCII antes de enviar: {uee}. Datos: {data_bytes!r}") + # Elevar una excepción clara porque no se puede continuar si la codificación falla. + raise Exception(f"Error al enviar datos: la cadena no pudo ser codificada a ASCII: {uee}") from uee + elif isinstance(data_bytes, (bytes, bytearray)): + data_to_send = data_bytes # Ya es bytes o bytearray (que .write/.send aceptan) + else: + # Si no es ni str ni bytes/bytearray, es un error de tipo fundamental. + print(f"ERROR CRÍTICO: ConnectionManager.send_data recibió un tipo inesperado: {type(data_bytes)}. Se esperaba bytes. Datos: {data_bytes!r}") + raise TypeError(f"Error al enviar datos: se esperaba un objeto tipo bytes, pero se recibió {type(data_bytes)}") + try: if self.connection_type == "Serial": - self.connection.write(data.encode('ascii')) + self.connection.write(data_to_send) elif self.connection_type == "TCP": - self.connection.send(data.encode('ascii')) + self.connection.send(data_to_send) elif self.connection_type == "UDP": - self.connection.sendto(data.encode('ascii'), self.dest_address) + self.connection.sendto(data_to_send, self.dest_address) except Exception as e: raise Exception(f"Error al enviar datos: {e}") - + def read_response(self, timeout=0.5): """Intenta leer una respuesta del dispositivo""" if not self.connection: @@ -132,12 +156,12 @@ class ConnectionManager: data = None if self.connection_type == "Serial": if self.connection.in_waiting > 0: - data = self.connection.read(self.connection.in_waiting).decode('ascii', errors='ignore') + data = self.connection.read(self.connection.in_waiting) # Returns bytes elif self.connection_type == "TCP": self.connection.settimeout(0.1) try: - data = self.connection.recv(1024).decode('ascii', errors='ignore') + data = self.connection.recv(1024) # Returns bytes if not data: # Conexión cerrada return None except socket.timeout: @@ -147,7 +171,7 @@ class ConnectionManager: self.connection.settimeout(0.1) try: data, addr = self.connection.recvfrom(1024) - data = data.decode('ascii', errors='ignore') + # data is already bytes except socket.timeout: pass diff --git a/maselli_simulator_config.json b/maselli_simulator_config.json index 51834f5..7ccd65f 100644 --- a/maselli_simulator_config.json +++ b/maselli_simulator_config.json @@ -11,6 +11,6 @@ "cycle_time": "10.0", "samples_per_cycle": "100", "manual_brix": "10.0", - "netcom_com_port": "COM3", - "netcom_baud_rate": "115200" + "netcom_com_port": "COM9", + "netcom_baud_rate": "9600" } \ No newline at end of file diff --git a/protocol_handler.py b/protocol_handler.py index ca9a53b..8f2b847 100644 --- a/protocol_handler.py +++ b/protocol_handler.py @@ -45,16 +45,35 @@ class ProtocolHandler: @staticmethod def create_adam_message(adam_address, brix_value, min_brix_map, max_brix_map): - """Crea un mensaje completo ADAM a partir de un valor Brix""" + """Crea un mensaje completo ADAM (como bytes) a partir de un valor Brix""" ma_val = ProtocolHandler.scale_to_ma(brix_value, min_brix_map, max_brix_map) ma_str = ProtocolHandler.format_ma_value(ma_val) message_part = f"#{adam_address}{ma_str}" checksum = ProtocolHandler.calculate_checksum(message_part) - full_message = f"{message_part}{checksum}\r" + full_message_str = f"{message_part}{checksum}\r" - return full_message, ma_val + return full_message_str.encode('ascii'), ma_val + @staticmethod + def ma_to_voltage(ma_value): + """Convierte valor mA a Voltaje (0-10V). 0mA -> 0V, 20mA -> 10V.""" + # Escala lineal: Voltage = (ma_value / 20mA) * 10V + voltage = (ma_value / 20.0) * 10.0 + return max(0.0, min(10.0, voltage)) # Asegurar que esté en el rango 0-10V + + @staticmethod + def voltage_to_ma(voltage_value): + """Convierte valor Voltaje (0-10V) a mA. 0V -> 0mA, 10V -> 20mA.""" + # Escala lineal: mA = (voltage_value / 10V) * 20mA + ma = (voltage_value / 10.0) * 20.0 + return max(0.0, min(20.0, ma)) # Asegurar que esté en el rango 0-20mA + + @staticmethod + def format_voltage_display(voltage_value): + """Formatea un valor de Voltaje para mostrar.""" + return f"{voltage_value:.2f} V" + @staticmethod def parse_adam_message(data): """ @@ -116,6 +135,25 @@ class ProtocolHandler: return None @staticmethod - def format_for_display(message): - """Formatea un mensaje para mostrar en el log (reemplaza caracteres no imprimibles)""" - return message.replace('\r', '').replace('\n', '').replace('\t', '') + def format_for_display(message, hex_non_printable=False): + """Formatea un mensaje (bytes o str) para mostrar en el log""" + if isinstance(message, bytes): + if hex_non_printable: + parts = [] + for byte_val in message: + # Caracteres ASCII imprimibles (32 a 126) se dejan como están. + # Otros se convierten a \xHH. + if 32 <= byte_val <= 126: + parts.append(chr(byte_val)) + else: + parts.append(f'\\x{byte_val:02x}') + message_str = "".join(parts) + else: + message_str = message.decode('ascii', errors='replace') # 'replace' muestra para no decodificables + else: # Asumir que es str + message_str = str(message) + + # Si no es formato hexadecimal, reemplazar caracteres de control comunes por representaciones legibles. + if not hex_non_printable: + message_str = message_str.replace('\r', '').replace('\n', '').replace('\t', '') + return message_str diff --git a/tabs/netcom_tab.py b/tabs/netcom_tab.py index a005dc8..d85745b 100644 --- a/tabs/netcom_tab.py +++ b/tabs/netcom_tab.py @@ -42,11 +42,49 @@ class NetComTab: self.com_port_var = tk.StringVar(value=self.shared_config.get('netcom_com_port', 'COM3')) self.com_port_entry = ttk.Entry(com_config_frame, textvariable=self.com_port_var, width=10) self.com_port_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew") - + ttk.Label(com_config_frame, text="Baud Rate:").grid(row=0, column=2, padx=5, pady=5, sticky="w") self.baud_rate_var = tk.StringVar(value=self.shared_config.get('netcom_baud_rate', '115200')) self.baud_rate_entry = ttk.Entry(com_config_frame, textvariable=self.baud_rate_var, width=10) self.baud_rate_entry.grid(row=0, column=3, padx=5, pady=5, sticky="ew") + + # Data bits, Parity, Stop bits + ttk.Label(com_config_frame, text="Data Bits:").grid(row=0, column=4, padx=5, pady=5, sticky="w") + self.bytesize_var = tk.StringVar(value=str(self.shared_config.get('netcom_bytesize', 8))) + self.bytesize_combo = ttk.Combobox(com_config_frame, textvariable=self.bytesize_var, + values=["5", "6", "7", "8"], state="readonly", width=5) + self.bytesize_combo.grid(row=0, column=5, padx=5, pady=5, sticky="ew") + + ttk.Label(com_config_frame, text="Parity:").grid(row=0, column=6, padx=5, pady=5, sticky="w") + self.parity_var = tk.StringVar(value=self.shared_config.get('netcom_parity', 'N')) + self.parity_combo = ttk.Combobox(com_config_frame, textvariable=self.parity_var, + values=["N", "E", "O", "M", "S"], state="readonly", width=5) # N: None, E: Even, O: Odd, M: Mark, S: Space + self.parity_combo.grid(row=0, column=7, padx=5, pady=5, sticky="ew") + + ttk.Label(com_config_frame, text="Stop Bits:").grid(row=0, column=8, padx=5, pady=5, sticky="w") + self.stopbits_var = tk.StringVar(value=str(self.shared_config.get('netcom_stopbits', 1))) + self.stopbits_combo = ttk.Combobox(com_config_frame, textvariable=self.stopbits_var, + values=["1", "1.5", "2"], state="readonly", width=5) + self.stopbits_combo.grid(row=0, column=9, padx=5, pady=5, sticky="ew") + + + + # Flow control options + self.rtscts_var = tk.BooleanVar(value=self.shared_config.get('netcom_rtscts', False)) + self.rtscts_check = ttk.Checkbutton(com_config_frame, text="RTS/CTS", variable=self.rtscts_var) + self.rtscts_check.grid(row=1, column=0, padx=5, pady=5, sticky="w") + self.dsrdtr_var = tk.BooleanVar(value=self.shared_config.get('netcom_dsrdtr', False)) + self.dsrdtr_check = ttk.Checkbutton(com_config_frame, text="DSR/DTR", variable=self.dsrdtr_var) + self.dsrdtr_check.grid(row=1, column=1, padx=5, pady=5, sticky="w") + self.xonxoff_var = tk.BooleanVar(value=self.shared_config.get('netcom_xonxoff', False)) + self.xonxoff_check = ttk.Checkbutton(com_config_frame, text="XON/XOFF", variable=self.xonxoff_var) + self.xonxoff_check.grid(row=1, column=2, padx=5, pady=5, sticky="w") + + # Bridge delay + ttk.Label(com_config_frame, text="Retardo Bridge (s):").grid(row=1, column=3, padx=5, pady=5, sticky="w") + self.bridge_delay_var = tk.StringVar(value=str(self.shared_config.get('netcom_bridge_delay', 0.001))) + self.bridge_delay_entry = ttk.Entry(com_config_frame, textvariable=self.bridge_delay_var, width=8) + self.bridge_delay_entry.grid(row=1, column=4, padx=5, pady=5, sticky="ew") # Info frame info_frame = ttk.LabelFrame(self.frame, text="Información de Conexión") @@ -194,11 +232,18 @@ class NetComTab: try: com_port = self.com_port_var.get() baud_rate = int(self.baud_rate_var.get()) + bridge_delay_str = self.bridge_delay_var.get() if not com_port.upper().startswith('COM'): raise ValueError("Puerto COM inválido") if baud_rate <= 0: raise ValueError("Baud rate debe ser mayor que 0") + try: + self.current_bridge_delay = float(bridge_delay_str) + if self.current_bridge_delay < 0: + raise ValueError("El retardo del bridge no puede ser negativo.") + except ValueError: + raise ValueError("Retardo del bridge inválido. Debe ser un número (ej: 0.001).") except ValueError as e: messagebox.showerror("Error", f"Configuración inválida: {e}") @@ -208,9 +253,22 @@ class NetComTab: try: self.com_connection.open_connection("Serial", { 'port': com_port, - 'baud': baud_rate + 'baudrate': baud_rate, + 'bytesize': int(self.bytesize_var.get()), + 'parity': self.parity_var.get(), + 'stopbits': float(self.stopbits_var.get()), + 'rtscts': self.rtscts_var.get(), + 'dsrdtr': self.dsrdtr_var.get(), + 'xonxoff': self.xonxoff_var.get() }) - self.log_message(f"Puerto COM abierto: {com_port} @ {baud_rate} bps") + + # Log basic serial config + serial_config_log = f"{com_port} @ {baud_rate} bps, {self.bytesize_var.get()}{self.parity_var.get()}{self.stopbits_var.get()}" + fc_log = [] + if self.rtscts_var.get(): fc_log.append("RTS/CTS") + if self.dsrdtr_var.get(): fc_log.append("DSR/DTR") + if self.xonxoff_var.get(): fc_log.append("XON/XOFF") + self.log_message(f"Puerto COM abierto: {serial_config_log}. Flow control: {', '.join(fc_log) if fc_log else 'Ninguno'}") except Exception as e: messagebox.showerror("Error", f"No se pudo abrir puerto COM: {e}") return @@ -282,8 +340,9 @@ class NetComTab: def run_bridge(self): """Thread principal del bridge""" - com_buffer = "" - net_buffer = "" + com_buffer = bytearray() + # net_buffer = bytearray() # Ya no se usa para el flujo NET->COM si pasamos los datos directamente + current_delay = self.current_bridge_delay while self.bridging: try: @@ -291,21 +350,25 @@ class NetComTab: com_data = self.com_connection.read_data_non_blocking() if com_data: com_buffer += com_data - + # Buscar mensajes completos para logging - while '\r' in com_buffer or '\n' in com_buffer or len(com_buffer) >= 10: + # Adaptar la condición para bytearray + while self._find_message_end_conditions(com_buffer): end_idx = self._find_message_end(com_buffer) if end_idx > 0: - message = com_buffer[:end_idx] + message_bytes = bytes(com_buffer[:end_idx]) com_buffer = com_buffer[end_idx:] # Log y parseo - display_msg = ProtocolHandler.format_for_display(message) + use_hex_format_for_raw = self.show_parsed_var.get() + display_msg = ProtocolHandler.format_for_display(message_bytes, hex_non_printable=use_hex_format_for_raw) self.log_message(f"Data: {display_msg}", "com_to_net") # Intentar parsear si está habilitado if self.show_parsed_var.get(): - parsed = ProtocolHandler.parse_adam_message(message) + # Decodificar solo para el parseo + message_str_for_parse = message_bytes.decode('ascii', errors='ignore') + parsed = ProtocolHandler.parse_adam_message(message_str_for_parse) if parsed: # Obtener valores de mapeo min_brix = float(self.shared_config['min_brix_map_var'].get()) @@ -322,7 +385,7 @@ class NetComTab: # Reenviar a la red try: - self.net_connection.send_data(message) + self.net_connection.send_data(message_bytes) self.com_to_net_count += 1 self.update_stats() except Exception as e: @@ -335,47 +398,42 @@ class NetComTab: # Leer de la red net_data = self.net_connection.read_data_non_blocking() if net_data: - net_buffer += net_data + # Los datos de la red (net_data) son bytes. + # Se reenvían directamente al puerto COM. - # Buscar mensajes completos para logging - while '\r' in net_buffer or '\n' in net_buffer or len(net_buffer) >= 10: - end_idx = self._find_message_end(net_buffer) - if end_idx > 0: - message = net_buffer[:end_idx] - net_buffer = net_buffer[end_idx:] + # Log y parseo (opcional, sobre los datos recibidos directamente) + use_hex_format_for_raw = self.show_parsed_var.get() + display_msg = ProtocolHandler.format_for_display(net_data, hex_non_printable=use_hex_format_for_raw) + self.log_message(f"Data: {display_msg}", "net_to_com") + + # Intentar parsear si está habilitado (puede ser sobre fragmentos) + if self.show_parsed_var.get(): + # Decodificar solo para el parseo + # Nota: parsear fragmentos puede no ser siempre significativo para protocolos como ADAM. + message_str_for_parse = net_data.decode('ascii', errors='ignore') + parsed = ProtocolHandler.parse_adam_message(message_str_for_parse) + if parsed: + min_brix = float(self.shared_config['min_brix_map_var'].get()) + max_brix = float(self.shared_config['max_brix_map_var'].get()) + brix_value = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix, max_brix) - # Log y parseo - display_msg = ProtocolHandler.format_for_display(message) - self.log_message(f"Data: {display_msg}", "net_to_com") - - # Intentar parsear si está habilitado - if self.show_parsed_var.get(): - parsed = ProtocolHandler.parse_adam_message(message) - if parsed: - # Obtener valores de mapeo - min_brix = float(self.shared_config['min_brix_map_var'].get()) - max_brix = float(self.shared_config['max_brix_map_var'].get()) - brix_value = ProtocolHandler.ma_to_brix(parsed['ma'], min_brix, max_brix) - - self.log_message( - f"ADAM - Addr: {parsed['address']}, " - f"mA: {parsed['ma']:.3f}, " - f"Brix: {brix_value:.3f}, " - f"Checksum: {'OK' if parsed.get('checksum_valid', True) else 'ERROR'}", - "parsed" - ) - - # Reenviar al COM - try: - self.com_connection.send_data(message) - self.net_to_com_count += 1 - self.update_stats() - except Exception as e: - self.log_message(f"Error enviando a COM: {e}", "error") - self.error_count += 1 - self.update_stats() - else: - break + self.log_message( + f"ADAM (datos red) - Addr: {parsed['address']}, " + f"mA: {parsed['ma']:.3f}, " + f"Brix: {brix_value:.3f}, " + f"Checksum: {'OK' if parsed.get('checksum_valid', True) else 'ERROR'}", + "parsed" + ) + + # Reenviar al COM + try: + self.com_connection.send_data(net_data) # Enviar los bytes tal cual se recibieron + self.net_to_com_count += len(net_data) # Contar bytes en lugar de "mensajes" + self.update_stats() + except Exception as e: + self.log_message(f"Error enviando a COM: {e}", "error") + self.error_count += 1 + self.update_stats() except Exception as e: if self.bridging: @@ -386,26 +444,52 @@ class NetComTab: # Pequeña pausa para no consumir demasiado CPU if not com_data and not net_data: - time.sleep(0.001) + time.sleep(current_delay) # Asegurar que el estado se actualice if not self.bridging: self.frame.after(0, self._ensure_stopped_state) - def _find_message_end(self, buffer): - """Encuentra el final de un mensaje en el buffer""" + def _find_message_end_conditions(self, buffer_bytes: bytearray): + """Verifica si hay condiciones para buscar el final de un mensaje.""" + if not buffer_bytes: + return False + has_terminator = any(byte_val in (ord(b'\r'), ord(b'\n')) for byte_val in buffer_bytes) + return has_terminator or len(buffer_bytes) >= 10 + + def _find_message_end(self, buffer_bytes: bytearray): + """Encuentra el final de un mensaje en el buffer de bytes.""" # Buscar terminadores - for i, char in enumerate(buffer): - if char in ['\r', '\n']: + for i, byte_val in enumerate(buffer_bytes): + if byte_val == ord(b'\r') or byte_val == ord(b'\n'): return i + 1 # Si no hay terminador pero el buffer es largo, buscar mensaje ADAM completo - if len(buffer) >= 10: - if buffer[0] == '#' or (buffer[2:8].replace('.', '').replace(' ', '').replace('-', '').isdigit()): - # Parece un mensaje ADAM - if len(buffer) > 10 and buffer[10] in ['\r', '\n']: + # Esta parte es una heurística para mensajes tipo ADAM que podrían no tener terminador + # y debe usarse con cuidado para no cortar mensajes prematuramente. + if len(buffer_bytes) >= 10: + starts_with_hash = (buffer_bytes[0] == ord(b'#')) + + is_adam_value_like = False + if len(buffer_bytes) >= 8: # Asegurar que el slice buffer_bytes[2:8] sea válido + try: + # Convertir la parte del valor a string para una verificación más sencilla + value_part_str = bytes(buffer_bytes[2:8]).decode('ascii') + # Formato ADAM es XX.XXX (6 caracteres) + if len(value_part_str) == 6 and value_part_str[2] == '.' and \ + value_part_str[0:2].isdigit() and value_part_str[3:6].isdigit(): + is_adam_value_like = True + except UnicodeDecodeError: + pass # No es ASCII, no es el formato ADAM esperado + + if starts_with_hash or is_adam_value_like: + # Heurística: si parece ADAM y tiene al menos 10 bytes. + # Si después de 10 bytes hay un terminador, incluirlo. + if len(buffer_bytes) > 10 and \ + (buffer_bytes[10] == ord(b'\r') or buffer_bytes[10] == ord(b'\n')): return 11 else: + # Asumir un mensaje de 10 bytes (ej: #AAXX.XXXCC) return 10 return -1 @@ -413,7 +497,11 @@ class NetComTab: def update_stats(self): """Actualiza las estadísticas en la GUI""" self.com_to_net_var.set(str(self.com_to_net_count)) - self.net_to_com_var.set(str(self.net_to_com_count)) + # Si net_to_com_count ahora cuenta bytes, el label "NET → COM:" seguido de un número + # podría interpretarse como mensajes. Para mayor claridad, se podría cambiar el label + # o el formato del valor (ej. self.net_to_com_var.set(f"{self.net_to_com_count} bytes")). + # Por ahora, solo actualizamos el valor; el label no cambia. + self.net_to_com_var.set(str(self.net_to_com_count)) self.errors_var.set(str(self.error_count)) def clear_log(self): @@ -427,6 +515,13 @@ class NetComTab: """Habilita/deshabilita los controles durante el bridge""" self.com_port_entry.config(state=state) self.baud_rate_entry.config(state=state) + self.bytesize_combo.config(state=state) + self.parity_combo.config(state=state) + self.stopbits_combo.config(state=state) + self.rtscts_check.config(state=state) + self.dsrdtr_check.config(state=state) + self.xonxoff_check.config(state=state) + self.bridge_delay_entry.config(state=state) # También deshabilitar controles compartidos if 'shared_widgets' in self.shared_config: @@ -444,10 +539,16 @@ class NetComTab: """Obtiene la configuración actual del NetCom""" return { 'netcom_com_port': self.com_port_var.get(), - 'netcom_baud_rate': self.baud_rate_var.get() + 'netcom_baud_rate': self.baud_rate_var.get(), + 'netcom_rtscts': self.rtscts_var.get(), + 'netcom_dsrdtr': self.dsrdtr_var.get(), + 'netcom_xonxoff': self.xonxoff_var.get() } def set_config(self, config): """Establece la configuración del NetCom""" self.com_port_var.set(config.get('netcom_com_port', 'COM3')) self.baud_rate_var.set(config.get('netcom_baud_rate', '115200')) + self.rtscts_var.set(config.get('netcom_rtscts', False)) + self.dsrdtr_var.set(config.get('netcom_dsrdtr', False)) + self.xonxoff_var.set(config.get('netcom_xonxoff', False))