Write BYTES to MIFARE without trancoding to ASCII-HEX

##########################################
NOTE:
the starting problem in this first post is solved.
Please scroll down to the problem described in the title.
#########################################

Hi,

I want to write a hex-string to an RFID Chip (MIFARE ultralight) without altering:
Let's say I have a string of a hex-number: "d73f7a79"
I could write the string in pairs: "d7 3f 7a 79"

Now I want to transfer the hex-pairs into a data block for sending to the MIFARE chip:

byte dataBlock[] = {
0xd7, 0x3f, 0x7a, 0x79 }

I want the stored data on the chip to be as followed:

Page 0 1 2 3
... ... ... ... ...
15 d7 3f 7a 79

Can anyone tell me how I could transform this string into the data block?

Thank you very much!

Cheers, Krassor

consider

byte buf [10];
char t [80];

void
disp (
    byte *buf,
    int   nByte )
{
    for (int n = 0; n < nByte; n++)  {
        sprintf (t, " 0x%02x", buf [n]);
        Serial.print (t);
    }
    Serial.println ();
}

// -----------------------------------------------------------------------------
int
func (
    char *s,
    byte *buf,
    int   bufSize )
{
    int       val;
    unsigned  i;
    for (i = 0; i < strlen(s); i += 2)  {
        sscanf (&s [i], "%02x", &val);
        *buf++ = val;
    }

    return i/2;
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);

    disp (buf, func ((char *)"d73f7a79", buf, sizeof(buf)));
    disp (buf, func ((char *)"1234567890123", buf, sizeof(buf)));
}

// -----------------------------------------------------------------------------
void
loop (void)
{
}

I am not clear what you want to do with the output but consider something like this method

char source[] = {"d73f7a79"};

void setup()
{
  Serial.begin(115200);
  static char output[3];  //zero in all elements
  for (int offset = 0; offset < 4; offset++)
  {
    memcpy(output, source + (2 * offset), 2);
    int value = strtol(output, 0, 16);
    Serial.print(output);
    Serial.print("\t");
    Serial.println(value);
  }
}

void loop()
{
}

@gcjr this looks promising! Sorry... I'm not experienced as a programmer, so could you please show me how I can use the string "d73f7a79" (string-variable) as input?
I can't really figure out what the hell is going on with the following^^:

(char *)"d73f7a79"

I have to put in my (for example):

String input = "d73f7a79";

Thank you very much!

as input? you just statically defined as a byte array. i don't know how you input the data.

the function i wrote, expects a char *s as an argument. but "d73f7a79" is a const char . C++ is finicky about using const char which are stored in flash as char * which are typically in RAM and can be modified. so I cast the const char * as a char * to satisfy the compiler.

why String? you defined is as byte above

consider the expanded code below which will read a c-string through the serial monitor

byte buf [10];
char t [80];

void
disp (
    byte *buf,
    int   nByte )
{
    for (int n = 0; n < nByte; n++)  {
        sprintf (t, " 0x%02x", buf [n]);
        Serial.print (t);
    }
    Serial.println ();
}

// -----------------------------------------------------------------------------
int
func (
    char *s,
    byte *buf,
    int   bufSize )
{
    int       val;
    unsigned  i;
    for (i = 0; i < strlen(s); i += 2)  {
        sscanf (&s [i], "%02x", &val);
        *buf++ = val;
    }

    return i/2;
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);

    disp (buf, func ((char *)"d73f7a79", buf, sizeof(buf)));
    disp (buf, func ((char *)"1234567890123", buf, sizeof(buf)));
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    char s [80];
    if (Serial.available ())  {
        int n = Serial.readBytesUntil ('\n', s, sizeof(s));
        s [n] = 0;
        disp (buf, func (s, buf, sizeof(buf)));
    }
}

Hi,

I figured it out partly:

//example code:
String input = "d73f7a79";

byte string_chunk_bytes[9];
input.getBytes(string_chunk_bytes, 9);

status = mfrc522.MIFARE_Ultralight_Write(i, string_chunk_bytes, 8);

the last line sends the data to the MIFARE chip.
The code above is just a simple example. In reality there are more strings that are separated in "chunks" of 8 characters (-> "d73f7a79").
Via for-loop "string_chunk_bytes" is generated several times and sent to different address pages of the chip.
Long story short: the output of strin_chunk_bytes:

11b701e0
bdb8b0d7
76f2c520
c9748ade
57c1be9a
.
.
.

and the result, when I read the newly written data of the chip (Page 6 to 15):

Firmware Version: 0x92 = v2.0
Scan PICC to see UID, SAK, type, and data blocks...
Card UID: 04 93 D4 12 5F 70 80
Card SAK: 00
PICC type: MIFARE Ultralight or Ultralight C
Page  0  1  2  3
  0   04 93 D4 CB
  1   12 5F 70 80
  2   BD 48 00 00
  3   E1 10 3E 00
  4   03 00 FE 00
  5   00 00 00 00
  6   31 31 62 37
  7   62 64 62 38
  8   37 36 66 32
  9   63 39 37 34
 10   35 37 63 31
.
.
.

As you can see, MFRC522 changes "my" bytes (e.g. the first pair: 11) to ASCII-hex 31 and 31...
"my" "b" changes to "62" and so on...

Is there a way to send the data "unchanged" to the chip?
Desired result:

Firmware Version: 0x92 = v2.0
Scan PICC to see UID, SAK, type, and data blocks...
Card UID: 04 93 D4 12 5F 70 80
Card SAK: 00
PICC type: MIFARE Ultralight or Ultralight C
Page  0  1  2  3
  0   04 93 D4 CB
  1   12 5F 70 80
  2   BD 48 00 00
  3   E1 10 3E 00
  4   03 00 FE 00
  5   00 00 00 00
  6   11 B7 01 E0
  7   BD B8 B0 D7
  8   76 F2 C5 20
  9   C9 74 8A DE
 10   57 C1 BE 9A
.
.
.

Thank you so much!

why represent the data as ASCII strings ?

consider

// simulate MRFC interface
struct Mfrc {
    void MIFARE_Ultralight_Write (int i, byte *buf, int nByte )  {
        Serial.print ("MIFARE_Ultralight_Write: "); 
        for (int n = 0; n < nByte; n++)  {
            char s [20];
            sprintf (s, " 0x%02x", buf [n]);
            Serial.print (s);
        }
        Serial.println ();
    }
} mrfc522;

// -----------------------------------------------------------------------------
#define DATA_LEN    4
byte data [][DATA_LEN] = {
    { 0x11, 0xb7, 0x01, 0xe0 },
    { 0xbd, 0xb8, 0xb0, 0xd7 },
    { 0x76, 0xf2, 0xc5, 0x20 },
    { 0xc9, 0x74, 0x8a, 0xde },
    { 0x57, 0xc1, 0xbe, 0x9a },
};
#define N_DATA      (sizeof(data)/DATA_LEN)

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);

    for (unsigned n = 0; n < N_DATA; n++)
        mrfc522.MIFARE_Ultralight_Write (n, & data [n][0], DATA_LEN);
        
}

// -----------------------------------------------------------------------------
void
loop (void)
{
}
1 Like

Hi,

@gcjr wow, thats perfect, it's exactly what I want!

Firmware Version: 0x92 = v2.0
Scan PICC to see UID, SAK, type, and data blocks...
Card UID: 04 93 D4 12 5F 70 80
Card SAK: 00
PICC type: MIFARE Ultralight or Ultralight C
Page  0  1  2  3
  0   04 93 D4 CB
  1   12 5F 70 80
  2   BD 48 00 00
  3   E1 10 3E 00
  4   03 00 FE 00
  5   00 00 00 00
  6   11 B7 01 E0
  7   BD B8 B0 D7
  8   76 F2 C5 20
  9   C9 74 8A DE
 10   57 C1 BE 9A
.
.
.

The last question is, how do I get from this:

String input = "11b701e0";

to this:

byte input[][DATA_LEN] = {0x11, 0xb7, 0x01, 0xe0};

The one problem is, that I get this string from the serial port and I first have to put it in the right format. I struggle with that because the Arduino platform doesn't give me the tools to "look behind the curtain" and figure it out by my own (as I usually get past issues in Matlab e.g).

Thank you very much, let's get the last problem resolved :slight_smile:

Don't use a String: use a c-string! Try something like this (tested on PC; needs some porting to the arduino):

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


const char    input_string[] = "11b701e0";
uint8_t       output_buffer[4];

size_t stringInterpreter  (const char* in, uint8_t* out);

int main (void)
{
    
    printf ("We are parsing: %s\n", input_string);
    
    stringInterpreter (input_string, output_buffer);    
    
    for (int i = 0; i < 4; ++i)
        printf ("Value #%i : %i\n", i, output_buffer[i]);
    
    return 0;
}

size_t stringInterpreter (const char* in, uint8_t* out)
{
    int i = 0;
    int j = 0;
    char hex_digits[3];
    
    for (i; in[i]; i += 2)
    {
        hex_digits[0] = in[i];
        hex_digits[1] = in[1+i];
        hex_digits[2] = '\0';
        
        out[j++] = (uint8_t) strtol (hex_digits, NULL, 16);
    }

    return j;
}

Output:

We are parsing: 11b701e0
Value #0 : 17
Value #1 : 183
Value #2 : 1
Value #3 : 224

EDIT: Will probably need some refining to get rid of magic numbers, etc.

the code posted in reply #5 translates a string of hex values into a byte array

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.