Separar binario por cada byte

Iniciado por Meta, 1 Abril 2021, 19:15 PM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Muy buen explicación.

En mi caso, siguiendo lo que me dicen, más la locura que tengo en la cabeza, el programa que hice es muy chapucero pero...

¡¡¡FUNCIONA!!!

;-) ;-) ;-) ;-) ;-) ;-) ;-) ;-)


Ver imagen.

Código C#:
Código (csharp) [Seleccionar]


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delimitador_consola_03
{
    class Program
    {
        static void Main(string[] args)
        {
            #region Configuración ventana.
            // Título de la ventana.
            Console.Title = "Probando manipulación de cadena";

            // Tamaño de la ventana, x, y.
            Console.SetWindowSize(100, 35);

            // Color de fondo.
            Console.BackgroundColor = ConsoleColor.DarkBlue;

            // Color de las letras.
            Console.ForegroundColor = ConsoleColor.Yellow;

            // Limpiar pantalla y dejarlo todo en color de fondo.
            Console.Clear();

            // Visible el cursor.
            Console.CursorVisible = true;
            #endregion

            // Cree una codificación ISO-8859-1.
            Encoding ISO_8859_1 = Encoding.GetEncoding("ISO-8859-1");

            #region Variables.
            // Partir a trocitos estos caracteres.
            char[] delimitadorComandoB = { '#', ',', 'O', 'I', 'L', 'B', 'V', 'F', 'H', 'R', 'S', };

            // Es la cadena de caracteres que me llegó desde el puerto serie.
            // En este ejemplo lo dejo en la varible directamente.
            // Una cadena completa empieza con # y termina en <cr>, o lo que es lo mismo, /r.
            string respuestaB = "#I223.3O224.0L000B100V26.4F50.2H50.2R0080S,,€€,,À"; // Comando B.

            // Se guarga en este array tipo string los datos ya partidos a tozos.
            string[] palabrasB = respuestaB.Split(delimitadorComandoB);

            // Tabla S1 descripción.
            string[] DESCRIPCION_S1 =
            {
                "Indica que este byte está disponible y es válido. [Siempre 1]",             // Posición [0].
                "Indica falla de energía de la red pública; ver detalles en S2.0 y S2.1.",
                "Indica que la capacidad de la batería es menor que el umbral de apagado.",
                "Indica que el zumbador está en estado de pitido.",
                "Indica que la prueba de batería se está procesando.",
                "Indica que el apagado programado está pendiente.",
                "Indica que la restauración programada está pendiente.",
                "Indica falla de hardware; ver detalles sobre el comando X71."               // Posición [7].
            };

            string[] DESCRIPCION_S2 =
            {
                "Para indicar que este byte está disponible y es válido. [Siempre 1].",
                "--",
                "XX",
                "Indica sobretemperatura del inversor.",
                "Indica que el inversor tiene una falla.",
                "Indica que el inversor está apagado.",
                "Indica que la frecuencia de la utilidad está fuera de rango.",
                "Indica que el voltaje de la red pública está fuera de rango."
            };

            string[] DESCRIPCION_S3 =
            {
                "Para indicar que este byte está disponible y es válido. [Siempre 1].",
                "Indica que la batería está completamente cargada.",
                "Indica que la capacidad de la batería aún es menor que el umbral restaurado del UPS cuando la energía de la red pública restaurado.",
                "Indica que la batería se está cargando.",
                "Indica que la batería se está descargando.",
                "Indica que la capacidad de la batería es inferior al 80 por ciento.",
                "Reservado, debe ser 0.",
                "Indica que la batería no está presente."
            };

            string[] DESCRIPCION_S4 =
{
                "Para indicar que este byte está disponible y es válido. [Siempre 1].",
                "Indica que el bypass es una sobrecarga.",
                "Indica que la derivación está activa.",
                "Indica que la salida sufre un cortocircuito.",
                "Indica que la salida tiene carga.",
                "Indica que la salida está sobrecargada.",
                "Indica que la frecuencia de salida está fuera de rango en bypass.",
                "Indica que el voltaje de salida está fuera de rango en derivación."
            };

            string[] DESCRIPCION_S5 =
{
                "Para indicar que este byte está disponible y es válido. [Siempre 1].",
                "Indica que no hay salida.",
                "Para indicar que el tiempo de ejecución restante es inferior al umbral.",
                "Para indicar que el zumbador está silenciado (no permanente) en este momento.",
                "Para indicar falla de cableado.",
                "Para indicar SAI en modo ECO.",
                "Para indicar UPS en Bypass manual.",
                "Arreglar 0."
            };

            string[] DESCRIPCION_S6 =
{
                "Para indicar que este byte está disponible y es válido. [Siempre 1].",
                "Indica UPS encendido.",
                "Reservado, debe ser 0.",
                "Reservado, debe ser 0.",
                "Reservado, debe ser 0.",
                "Reservado, debe ser 0.",
                "Reservado, debe ser 0.",
                "Reservado, debe ser 0."
            };

            bool boolS1 = true;
            bool boolS2 = false;
            bool boolS3 = false;
            bool boolS4 = false;
            bool boolS5 = false;
            bool boolS6 = false;
            bool boolContador = true;
            bool boolContador2 = false;
            #endregion

            // Muestra los resultados en pantalla.
            Console.WriteLine();
            Console.WriteLine("El voltaje de la utilidad es de {0} voltios. ", palabrasB[2]); // I.
            Console.WriteLine("El voltaje de salida del UPS es de {0} voltios. ", palabrasB[3]); // O.
            Console.WriteLine("La carga actual de UPS es del {0} por ciento. ", palabrasB[4]); // L.
            Console.WriteLine("La capacidad de la batería es del {0} por ciento. ", palabrasB[5]); // B.
            Console.WriteLine("El voltaje de la batería es de {0} voltios. ", palabrasB[6]); // V.
            //Console.WriteLine("La temperatura del gabinete del UPS es de {0} grados centígrados. ", palabrasB[7]); // T. No hay T. en mi versión.
            Console.WriteLine("La frecuencia de salida del SAI es de {0} Hz. ", palabrasB[7]); // F.
            Console.WriteLine("La frecuencia de salida del SAI es de {0} Hz. ", palabrasB[8]); // H.
            Console.WriteLine("El tiempo de funcionamiento restante de la batería es de {0} minutos. ", palabrasB[9]);
            //Console.WriteLine(@"Estos son los bits de estados que no se entiende.S:
            //Aquí hay que leer cada bits como cuando se leyeron cada Byte arriba: ", (char)palabrasB[10]);

            char[] bits = palabrasB[10].ToCharArray();

            Tabla();
            int contador = 0;
            for (int b = 0; b < bits.Length; b++)
            {
                for (int a = 7; a >= 0; a--)
                {
                   
                    Console.Write((((byte)bits[b]) & (1 << a)) >> a);
                    Console.Write(" | ");

                    if ((contador <= 7) && (boolS1 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S1[contador]);

                        if (contador == 7)
                        {
                            boolS1 = false;
                            boolS2 = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }
                    else if ((contador <= 7) && (boolS2 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S2[contador]);
                        boolContador2 = false;
                        if (contador == 7)
                        {
                            boolS2 = false;
                            boolS3 = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }
                    else if ((contador <= 7) && (boolS3 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S3[contador]);
                        boolContador2 = false;
                        if (contador == 7)
                        {
                            boolS3 = false;
                            boolS4 = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }
                    else if ((contador <= 7) && (boolS4 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S4[contador]);
                        boolContador2 = false;
                        if (contador == 7)
                        {
                            boolS4 = false;
                            boolS5 = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }
                    else if ((contador <= 7) && (boolS5 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S5[contador]);
                        boolContador2 = false;
                        if (contador == 7)
                        {
                            boolS5 = false;
                            boolS6 = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }
                    else if ((contador <= 7) && (boolS6 == true))
                    {
                        Console.WriteLine(DESCRIPCION_S6[contador]);
                        boolContador2 = false;
                        if (contador == 7)
                        {
                            boolS6 = true;
                            boolContador = true;
                            boolContador2 = true;
                            contador = 0;
                        }
                    }

                    if (boolContador == true)
                    {
                        contador++;

                        if (boolContador2 == true)
                        {
                            contador = 0;
                        }
                    }
                    //Console.WriteLine();
                }
                Console.WriteLine();
            }
           

            #region Tabla.
            void Tabla()
            {
                Console.WriteLine("Byte | Bit | Estado | Descripción");
                Console.WriteLine("-----+-----+-----------------------------------------------------------------------");
            }
            #endregion

            // Pulse cualquier tecla para salir.
            Console.ReadKey();
        }
    }
}



Código chapuza pero funciona.

Ahora la pregunta del millón.

Cada vez que envío un comando me da un resultado diferente.

¿Cómo procesaría cada resultado correspondiente a cada comando?

Está claro que el comando B<cr>, la cadena al recibir no tiene nada que ver con otros comandos.

¿Se entiende lo qué quiero decir?

Si no entiendes, lo pregunto de otra manera.

Gracias.

Gracias a todos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

#11
No estoy seguro de entenderte, pero quizás si...

Tu lo que creo que quieres ahora es decodificar el byte que te llega...Si es así, es suficiente pcoo código, bastan unas constantes, y un par de funciones...

Déjame que parta de un ejemplo con suposiciones (abstracción, no necesito empaparme del asunto concreto que trates).

// Constantes para la bateria: (un supuesto comando, que te devuelve 1 byte y cada bit tiene un significado propio)
Enumeracion ConstantesDeBateria
   BATERIAPRESENTE = 1   // 0000.0001
   BATERIAAGOTADA = 2   //  0000.0010
   BATERIACARGANDO = 4 // 0000.0100
   BATERIAAL80OMAS = 8 // 0000.1000
   BATERIAW = 16 // 0001.0000
   BATERIAX = 32  // 0010.0000
   BATERIAY = 64 // 0100.0000
   BATERIAZ= 128 // 1000.0000
Fin enumeracion

enumeracion ConstantesDeComandos
   COMANDO_BATERIA = 136  // POR EJEMPLO
   ...otros comandos (aunque algunas veces admiten string en vez de numeros, no creo que sea el caso presente).
fin enumeracion

array de string mensajeBateriaOK(0 a 7)  //mensaje generico para cada bit cuando es '1'.
array de string mensajeBateriaNO(0 a 7)  // mensaje generico para cada bit cuando es '0'.


// el comando típicamente podría quedar aparte del valor (no ser recibido, solo enviado), o podria venir conjunto, precediendo o sucediendo uno al otro, depende de qué hardware se trate...
funcion RecibirComando(ConstantesDeComandos comando, byte valor)
   selecccionar caso comando
       caso COMANDO_BATERIA
           llamada a ProcesarBateria(valor)
      caso X
      caso Y
      ...mas casos...
   fin casos
fin funcion

funcion ProcesarBateria(byte valor)
   entero k
   string mensaje
   ConstantesDeBateria cb

   cb= 1
   bucle para k desde 0 hasta 7
       si TestBit(valor, cb)
           escribirmensaje = mensajeBateriaOK(k) + ...quizás algun valor
       sino
          escribirmensaje = mensajeBateriaNO(k) + ...quizás algun valor
       fin si
        cb = (cb * 2)  ' pasará por los valores: 1,2,4,8,16...128
   siguiente
fin funcion

buleano = funcion TestBit(byte valor, byte Bit)
  devolver (valor and Bit)
fin funcion


Eso de '+ ...quizás algun valor', es para recordarte la respuesta de otro día que trataba sobre concatenar cadenas complejas con valores parametrizables en medio (¿recuerdas?)...

Es solo pasarlo a código y 'ampliar' la oferta de los comandos...
Si es otra cosa lo que pides, me temos que tendrás que expresarte con más claridad.

Meta

#12
Buenas:

Me gustó el ejemplo que usaste máscaras a la hora de tratar bits en un Byte. Lo he hecho en Windows Form como ejemplo.

Ver zoom.

Código (csharp) [Seleccionar]
using System;
using System.Windows.Forms;

namespace Leer_bits_de_un_Byte_01
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       int ascii;
       int resultado;
       readonly int[] mascara = new int[8]
       {
           0b_0000_0001, // Posición [0].
           0b_0000_0010,
           0b_0000_0100,
           0b_0000_1000,
           0b_0001_0000,
           0b_0010_0000,
           0b_0100_0000,
           0b_1000_0000  // Posición [7].
       };

       private void textBox_ASCII_TextChanged(object sender, EventArgs e)
       {
           try
           {
               ascii = int.Parse(textBox_ASCII.Text);
               resultado = ascii & mascara[0];
               if (resultado == 0) { label_c0.Text = "0"; } else { label_c0.Text = "1"; }
               resultado = ascii & mascara[1];
               if (resultado == 0) { label_c1.Text = "0"; } else { label_c1.Text = "1"; }
               resultado = ascii & mascara[2];
               if (resultado == 0) { label_c2.Text = "0"; } else { label_c2.Text = "1"; }
               resultado = ascii & mascara[3];
               if (resultado == 0) { label_c3.Text = "0"; } else { label_c3.Text = "1"; }
               resultado = ascii & mascara[4];
               if (resultado == 0) { label_c4.Text = "0"; } else { label_c4.Text = "1"; }
               resultado = ascii & mascara[5];
               if (resultado == 0) { label_c5.Text = "0"; } else { label_c5.Text = "1"; }
               resultado = ascii & mascara[6];
               if (resultado == 0) { label_c6.Text = "0"; } else { label_c6.Text = "1"; }
               resultado = ascii & mascara[7];
               if (resultado == 0) { label_c7.Text = "0"; } else { label_c7.Text = "1"; }
           }
           catch(Exception error)
           {
               MessageBox.Show(error.Message, "Aviso:",
               MessageBoxButtons.OK, MessageBoxIcon.Warning);
           }
       }
   }
}


En cuanto a lo que quiero decir desde el principio, lo comento de otra manera para que se entienda mejor.

El progrma de ahora mismo está hecho en consola, solo está diseñado para recibir una respuesta de un comando.

Por ejemplo el comando B<cr>

Si envío el comando B<cr> recibo una trama de Bytes, que cada respuesta recibida, siempre empieza la cadena en # como inicio y en <cr> como fin. <cr> es Retorno de Carro. En código es así, /r.

¿Qué ocurre cuando envío otro comando diferente a un dispositivo?

Que me devuelve otro resultado diferente y este programa en C# no lo procesa como debería.

Dejo un ejemplo de un Terminal indicado abajo.
Envío comando B<cr> me da una respuesta larga. Luego envío otro comando llamado X87<cr> y me llega otra cadena más corta y no tiene nada que ver con la B, así con todos los comandos.


Ver zoom.

Aquí abajo dejo un PDF que me dio el fabricante de un SAI. Se muestra el protocolo de comunicación, los comandos y que respuesta recibes.

Descargar.

En resumen.
Quiero hacer un programa, que al enviar un comando, el que sea, me procese la cadena de caracteres recibidos correspondiente.

Espero que esta vez se entienda.

Muchas gracias.  :D

PD: Con tu ejemplo de las máscaras, voy hacer un ejemplo con enum como hicistes en un programa a parte para cotillear y aprender mejor.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

#13
Me obligas a leerme el pdf, y es precisamente lo que uno trata de evitar, porque ir al detalle fino, requiere mucho más tiempo en responder y sale un mensaje más largo.

Es definitiva es como te señalaba en mi mensaje anterior...
En ese incluí el ejemplo para decodificar un supuesto comando de la bateria (que existe se llama B (Battery), pero con sus valores específicos).

El comando X27, viene explicado también en el pdf, recibe '#' con 6 bytes, un cóoodigo de error viene en la forma: "#- loque sea".

Lo más sencillo al caso una vez leído por encima en pdf, es hacer un parsing genérico y luego especifico para cada comando... es más o menos el pseudocódigo previo que puse en mi mensaje anterior... la parte del preparsing, sería algo como:


enumeracion PartesResultado
  COMANDO_INICIO = 35  // el ASCII de '#'
  COMANDO_FIN = 13  // el ASCII de 'retorno de carro
  //COMANDO_MEDIO = 1   // referencia al medio, luego se explica mejor.
fin enumeracion


Ahora una funcion que preprocesa el comando recibido:

funcion ParsingComando(string comando, string valor)
   entero inicio, cantidad

   si ((valor comienza con COMANDO_INICIO) y (termina con COMANDO_FIN))
       
       Si (valor.charat(1) = "-")          // parece ser un código de error. "#- loquesea"
            llamada a InterpetarCodigoError(substring(valor, 2,1))   //enviamos el carácter 3 de los 4 que tiene
              // (ignoro si tienen más de 1 byte-char como codigo de error.
       Sino  // el resultado tiene valores interpretables:
           // enviamos ya 'recortdo' el string, sin los caracteres inicial y final
           inicio = 1
           cantidad =  valor.length -2
           llamada a ProcesarComandos(comando, valor.Substring(inicio, cantidad))
         
       fin si
   sino
       mensaje = "Error, el valor del comando recibido, tiene un formato desconocido..."
   fin si
fin funcion


Como decía conviene tener una enumeracion que represente cada comando:
Hay todos estos comandos:  "The I, O, L, B, V, T, F, H, R, C, Q, S, W, X are single uppercase

enumeracion ComandosSAI
   SAI_COMANDO_BATERIA = 66    // ASCII de 'B'
   SAI_COMANDO_UTILITY_VOLT = 73  // ASCII de 'I' (una 'i').
   //
   //
   ...
   SAI_COMANDO_STATUS_FLAG = 83  //ASCII de 'S'.
   SAI_COMANDO_W...     = 87   //   idem de 'W'
   SAI_COMANDO_X...     = 88   // " 'X'
character"



La funcion procesar comando, tendrá en selector de casos, con un caso para cada comando que te interese y un 'else', para el resto...
Esto viene a ser equivalente al código de más arriba, solo que allí se recibía 1 solo byte y se ejemplificaba solo el comando 'B' de batería.
Algunos comandos  como el X, tienen 'subcomandos' en la forma Xn, donde 'n' es un numero...
Estos comandos dento de su 'caso', examina precisamente el 'subcomando', y lo gestiona a su vez con otro 'selector de casos'.
Como los comandos al final tienen varos bytes, interesa más hacer una llamada en esta funcion para dedicar una funcion exclusiva para procesar cada comando o subcomando, incluso aunque haya partes comunes entre ellos, será m
ás fácil de implementar y de mantener aunque sea a costa de más código:


funcion ProcesarComandos(string comando, string valor) //valor ya viene filtrado de # y 'cr'
  ComandosSAI SaiComando = comando.left(1).ToByte
 

   seleccionar caso para SaiComando
       caso SAI_COMANDO_BATERIA
           llamada a ProcesarBateria(valor)
       caso SAI_COMANDO_UTILITY_VOLT
           llamada a ProcesarUtilityVolt(valor)
          ....
       caso SAI_COMANDO_STATUS_FLAG
           llamada a ProcesarStatusFlag(valor)
       caso SAI_COMANDO_W...
           llamada a ProcesarW(valor)
       caso SAI_COMANDO_X...
            comando = comando.substring(1, comando.length-1)
            llamada a ProcesarX(comando, valor)   // <-------- ejemplo de un comando que tiee subcomandos
       otros casos
               mensaje "Actualmente no procesamos el comando: " + comando + nuevalinea + valor
   fin casos
fin funcion

funcion ProcesarX(string comando, string valor)
   byte servico = comando.Tobyte

   seleccionar caso para servicio
       caso 5    
       caso 15  
         ...
       caso 27   // tiene 6 chars
           llamada a ProcesarX27(valor)
       caso 28
         ...
       otros casos
           mensaje "Actualmente noe staos procesando el subcomando '" servicio.Tostring + "' del comando 'X', con valor: " + valor
   fin seleccionar casos
fin funcion

// Según el pdf: #output_voltage,high_transfer_voltage,low_transfer_voltage, battery_threshold,runtime_threshold<cr>
funcion ProcesarX27(string valor)
   llamada a procesarOutputVoltage(valor.charat(0).tobyte)
   llamada a procesarHighTransferV(valor.charat(1).tobyte)    
   llamada a procesarLowTransferV(valor.charat(2).tobyte)
   llamada a procesarBatteryThreshold(valor.charat(3).tobyte)
   llamada a procesarThreshold(valor.substring(4,2))      // este parametro ocupa creo que 2 bytes.
fin funcion


Y bueno, este es el esqueleto para decodificar todo... fíjate que es un simple parsing, donde primero se verifica si el resultado es un codigo de erro o no... sino, luego se verifica que comando se trata, luego cada comando si tiene subcomandos, deriva a otra funcion que identifique de qué subcomando se trata, al final cada comando final, tiene que ser procesado individualmente, porque los bits de cada uno tendran un significado unico y específico...
El caso de error, igualmente en su llamada debe derivar descendeidno e comandos y subcomandos, segun sea el caso, para que al final procesar el error. Ignoro si cuando es un código de error, se compone de un unico byte o más... si es solo uno, una unica funcion (a nivel de comandos y subcomandos) podría ser suficiente, en cambio si tiene varios bytes, y el codigo puede ser excesivo (generaría una función muy larga), convendría en ese caso, tener una etapa más donde se procese cada byte (si cada bit tiene un significado propio, si cada byte tiene un significado propio es lo mismo que recibir 1 solo byte con significado propio a nivel de bit (o más de 1).

En fin, el trabajo no es complicado, solo largo y algo tedioso, porque son más de una docena de comandos y algunos tienen subcomandos, y luego cada caso se procesa a nivel de bit, por lo que necesitas constantes a mogollon...

pd.: Olvidaba adjuntar una captura que hice, para que veas que viene explicado, tienes que leerlo primero entero, para tener una idea global y luego ocn más detenimiento en el apartado que más te interese, si te interesan todos, pués paciencia, hoy uno y mañana otro.

Meta

Muy bueno:
;-) ;-) ;-) ;-) ;-) ;-) ;-)

Sí, es largo y tedioso.

Los comandos de error he recibido estos.
#-0
#-1
#-3
#-10

Tendría que probocar algo para que me dieran más respuestas erróneas. El fabricante no me hace caso sobre qué significa estos errores. Lo del PDF lo tengo más que leído, es más, este documento que me dieron que es del 2018, mi versión de la UPS aunque lo compré hace semanas, es la 2.020. El firmware que tiene una versión y no se si se puede actualizar.

Si te fijas bien, hay comando que no vienen como indica en el PDF.
CitarHay todos estos comandos:  "The I, O, L, B, V, T, F, H, R, C, Q, S, W, X are single uppercase

Su respuesta es esta.
Citar#I223.3O224.0L000B100V26.4F50.2H50.2R0080S,,€€,,À

Otra cosa.
La interfaz oficial es por Web.

Pruebo los comandos del en el Hyper Terminal de Windows o otro similar y me funciona. He hecho un poco mi propio programa en Windows Form y controlado el puerto serie en el cual puedo con botones apagar y encender el zumbador o pitido del SAI o UPS.

El programa que incluye es por Web local. La ruta para acceder es con un archivo que se llama agent.cmd y en su interior tiene este código.

start http://localhost:3052/local/


Ver imagen.

Lo curioso que la forma de controlar el puerto serie el programa oficial, es con un programa modo servicio, que lo puedo detener o arrancar como dice abajo.

Ver imagen.

Este detalle lo intentaré hacerlo en otro proyecto mucho más adelante. ;)
No controlar la UPS, sino otros aparatos como Arduino por puerto serie de esta manera, por vía Web.

Antes lo hacía de esta manera por capaz.
Actuadores <-----> Arduino <-----> PC <-----> Base de datos <-----> Interfaz <-----> Conexión a Internet.


  •     Un ejemplo. Uso Arduino que tiene un display LCD 20x4 en el cual me muestra en todo momento los estados de entradas y salidas. Arduino controla una habitación, ventilador, extractor de aire, ventana motorizada, deteción de gases, alarma, temperatura, humedad, detección si hay apagón de luz y incluye su UPS, etc...
        Ese Arduino lo tengo directamente conectado a su USB al PC.
        En el PC tengo una interfaz que controla el puerto serie/USB y una base de datos.
        Tengo conexión en el PC a Internet.
        La base de datos instalada tengo una buena tabla hecha sobre control de relés y estados de avisos o alarmas.
        Si cambio un valor en una base de datos, por ejemplo, un 1, se me enciende un Led, si pongo un 0, se apaga un Led.
        La interfaz detecta un cambio en la base de datos los datos, lo envía al puerto serie ese valor y le llega a Arduino.
        En la propia Interfaz de un programa de escritorio o Web, puede cambiar valores en la base de datos que también envía datos a Arduino.

Es otra historia.

Sigo interpretado tu código, ya que me ha aportado muchas ideas. Sobre todo de diferenciar códigos de respuestas según código enviado.

Ahora estoy en plan chamuzqueándome la cabeza. A ver si me sale todo esto de alguna vez por todas.

Y sí, es muyyyyyyyyyyyyyyyyyyyy, laaaaaaaaaarrrrrrrrrrrrrrrrrrrrrrrrrrgo y tedioso de la leche.  ;D

Se hará poco a poco, mientras entiendas lo básico, todo lo demás saldrá poco a poco.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Meta

Aunque no lo parezca, sigo comiéndome las neuronas sobre código a a enviar y cuando recibos los comandos.

Ya daré con el tiempo códigos de ejemplos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Meta

#16
Hola:

Los comandos que tiene subcomandos como el K60:1 no hay problemas. Hay respuesta que me lelgan de error,el que no tiene error es este.

Aquí un terminal que ejecuto B y X87.

ver imagen.

Cuando hay errore sraros, suele recibir estos mensajes.
#0
#-1
#-3
#-10
Con guines en medio.

Aquí abajo activa y desactiva el zumbador del SAI cuyo comando tiene subcomando.



Cualquier comando enviado se envía fácil, aquí el comando a enviar.
Código (csharp) [Seleccionar]
       private void button_Desactivar_Click(object sender, EventArgs e)
       {
           byte[] mBuffer = Encoding.ASCII.GetBytes("K60:0\r"); // Comando K60:0 desactivar.
           serialPort1.Write(mBuffer, 0, mBuffer.Length);
       }


El problema está cuando hay que recibir respuesta de dicho comando y ya no estan fácil.

Hay que organizar todo, las respuestas. Como se dijo arriba, cada día una interpretación de cada comando que tarda uno por día porque es laaaaaarrrrrrrrrrgo y tedioso.

Aquí dejo un programa completo solo de un comando, el K60 que activa y desactiva el zumbador.

Código (csharp) [Seleccionar]
using System;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Terminal_UPS_SAI_02
{
   public partial class Form1 : Form
   {
       // Utilizaremos un string como buffer de recepción.
       string recibidos;

       public Form1()
       {
           InitializeComponent();
       }


       private void Form1_Load(object sender, EventArgs e)
       {
           try
           {
               // Codificación.
               //serialPort1.Encoding = Encoding.GetEncoding(437);
               //serialPort1.Encoding = Encoding.GetEncoding(28591); // 28591 es lo mismo que ISO-8859-1.
               serialPort1.Encoding = Encoding.GetEncoding("ISO-8859-1");
               
               // Añado los puertos disponible en el PC con SerialPort.GetPortNames() al comboBox_Puerto.
               comboBox_Puerto.DataSource = SerialPort.GetPortNames();

               // Añade puertos disponibles físicos  y virtuales.
               serialPort1.PortName = comboBox_Puerto.Text.ToString();

               // Añadir datos recibidos en el evento.
               serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
           }

           catch (Exception error)
           {
               MessageBox.Show(error.Message, "Aviso:",
                   MessageBoxButtons.OK, MessageBoxIcon.Warning);
           }
       }

       // Detecta USB o puerto serie virtual cuando lo conecta y desconecta del cable.
       protected override void WndProc(ref Message USB)
       {
           if (USB.Msg == 0x219)
           {
               comboBox_Puerto.DataSource = SerialPort.GetPortNames();
           }

           // Detecta si hay cambios en el usb y si los hay los refleja.
           base.WndProc(ref USB);
       }

       private void button_Conectar_Click(object sender, EventArgs e)
       {
           try
           {
               serialPort1.PortName = comboBox_Puerto.Text.ToString(); // Puerto seleccionado previamente.
               serialPort1.BaudRate = Convert.ToInt32(comboBox_Baudios.Text); // Baudios.
               serialPort1.Open(); // Abrir puerto.
               comboBox_Puerto.Enabled = false;
               comboBox_Baudios.Enabled = false;
               button_Conectar.Enabled = false;
               button_Desconectar.Enabled = true;
               groupBox_Control_Zumbador.Enabled = true;
           }
           catch (Exception error)
           {
               MessageBox.Show(error.Message, "Aviso:",
               MessageBoxButtons.OK, MessageBoxIcon.Warning);
           }
       }

       private void button_Desconectar_Click(object sender, EventArgs e)
       {
           try
           {
               serialPort1.Close(); // Cerrar puerto.
               comboBox_Puerto.Enabled = true;
               comboBox_Baudios.Enabled = true;
               button_Conectar.Enabled = true;
               button_Desconectar.Enabled = false;
               groupBox_Control_Zumbador.Enabled = false;
           }

           catch (Exception error)
           {
               MessageBox.Show(error.Message, "Aviso:",
               MessageBoxButtons.OK, MessageBoxIcon.Warning);
           }
       }

       // Al cerrar el formulario, cierra el puerto si está abierto.
       private void Form1_FormClosing(object sender, FormClosingEventArgs e)
       {
           try
           {
               serialPort1.Close(); // Cerrar puerto.
           }

           catch (Exception error)
           {
               MessageBox.Show(error.Message, "Aviso:",
               MessageBoxButtons.OK, MessageBoxIcon.Warning);
           }
       }

       // Al recibir datos.
       private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
       {
           // Retardo de 500 ml.
           //Thread.Sleep(500);

           // Acumula los caracteres recibidos a nuestro 'buffer' (string).
           recibidos += serialPort1.ReadExisting();

           // Invocar o llamar al proceso de tramas.
           this.Invoke(new EventHandler(Actualizar));
       }

       // Procesar los datos recibidos en el bufer y extraer tramas completas.
       private void Actualizar(object sender, EventArgs e)
       {

           // Asignar el valor de la trama al richTextBox.
           richTextBox1.Text += recibidos;

           // Pasar a hexadecimal.
           foreach (byte b in recibidos)
           {
               // x = minúscula, X = mayúscula.
               richTextBox1.Text += b.ToString("X2");
           }

           // Nueva línea.
           richTextBox1.Text += Environment.NewLine;

           // Pasar a binario.
           foreach (string leer in recibidos.Select(c => Convert.ToString(c, 2)))
           {
               richTextBox1.Text += leer.ToString();
           }

           // Nueva línea.
           richTextBox1.Text += Environment.NewLine;
           richTextBox1.Text += Environment.NewLine;

           // Selecciona la posición final para leer los mensajes entrantes.
           richTextBox1.SelectionStart = richTextBox1.Text.Length;

           // Mantiene el scroll en la entrada de cada mensaje.
           richTextBox1.ScrollToCaret();

           // Limpiar.
           recibidos = "";
       }

       private void button_Activar_Click(object sender, EventArgs e)
       {
           byte[] mBuffer = Encoding.ASCII.GetBytes("K60:1\r"); // Comando K60:1 activar.
           serialPort1.Write(mBuffer, 0, mBuffer.Length);
       }

       private void button_Desactivar_Click(object sender, EventArgs e)
       {
           byte[] mBuffer = Encoding.ASCII.GetBytes("K60:0\r"); // Comando K60:0 desactivar.
           serialPort1.Write(mBuffer, 0, mBuffer.Length);
       }

       private void button_Mute_temporal_Click(object sender, EventArgs e)
       {
           byte[] mBuffer = Encoding.ASCII.GetBytes("K60:2\r"); // Comando K60:2 Mute temporal.
           serialPort1.Write(mBuffer, 0, mBuffer.Length);
       }

       private void button_Limpiar_Click(object sender, EventArgs e)
       {
           // Limpiar.
           richTextBox1.Clear();
       }

       #region DTR y RTS.
       private void checkBox_DTR_CheckedChanged(object sender, EventArgs e)
       {
           // ¿Marcado en true?
           if (checkBox_DTR.Checked == true)
           {
               // Sí.
               serialPort1.DtrEnable = true;
               checkBox_DTR.Checked = true;
           }

           // No. Entonces...
           else
           {
               serialPort1.DtrEnable = false;
               checkBox_DTR.Checked = false;
           }
       }

       private void checkBox_RTS_CheckedChanged(object sender, EventArgs e)
       {
           // ¿Marcado en true?
           if (checkBox_RTS.Checked == true)
           {
               // Sí.
               serialPort1.RtsEnable = true;
               checkBox_RTS.Checked = true;
           }

           // No. Entonces...
           else
           {
               serialPort1.RtsEnable = false;
               checkBox_RTS.Checked = false;
           }
       }
       #endregion
   }
}


Otra cosa que no se si hay que usar el codificador Encoder que usé, por ejemplo este.
Código (csharp) [Seleccionar]
Encoding.GetEncoding("ISO-8859-1");

Y no se si realmente usar DTR como indica en el manual.


A ver si me responde que sistema de codificación usar realmente para que cuando me devuelva ASCII sea el que realmente es.

Estaba pensando en hacer un programa padre que cada comando tiene su propia interfaz hijo, así lo interpreta la respuesta recibida por cada interfaz. Suena chapuza pero pinta que funciona.

Interpretar el mismo interfaz diferentes respuestas ya es otro cantar.

Lo buenoq eu tiene al recibir respueta, es que empieza por # y termina en <cr> y ya se puede dibidir cadenas para analizarlas.

Sigo investigando y interpretando tus consejos.

Gaacias.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/