Enhance NetCom configuration options and improve data handling

- Added support for additional NetCom parameters: data bits, parity, stop bits, and flow control options (RTS/CTS, DSR/DTR, XON/XOFF).
- Updated configuration loading and saving to include new parameters.
- Improved data handling in NetComTab for better byte management and logging.
- Refactored message parsing and sending to accommodate new data types and formats.
This commit is contained in:
Miguel 2025-05-23 12:20:38 +02:00
parent e1c9199cb5
commit 1266fa705d
5 changed files with 268 additions and 84 deletions

View File

@ -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', '')

View File

@ -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

View File

@ -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"
}

View File

@ -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', '<CR>').replace('\n', '<LF>').replace('\t', '<TAB>')
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', '<CR>').replace('\n', '<LF>').replace('\t', '<TAB>')
return message_str

View File

@ -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))