• Publicidad

Problemilla al trabajar con hexadecimal

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

Problemilla al trabajar con hexadecimal

Notapor maschino2 » 2010-05-25 02:59 @166

Buenas,

Tengo un script que básicamente recorre un csv separado por comas, y utiliza el primer campo para pasarlo a hexadecimal y hacer un xor de los valores.
El problema está en que no consigo que el cálculo me lo haga correctamente, pero tampoco sé dónde está el fallo.

Aquí os dejo el código a ver si alguno me podéis iluminar, ya que yo no lo encuentro.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. # Valores fijos para el cálculo del checksum
  2. $bit1=0x09;
  3. $bit2=0x02;
  4. $bit6=0x03;
  5. $bit7=0xBC;
  6. $bit8=0xFF;
  7. $bit9=0x7E;
  8.  
  9.  
  10. #  Damos la ubicacion del fichero SecurityCodes y lo abrimos para leer
  11. $Fichero_SecurityCodes="Serial.csv";
  12. open (ENTRADA,"<$Fichero_SecurityCodes") || die "ERROR: No puedo abrir el fichero $Fichero_SecurityCodes";
  13.  
  14. #  Damos la ubicacion del fichero de salida y lo abrimos para escribir
  15. $Fichero_Checksum="Salida.csv";
  16. open (SALIDA,">$Fichero_Checksum") || die "ERROR: No puedo abrir el fichero $Fichero_Checksum";
  17.  
  18. # Metemos en tabla el fichero
  19. # Y usamos las entradas lista[0] para el nº de serie
  20.  
  21. while (<ENTRADA>)
  22. {
  23.         @lista = split( ";", $_);
  24.  
  25.         # Pasamos a hexadecimal el numero de serie
  26.         $hexval = sprintf("%x", $lista[0]);
  27.  
  28.  
  29.                 # Comprobamos el tamaño del hexadecimal que nos sale para añadirle un 0 en caso de ser 5 digitos, ya que necesitamos trabajar de 2 en dos
  30.                 $length_hexval = length($hexval);
  31.        
  32.                 # Si la longitud es menor de 6, ponemos un 0 al principio para que sean 6 digitos
  33.                 # y poder tener bytes de 2 digitos
  34.                 if ($length_hexval<6)
  35.                 {
  36.                         $hexval="0$hexval";
  37.                 }
  38.         # Dividimos el hexadecimal en 3 bytes para usarlos posteriormente
  39.         # $portion = substr($string_variable, start number, length);
  40.         $bit3 = substr($hexval,0,2);
  41.         $bit4 = substr($hexval,2,2);
  42.         $bit5 = substr($hexval,4,2);
  43.  
  44. #
  45. # Ponemos en mayúsculas los valores por si acaso
  46.  
  47. $bit3=uc $bit3;
  48. $bit4=uc $bit4;
  49. $bit5=uc $bit5;
  50.  
  51. # $bit3 =  hex($bit3);
  52. # $bit4 =  hex($bit4);
  53. # $bit5 =  hex($bit5);
  54.  
  55. # $bit3=sprintf("%#X",$bit3);
  56. # $bit4=sprintf("%#X",$bit4);
  57. # $bit5=sprintf("%#X",$bit5);
  58.  
  59.  
  60.  
  61. #  Ejecutamos para conseguir el Checksum
  62. $res1 = $bit1 ^ $bit2 ^ $bit3 ^ $bit4 ^ $bit5 ^ $bit6 ^ $bit7 ^ $bit8 ^ $bit9;
  63.  
  64.  
  65. #  Convertimos el valor del checksum que sale en decimal a hexadecimal
  66. $decval2=sprintf("%#X",$res1);
  67. $decval =  hex($res1);
  68.  
  69. # Sacamos por pantalla lo que nos interesa
  70. print "\n";
  71. print "El nº de serie es $lista[0]\n";
  72. print "En hexadecimal $hexval \n";
  73. print "El bit3 es $bit3 \n";
  74. print "El bit4 es $bit4 \n";
  75. print "El bit5 es $bit5 \n";
  76. print "El checksum normal es: $res1 \n";
  77. print "El checksum en Hexadecimal es: $decval\n";
  78. print "El checksum en Hexadecimal es: $decval2\n";
  79. }
  80.  
  81.  
  82. close ENTRADA;
  83. close SALIDA;
  84.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Los valores que tiene el csv son:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
00958566;ADCB
00955935;ADCB
00938668;ADCB
00936859;ADCB
00936669;ADCB
00961979;ADCB
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


He intentado pasar los valores a decimal para trabajar con ellos, pero tampoco; y no consigo ver qué me está haciendo incorrectamente

Aún no lo he sacado al fichero porque en pantalla me muestra mal los valores...

Muchas gracias
maschino2
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2010-05-24 05:49 @284

Publicidad

Re: Problemilla al trabajar con hexadecimal

Notapor explorer » 2010-05-25 05:17 @262

Bienvenido a los foros de Perl en Español, maschino2.

El problema que veo es que estás haciendo una conversión a cadena de caracteres, en las líneas 47 a 49, por medio de la función uc(). Te vale con cambiarla por la función hex() para que todo funcione. Esa función está indicando que lo que contiene las variables $byte está en hexadecimal y queremos pasarlo a entero. Así, la operación matemática del xor, a continuación, funcionará bien.

Esta es otra solución, usando datos puramente binarios, usando chr() y ord() para hacer la conversión de entero a valor entero binario.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. # Valores fijos para el cálculo del checksum
  4. $byte1 = chr 0x09;
  5. $byte2 = chr 0x02;
  6. $byte6 = chr 0x03;
  7. $byte7 = chr 0xBC;
  8. $byte8 = chr 0xFF;
  9. $byte9 = chr 0x7E;
  10.  
  11. # Damos la ubicación del fichero SecurityCodes y lo abrimos para leer
  12. $Fichero_SecurityCodes="Serial.csv";
  13. open (ENTRADA,"<$Fichero_SecurityCodes") or die "ERROR: No puedo abrir el fichero $Fichero_SecurityCodes";
  14.  
  15. #  Damos la ubicacion del fichero de salida y lo abrimos para escribir
  16. $Fichero_Checksum="Salida.csv";
  17. open (SALIDA,">$Fichero_Checksum")       or die "ERROR: No puedo abrir el fichero $Fichero_Checksum";
  18.  
  19. # Metemos en tabla el fichero
  20. # Y usamos las entradas lista[0] para el nº de serie
  21. print "Nº serie hex   bit1    bit2    bit3   cksum\n";
  22.  
  23. while (<ENTRADA>)
  24. {
  25.     @lista = split q[;], $_;
  26.  
  27.     # Pasamos a hexadecimal el numero de serie
  28.     $hexval = sprintf("%06X", $lista[0]);
  29.  
  30.     # Dividimos el hexadecimal en 3 bytes para usarlos posteriormente
  31.     $byte3 = chr hex substr $hexval, 0, 2;
  32.     $byte4 = chr hex substr $hexval, 2, 2;
  33.     $byte5 = chr hex substr $hexval, 4, 2;
  34.  
  35.     # Ejecutamos para conseguir el Checksum
  36.     $res1 = $byte1 ^ $byte2 ^ $byte3 ^ $byte4 ^ $byte5 ^ $byte6 ^ $byte7 ^ $byte8 ^ $byte9;
  37.  
  38.     # Convertimos el valor del checksum que sale en decimal a hexadecimal
  39.     $decval = ord $res1;
  40.  
  41.     # Sacamos por pantalla lo que nos interesa
  42. #    print "\n";
  43. #    print "El nº de serie es $lista[0]\n";
  44. #    print "En hexadecimal $hexval \n";
  45. #    printf "El byte1 es %02X %08b\n", ord($byte1), ord($byte1);
  46. #    printf "El byte2 es %02X %08b\n", ord($byte2), ord($byte2);
  47. #    printf "El byte3 es %02X %08b\n", ord($byte3), ord($byte3);
  48. #    printf "El byte4 es %02X %08b\n", ord($byte4), ord($byte4);
  49. #    printf "El byte5 es %02X %08b\n", ord($byte5), ord($byte5);
  50. #    printf "El byte6 es %02X %08b\n", ord($byte6), ord($byte6);
  51. #    printf "El byte7 es %02X %08b\n", ord($byte7), ord($byte7);
  52. #    printf "El byte8 es %02X %08b\n", ord($byte8), ord($byte8);
  53. #    printf "El byte9 es %02X %08b\n", ord($byte9), ord($byte9);
  54. #    printf "El checksum normal es: %d \n"         , $decval;
  55. #    printf "El checksum en Hexadecimal es: %02X\n", $decval;
  56. #    printf "El checksum en Hexadecimal es: %0#X\n", $decval;
  57.  
  58.     printf "%07d %6s  %02X      %02X      %02X      %02X\n", $lista[0], $hexval, ord($byte3), ord($byte4), ord($byte5), $decval;
  59. }
  60.  
  61. close ENTRADA;
  62. close SALIDA;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Estos son los cambios principales:
* hacemos uso de la función ord() para transformar un valor entero binario a entero decimal
* hacemos uso de la función chr() para transformar un entero decimal a entero binario.

Las líneas que definen a los bytes 1, 2, y 6 al 9, son de esta manera:

$byte1 = chr 0x09;

en la que estamos pasando un valor entero (en formato de Perl) a entero binario. Ahora, $byte1 sí que guarda la representación binaria de un nueve. Si no hiciéramos esto, guardaría un 9 como entero escalar de Perl.

Ahora ya podemos realizar las operaciones binarias con xor.

En cambio, cuando necesitemos sacar la representación decimal de ese valor, necesitaremos usar la función ord(), como en el caso de los printf(). Primero pasamos ese número 9 almacenado de forma binaria a un número decimal 9 con la ayuda de ord(). Y luego printf() lo transforma al formato visual que necesitamos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemilla al trabajar con hexadecimal

Notapor maschino2 » 2010-05-25 05:43 @280

Muchas gracias por la bienvenida y la solución.... aunque no lo entiendo demasiado bien...

Tu código me falla, en la generación de los substring. Lo revisaré a ver si encuentro dónde está el problema (como soy novato yo le meto todos los paréntesis del mundo mundial y alguno más...)

Aparte de eso, cuando le meto el número de serie a través de una variable fija, en vez de pasárselo en un array me funciona correctamente, con lo que no tengo muy claro qué está pasando. Revisaré el script con la información que me has dado a ver qué se puede hacer...

Muchas gracias por tu tiempo

<edito> Comprobado, con la opción chr() tampoco hace los cálculos correctamente

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Nº serie hex   bit1    bit2    bit3   cksum
1659876 1953E4  19      53      E4      9B
1588878 183E8E  18      3E      8E      9D
1588859 183E7B  18      3E      7B      68
1587556 183964  18      39      64      70
1586765 18364D  18      36      4D      56
1578855 181767  18      17      67      5D
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Estos están calculados con la calculadora, y no son los que salen ni con el chr() ni con las mías.

¿¿¿Sera por cómo hace el xor con hexadecimales???
maschino2
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2010-05-24 05:49 @284

Re: Problemilla al trabajar con hexadecimal

Notapor explorer » 2010-05-25 10:27 @477

No nos das un ejemplo de salida correcta, así que he tenido que deducirlo viendo el código, y en el código, se aplica xor a los nueve valores (línea 34).

Y con la calculadora en la mano ;) sí que me funciona.

P.D. xor no puede realizar operaciones con hexadecimales, solo con operandos binarios.

perl -le '$x = chr 0x10; $y = chr 0x01; print ord($x ^ $y)'

La salida es 17 (0x11).

Haciendo unos cambios al programa, y siendo la entrada esta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
00958566;ADCB
00955935;ADCB
00938668;ADCB
00936859;ADCB
00936669;ADCB
00961979;ADCB
1659876;ADCB
1588878;ADCB
1588859;ADCB
1587556;ADCB
1586765;ADCB
1578855;ADCB
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

la salida es ahora:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Nº serie hex   bit1    bit2    bit3   cksum
0958566 0EA066  0E      A0      66      FD
0955935 0E961F  0E      96      1F      B2
0938668 0E52AC  0E      52      AC      C5
0936859 0E4B9B  0E      4B      9B      EB
0936669 0E4ADD  0E      4A      DD      AC
0961979 0EADBB  0E      AD      BB      2D
1659876 1953E4  19      53      E4      9B
1588878 183E8E  18      3E      8E      9D
1588859 183E7B  18      3E      7B      68
1587556 183964  18      39      64      70
1586765 18364D  18      36      4D      56
1578855 181767  18      17      67      5D
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemilla al trabajar con hexadecimal

Notapor maschino2 » 2010-05-26 01:48 @117

Buenas

Muchas gracias por tu interés. Lo que te puse al final del anterior post eran pruebas con calculadora, siendo el checksum el valor del xor de todos los valores.

Usando el script y la calculadora, los valores son distintos. Tanto con la cadena chr() como sin ella, y eso es lo que me está volviendo un tanto loco...

¿¿Qué modificaciones has hecho para que te funcione correctamente?? ¿¿Es con tu script inicial?? A mi con tu script o con el mio me da los valores erróneos.

Muchas gracias
maschino2
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2010-05-24 05:49 @284

Re: Problemilla al trabajar con hexadecimal

Notapor explorer » 2010-05-26 03:48 @200

He editado mi mensaje anterior y he colocado las modificaciones: era comentar todos los print() y colocar dos líneas nuevas con print() diferentes, para que saliera como tu última salida.

Sería interesante ver qué te sale a ti.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemilla al trabajar con hexadecimal

Notapor maschino2 » 2010-05-26 04:11 @216

¡¡¡¡Funciona de lujo!!!! Muchas gracias por todo, pero sigo sin entender dónde tenía exactamente el problema...

¿¿Era porque no almacenaba las variables como chr()?? ¿¿O por el ord()??
maschino2
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2010-05-24 05:49 @284

Re: Problemilla al trabajar con hexadecimal

Notapor explorer » 2010-05-26 12:52 @577

No sé por qué no te funcionaba, sin ver el código que tenías.

Para la explicación del porqué del uso de chr() y ord(), me remito al comentario anterior.

Ahora que funciona, podemos probar con cosas más sencillas: toda la explicación anterior de que los datos en Perl estaban en un formato entero y que había que pasarlo a enteros binarios... no es del "todo" exacto...

Resulta que Perl puede tratar al contenido de un escalar, básicamente, como una cadena de caracteres o un valor entero (aparte de otras cosas). Eso quiere decir que si una variable que contiene un número, la tratamos como cadena de caracteres, si queremos obtener su representación binaria, estamos obligados a usar el juego chr()/ord(). Pero también quiere decir que si a las variables siempre las consideramos como que contienen valores numéricos, entonces Perl los tratará como tales (en nuestro sentido de hacer operaciones binarias con ellos).

Entonces, tu problema puede reducirse a esto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. ### Configuración
  6. my @checksum = ( 0x09, 0x02, 0x03, 0xBC, 0xFF, 0x7E );      # Valores fijos para el cálculo del checksum
  7.  
  8. my $fichero_entrada = 'Serial.csv';
  9. my $fichero_salida  = 'Salida.csv';
  10.  
  11. ### Fin Configuración
  12.  
  13. # Abrimos ficheros
  14. open my $ENTRADA, q[<], $fichero_entrada  or  die "ERROR: No puedo abrir el fichero de entrada $fichero_entrada: $!\n";
  15. open my $SALIDA,  q[>], $fichero_salida   or  die "ERROR: No puedo abrir el fichero de salida $fichero_salida: $!\n";
  16.  
  17. ### Proceso
  18. while (<$ENTRADA>) {
  19.  
  20.     my $numero_serie = (split q[;])[0];                 # el número de serie está en la primera columna
  21.  
  22.     my @bytes = unpack "C*", pack "L", $numero_serie;   # extraemos los bytes que forman el número de serie
  23.  
  24.     my $suma_control;                                   # Cálculo de la suma de control
  25.  
  26.     $suma_control ^= $_ for @checksum, @bytes;          # xor con los @checksum y @bytes
  27.  
  28.     printf $SALIDA "%08d : %06X : %02X\n", $numero_serie, $numero_serie, $suma_control;
  29. }
  30.  
  31. ### Cerramos
  32. close $ENTRADA;
  33. close $SALIDA;
  34.  
  35. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La salida es la esperada:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
00958566 : 0EA066 : FD
00955935 : 0E961F : B2
00938668 : 0E52AC : C5
00936859 : 0E4B9B : EB
00936669 : 0E4ADD : AC
00961979 : 0EADBB : 2D
01659876 : 1953E4 : 9B
01588878 : 183E8E : 9D
01588859 : 183E7B : 68
01587556 : 183964 : 70
01586765 : 18364D : 56
01578855 : 181767 : 5D
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

y no hemos tenido que utilizar para nada las funciones hex(), chr() y ord(). ¿Por qué? pues porque en todo momento estamos haciendo operaciones de enteros.

De tu primer programa que has publicado en este hilo, solo habría que hacer un cambio para que funcionara bien: en las líneas 47 a 49 cambias la función uc() por hex(), y en ese momento todas las variables ya son enteras, y la función xor a continuación funciona perfectamente.

Perdona si te he liado con todo el follón chr()/ord().

perl -le '$x=16; $y=1; print $x ^ $y'
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problemilla al trabajar con hexadecimal

Notapor maschino2 » 2010-05-27 01:57 @123

Muuuuchas gracias por la explicación... así me podía estar yo volviendo loco y sin ver por dónde estaban los tiros...

Si es que esto de Perl es muuuu bonito, pero muuuu complicado :lol:
maschino2
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2010-05-24 05:49 @284


Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 18 invitados