diff --git a/LecturaDM.sln b/LecturaDM.sln
new file mode 100644
index 0000000..24c66c2
--- /dev/null
+++ b/LecturaDM.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.37314.3 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LecturaDM", "LecturaDM\LecturaDM.csproj", "{141E22A4-743C-4BA9-993D-E9567E795412}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {141E22A4-743C-4BA9-993D-E9567E795412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {141E22A4-743C-4BA9-993D-E9567E795412}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {141E22A4-743C-4BA9-993D-E9567E795412}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {141E22A4-743C-4BA9-993D-E9567E795412}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3C23E5E6-ADAD-41F2-99AC-98A314405931}
+ EndGlobalSection
+EndGlobal
diff --git a/LecturaDM/Lectura.txt b/LecturaDM/Lectura.txt
new file mode 100644
index 0000000..e69de29
diff --git a/LecturaDM/LecturaDM.csproj b/LecturaDM/LecturaDM.csproj
new file mode 100644
index 0000000..59296f0
--- /dev/null
+++ b/LecturaDM/LecturaDM.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+ ..\..\..\..\Cognex\DataMan SDK 5.6.3\Binaries\PC\Cognex.DataMan.CogNamer.PC.dll
+
+
+ ..\..\..\..\Cognex\DataMan SDK 5.6.3\Binaries\PC\Cognex.DataMan.SDK.Discovery.PC.dll
+
+
+ ..\..\..\..\Cognex\DataMan SDK 5.6.3\Binaries\PC\Cognex.DataMan.SDK.PC.dll
+
+
+ ..\..\..\..\Cognex\DataMan SDK 5.6.3\Binaries\PC\Cognex.DataMan.SDK.Utils.PC.dll
+
+
+
+
diff --git a/LecturaDM/Program.cs b/LecturaDM/Program.cs
new file mode 100644
index 0000000..3d1d223
--- /dev/null
+++ b/LecturaDM/Program.cs
@@ -0,0 +1,372 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Xml;
+using System.Text.RegularExpressions;
+using Cognex.DataMan.SDK;
+
+class Program
+{
+ private static Mutex _mutex = new Mutex(true, "EscudoLecturaDMCognex");
+ private static AutoResetEvent _esperaLectura = new AutoResetEvent(false);
+ private static bool _lecturaExitosa = false;
+ private static object _lock = new object();
+
+ private static string _configDirectory = "C:\\Jabil DM Config Station\\Files\\";
+ private static string _configPath = "";
+ private static string _resultLecturaPath = "";
+ private static string _lecturaDataPath = "";
+
+ private static volatile bool _triggerEnviado = false;
+
+ // ARREGLOS PARA EL RESPALDO
+ private static string[] _backupStandard = new string[4];
+ private static string[] _backupToken = new string[4];
+ private static string[] _backupDelimiter = new string[4];
+ private static bool _configModificada = false;
+
+ static void Main(string[] args)
+ {
+ _configPath = Path.Combine(_configDirectory, "ConfigIP.txt");
+ _resultLecturaPath = Path.Combine(_configDirectory, "ResultLectura.txt");
+ _lecturaDataPath = Path.Combine(_configDirectory, "Lectura.txt");
+
+ if (!_mutex.WaitOne(TimeSpan.Zero, true))
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine("[ALERTA] Ya hay una instancia de LecturaDM corriendo. Abortando colisión...");
+ Console.ResetColor();
+ return;
+ }
+
+ try
+ {
+ Console.WriteLine("==========================================");
+ Console.WriteLine(" PROGRAMA: LECTURA DM GEOMETRÍA ");
+ Console.WriteLine("==========================================\n");
+
+ ActualizarResultControl("0");
+
+ if (!File.Exists(_configPath))
+ {
+ Console.WriteLine($"[ERROR] No se encontró el archivo base: {_configPath}");
+ ActualizarResultControl("2");
+ Thread.Sleep(3000);
+ return;
+ }
+
+ string[] configLines = File.ReadAllLines(_configPath);
+ if (configLines.Length < 2)
+ {
+ Console.WriteLine("[ERROR] El archivo ConfigIP.txt no tiene el formato correcto.");
+ ActualizarResultControl("2");
+ Thread.Sleep(3000);
+ return;
+ }
+
+ string ipString = configLines[1].Trim();
+ if (!IPAddress.TryParse(ipString, out var lectorIp))
+ {
+ Console.WriteLine($"[ERROR] La IP '{ipString}' no es válida.");
+ ActualizarResultControl("2");
+ Thread.Sleep(3000);
+ return;
+ }
+
+ Console.WriteLine($"Conectando al DataMan en la IP: {lectorIp}...");
+ EthSystemConnector connector = new EthSystemConnector(lectorIp);
+ DataManSystem myDevice = new DataManSystem(connector);
+
+ try
+ {
+ myDevice.Connect(5000);
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("[OK] Conectado con éxito.");
+ Console.ResetColor();
+
+ try { myDevice.SendCommand("TRIGGER OFF"); } catch { }
+ Thread.Sleep(100);
+ try { myDevice.SendCommand("SET TRIGGER.TYPE 0"); } catch { }
+
+ // =====================================================================
+ // FASE DE RESPALDO Y MODIFICACIÓN
+ // =====================================================================
+ Console.WriteLine("[SISTEMA] Respaldando y preparando perfiles...");
+ _configModificada = true;
+
+ for (int i = 0; i <= 3; i++)
+ {
+ try { myDevice.SendCommand($"SET FORMAT.PROG-TARG {i}"); }
+ catch { continue; }
+
+ try { _backupStandard[i] = myDevice.SendCommand("GET FORMAT.STANDARD").PayLoad.Trim(); } catch { }
+ try { _backupToken[i] = myDevice.SendCommand("GET FORMAT.TOKEN").PayLoad.Trim(' ', '"'); } catch { }
+ try { _backupDelimiter[i] = myDevice.SendCommand("GET FORMAT.DELIMITER").PayLoad.Trim(); } catch { }
+
+ // INYECTAMOS EL TOKEN COMPLETO PARA OBLIGARLA A DARNOS EL XML
+ try { myDevice.SendCommand("SET FORMAT.STANDARD ON"); } catch { }
+ try { myDevice.SendCommand("SET FORMAT.TOKEN \"\""); } catch { }
+ try { myDevice.SendCommand("SET FORMAT.DELIMITER 5"); } catch { }
+ }
+
+ myDevice.SetResultTypes(ResultTypes.ReadString | ResultTypes.ReadXml);
+
+ myDevice.XmlResultArrived += (sender, e) =>
+ {
+ if (!_triggerEnviado) return;
+
+ lock (_lock)
+ {
+ if (_lecturaExitosa) return;
+
+ if (string.IsNullOrEmpty(e.XmlResult)) return;
+
+ try
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(e.XmlResult);
+
+ XmlNode? statusNode = doc.SelectSingleNode("//general/status");
+ if (statusNode == null || !statusNode.InnerText.ToUpper().Contains("GOOD READ"))
+ return;
+
+ // ======= DIAGNÓSTICO TEMPORAL - BORRAR DESPUÉS =======
+ /*Console.WriteLine("=== XML EXTERIOR COMPLETO ===");
+ Console.WriteLine(e.XmlResult);
+ Console.WriteLine("=== FIN XML EXTERIOR ===");
+
+ XmlNode? outerFullString_diag = doc.SelectSingleNode("//general/full_string");
+
+ if (outerFullString_diag != null)
+ {
+ Console.WriteLine("=== CONTENIDO FULL_STRING EXTERIOR ===");
+ Console.WriteLine($"InnerText: [{outerFullString_diag.InnerText}]");
+ Console.WriteLine($"InnerXml: [{outerFullString_diag.InnerXml}]");
+ Console.WriteLine($"Encoding attr: [{outerFullString_diag.Attributes?["encoding"]?.Value ?? "ninguno"}]");
+ Console.WriteLine("=== FIN FULL_STRING ===");
+ }
+ */
+
+ // El full_string exterior contiene otro XML completo como texto
+ XmlNode? outerFullString = doc.SelectSingleNode("//general/full_string");
+ if (outerFullString == null) return;
+
+ string innerXmlText = outerFullString.InnerText;
+
+ // Si está en base64, decodificar
+ string? enc = outerFullString.Attributes?["encoding"]?.Value;
+ if (enc != null && enc.ToLower() == "base64")
+ {
+ try
+ {
+ byte[] bytes = Convert.FromBase64String(innerXmlText);
+ innerXmlText = System.Text.Encoding.UTF8.GetString(bytes);
+ }
+ catch { }
+ }
+
+ string posX = "0";
+ string posY = "0";
+ string angulo = "0";
+ string codigoFinal = "";
+
+ try
+ {
+ // CDATA: extraer el código real
+ var matchCdata = Regex.Match(innerXmlText, @"");
+ if (matchCdata.Success)
+ codigoFinal = matchCdata.Groups[1].Value.Trim();
+
+ // Primer punto de code_position = posición del código
+ var matchX = Regex.Match(innerXmlText, @"\s*\s*([\d]+)\s*([\d]+)");
+ if (matchX.Success)
+ {
+ posX = matchX.Groups[1].Value;
+ posY = matchX.Groups[2].Value;
+ }
+
+ // Ángulo
+ var matchAng = Regex.Match(innerXmlText, @"([\d]+)");
+ if (matchAng.Success)
+ angulo = matchAng.Groups[1].Value;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[AVISO] Error extrayendo datos: {ex.Message}");
+ }
+
+ if (string.IsNullOrEmpty(codigoFinal))
+ codigoFinal = innerXmlText;
+
+ if (string.IsNullOrEmpty(codigoFinal)) return;
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+ Console.WriteLine($"\n[ÉXITO]");
+ Console.WriteLine($"-> Lectura: {codigoFinal}");
+ Console.WriteLine($"-> Posición X: {posX}");
+ Console.WriteLine($"-> Posición Y: {posY}");
+ Console.WriteLine($"-> Ángulo: {angulo}°");
+ Console.ResetColor();
+
+ _lecturaExitosa = true;
+ GuardarDatosLectura(codigoFinal, posX, posY, angulo);
+ ActualizarResultControl("1");
+ _esperaLectura.Set();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[ERROR PARSEO XML]: {ex.Message}");
+ }
+ }
+ };
+
+ Console.WriteLine("[SISTEMA] Drenando buffer de red...");
+ Thread.Sleep(600);
+
+ Console.WriteLine("[SISTEMA] Habilitando recepción...");
+ _triggerEnviado = true;
+
+ Console.WriteLine("Enviando disparo por software...");
+ myDevice.SendCommand("TRIGGER ON");
+
+ _esperaLectura.WaitOne(10000);
+
+ if (!_lecturaExitosa)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine("\n[TIEMPO AGOTADO] No se detectó código o falló la captura.");
+ Console.ResetColor();
+ ActualizarResultControl("2");
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"\n[ERROR CRÍTICO] Problema de conexión: {ex.Message}");
+ Console.ResetColor();
+ ActualizarResultControl("2");
+ }
+ finally
+ {
+ // =====================================================================
+ // FASE DE RESTAURACIÓN
+ // =====================================================================
+ try { myDevice.SendCommand("TRIGGER OFF"); } catch { }
+ Thread.Sleep(100);
+
+ if (_configModificada)
+ {
+ Console.WriteLine("[SISTEMA] Restaurando formato de salida original de la cámara...");
+ for (int i = 0; i <= 3; i++)
+ {
+ try { myDevice.SendCommand($"SET FORMAT.PROG-TARG {i}"); } catch { continue; }
+
+ if (!string.IsNullOrEmpty(_backupStandard[i]))
+ try { myDevice.SendCommand($"SET FORMAT.STANDARD {_backupStandard[i]}"); } catch { }
+
+ if (!string.IsNullOrEmpty(_backupDelimiter[i]))
+ try { myDevice.SendCommand($"SET FORMAT.DELIMITER {_backupDelimiter[i]}"); } catch { }
+
+ if (!string.IsNullOrEmpty(_backupToken[i]))
+ try { myDevice.SendCommand($"SET FORMAT.TOKEN \"{_backupToken[i]}\""); } catch { }
+ else
+ try { myDevice.SendCommand("SET FORMAT.TOKEN \"\""); } catch { }
+ }
+ }
+
+ try { myDevice.Disconnect(); } catch { }
+ }
+
+ Console.WriteLine("\nEl programa finalizará en 3 segundos...");
+ Thread.Sleep(3000);
+ }
+ finally
+ {
+ _mutex.ReleaseMutex();
+ }
+ }
+
+ private static void ActualizarResultControl(string estado)
+ {
+ try
+ {
+ // Paso 1: Escribir en la carpeta local del .exe
+ string localResultPath = "ResultLectura.txt";
+ string localCopiaPath = "ResultLectura_Copia.txt";
+
+ File.WriteAllText(localCopiaPath, estado);
+
+ if (File.Exists(localResultPath))
+ {
+ File.Delete(localResultPath);
+ Thread.Sleep(100);
+ }
+
+ File.Move(localCopiaPath, localResultPath);
+ Console.WriteLine("[SISTEMA] ResultLectura.txt actualizado localmente con estado: " + estado);
+
+ // Paso 2: Copiar al configDirectory
+ Thread.Sleep(100);
+ string configCopiaPath = Path.Combine(_configDirectory, "ResultLectura_Copia.txt");
+ File.Copy(localResultPath, configCopiaPath, true);
+
+ if (File.Exists(_resultLecturaPath))
+ {
+ File.Delete(_resultLecturaPath);
+ Thread.Sleep(100);
+ }
+
+ File.Move(configCopiaPath, _resultLecturaPath);
+ Console.WriteLine("[SISTEMA] ResultLectura.txt copiado a configDirectory.");
+ }
+ catch (Exception ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"[ERROR ARCHIVO CONTROL] No se pudo guardar estado: {ex.Message}");
+ Console.ResetColor();
+ }
+ }
+
+ private static void GuardarDatosLectura(string resultado, string x, string y, string angle)
+ {
+ try
+ {
+ // Paso 1: Escribir en la carpeta local del .exe
+ string localLecturaPath = "Lectura.txt";
+ string localCopiaPath = "Lectura_Copia.txt";
+ string[] lineas = new string[] { resultado, x, y, angle };
+
+ File.WriteAllLines(localCopiaPath, lineas);
+
+ if (File.Exists(localLecturaPath))
+ {
+ File.Delete(localLecturaPath);
+ Thread.Sleep(100);
+ }
+
+ File.Move(localCopiaPath, localLecturaPath);
+ Console.WriteLine("[SISTEMA] Lectura.txt actualizado localmente.");
+
+ // Paso 2: Copiar al configDirectory
+ Thread.Sleep(100);
+ string configCopiaPath = Path.Combine(_configDirectory, "Lectura_Copia.txt");
+ File.Copy(localLecturaPath, configCopiaPath, true);
+
+ if (File.Exists(_lecturaDataPath))
+ {
+ File.Delete(_lecturaDataPath);
+ Thread.Sleep(100);
+ }
+
+ File.Move(configCopiaPath, _lecturaDataPath);
+ Console.WriteLine("[SISTEMA] Lectura.txt copiado a configDirectory.");
+ }
+ catch (Exception ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"[ERROR ARCHIVO DATA] No se pudo guardar: {ex.Message}");
+ Console.ResetColor();
+ }
+ }
+}
\ No newline at end of file
diff --git a/LecturaDM/ResultLectura.txt b/LecturaDM/ResultLectura.txt
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/LecturaDM/ResultLectura.txt
@@ -0,0 +1 @@
+0
\ No newline at end of file