248 lines
8.4 KiB
C#
248 lines
8.4 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Reemplazo del ReaderSearcher del SDK
|
|
/// Busca sensores SR-X300W en la red mediante escaneo TCP
|
|
/// </summary>
|
|
public class TcpReaderSearcher : IDisposable
|
|
{
|
|
private bool isSearching = false;
|
|
private List<NicSearchResult> nicList = new List<NicSearchResult>();
|
|
|
|
public bool IsSearching => isSearching;
|
|
public NicSearchResult SelectedNicSearchResult { get; set; }
|
|
|
|
/// <summary>
|
|
/// Lista las interfaces de red disponibles en el equipo
|
|
/// Compatible con: m_nicList = m_searcher.ListUpNic()
|
|
/// </summary>
|
|
public List<NicSearchResult> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inicia búsqueda de sensores en la red
|
|
/// Compatible con: m_searcher.Start((res) => { ... })
|
|
/// </summary>
|
|
public void Start(Action<SearchResult> 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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Busca sensores SR-X300W en la red local
|
|
/// Prueba conectar al puerto 9004 (puerto de comandos SR-X300W)
|
|
/// </summary>
|
|
private async void SearchSensorsInNetwork(Action<SearchResult> 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<Task> scanTasks = new List<Task>();
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Intenta conectar a una IP:Puerto con timeout
|
|
/// </summary>
|
|
private async Task<bool> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtiene la subred de una IP (ejemplo: 192.168.100.1 -> 192.168.100)
|
|
/// </summary>
|
|
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
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detiene la búsqueda
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
isSearching = false;
|
|
Console.WriteLine("[SEARCH] Búsqueda detenida");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Stop();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resultado de búsqueda de NIC (compatible con SDK)
|
|
/// </summary>
|
|
public class NicSearchResult
|
|
{
|
|
public string NicIpAddr { get; set; }
|
|
public string NicName { get; set; }
|
|
public string NicDescription { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resultado de búsqueda de sensor
|
|
/// </summary>
|
|
public class SearchResult
|
|
{
|
|
public string IpAddress { get; set; }
|
|
public int Port { get; set; }
|
|
public bool IsResponding { get; set; }
|
|
}
|
|
} |