Code to reverse a HEX value and convert to Decimal

Hi all,

I am using a PN532 RFID reader module.

In its example library is a Mifare UID reading sketch.

It outputs a reverse HEX value on the serial monitor like so; 0xCE 0x67 0x6E 0x5A

So, to get the correct UID you need to reverse this value (5A6E67CE) and then I have been using online converters etc to get the value I want (1517184974)

Ideally I would like the serial monitor to just spit out this value rather than the reverse code, I know (I'm fairly sure) it can be done in code but unfortunately don't have the ability (I'm really bad at maths), so was hoping somebody could come to my rescue...

I don't think the modification would necessarily be too complicated if you know what you are doing, although I'm not qualified to make that assertion.

Thank you for reading and any advice you may have to offer...

Here is the original code for reference;

/**************************************************************************/
/*! 
    This example will attempt to connect to an ISO14443A
    card or tag and retrieve some basic information about it
    that can be used to determine what type of card it is.   
   
    Note that you need the baud rate to be 115200 because we need to print
    out the data and read from the card at the same time!

    
*/
/**************************************************************************/

// choose to SPI or I2C or HSU
#if 0
  #include <SPI.h>
  #include <PN532_SPI.h>
  #include "PN532.h"

  PN532_SPI pn532spi(SPI, 10);
  PN532 nfc(pn532spi);
#elif 0
  #include <PN532_HSU.h>
  #include <PN532.h>
      
  PN532_HSU pn532hsu(Serial1);
  PN532 nfc(pn532hsu);
#else 
  #include <Wire.h>
  #include <PN532_I2C.h>
  #include <PN532.h>

  PN532_I2C pn532i2c(Wire);
  PN532 nfc(pn532i2c);
#endif

void setup(void) {
  Serial.begin(115200);
  Serial.println("Hello!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  
  // Set the max number of retry attempts to read from a card
  // This prevents us from waiting forever for a card, which is
  // the default behaviour of the PN532.
  nfc.setPassiveActivationRetries(0xFF);
  
  // configure board to read RFID tags
  nfc.SAMConfig();
    
  Serial.println("Waiting for an ISO14443A card");
}

void loop(void) {
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
  
  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
  
  if (success) {
    Serial.println("Found a card!");
    Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
    Serial.print("UID Value: ");
    for (uint8_t i=0; i < uidLength; i++) 
    {
      Serial.print(" 0x");Serial.print(uid[i], HEX); 
    }
    Serial.println("");
    // Wait 1 second before continuing
    delay(1000);
  }
  else
  {
    // PN532 probably timed out waiting for a card
    Serial.println("Timed out waiting for a card");
  }
}

It outputs a reverse HEX value on the serial monitor like so; 0xCE 0x67 0x6E 0x5A

What? Why do YOU think the bytes are output in the reverse order?

Ideally I would like the serial monitor to just spit out this value rather than the reverse code, I know (I'm fairly sure) it can be done in code but unfortunately don't have the ability (I'm really bad at maths), so was hoping somebody could come to my rescue...

How good at math do you have to be to output the data in order 3, 2, 1, 0 instead of 0, 1, 2, 3? It's a one line of code change. Here's a hint: It's the for loop that needs changing.

Thanks for getting back to me.

PaulS:
What? Why do YOU think the bytes are output in the reverse order?

Because it is necessary to reverse those values and convert to get the correct UID given by a different reader. Converted in the order given, the value is too long.

Also I read that the on the Mifare Classic 1k Datasheet that the UID is stored in 'normal' order and again in reverse, so that is what the reader is spitting out.

PaulS:
How good at math do you have to be to output the data in order 3, 2, 1, 0 instead of 0, 1, 2, 3? It's a one line of code change. Here's a hint: It's the for loop that needs changing.

Not very when it's written out like that, unfortunately I am not good enough at maths/programming to implement the change.

Thank you for pointing me in the right direction, I had a feeling that the key would be to modify the section where it handles the values.

PaulS:
It's a one line of code change

I would greatly appreciate it if you could elaborate or help me a little further, I'm kinda stabbing in the dark, tried changing

for (uint8_t i=0; i < uidLength; i++)

to

for (uint8_t i=0; i < uidLength; i--)

and

Serial.print(" 0x");Serial.print(uid[i], HEX);

to

Serial.print(uid[i], DEC);

But am just getting random (looking) numbers, not my known UID :~

I am not good enough at maths/programming to implement the change.

Cut the crap. You don't have to be good at math to program. The Arduino is.

tried changing... to...

Look at the reference page. The for loop consists of three simple parts - the initial condition, the continue condition, and the after-each-iteration part.

You got the right idea about what you need to change in the after-each iteration part. Now, what is the correct initial condition to start at 3 instead of 0? What is the correct continue condition when i is greater than 0, instead of when i is less than 4?

PaulS:

I am not good enough at maths/programming to implement the change.

Cut the crap. You don't have to be good at math to program. The Arduino is.

That doesn't make any sense at all. The Arduino is so good at maths it will overcome my programming inadequacy and do so itself?

I've been staring at it for quite some time, nothing happening.

Why would I ask for help if I didn't need it?

And I don't see why you would even bother typing a hostile message when you could just not type one at all, seriously wasting your own time.

Since googling "PN532 output UID as decimal value" just turned up this tread, and that was disheartening...

Here's the code to do it for anybody else who needs to...

/**************************************************************************/
/*! 
    This example will attempt to connect to an ISO14443A
    card or tag and retrieve some basic information about it
    that can be used to determine what type of card it is.   
   
    Note that you need the baud rate to be 115200 because we need to print
    out the data and read from the card at the same time!

    
*/
/**************************************************************************/

// choose to SPI or I2C or HSU
#if 0
  #include <SPI.h>
  #include <PN532_SPI.h>
  #include "PN532.h"

  PN532_SPI pn532spi(SPI, 10);
  PN532 nfc(pn532spi);
#elif 0
  #include <PN532_HSU.h>
  #include <PN532.h>
      
  PN532_HSU pn532hsu(Serial1);
  PN532 nfc(pn532hsu);
#else 
  #include <Wire.h>
  #include <PN532_I2C.h>
  #include <PN532.h>

  PN532_I2C pn532i2c(Wire);
  PN532 nfc(pn532i2c);
#endif

void setup(void) {
  Serial.begin(115200);
  Serial.println("Hello!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  
  // Set the max number of retry attempts to read from a card
  // This prevents us from waiting forever for a card, which is
  // the default behaviour of the PN532.
  nfc.setPassiveActivationRetries(0xFF);
  
  // configure board to read RFID tags
  nfc.SAMConfig();
    
  Serial.println("Waiting for an ISO14443A card");
}

void loop(void) {
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
  
  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
  
  uint32_t cardidentifier = 0;
  
  if (success) {
    // Found a card!

    Serial.print("Card detected, UID: ");
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
    Serial.println("");
    // Wait 1 second before continuing
    delay(1000);
  }
  else
  {
    // PN532 probably timed out waiting for a card
    Serial.println("Timed out waiting for a card");
  }
}

That doesn't make any sense at all. The Arduino is so good at maths it will overcome my programming inadequacy and do so itself?

There is no math involved in making a for loop start at 4 and count down to zero. Stop making the excuse that your poor math skills have any bearing on this situation.

Why would I ask for help if I didn't need it?

I can't see that it is all that difficult to figure out that counting 3, 2, 1, 0 requires that you start at 3 and stop when you get to 0. Can you explain to me why that IS difficult?

I have no reason to explain myself to you, you're an arrogant POS, but I'll be brief.

Never said it was difficult, just said I couldn't do it.

Or program an Arduino to do it rather.

Why don't you go try screw a female/male/whatever instead of being a condescending dick? It might loosen you up.

Unless that's not an option for you, in that case I'm sorry you're such a wanker.

Is it only the 4-byte scenario that you need to deal with? The sketch you posted that some UIDs might be 7-byte values. Processing those as you describe would be a very different proposition.

For the 4-byte scenario, I think you just need to convert the 4 byte values into a 32-bit long by shifting and adding the bytes in the right order. A 'for' loop would be the natural way to do that.

    long result = 0;
    for (int i=3; i >= 0; i--) 
    {
        result = (result << 8) + uid[i];
    }

Then you can just print the value. You want it printed as a decimal number, and the print() method will do that by default if you don't specify the radix.

PeterH:
Is it only the 4-byte scenario that you need to deal with? The sketch you posted that some UIDs might be 7-byte values. Processing those as you describe would be a very different proposition.

For the 4-byte scenario, I think you just need to convert the 4 byte values into a 32-bit long by shifting and adding the bytes in the right order. A 'for' loop would be the natural way to do that.

    long result = 0;

for (int i=3; i >= 0; i--)
    {
        result = (result << 8) + uid[i];
    }




Then you can just print the value. You want it printed as a decimal number, and the print() method will do that by default if you don't specify the radix.

Yep, it is.

Thanks mate, I already figured a solution that works for me 3 posts up.

I should have taken that section of code out, but it was the UID example from the PN532 library, so I just pasted it in it's entirety.

All of the cards I will be encountering will be the Mifare 1K S50 (Classic), so will only have 4 byte UID's.

I'm sure perhaps the same method could be used for the Mifare Plus cards, but it's not applicable to my situation.

Thanks all the same...