using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading.Tasks; namespace ScaBox30.Controller { /// /// Reemplazo del ReaderSearcher del SDK /// Busca sensores SR-X300W en la red mediante escaneo TCP /// public class TcpReaderSearcher : IDisposable { private bool isSearching = false; private List nicList = new List(); public bool IsSearching => isSearching; public NicSearchResult SelectedNicSearchResult { get; set; } /// /// Lista las interfaces de red disponibles en el equipo /// Compatible con: m_nicList = m_searcher.ListUpNic() /// public List ListUpNic() { nicList.Clear(); try { foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) { // Filtrar solo interfaces activas y Ethernet/Wi-Fi if (ni.OperationalStatus == OperationalStatus.Up && (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet || ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)) { IPInterfaceProperties ipProps = ni.GetIPProperties(); foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses) { // Solo IPv4 if (ip.Address.AddressFamily == AddressFamily.InterNetwork) { var nicResult = new NicSearchResult { NicIpAddr = ip.Address.ToString(), NicName = ni.Name, NicDescription = ni.Description }; nicList.Add(nicResult); Console.WriteLine($"[NIC] Encontrada: {nicResult.NicIpAddr} ({nicResult.NicName})"); } } } } } catch (Exception ex) { Console.WriteLine($"[NIC] Error listando interfaces: {ex.Message}"); } return nicList; } /// /// Inicia búsqueda de sensores en la red /// Compatible con: m_searcher.Start((res) => { ... }) /// public void Start(Action onSensorFound) { if (isSearching) { Console.WriteLine("[SEARCH] Ya hay una búsqueda en curso"); return; } if (SelectedNicSearchResult == null) { Console.WriteLine("[SEARCH] ERROR: No se ha seleccionado una NIC"); return; } isSearching = true; Console.WriteLine($"[SEARCH] Iniciando búsqueda desde {SelectedNicSearchResult.NicIpAddr}..."); // Ejecutar búsqueda en background Task.Run(() => SearchSensorsInNetwork(onSensorFound)); } /// /// Busca sensores SR-X300W en la red local /// Prueba conectar al puerto 9004 (puerto de comandos SR-X300W) /// private async void SearchSensorsInNetwork(Action onSensorFound) { try { string localIP = SelectedNicSearchResult.NicIpAddr; string subnet = GetSubnet(localIP); int port = 9004; // Puerto TCP comandos SR-X300W Console.WriteLine($"[SEARCH] Escaneando subnet {subnet}.x en puerto {port}"); // Escanear rango de IPs (ejemplo: 192.168.100.1 - 192.168.100.254) List scanTasks = new List(); for (int i = 1; i <= 254; i++) { string testIP = $"{subnet}.{i}"; // No probar la IP local if (testIP == localIP) continue; // Lanzar escaneo asíncrono scanTasks.Add(Task.Run(async () => { if (await TryConnectToSensor(testIP, port, 500)) // 500ms timeout { Console.WriteLine($"[SEARCH] ✓ Sensor encontrado en {testIP}:{port}"); var result = new SearchResult { IpAddress = testIP, Port = port, IsResponding = true }; onSensorFound?.Invoke(result); } })); // Limitar concurrencia para no saturar la red if (scanTasks.Count >= 20) { await Task.WhenAll(scanTasks); scanTasks.Clear(); } } // Esperar tareas restantes await Task.WhenAll(scanTasks); Console.WriteLine("[SEARCH] Búsqueda completada"); } catch (Exception ex) { Console.WriteLine($"[SEARCH] Error en búsqueda: {ex.Message}"); } finally { isSearching = false; } } /// /// Intenta conectar a una IP:Puerto con timeout /// private async Task TryConnectToSensor(string ip, int port, int timeoutMs) { try { using (var client = new TcpClient()) { var connectTask = client.ConnectAsync(ip, port); var timeoutTask = Task.Delay(timeoutMs); if (await Task.WhenAny(connectTask, timeoutTask) == connectTask) { // Conexión exitosa if (client.Connected) { // Verificar que responda a un comando básico using (var stream = client.GetStream()) { stream.ReadTimeout = 500; byte[] testCmd = System.Text.Encoding.ASCII.GetBytes("NUM\r"); await stream.WriteAsync(testCmd, 0, testCmd.Length); byte[] buffer = new byte[256]; int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); return bytesRead > 0; // Si responde, es un sensor válido } } } } } catch { // Silenciosamente ignorar fallos (IP no responde) } return false; } /// /// Obtiene la subred de una IP (ejemplo: 192.168.100.1 -> 192.168.100) /// private string GetSubnet(string ip) { string[] parts = ip.Split('.'); if (parts.Length == 4) { return $"{parts[0]}.{parts[1]}.{parts[2]}"; } return "192.168.100"; // Fallback } /// /// Detiene la búsqueda /// public void Stop() { isSearching = false; Console.WriteLine("[SEARCH] Búsqueda detenida"); } public void Dispose() { Stop(); } } /// /// Resultado de búsqueda de NIC (compatible con SDK) /// public class NicSearchResult { public string NicIpAddr { get; set; } public string NicName { get; set; } public string NicDescription { get; set; } } /// /// Resultado de búsqueda de sensor /// public class SearchResult { public string IpAddress { get; set; } public int Port { get; set; } public bool IsResponding { get; set; } } }