Separar binario por cada byte

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

0 Miembros y 2 Visitantes están viendo este tema.

Meta

Hola:

Al mostrar una trama de bytes, lo presento en binario y me muestra esto.

001000111100011110010111110000001011000000001101

Hay 6 Bytes que en realidad en hexadecimal es 23 C7 97 C0 B0 0D

Quiero que se me separe así en cada byte o cada 8 bit.

00100011 11000111 10010111 11000000 10110000 00001101

He intentado hacerlo con este código:
Código (csharp) [Seleccionar]
            // Pasar a binario.
            foreach (string leer in recibidos.Select(c => Convert.ToString(c, 2)))

            {
                richTextBox1.Text += leer.ToString();
            }


Me pasa dos cosas.
Como en el ejemplo de arriba, si los bits empieza por cero y encuentro un uno, por ejemplo. 00000001, en la pantalla me aparece solo el 1 ignorando los sietes primeros 0. Me gusta más que se muestre así 00000001 en vez de tipo ahorrador con solo un 1.

La otra cosa, que por cada 8 bytes en binario se muestre separado como indicado arriba.

¿Es posible hacerlo?

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

WHK

Intenta procesarlo con un arreglo de bytes en ves de un string, mira esto:

https://stackoverflow.com/questions/5664345/string-to-binary-in-c-sharp

string.Join(" ", data.Select(byt => Convert.ToString(byt, 2).PadLeft(8, '0')));

Meta

Buenas mi muy distinguido amigo:

El problema que el código y variable recibidos me viene en string.

Lo he intentado poner en Byte y me da más problemas por todas partes. El código es enorme.

Dejo un ejemplo para que lo veas y te hagas una gran idea.


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

namespace Ejemplo
{
    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)
        {
            // Acumula los caracteres recibidos a nuestro 'buffer' (string).
            recibidos += serialPort1.ReadExisting();

            // Invocar o llamar al proceso de tramas.
            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.
            byte[] mBuffer = Encoding.ASCII.GetBytes("X87\r"); // Comando X87 Flags.
            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("B\r"); // Comando K60:2 Mute temporal.
            serialPort1.Write(mBuffer, 0, mBuffer.Length);
        }

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

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

@XSStringManolo

Usa un bucle

Código (cpp) [Seleccionar]
string binario = "001000111100011110010111110000001011000000001101";
string resultado = "";
for (int i = 0; i < binario.Length; i += 8) {
  resultado += binario.Substring(i, 8) + " ";
}


Substring pilla desde el index hasta los siguientes 8 caracteres, asique si solo quedan por ejemplo 3, los pillas igual.

Te sobra un espacio al final. Puedes sumarle 8 al iterador para ver si en la siguiebte iteración ya no vas a entrar en el bucle A.K.A no añadas el espacio la última vez que iteras porque ya acabaste de añadir bytes. O reasignas con Substring usando 0, y resultado.Length -1

Meta

#4
Buenas:

Como veo la base ya tienes una variable con 0 y 1.
Hice el foreach y for que indicaste. Me da problemas. Lo hice así para que lo pase a binario y elfor tuyo para que lo separe.


Ver zoom.

Código (csharp) [Seleccionar]
           // Pasar a binario.
           string resultado = "";
           foreach (string leer in recibidos.Select(c => Convert.ToString(c, 2)))
           {
               resultado += leer.ToString();
           }    
           
           for (int i = 0; i < resultado.Length; i += 8)
           {
               richTextBox1.Text += resultado.Substring(i, 8) + " ";
           }


Si lo hago solo así que se muestre en richTextBox me da el  mismo error.
Código (csharp) [Seleccionar]
            for (int i = 0; i < recibidos.Length; i += 8)
            {
                richTextBox1.Text += recibidos.Substring(i, 8) + " ";
            }
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

@XSStringManolo

Uhh, no sabía que sucedía ese error.

Suma de 1 en 1 en lugar de 8 en 8 y cuando i % 8 == 0 añades un espacio.

WHK

Eso pasa porque el tipo String en .net tiene pre filtros como la eliminación de padding vacío, hay que procesarlo como un arreglo de bytes, sino pasarás haciendo parches y de una u otra manera tendrás problema con algún valor.

Meta

Cita de: @XSStringManolo en  2 Abril 2021, 23:05 PM
Uhh, no sabía que sucedía ese error.

Suma de 1 en 1 en lugar de 8 en 8 y cuando i % 8 == 0 añades un espacio.

Si te refieres a esto.
Código (csharp) [Seleccionar]
for (int i = 0; i < recibidos.Length; i += 8)
           {
               richTextBox1.Text += recibidos.Substring(i, 1) + " ";
           }


O a esto ottro.
Código (csharp) [Seleccionar]
for (int i = 0; i < recibidos.Length; i += 1)
           {
               richTextBox1.Text += recibidos.Substring(i, 8) + " ";
           }


No funciona.

Cita de: WHK en  3 Abril 2021, 03:14 AM
Eso pasa porque el tipo String en .net tiene pre filtros como la eliminación de padding vacío, hay que procesarlo como un arreglo de bytes, sino pasarás haciendo parches y de una u otra manera tendrás problema con algún valor.

Los ejemplos de Microsoft, tiene la manía de recibir datos tipo sttring aquí y pòr aquí. Es verdad que en el puerto serie se transmite byte por byte. Aquí en SerialPort.ReadExisting es funciona con string.

Dicen muchos por Internet, que para estas cosas mejor aceptar las tramas de byte tal como vienen, en byte. Guardar los datos en Byte y luego procesarlo. Ya se usaría esto otro SerialPort.Read.

El problema si usas tipo arreglo con Byte[] tienes que saber el tamaño que te llega en ese arreglo. El programa completo cambiaría por todas partes, no es cambiar de tipo a string a Byte[] así sin más. Ahí está el problema.

Encuentro otro problema con el invoke al recibir datos por el puerto serie el como se comporta.
Código (csharp) [Seleccionar]
// Al recibir datos.
       private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
       {
           // Acumula los caracteres recibidos a nuestro 'buffer' (string).
           recibidos += serialPort1.ReadExisting();

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


Si recibo este mensaje en ASCII, o lo que sea, por ejemplo. Debería mostrar el mensaje recibido tal como aparece en el Ejemplo 1. En el Ejemlo 2, a veces se corta, como si alguien le diera Enter en medio de la frase.

Ejemplo 1:
No hay mayor tesoro que un amigo.

Ejemplo 2:
No hay mayor tesoro q
ue un amigo.

No he conseguido ningún programa estable que funcione siempre como el Ejemplo 1.

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

@XSStringManolo

Cita de: @XSStringManolo en  2 Abril 2021, 23:05 PMSuma de 1 en 1 en lugar de 8 en 8 y cuando i % 8 == 0 añades un espacio.
Me refiería a esto.
Código (cpp) [Seleccionar]
for (int i = 0; i < recibidos.Length; i += 1) {
 richTextBox1.Text += recibidos[i];
 if (i % 8 == 0) {
   richTextBox1.Text += " ";
 }
}

Serapis

En efecto cuando conviertes un numero a string y lo presentas, elimina los ceros a la izquierda. Para conservarlos, hay que formatearlo de alguna manera...

...por ejemplo tu mismo puedes crear una función exprofeso... Sí, tratando con bytes.

// Toma 1 en cada ciclo del bucle y lo concatena.
// NOTA: Va tomando el bit mas alto para concatenarlo a la derecha.
string = Funcion ByteToString(byte x)
   byte k
   entero n=128
   string s

   bucle para k desde 0 a 7
         s += (x and n)
         n /= 2
   siguiente

   devolver s
fin funcion

Tras la devolucion tu vas concatenando la secuencia al lado que interese, con un espacio o el separador que te interese.

Por otro lado, si tienes una 'ristra de bits' en una cadena de texto, ('100011100011100001110000111...'), puedes igualmente contar su longitud (o puede que sepas directamente cuantos bytes son), y seccionar la cadena en un bucle con cada 8 bits...

string = Funcion SepararBitString(string bits, string separador, buleano LtoR)  ' Left To Rigth
    entero k, j
    string s

    // comenzamos desde la derecha, por que
    // los numeros estan alineados siempre desde la derecha
    // a diferencia de los strings... esto es,
    // si faltara algun bit, seguiremos teniendo bien divididos los bytes.

    // separador se puede omitir. Si siempre sera un espacio, ponlo directamente.
   
    j = (bits.length-1)
    Si LtoR= False
        j -= 8
        s = bits.substring(j, 8)
        bucle para k desde j-8 hasta 0 en pasos de -8
            s = bits.substring(k, 8) + separador + s
        siguiente   

        // si los bits son forman bytes completos, al acabar el bucle k = -8, si no...
        si (k > -8)  // sobran bits a la izquierda que no completan un byte???
            s = bits.left(-k) + separador + s
        fin si
    si no
        bucle para k desde 0 hasta j en pasos de 8
            s += (separador + bits.substring(k, 8))
        siguiente

        // si los bits son forman bytes completos, al acabar el bucle k = j+8, si no...
        si (k < (j+8))  // sobran bits a la izquierda que no completan un byte???
            s += (separador + bits.right(k-j) )
        fin si
    fin si

    devolver s
fin funcion

En este caso tratándose del puerto serie es muy importante que tengas claro el orden en que los bits son recibidos en secuencia si de derecha a izquierda o al revés... para que la funcion opere exactamente como se espera que los datos  aparezcan y no se confundan.
A menudo si hay que hacer mas que un procesado, no importa en primera instancia que los bits queden invertidos en orden dentro del string (pudiera ser así más eficiente), siempre que la funcion final los procese y devuelve correctamente ordenados.
Es cómodo añadir bits a una cadena de texto, a la derecha a medida que se reciben serialmente... por lo que cuando deban procesarse estan al revés. Sería interesante en este caso tener un función que admita un parámetro adicional que indique justamente si deben ordenarse de derecha a izquierda o al revés y así, la misma función puede tratar ambos casos. Esta ultima funcion cumple ese requisito...

Si la secuencia de bits es muy larga, te sugiero utilizar la clase bitarray (localizada en Collections), que permite operar a muy alta velocidad operando con bits, si bien parece que tu caso es operar con cadenas. En ese caso la funcion ByteToString es muy clara y sencilla.

Suele ser más eficiente (cuando la secuencia de bits sea enorme (pongamos millones)), calcular el tamaño de la cadena de salida de antemano y crearla en su tamaño total antes de entrar al bucle, y luego en vez de añadir, simplemente se 'pega' en su ubicación de destino. La concatenacion de cadenas, exige crear para la concatenación una nueva cadena... con cadenas cortas o poco numerosas no se nota perdida de eficiencia, si se notaría si por ejemplo hubiera que procesar un fichero de cierto tamaño... pongamos 20Mb. en tanto que crear el string de una tacada y procesarlo, sería prácticamente inmediato, una concatenación cada pocos bits para 20Mb. podría demorarse algunos o bastantes segundos (depende de la potencia del equipo, obviamente).

Un control ricthtextbox, es un control pesado, no lo utilices si no vas a hacer nada complejo... si es una simple presentacion de datos usa cualquier otro control ligero de texto. Sería como contratar un camión de 4 ejes, para ir al super a hacer la compra semanal... para lo que basta el 'carrito de la compra'...