MIFARE_Read byte array to string

I am reading multiple pages from a Mifare Ultralight tag and i would like to send that information to my server api to check if the card is valid.

The output of mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); is:


Page  0  1  2  3
  0   04 7F 7F 8C
  1   02 66 60 81
  2   85 48 00 00
  3   E1 10 12 00
  4   01 03 A0 0C
  5   34 03 00 FE
  6   00 00 00 00
  7   00 00 00 00
  8   00 00 00 00
  9   00 00 00 00
 10   00 00 00 00
 11   00 00 00 00
 12   00 00 00 00
 13   00 00 00 00
 14   00 00 00 00
 15   00 00 00 00

With the next code i can read individual pages and i get the following result:

for(byte page = 0; page <= 10; page++) {
    MFRC522::StatusCode status = mfrc522.MIFARE_Read(page, buffer, &Count); 
       
    if(status==mfrc522.STATUS_OK){
        Serial.print("page ");
        Serial.print(page);
        Serial.print(": ");
        dumpInfo(buffer,4);
    }
    Count = sizeof(buffer);
}

void dumpInfo(byte *ar, int len){
    for(int i=0 ; i<len ; i++){
        if(ar[i]<0x10) {
            Serial.print(F("0"));
        }
        Serial.print(ar[i], HEX);
        Serial.print(F(" "));
    }
    Serial.println("");
}
page 0: 04 7F 7F 8C 
page 1: 02 66 60 81
page 2: 85 48 00 00
page 3: E1 10 12 00
page 4: 01 03 A0 0C
page 5: 34 03 00 FE
page 6: 00 00 00 00
page 7: 00 00 00 00
page 8: 00 00 00 00
page 9: 00 00 00 00 
page 10: 00 00 00 00

I just don't know how to send the single page information as a string**?** or char array to my webserver.

What would be a good way, i can convert the hex values on my server but if i need to do it in C++ that would be also okay for me

For me the best would be some kind of array:

pages [
    0: [04,
        7F,
        7F,
        8C],
    1: [02,
        66,
        60,
        81],
    2: [E1,
        10,
        12,
        00],
   3: ...
]

Is this possible?

What string do you expect to send to your webserver ? Give an example. Most of those hex values are not printable ASCII characters.

This would be great but i understand if that is not doable.

If the result could be a string with each value seperated with a ; would also be okay, but if another option would be better i would be happy to hear that

result = "04;7F;7F;8C;02;66;60;81;85;48;00;00;E1;10;...."

consider which produces. (modify for you needs)

page  1:0x04, 0x7f, 0x7f, 0x8c
#include <stdio.h>
#include <string.h>

char *
genStr (
    int            page,
    unsigned char *buf,
    int            size )
{
    static char    s [80];
    char           t [10];

    sprintf (s, "page %2d:0x%02x", page, buf [0]);
    for (unsigned n = 1; n < sizeof(buf); n++)  {
        sprintf (t, ", 0x%02x", buf [n]);
        strcat (s, t);
    }

    return s;
}

int
main () {
    unsigned char  buf [] = { 0x04, 0x7f, 0x7f, 0x8c };
    int            page   = 1;

    printf ("%s\n", genStr (page, buf, sizeof(buf)));

    return 0;
}

Thanks, it is almost exactly what i need, the only thing that would make it better is when i am able to combine pages, i send the information after i read page 10.

Can i combine all 10 pages?

Thanks a lot for your help

if you study the code, you'll see that it constructs a string by concatenating formatted strings together resulting in a single string containing one page (?) of values.

that string could in turn be concatenated to a longer string (make sure it's long enough) so that one multiple line (add some line terminator) string is sent.

you can decide which pages of values to construct the final string from

Yes with sprintf it's easy

Here is another example looking like your "array" : CG3TRJ - Online C++ Compiler & Debugging Tool - Ideone.com

Thank you but it is still a bit difficult for me, @gcjr the function genStr creates a string per page, if i want 1 string for 2 pages, i need to call the function twice but it creates a new string each time the function is called.

@guix, thanks also for the example. It shows the "array" as string what i asked, but it does it from this: uint8_t values[][4], how do i use my buffer variable to fill it?

I am a php developer so C++ is a bit difficult with types for me

i had hoped you studied the code, understood the concepts and modified it to suit your needs.

here's an approach that produces the following.
think about what you need to do to s at the beginning of each transmission

page  1: 0x04, 0x7f, 0x7f, 0x8c

page  1: 0x04, 0x7f, 0x7f, 0x8c
page  2: 0x04, 0x7f, 0x7f, 0x8c

page  1: 0x04, 0x7f, 0x7f, 0x8c
page  2: 0x04, 0x7f, 0x7f, 0x8c
page  3: 0x04, 0x7f, 0x7f, 0x8c

page  1: 0x04, 0x7f, 0x7f, 0x8c
page  2: 0x04, 0x7f, 0x7f, 0x8c
page  3: 0x04, 0x7f, 0x7f, 0x8c
page  4: 0x04, 0x7f, 0x7f, 0x8c

#include <stdio.h>
#include <string.h>

char *
genStr (
    char          *s,
    int            page,
    unsigned char *buf,
    int            size )
{
    char           t [10];

    sprintf (t, "page %2d: 0x%02x", page, buf [0]);
    strcat (s, t);
    for (unsigned n = 1; n < sizeof(buf); n++)  {
        sprintf (t, ", 0x%02x", buf [n]);
        strcat (s, t);
    }
    strcat (s, "\n");

    return s;
}

int
main () {
    char           s [200] = "";
    unsigned char  buf [] = { 0x04, 0x7f, 0x7f, 0x8c };
    int            page   = 1;

    printf ("%s\n", genStr (s, page++, buf, sizeof(buf)));
    printf ("%s\n", genStr (s, page++, buf, sizeof(buf)));
    printf ("%s\n", genStr (s, page++, buf, sizeof(buf)));
    printf ("%s\n", genStr (s, page++, buf, sizeof(buf)));

    return 0;
}

Thank you again for the reply. I understand what you mean but you still print the genStr function 4 times. I just don't know how to send data to my server once with the result "glued" together of the 4 strings

won't you be sending more than one message to your server, recreating the multi-page string each time, calling genStr() for each page?

your code sends the string being printed

In my example it was because it was from an online example. I just don't know how to change it so i can send one request to my server with all of the pages together (page 1 till 10 for example)

consider (think building blocks)

output

page  0: 0x04, 0x7f, 0x7f, 0x8c
page  1: 0x04, 0x7f, 0x7f, 0x8c
page  2: 0x04, 0x7f, 0x7f, 0x8c
page  3: 0x04, 0x7f, 0x7f, 0x8c
page  4: 0x04, 0x7f, 0x7f, 0x8c
page  5: 0x04, 0x7f, 0x7f, 0x8c
page  6: 0x04, 0x7f, 0x7f, 0x8c
page  7: 0x04, 0x7f, 0x7f, 0x8c
page  8: 0x04, 0x7f, 0x7f, 0x8c
page  9: 0x04, 0x7f, 0x7f, 0x8c
#include <stdio.h>
#include <string.h>

char *
genStr (
    char          *s,
    int            page,
    unsigned char *buf,
    int            size )
{
    char           t [10];

    sprintf (t, "page %2d: 0x%02x", page, buf [0]);
    strcat (s, t);
    for (unsigned n = 1; n < sizeof(buf); n++)  {
        sprintf (t, ", 0x%02x", buf [n]);
        strcat (s, t);
    }
    strcat (s, "\n");

    return s;
}


// -----------------------------------------------------------------------------
void
send (
    char    *s )
{
    printf ("%s\n", s);
}


// -----------------------------------------------------------------------------
unsigned char  buf [] = { 0x04, 0x7f, 0x7f, 0x8c };

void
request (
    int pageStart,
    int pageEnd )
{
    char s [800] = "";

    for (int page = pageStart; page <= pageEnd; page++)
        genStr (s, page, buf, sizeof(buf));

    send (s);
}

// -----------------------------------------------------------------------------
int
main () {
    request (0, 9);

    return 0;
}

Thanks for the help. I will check this monday and try to learn how it works.

I am not sure why i can't get this to work. The code seems to work fine for page 0, but after that the ESP panics and the debugger shows this:

Breakpoint 
6, Cardreader::genStr (this=<optimized out>, s=0x3ffb2ffc "page  0: 0x04, 0x53, 0x7e, 0xa1\n", page=<optimized out>, buf=<optimized out>, size=24) at lib\Cardreader\Cardreader.cpp:176
176	}
3
Info : esp32.cpu0: Target halted, PC=0x40091856, debug_reason=00000001
Info : esp32.cpu0: Target halted, PC=0x40085B57, debug_reason=00000001
Info : Set GDB target to 'esp32.cpu0'
esp32.cpu0: Target halted, PC=0x40085B57, debug_reason=00000001
Set GDB target to 'esp32.cpu0'
Info : esp32.cpu1: Target halted, PC=0x400D5A30, debug_reason=00000000
esp32.cpu1: Target halted, PC=0x400D5A30, debug_reason=00000000

Program received signal 
SIGTRAP, Trace/breakpoint trap.
3
Info : esp32.cpu0: Target halted, PC=0x40091856, debug_reason=00000001
invoke_abort () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:154
154	/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c: No such file or directory.

I have it like this now:


    if(mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
        byte buffer[24];
        byte Count = sizeof(buffer);
        char s [800] = "";
        for(byte page = 0; page <= 10; page++) {
            MFRC522::StatusCode status = mfrc522.MIFARE_Read(page, buffer, &Count);
            
            if(status==mfrc522.STATUS_OK){
                genStr(s, page, buffer, sizeof(buffer));
            }
            Count = sizeof(buffer);
        }
        
        JSONVar registration;
        registration["deviceId"] = _internet->getDeviceId();
        registration["cardInformation"] = s;
        _internet->callAPI("readcard", registration);        
        mfrc522.PICC_WakeupA(buffer, &Count);
        delay(1000);
    }

This is what the serial monitor shows:

page 0: 
Stack smashing protect failure!

abort() was called at PC 0x400e74f4 on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x40085b5c:0x3ffb2ef0 0x40085dd9:0x3ffb2f10 0x400e74f4:0x3ffb2f30 0x400d2bb1:0x3ffb2f50 0x400d2c7d:0x3ffb2f80 0x400d2e93:0x3ffb3340 0x40086dea:0x3ffb3360
  #0  0x40085b5c:0x3ffb2ef0 in invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #1  0x40085dd9:0x3ffb2f10 in abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:715
  #2  0x400e74f4:0x3ffb2f30 in __stack_chk_fail at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/stack_check.c:36
  #3  0x400d2bb1:0x3ffb2f50 in Cardreader::genStr(char*, int, unsigned char*, int) at lib\Cardreader/Cardreader.cpp:176
  #4  0x400d2c7d:0x3ffb2f80 in Cardreader::process() at lib\Cardreader/Cardreader.cpp:83
  #5  0x400d2e93:0x3ffb3340 in Cardreader::scanCard(void*) at lib\Cardreader/Cardreader.cpp:189 (discriminator 1)
  #6  0x40086dea:0x3ffb3360 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)

Rebooting...

Ah, the problem is here in the genStr function:

    char           t [10];

If i increase the length it will work, do i just need to count characters or what is the best value for this t?

I can use t[100] but maybe that will result into other problems i don't know about

it's always good to understand why something fixes a problem

a 10 byte "t" string buffer should be long enough for a 2 digit hex values. however, it won't be long enough for a 6 digit value (e.g. 0x123456) because ", 0x" plus the NULL terminator requires 5 bytes.

in order to handle a presumably maximum 8-digit value therefore requires 13 bytes (8 + 5). making it 20 bytes isn't too excessive for a stack variable.

are all you page values 5 digits or less?

Well, this is the result for example

p_0:_0x04,_0x53,_0x7e,_0xa1
p_1:_0x02,_0x66,_0x60,_0x81
p_2:_0x85,_0x48,_0x00,_0x00
p_3:_0xe1,_0x30,_0x32,_0x20
p_4:_0x63,_0x72,_0x73,_0x5f
p_5:_0x31,_0x32,_0x33,_0x34
p_6:_0x35,_0x36,_0x5f,_0x5f
p_7:_0x39,_0x38,_0x37,_0x36
p_8:_0x20,_0x20,_0x20,_0x20
p_9:_0x20,_0x20,_0x20,_0x20
p10:_0x20,_0x20,_0x20,_0x20
p11:_0x00,_0x00,_0x00,_0x00
p12:_0x00,_0x00,_0x00,_0x00
p13:_0x00,_0x00,_0x00,_0x00
p14:_0x00,_0x00,_0x00,_0x00
p15:_0x00,_0x00,_0x00,_0x00

Every row contains 27 characters. Does it mean i should use t[27] or am i thinking wrong here? Probably i can remove the undercase to shorten the row

i'm sorry, the code i posted has an error.

   sprintf (t, "page %2d: 0x%02x", page, buf [0]);

since "t" is used for format the beginning of the string with "page", it needs to be longer, at least 14 (e.g. "page 12: 0xab"

Thank you, that works!