1

I'm a beginner to C++ and I'm clearly missing some fundamental knowledge of data types. As such, I'm struggling to adapt the examples in the miguelbalboa/rfid library to my use case. I'm simply trying to write an integer to a 13.56Mhz RFID tag. Ideally I'd like to optimize the data so as to be quick to read (it seems fully reading these cards can take a while and I'd like to read the integer, an ID, as quickly as possible).

So on to my actual questions... what is the data type shown in this block of example code (shown below) and how can I turn an integer into the same data type? Finally, how should I read this saved value back into the familiar integer data type?

byte dataBlock[]    = {
    0x01, 0x02, 0x03, 0x04, //  1,  2,   3,  4,
    0x05, 0x06, 0x07, 0x08, //  5,  6,   7,  8,
    0x09, 0x0a, 0xff, 0x0b, //  9, 10, 255, 11,
    0x0c, 0x0d, 0x0e, 0x0f  // 12, 13, 14, 15
};
1
  • really important info that you failed to mention ... what is the model of the device that you are using?
    – jsotola
    Dec 19, 2017 at 5:43

2 Answers 2

1

The dataBlock[] variable is an array of bytes. One byte can represent an integer ranging from -128 to 127, or a positive integer ranging from 0 to 255. If your integer value will always be in one of those ranges, then you can just put your integer in the first element of the array and zero out the remaining.

byte dataBlock[]    = {
    0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00
};

(That saves a value of 1 to the first element, and zeros to the rest. If you want to change the first element:

dataBlock[0] = yourValue;

If your integer is a 2-byte integer, as is typically found in Arduino with type int, you need to split your value into the high byte and low byte:

dataBlock[0] = (byte)(yourValue & 0xFF); // Low byte
dataBlock[1] = (byte)(yourValue >> 8);   // High byte

Then you write the data block as per the example. To get your 2-byte integer value back:

yourValue = ((int)dataBlock[1])<<8 | dataBlock[0];  // Shift high byte, OR with low byte.
0

Well, the example is using the MIFARE_Write and MIFARE_Read functions. These functions, as explained in the library, accept at least 16 bytes, so the 16-bytes buffer is the smallest you can read/write. Consequently I suggest you, if you don't have any additional data, to use 16-bytes IDs (you get a much wider code space).

If you strictly want to use 2 or 4-bytes integers, the first solution which comes to my mind is jose's one, so manually split the int in two (or the long in four) bytes and store them in the array. For instance

// Big endian format
dataBlock[idx]   = (byte)(intValue >> 8); // Byte 1
dataBlock[idx+1] = (byte)(intValue);      // Byte 0
// or
dataBlock[idx]   = (byte)(longValue >> 24); // Byte 3
dataBlock[idx+1] = (byte)(longValue >> 16); // Byte 2
dataBlock[idx+2] = (byte)(longValue >> 8);  // Byte 1
dataBlock[idx+3] = (byte)(longValue);       // Byte 0

// Little endian format
dataBlock[idx]   = (byte)(intValue);      // Byte 0
dataBlock[idx+1] = (byte)(intValue >> 8); // Byte 1
// or
dataBlock[idx]   = (byte)(longValue);       // Byte 0
dataBlock[idx+1] = (byte)(longValue >> 8);  // Byte 1
dataBlock[idx+2] = (byte)(longValue >> 16); // Byte 2
dataBlock[idx+3] = (byte)(longValue >> 24); // Byte 3

NOTE: idx can be any value; the easiest approach is to put the int at the beginning (so substitute idx with 0) This is the safest way to handle this, since the endianness is explicit. You can, however, trust the compiler and use its implicit handling of multi-byte variables in this way:

*((int*)(&datablock[idx])) = intValue;
// or
*((long*)(&datablock[idx])) = longValue;

You take the cell where you want to put the beginning of the data, get its pointer, cast it to the pointer type you need, then write inside that pointer the value you want. Please note, however, that cells idx and idx+1 in the case of an int, or idx to idx+3 for long, will be written. If your array ends, you will pollute the memory in unpredictible ways (just like if you write dataBlock[18] = something when dataBlock has 16 cells).

Note you cannot control the endianness of the byte array, but if you always use the same device to read and write you should not worry. FYI, at present the compiler used by Arduino IDE is little endian.

Note also that, for idx = 0, (&datablock[idx]) can be simplified in (datablock).

To read back the data, you have the following ways

// Big endian format
intValue = (((int)dataBlock[idx]) << 8) | dataBlock[idx+1];
// or
longValue = (((long)dataBlock[idx]) << 24) | (((long)dataBlock[idx+1]) << 16) | (((long)dataBlock[idx+2]) << 8) | dataBlock[idx+3];

// Little endian format
intValue = (((int)dataBlock[idx+1]) << 8) | dataBlock[idx];
// or
longValue = (((long)dataBlock[idx+3]) << 24) | (((long)dataBlock[idx+2]) << 16) | (((long)dataBlock[idx+1]) << 8) | dataBlock[idx];

Or, in the last case,

intValue = *((int*)(&datablock[idx]));
// or
longValue = *((long*)(&datablock[idx]));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.