# Traducir funcion/procedimiento de C++ a Basic



## zgouki (Abr 21, 2009)

Que tal amigos de forosdeelectronica. Hoy les traigo un asunto que me tiene bastante alterado, ya que he intentado de todas las formas posibles de entender lo que sucede (o para que sirve) esta funcion de un programa escrito en C++ para un microcontrolador PIC. Necesitaría su ayuda para traducirlo aunque sea en forma de algoritmo escrito (nose si me explico).


```
/********** INT-RAM WORKING AREA **********/
unsigned char SMCBUF[8];
/********** BASIC FUNCTION **********/
unsigned char smcver (unsigned char p1,p2,p3) { 
    unsigned char mask,i;                             // out 0=OK 1,2,3=Error
    mask = 1;
    SMCBUF[0] = //Aca depende de lo que se quiera almacenar en SMCBUF[0],este comment se lo agregue yo
    if (SMCBUF[0]>0) {
        for (i=0;i<=2;i++) {
            if (SMCBUF[0] & mask) break;
            mask <<= 1;
        }
        SMCBUF[0] ^= mask;                                      *?*
    }   
    mask = 0;                             
    for (i=0;i<=2;i++) {
        if ((SMCBUF[0] & 0x01)==0) mask++;
	    SMCBUF[0] >>= 1;
    }
    return (mask);                                                     *?*
}
```

Se que la funcion evalua lo que hay almacenado en SMCBUF[0] (que creo que es un byte), lo que no se es que es lo que evalua....  . Que se obtiene como salida en al funcion? 
Hay un comentario : out 0=OK 1,2,3=Error. Por lo que entiendo, dice que de la funcion sale la variable mask como resultado, y esta puede ser 0, 1, 2 o 3. De todos modos no entiendo como obtiene esto la funcion  .
Como datos les puedo indicar que en SMCBUF[0] solo pueden variar los bits 0, 1 y 2, y que los 5 restantes bits se mantienen siempre en 0 (osea: %00000XXX). Me gustaria saber como queda SMCBUF[0] en los puntos donde puse *?* (eso se los agregue yo, no estaban en el programa original).
En resumen, les estaría muy agradecido si pueden ayudarme a  entender esta funcion, ya que mi meta es poder escribirla en Basic (el cual domino mucho mejor q C).
Saludos.


----------



## Eduardo (Abr 21, 2009)

SMCBUF[0] ^= mask;     

Eso es equivalente a SMCBUF[0] = SMCBUF[0]  XOR mask
Como mask es un contiene solo un 1 que coincide con el primer 1 de SMCBUF[0], lo que hace es cambiar ese 1 de SMCBUF[0] por 0.


return (mask);

Es el valor de retorno de la funcion.
Es la cuenta en que termina el segundo bucle, que es la cantidad de ceros (los 3 primeros bits) de SMCBUF[0].

Esto tiene que tener algun error, porque en el bucle anterior ya se resetea un bit --> nunca puede devolver 0.


----------



## zgouki (Abr 21, 2009)

Muchas gracias Eduardo por tu respuesta   . Pasemos a analizarla (haber si te entendi mas o menos):
En el primer If (*if (SMCBUF[0]>0) {....*) solo se ejecuta si SMCBUF[0] es distinto de cero.
Si es igual a cero al principio se pasa directamente a mask = 0 (mask supuestamente refleja lo que hay en SMCBUF[0]) y luego comienza el bucle for (*for (i=0;i<=2;i++) {....*) el cual tiene un If anidado (que nose lo que hace). Creo que me intentaste explicar que luego de este for con el if anidado,  sale algo....pero no te entiendo muy bien que es. 
Si en el 1er If el byte SMCBUF[0] es distinto de cero, lo que hace todo el codigo dentro del if es justamente poner SMCBUF[0] = 0 (me equivoco en esta deduccion?)
Mencionas un error. Puedes tratar de explicarmelo mejor asi yo también lo diviso a ese error?  
Disculpa que sea ignorante, es por eso que recurro a tu ayuda. 
Saludos y espero sus respuestas.

*EDIT=* Osea, tratemos de analizar lo que sucede a partir de aqui (si es que SMCBUF[0] = 0)
Al entrar al bucle.....cuanto vale mask?:

```
for (i=0;i<=2;i++) {
        if ((SMCBUF[0] & 0x01)==0) mask++;
       SMCBUF[0] >>= 1;
    }
```


----------



## Dr. Zoidberg (Abr 21, 2009)

A ver:
1- SMCBUF es un arreglo de 8 bytes, pero el algoritmo solo opera sobre el primer byte (SMCBUF[0] -> primer byte del arreglo).
2- Pongo en 1 en el primer bit de la mascara.
3- Si ese primer byte es distinto de cero, entonces recorro los tres primeros bits (0..2) empezando por el menos significativo. Si uno de esos bits es 1 (SMCBUF[0] & mask -> si esa AND me da distinto de cero, el bit correspondiente vale 1) entonces se acabó el for. Si no es cero, corro la mascara un bit a la izquierda y pruebo de nuevo con el bit que sigue, hasta que se acabe el for. Si se acabó el for, hago la XOR con mask, lo que equivale a invertir el valor del bit en el lugar que le corresponde al 1 en mask (*ojo con esto, por que si los tres primeros bits son cero, el algoritmo va a invertir el bit 3*).
4- Ahora ponemos toda la mascara en 0 y hago una AND con 1 para todos los tres primeros bits (del 0 al 2) de a uno por vez, y por cada bit que encuentre que vale 0 le sumo uno a la máscara y eso es lo que retorno.

En definitiva, esta función te cuenta cuantos ceros quedaron en los tres primeros bits luego del jueguito con la XOR.

No conozco el contexto de invocación de esta función, así que no te puedo decir para que corno sirve ni que diablos hacen los parámetros p1, p2 y p3 que no los usa en el cuerpo del método.

Saludos!


----------



## Eduardo (Abr 21, 2009)

Ahi va con comentarios


```
/********** INT-RAM WORKING AREA **********/
unsigned char SMCBUF[8];                // Define SMCBUF como un array de 9 bytes


/********** BASIC FUNCTION **********/
unsigned char smcver (unsigned char p1,p2,p3) {   // Inicio de la funcion  smcver cuyo
                                        // argumento son 3 bytes y devuelve 1 byte    


    unsigned char mask,i;               // Declara las variables locales mask y i como bytes
    mask = 1;                           // Pone un 1 en mask
    SMCBUF[0] =  Lo_que_sea ;           // Evidente
    
    if (SMCBUF[0]>0) {                  // Se ejecutan las siguientes lineas si SMCBUF[0]>0
        for (i=0;i<=2;i++) {            // Equiv. a FOR i=0 TO 2 
            if (SMCBUF[0] & mask) break;// Hace la funcion AND , si es <>0 sale del bucle FOR
            mask <<= 1;                 // Desplaza a la izquierda el 1
        }                               // la secuencia en cada iteracion resulta 001 - 010 - 100 
        SMCBUF[0] ^= mask;              // Al interrumpirse el bucle, con ese XOR esta reseteando   
                                        // el 1 encontrado.
                                        // Si no encuentra nada, termina el FOR con mask = 1000 ,
                                        // asi que cambia un bit que no interesa.
    }                                   // NEXT i
    
    
    mask = 0;                           // Inicializa mask
    for (i=0;i<=2;i++) {                // FOR i=0 TO 2 
        if ((SMCBUF[0] & 0x01)==0) mask++;  // Nuevamente un AND, si el 1er bit es 0 incrementa el 
                                        // contador (mask)
        SMCBUF[0] >>= 1;                // Desplaza SMCBUF[0] una posicion a la derecha 
    }                                   // NEXT i
    
    return (mask);                      // Retorno de la funcion 
                                        // El valor de mask es la cantidad de ceros de los 3
                                        // primeros bits que hay en SMCBUF[0] despues de resetearle
                                        // el primer 1 encontrado.
                                        // Por eso supongo que hay un error, nunca se devuelve 0 
                                        // que es la condicion OK.
                                         
}                                       // END FUNCTION
```


----------



## zgouki (Abr 21, 2009)

Gracias Conde Doku...digo, ezavalla . Analicemos ahora tu respuesta  



			
				ezavalla dijo:
			
		

> (...) Si ese primer byte es distinto de cero, entonces recorro los tres primeros bits (0..2) empezando por el menos significativo. Si uno de esos bits es 1 (SMCBUF[0] & mask -> si esa AND me da distinto de cero, el bit correspondiente vale 1) entonces se acabó el for. Si no es cero, corro la mascara un bit a la izquierda y pruebo de nuevo con el bit que sigue, hasta que se acabe el for (...)


Donde esta subrayado, no seria "Si es cero" lo que me quiziste decir? (ya que antes habias analizado si habia algun 1 en los 3 primeros bits de SMCBUF[0]) 



			
				ezavalla dijo:
			
		

> (...) Si se acabó el for, hago la XOR con mask, lo que equivale a invertir el valor del bit en el lugar que le corresponde al 1 en mask (*ojo con esto, por que si los tres primeros bits son cero, el algoritmo va a invertir el bit 3*). (...)


Pero no estas equivocado al decir que si los 3 primeros bits son cero se invierte el bit 3?  Ya que si los b0,b1,b2 = 0 entonces todo el byte SMCBUF[0] =  0 (recuerda que solo cambian los 3 1eros bits, los demas siempre son 0) lo que implica q nunca se entraría al If :

```
if (SMCBUF[0]>0) {
        for (i=0;i<=2;i++) {
            if (SMCBUF[0] & mask) break;
            mask <<= 1;
        }
        SMCBUF[0] ^= mask; 
    }
```



			
				ezavalla dijo:
			
		

> 4- Ahora ponemos toda la mascara en 0 y hago una AND con 1 para todos los tres primeros bits (del 0 al 2) de a uno por vez, y por cada bit que encuentre que vale 0 le sumo uno a la máscara y eso es lo que retorno.


Osea que *nunca* (como dijo marcelo anteriormente) vamos a terminar obteniendo mask = 0....pero justamente debe haber un error....
Este expresion : *(SMCBUF[0] & 0x01)==0* Cuando es TRUE y cuando es FALSE ?
Saludos


----------



## Dr. Zoidberg (Abr 21, 2009)

zgouki dijo:
			
		

> Donde esta subrayado, no seria "Si es cero" lo que me quiziste decir? (ya que antes habias analizado si habia algun 1 en los 3 primeros bits de SMCBUF[0])



Ooopppsss....tenes razón....*Si es cero...*



			
				zgouki dijo:
			
		

> Pero no estas equivocado al decir que si los 3 primeros bits son cero se invierte el bit 3?  Ya que si los b0,b1,b2 = 0 entonces todo el byte SMCBUF[0] =  0 (recuerda que solo cambian los 3 1eros bits, los demas siempre son 0) lo que implica q nunca se entraría al If :
> 
> ```
> if (SMCBUF[0]>0) {
> ...



Vos estas asumiendo eso, pero en el código que enviaste no hay garantía de que eso suceda. Esa es una pre-condición que hay que garantizar pero el if no lo hace, mas siendo SMCBUF una variable global. Si se cumple tu suposición todo está OK, pero si no...
Para garantizarlo tenés que agregar:

```
SMCBUF[0] &= 0x07;
```
antes del if.




			
				zgouki dijo:
			
		

> Osea que *nunca* (como dijo marcelo anteriormente) vamos a terminar obteniendo mask = 0....pero justamente debe haber un error....



Así parece...



			
				zgouki dijo:
			
		

> Este expresion : *(SMCBUF[0] & 0x01)==0* Cuando es TRUE y cuando es FALSE ?



Es TRUE cuando el primer bit de SMCBUF[0] vale 0.

Saludos!


----------



## zgouki (Abr 21, 2009)

Gracias ezavalla y marcelo nuevamente por sus respuestas 
Disculpa Marcelo, mientras escribia la respuesta a ezavalla, llego tu respuesta, asiq ahora paso a comentarla:

Aqui esta todo el código en C++ (es para poder leer/escribir una SMART CARD SLE 4442), estoy tratando de entender mas que nada los comoandos de escritura:

```
/*  Filename     XSLE4442.C
    Description  SLE4442 Smartcard Example Program
    Hardware     START-C51 + Smartcard Socket
    Clock        11.0592 Mhz (x2)
    Compiler     Keil CA51 v5.0
    Engineer     Sanon & Kriangsak
    Company      Sila Research Co.,Ltd. 
*/

#include <reg51.h>
#include <absacc.h>
#include <assert.h>
#include <ctype.h>
#include <intrins.h>
#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/********** I/O PORT **********/

sbit 	 RST  = P1^0;
sbit 	 CLK  = P1^1;
sbit 	 IO   = P1^2;

/********** INT-RAM WORKING AREA **********/

unsigned char SMCBUF[8];

/********** BASIC FUNCTION **********/

void dmsec (unsigned int count) {      // mSec Delay
    unsigned char i;                   // for Franklin C51 & 22.1184 Mhz
    while (count) {
        for (i=1;i<=228;i++);
        count--;
    }
}

void start (void) {
    SCON = 0x52;                       // set RS232 parameter
    TMOD = 0x20;
    TH1  = 0xfd;                       // speed 19200
    TR1  = 1;

    RST = 0;                           // init I/O for smart card
    CLK = 0;
    IO  = 1;
}

void smcdelay (void) {                 // pluse delay
    unsigned char i;
    i = 20;
    while (i>0) i--;
}

void smcgetatr (void) {                // get answer-to-reset
    unsigned char a,c,x,i;             // out = SMCBUF (4 byte)

    RST = 1;                           // reset
    smcdelay ();
    CLK = 1;
    smcdelay ();
    CLK = 0;
    smcdelay ();
    RST = 0;
    smcdelay ();
    
    c = 0;
    a = 0;
    x = 0;
    for (i=0;i<=31;i++) {              // read 32 bit atr
        IO = 1;
        a >>= 1;
        if (IO) a |= 0x80; else a &= 0x7f;
        CLK = 1;
        smcdelay ();
        CLK = 0;
        smcdelay ();
        if (++c==8) {
            SMCBUF[x++] = a;
            c = 0;
            a = 0;
        }       
    }
}

void smcstart (void) {                 // start condition
    CLK = 0;
    IO  = 1;
    CLK = 1;
    smcdelay ();
    IO  = 0;
    smcdelay ();
    CLK = 0;
    smcdelay ();
}

void smcstop (void) {                  // stop condition 
    IO  = 0;
    CLK = 1;
    smcdelay ();
    IO  = 1;
    smcdelay ();
    CLK = 0;
    smcdelay ();
}

void smcwbyte (unsigned char x) {      // write 1 byte 
    unsigned char i;
    for (i=0;i<=7;i++) {
        IO = (x & 0x1) ? 1 : 0;
        CLK = 1;
        smcdelay ();
        CLK = 0;
        smcdelay ();
        x >>= 1;
    }
}

unsigned char smcrbyte (void) {        // read 1 byte
    unsigned char i,x;
    x = 0;
    for (i=0;i<=7;i++) {
        IO = 1;
        x >>= 1;
        if (IO) x |= 0x80; else x &= 0x7f;
        CLK = 1;
        smcdelay ();
        CLK = 0;
        smcdelay ();
    }
    return (x);
}

void smcread (unsigned char com,add,len) {  // read data
    unsigned char i;                        // output = SMCBUF[] 
    smcstart ();                            // start 
    smcwbyte (com);                         // command 
    smcwbyte (add);                         // address
    smcwbyte (0);
    smcstop ();                             // stop 
    for (i=0;i<len;i++) {                   // data
        SMCBUF[i] = smcrbyte ();
    }
    RST = 1;                                // reset
    smcdelay ();
    RST = 0;
}

void smcwrite (unsigned char com,add,dat) { // write data 
    smcstart ();                            // start 
    smcwbyte (com);                         // command 
    smcwbyte (add);                         // address
    smcwbyte (dat);                         // data
    smcstop ();                             // stop 
    do {                                    // wait
        CLK = 1;
        smcdelay ();
        CLK = 0;
        smcdelay ();
        IO = 1;
    } while (!IO);
}

unsigned char smcver (unsigned char p1,p2,p3) {       // verify PSC code 
    unsigned char mask,i;                             // out 0=OK 1,2,3=Error
    mask = 1;
    smcread (0x31,0,4);                     // check error counter (EC)
    if (SMCBUF[0]>0) {
        for (i=0;i<=2;i++) {
            if (SMCBUF[0] & mask) break;
            mask <<= 1;
        }
        SMCBUF[0] ^= mask; 
        smcwrite (0x39,0,SMCBUF[0]);        // write free bit in EC
        smcwrite (0x33,1,p1);               // compare verification data
        smcwrite (0x33,2,p2);              
        smcwrite (0x33,3,p3);              
        smcwrite (0x39,0,0xff);             // erase EC
        smcread (0x31,0,4);                 // check EC
    }   
    mask = 0;                               // change EC to 1,2,3  
    for (i=0;i<=2;i++) {
        if ((SMCBUF[0] & 0x01)==0) mask++;
	    SMCBUF[0] >>= 1;
    }
    return (mask);
}

/********** MAIN **********/

void clearbuf (void) {                      // clear ram buffer 
    unsigned char i;
    for (i=0;i<=7;i++) SMCBUF[i] = 0;
}

void dump (unsigned char len) {             // dump 8 byte
    unsigned char i;                   
    for (i=0;i<len;i++) { 
        printf ("%02bX ",SMCBUF[i]);
    }
    printf ("\n");
}

void main (void) {
    unsigned char i,a;

    dmsec (300);                            // power delay
    start ();                               // start RS232 & init I/O
    dmsec (200);

    printf ("XSLE4442.C Example Program ...\n");
    clearbuf ();
    printf ("ATR code ...\n");
    smcgetatr ();
    dump (4);

    printf ("Dump 64 byte memory ...\n");
    a = 0;
    for (i=0;i<=7;i++) {
        smcread (0x30,a,8);
        dump (8);
        a += 8;
    }     

    printf ("Verify PSC code ...\n");
    a = smcver (0xff,0xff,0xff);
    if (a==0) {
        printf ("OK\n");
        printf ("Write 11h,22h,33h,44h, at 20-23h ...\n");
        smcwrite (0x38,0x20,0x11);         
        smcwrite (0x38,0x21,0x22);
        smcwrite (0x38,0x22,0x33);
        smcwrite (0x38,0x23,0x44);
    }
    else printf ("Error ... %bu\n",a);

    while (1);                              // stop   
}
```
Anteriormente habia borrado la llamada a funciones q me parecian irrelevantes para la explicacion de la funcion que queria entender (es por eso que ezavalla no me podia decir para que cornos servian los parámetros p1, p2 y p3 que no los usa en el cuerpo de la funcion)
Segun lo que entendi de la datasheet, es necesario introducir un codigo de 3 bytes (en las genericas es FF FF FF) antes de cualquier proceso de escritura en la tarjeta. Para introducir este codigo, se debe realizar paso a paso un procedimiento llamado PSC Verification (el cual implica comandos de escritura, lectura, etc.)
Adjunto aqui el diagrama de bloques del procedimiento *Verificacion del PSC (Codigo de Seguridad Programable)* obtenida de la pagina 22 del datasheet de la SLE 4442 de SIEMENS (no puedo adjuntar el datasheet porq es muy pesado  ):





Y aqui transcribo lo que dice el daatsheet sobre como escribir en la EEPROm de la tarjeta (que es lo que me interesa)
_"*PSC Verification (SLE 4442 only)*
The SLE 4442 requires a correct verification of the Programmable Security Code PSC stored in the
Security Memory for altering data if desired.
The following procedure has to be carried out exactly as described. Any variation leads to a failure,
so that a write/erase access will not be achieved. As long as the procedure has not been
successfully concluded the error counter bits can only be changed from “1” to “0” but not erased.
At first an error counter bit has to be written to “0” by an UPDATE command (see figure 11) followed
by three COMPARE VERIFICATION DATA commands beginning with byte 1 of the reference data.
A successful conclusion of the whole procedure can be recognized by being able to erase the error
counter which is not automatically erased. Now write/erase access to all memory areas is possible
as long as the operating voltage is applied. In case of error the whole procedure can be repeated as
long as erased counter bits are available. Having been enabled, the reference data are allowed to
be altered like any other informaciónrmation in the EEPROM.
The following table gives an overview of the necessary commands for the PSC verification. The
sequence of the shaded commands is mandatory.




As shipped, the PSC is programmed with a code according to individual agreement with the
customer. Thus, knowledge of this code is indispensable to alter data."_

Bueno, espero no haberlos dormido tanto con tanta charla, ojala puedan ayudarme.
Saludos

*EDIT:*
Gente, de nuevo aqui. Segun una página de internet (http://hackaday.com/2008/11/25/how-to-read-a-fedex-kinkos-smart-card-sle4442/) que muestra como que leer los bytes de una SLE 4442, al final del articulo comenta lo siguiente:
_*Dump security memory (4 bytes)*

The security memory contains a password verification attempt counter, and the three byte password. We can read the read the security memory without the password, but the password bytes will read as 0. The security memory address is 0×31.

    RAW2>{0×31 0 0} 0r4 <–command
    410 RAW2WIRE START CONDITION (\-/_\)
    420 RAW2WIRE WRITE: 0b00110001
    420 RAW2WIRE WRITE: 0b00000000
    420 RAW2WIRE WRITE: 0b00000000
    440 RAW2WIRE STOP CONDITION (_/-\)
    431 RAW2WIRE BULK READ, 0b00000100 BYTES:
    0b00000100 0b00000000 0b00000000 0b00000000<–bytes
    RAW2>

The attempt counter starts at three (0b00000111), and counts down to 0. When the counter reads 0, the card is essentially destroyed. We used two access attempts to test the password commands, this card has one try left_

Bueno, esto es totalmente lo contrario a lo que deducia leyendo el datasheet (todo porq soy medio bruto traduciendo el ingles ops: ) . Osea, segun entiendo, la tarjeta comienza con el counter de error en %00000111 y baja a cero a medida que le marramos en el password al intentar escribir (por eso en la procedure anterior en C++ nunca se cumplia mask=0, ya que si pasaba esto la tarjeta quedaba bloqueada para siempre, los que nos hizo confundir fue el comentario ese del creador del código =  *// out 0=OK 1,2,3=Error* que todavia no lo entiendo).
Bueno, comentado esto, me pongo las pilas a ver si puedo terminar de entender todo el procedimeinto de verificar el pass para poder escribir en estas tarjetas. Muchas gracias por su atensión y cualquier consejo sera agradecido. 
Saludos


----------

