diff --git a/HydraulicSimulator/HydraulicSimulationManager.cs b/HydraulicSimulator/HydraulicSimulationManager.cs
index 33996a0..4816a85 100644
--- a/HydraulicSimulator/HydraulicSimulationManager.cs
+++ b/HydraulicSimulator/HydraulicSimulationManager.cs
@@ -534,7 +534,7 @@ namespace CtrEditor.HydraulicSimulator
/*
if (VerboseOutput)
{
- Debug.WriteLine($"Bomba {pump.GetType().Name}: Velocidad={pump.SpeedRatio:F2}, " +
+ Trace.WriteLine($"Bomba {pump.GetType().Name}: Velocidad={pump.SpeedRatio:F2}, " +
$"Funcionando={pump.IsRunning}, Dirección={pump.PumpDirection}");
}
*/
@@ -567,17 +567,18 @@ namespace CtrEditor.HydraulicSimulator
// Calcular presión basada en nivel si no es presión fija
if (!tank.IsFixedPressure)
{
- // P = ρgh + P_atmosferica
+ // P = ρgh + P_atmosferica (resultado en Pa)
double pressureFromLevel = SimulationFluid.Rho * 9.80665 * tank.Level; // + presión atmosférica
- tank.TankPressure = pressureFromLevel;
+ // Convertir de Pa a bar (1 bar = 100000 Pa)
+ tank.TankPressure = pressureFromLevel / 100000.0;
}
// Debug output deshabilitado para mejorar rendimiento
/*
if (VerboseOutput)
{
- Debug.WriteLine($"Tanque {tank.GetType().Name}: Nivel={tank.Level:F2}m, " +
- $"Presión={tank.TankPressure:F0}Pa, PresionFija={tank.IsFixedPressure}");
+ Trace.WriteLine($"Tanque {tank.GetType().Name}: Nivel={tank.Level:F2}m, " +
+ $"Presión={tank.TankPressure:F3}bar ({tank.TankPressure * 100000.0:F0}Pa), PresionFija={tank.IsFixedPressure}");
}
*/
}
diff --git a/HydraulicSimulator/simHydraulicBase.cs b/HydraulicSimulator/simHydraulicBase.cs
index c4ee0c1..ee2351c 100644
--- a/HydraulicSimulator/simHydraulicBase.cs
+++ b/HydraulicSimulator/simHydraulicBase.cs
@@ -111,9 +111,9 @@ namespace CtrEditor.HydraulicSimulator
if (WpfObject is osHydTank tank)
{
TankPressure = tank.TankPressure;
- CurrentLevel = tank.CurrentLevel;
- MaxLevel = tank.MaxLevel;
- MinLevel = tank.MinLevel;
+ CurrentLevel = tank.CurrentLevelM;
+ MaxLevel = tank.MaxLevelM;
+ MinLevel = tank.MinLevelM;
CrossSectionalArea = tank.CrossSectionalArea;
IsFixedPressure = tank.IsFixedPressure;
}
diff --git a/MainViewModel.cs b/MainViewModel.cs
index 036d0ad..9c69161 100644
--- a/MainViewModel.cs
+++ b/MainViewModel.cs
@@ -23,6 +23,7 @@ using System.Timers; // Para el nuevo timer de simulación más preciso
using CtrEditor.PopUps;
using System.Windows.Data;
using CommunityToolkit.Mvvm.Input;
+using CtrEditor.Services; // Para MCPServer y DebugConsoleServer
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using CtrEditor.Serialization; // Add this line
@@ -75,6 +76,9 @@ namespace CtrEditor
// Servidor MCP para control remoto
private MCPServer _mcpServer;
+ // Servidor de debug console para logging
+ private DebugConsoleServer _debugConsoleServer;
+
[ObservableProperty]
private int mcpServerPort = 5006;
@@ -1787,6 +1791,9 @@ namespace CtrEditor
await _mcpServer.StartAsync();
Debug.WriteLine($"[MCP] Servidor MCP iniciado en puerto {McpServerPort}");
+
+ // Iniciar también el servidor de debug console
+ StartDebugConsoleServer();
}
catch (Exception ex)
{
@@ -1803,8 +1810,10 @@ namespace CtrEditor
try
{
_mcpServer?.Stop();
-
Debug.WriteLine("[MCP] Servidor MCP detenido");
+
+ // Detener también el servidor de debug console
+ StopDebugConsoleServer();
}
catch (Exception ex)
{
@@ -1821,6 +1830,9 @@ namespace CtrEditor
{
_mcpServer?.Dispose();
_mcpServer = null;
+
+ // Limpiar también el servidor de debug console
+ CleanupDebugConsoleServer();
}
catch (Exception ex)
{
@@ -1828,6 +1840,61 @@ namespace CtrEditor
}
}
+ ///
+ /// Inicia el servidor de debug console
+ ///
+ private void StartDebugConsoleServer()
+ {
+ try
+ {
+ if (_debugConsoleServer != null)
+ {
+ _debugConsoleServer.Dispose();
+ }
+
+ _debugConsoleServer = new DebugConsoleServer(5007); // Puerto fijo para debug
+ _debugConsoleServer.Start();
+
+ Debug.WriteLine("[Debug Console] Servidor de debug console iniciado en puerto 5007");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[Debug Console] Error iniciando servidor de debug console: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Detiene el servidor de debug console
+ ///
+ private void StopDebugConsoleServer()
+ {
+ try
+ {
+ _debugConsoleServer?.Stop();
+ Debug.WriteLine("[Debug Console] Servidor de debug console detenido");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[Debug Console] Error deteniendo servidor de debug console: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Limpia el servidor de debug console al cerrar la aplicación
+ ///
+ private void CleanupDebugConsoleServer()
+ {
+ try
+ {
+ _debugConsoleServer?.Dispose();
+ _debugConsoleServer = null;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[Debug Console] Error limpiando servidor de debug console: {ex.Message}");
+ }
+ }
+
#endregion
}
diff --git a/ObjetosSim/HydraulicComponents/osHydTank.cs b/ObjetosSim/HydraulicComponents/osHydTank.cs
index 1fa392f..91fe4f2 100644
--- a/ObjetosSim/HydraulicComponents/osHydTank.cs
+++ b/ObjetosSim/HydraulicComponents/osHydTank.cs
@@ -634,10 +634,10 @@ namespace CtrEditor.ObjetosSim
// El tanque siempre es un nodo de presión fija si está configurado así
if (IsFixedPressure)
{
- // Convertir bar a Pa para el sistema hidráulico interno
- var pressurePa = TankPressure * 100000.0;
+ // TankPressure ya está en Pa, no necesita conversión
+ var pressurePa = TankPressure;
nodes.Add(new HydraulicNodeDefinition(Nombre, true, pressurePa, GetTankDescription()));
- //Debug.WriteLine($"Tanque {Nombre}: Nodo de presión fija creado - {TankPressure:F2} bar ({pressurePa:F0} Pa)");
+ //Debug.WriteLine($"Tanque {Nombre}: Nodo de presión fija creado - {TankPressure:F0} Pa ({TankPressure/100000.0:F2} bar)");
}
else
{
@@ -655,10 +655,10 @@ namespace CtrEditor.ObjetosSim
// Obtener flujos conectados
UpdateFlowsFromConnectedPipes(flows);
- // Actualizar presión (convertir de Pa a bar)
+ // Actualizar presión (convertir de Pa a bar para consistencia)
if (pressures.ContainsKey(Nombre))
{
- CurrentPressure = pressures[Nombre] / 100000.0; // Pa a bar
+ CurrentPressure = pressures[Nombre] / 100000.0; // Convertir Pa a bar
}
// Actualizar nivel basado en balance de flujo
@@ -666,9 +666,9 @@ namespace CtrEditor.ObjetosSim
if (VerboseLogging())
{
- Debug.WriteLine($"Tanque {Nombre}: Nivel={CurrentLevelM:F2}m ({FillPercentage:F1}%), " +
+ Trace.WriteLine($"Tanque {Nombre}: Nivel={CurrentLevelM:F2}m ({FillPercentage:F1}%), " +
$"Flujo_entrada={InletFlow:F2}L/min, Flujo_salida={OutletFlow:F2}L/min, " +
- $"Balance={FlowBalance:F2}L/min, Presión={CurrentPressure:F2}bar, Fluido={CurrentFluidDescription}");
+ $"Balance={FlowBalance:F2}L/min, Presión={CurrentPressure:F3}bar ({CurrentPressure * 100000.0:F0}Pa), Fluido={CurrentFluidDescription}");
}
}
@@ -1013,7 +1013,7 @@ namespace CtrEditor.ObjetosSim
// Debug para verificar cambios
if (VerboseLogging() && Math.Abs(volumeChangeL) > 0.1)
{
- Debug.WriteLine($"Tanque {Nombre}: Δt={deltaTime:F3}min, ΔVolumen={volumeChangeL:F2}L, " +
+ Trace.WriteLine($"Tanque {Nombre}: Δt={deltaTime:F3}min, ΔVolumen={volumeChangeL:F2}L, " +
$"Volumen={CurrentVolumeL:F1}L, Estado={MixingState}, Fluido={CurrentFluidDescription}");
}
}
diff --git a/Services/DebugConsoleServer.cs b/Services/DebugConsoleServer.cs
new file mode 100644
index 0000000..b9d0fb5
--- /dev/null
+++ b/Services/DebugConsoleServer.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace CtrEditor.Services
+{
+ ///
+ /// Servidor TCP que captura y retransmite mensajes de debug console
+ /// Permite al MCP Proxy escuchar los logs de debug de CtrEditor
+ ///
+ public class DebugConsoleServer : IDisposable
+ {
+ private readonly int _port;
+ private TcpListener _tcpListener;
+ private bool _isRunning;
+ private CancellationTokenSource _cancellationTokenSource;
+ private readonly object _lockObject = new object();
+ private readonly ConcurrentQueue _messageQueue = new ConcurrentQueue();
+ private readonly ConcurrentBag _connectedClients = new ConcurrentBag();
+
+ // Custom TraceListener para capturar Debug.WriteLine
+ private DebugTraceListener _traceListener;
+
+ public DebugConsoleServer(int port = 5007)
+ {
+ _port = port;
+ _cancellationTokenSource = new CancellationTokenSource();
+ }
+
+ ///
+ /// Inicia el servidor de debug console
+ ///
+ public void Start()
+ {
+ if (_isRunning) return;
+
+ try
+ {
+ _tcpListener = new TcpListener(IPAddress.Loopback, _port);
+ _tcpListener.Start();
+ _isRunning = true;
+
+ // Instalar el trace listener personalizado solo para Trace
+ _traceListener = new DebugTraceListener(this);
+ Trace.Listeners.Add(_traceListener);
+
+ Trace.WriteLine($"[Debug Console Server] Servidor de debug iniciado en puerto {_port}");
+
+ // Procesar conexiones en background
+ _ = Task.Run(async () => await AcceptConnectionsAsync(_cancellationTokenSource.Token));
+
+ // Procesar cola de mensajes
+ _ = Task.Run(async () => await ProcessMessageQueueAsync(_cancellationTokenSource.Token));
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[Debug Console Server] Error al iniciar servidor: {ex.Message}");
+ throw;
+ }
+ }
+
+ ///
+ /// Detiene el servidor de debug console
+ ///
+ public void Stop()
+ {
+ if (!_isRunning) return;
+
+ lock (_lockObject)
+ {
+ if (!_isRunning) return;
+
+ _isRunning = false;
+ _cancellationTokenSource?.Cancel();
+
+ // Remover el trace listener
+ if (_traceListener != null)
+ {
+ Trace.Listeners.Remove(_traceListener);
+ _traceListener = null;
+ }
+
+ _tcpListener?.Stop();
+
+ // Cerrar todas las conexiones de clientes
+ foreach (var client in _connectedClients)
+ {
+ try
+ {
+ client?.Close();
+ }
+ catch { }
+ }
+
+ Debug.WriteLine("[Debug Console Server] Servidor de debug detenido");
+ }
+ }
+
+ ///
+ /// Acepta conexiones de clientes
+ ///
+ private async Task AcceptConnectionsAsync(CancellationToken cancellationToken)
+ {
+ try
+ {
+ while (_isRunning && !cancellationToken.IsCancellationRequested)
+ {
+ Debug.WriteLine("[Debug Console Server] Esperando conexión de cliente...");
+ var tcpClient = await _tcpListener.AcceptTcpClientAsync();
+ _connectedClients.Add(tcpClient);
+
+ Debug.WriteLine("[Debug Console Server] Cliente debug conectado");
+
+ // Manejar cliente en background
+ _ = Task.Run(async () => await HandleClientAsync(tcpClient, cancellationToken));
+ }
+ }
+ catch (Exception ex)
+ {
+ if (_isRunning)
+ {
+ Debug.WriteLine($"[Debug Console Server] Error aceptando conexión: {ex.Message}");
+ }
+ }
+ }
+
+ ///
+ /// Maneja un cliente conectado
+ ///
+ private async Task HandleClientAsync(TcpClient client, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var stream = client.GetStream();
+
+ // Enviar mensaje de bienvenida
+ var welcomeMessage = $"[Debug Console Server] Conectado al servidor de debug de CtrEditor en puerto {_port}\n";
+ await SendMessageToClientAsync(stream, welcomeMessage);
+
+ // Mantener conexión viva hasta cancelación
+ while (_isRunning && client.Connected && !cancellationToken.IsCancellationRequested)
+ {
+ await Task.Delay(1000, cancellationToken);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[Debug Console Server] Error en cliente debug: {ex.Message}");
+ }
+ finally
+ {
+ try
+ {
+ client?.Close();
+ }
+ catch { }
+ Debug.WriteLine("[Debug Console Server] Cliente debug desconectado");
+ }
+ }
+
+ ///
+ /// Procesa la cola de mensajes y los envía a todos los clientes conectados
+ ///
+ private async Task ProcessMessageQueueAsync(CancellationToken cancellationToken)
+ {
+ try
+ {
+ while (_isRunning && !cancellationToken.IsCancellationRequested)
+ {
+ if (_messageQueue.TryDequeue(out string message))
+ {
+ await BroadcastMessageAsync(message);
+ }
+ else
+ {
+ await Task.Delay(50, cancellationToken); // Pequeña pausa si no hay mensajes
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (_isRunning)
+ {
+ Debug.WriteLine($"[Debug Console Server] Error procesando cola de mensajes: {ex.Message}");
+ }
+ }
+ }
+
+ ///
+ /// Envía un mensaje a todos los clientes conectados
+ ///
+ private async Task BroadcastMessageAsync(string message)
+ {
+ var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
+ var formattedMessage = $"[{timestamp}] {message}\n";
+
+ var clientsToRemove = new List();
+
+ foreach (var client in _connectedClients)
+ {
+ try
+ {
+ if (client.Connected)
+ {
+ var stream = client.GetStream();
+ await SendMessageToClientAsync(stream, formattedMessage);
+ }
+ else
+ {
+ clientsToRemove.Add(client);
+ }
+ }
+ catch
+ {
+ clientsToRemove.Add(client);
+ }
+ }
+
+ // Remover clientes desconectados
+ // Nota: ConcurrentBag no permite eliminación directa, pero no es crítico
+ // Los clientes desconectados se manejan en HandleClientAsync
+ }
+
+ ///
+ /// Envía un mensaje a un cliente específico
+ ///
+ private async Task SendMessageToClientAsync(NetworkStream stream, string message)
+ {
+ var data = Encoding.UTF8.GetBytes(message);
+ await stream.WriteAsync(data, 0, data.Length);
+ await stream.FlushAsync();
+ }
+
+ ///
+ /// Agrega un mensaje a la cola para transmisión
+ ///
+ public void QueueMessage(string message)
+ {
+ if (_isRunning)
+ {
+ _messageQueue.Enqueue(message);
+ }
+ }
+
+ public void Dispose()
+ {
+ Stop();
+ _cancellationTokenSource?.Dispose();
+ }
+ }
+
+ ///
+ /// TraceListener personalizado que captura mensajes de Debug.WriteLine
+ /// y los envía al servidor de debug console
+ ///
+ internal class DebugTraceListener : TraceListener
+ {
+ private readonly DebugConsoleServer _server;
+
+ public DebugTraceListener(DebugConsoleServer server)
+ {
+ _server = server;
+ }
+
+ public override void Write(string message)
+ {
+ _server?.QueueMessage(message);
+ }
+
+ public override void WriteLine(string message)
+ {
+ _server?.QueueMessage(message);
+ }
+ }
+}