I am working with a RFID reader that sends the RFID number to our particle in 5 HEX bytes. The human readable version of this is essentially a 40 bit word. As this is bigger than an unsigned long, what is the best way for me to convert these 5 Hex bytes into a potentially 12 digit human readable number?
Ultimately this number will be converted to a char array to be published as the identifying number of the RFID tag that has been read.
CONCATENATING BYTES
Incase someone else is looking at this in the future, for verification, the bytes I am concatenating 31 9A 54 DE 9A. FYI these bytes are stored backwards in my rfidData array. i.e byte 31 is rfidData[11], 9A is rfidData[10] etc
uint64_t val = 0;
val += (uint64_t)rfidData[11] << 32;
val += (uint64_t)rfidData[10] << 24;
val += (uint64_t)rfidData[9] << 16;
val += (uint64_t)rfidData[8] << 8;
val += (uint64_t)rfidData[7];
Serial.println(val);
You can use uint64_t (aka long long) - although I’m not entirely sure that printf() and its siblings do treat them correctly on Particle devices - still worth a test tho’.
You may need to come up with your own string translation.
It is true, sprintf-style formatting, including snprintf() , Log.info() , Serial.printf() , String::format() etc. do not support 64-bit integers. They do not support %lld , %llu or Microsoft-style %I64d or %I64u .
As a workaround you can use the Print64 firmware library in the community libraries. The source and instructions can be found in GitHub.
No, that approach won’t work. You are making a static copy of the pointer, but the underlying character array is declared local on the stack and will not survive the function return. Using the pointer after the function returns will result in undefined behavior and probably a hard fault.
I have not seen Rick’s code but I would guess that he converted the local character array into a String object in order to extend the lifetime of the string so it can be used outside the function.
One possible solution would be to declare the temp character array as static so that it survives the call. Not efficient though since 68 bytes of memory will be reserved for this purpose only.
I’m with @Muskie on that, but I’d go down the route most standard functions dealing with strings go: Pass in your array you want populated and work on that instead of working on a temporary array
You just want to add some sanity checks about the length of the buffer to avoid overflow errors.
Just for geeks: Instead of [value % base] and value /= base you could use lldiv() for some extra speed
So here the value to be converted is just divided by base and the remainder is placed at the back of the temp array? And this dividing continues until all is said and done?
String result(cp);
This syntax confused me a bit, is it just creating a String variable called result and letting the first value be the front of cp?
Yes he is limiting the base of the number. Arithmetic on a base greater than 16 is unlikely to be useful.
Not sure why 4 extra but there needs to be at least one extra position for the trailing null character. Since base 2 generates the longest string, 64 characters are needed to represent the number plus an extra for null terminator. Anyone else see why the extra 3?
3 This line creates a pointer to the last entry in the array.
Adds the null terminator at the last entry so the final result is properly terminated.
He is using modulo arithmetic to extract the digits. For example, the number 47 modulo 10 leaves 7, which is the least significant digit. Thus, he extracts the digits in reverse order, LSD first, then the next and so on. Each digit is placed starting at the end of the array moving towards the front (and the MSD). While the value is not zero he adds another digit by modulo division and then uses normal divide to get the result of the divide. Again 47 divided by 10 leaves 4. The number gets smaller on each iteration of the loop until the value is zero and all digits have been written.
The string value is being initialized by a pointer to the very first character of the string, which happens to be the last digit he wrote to the array and is the final value of cp. When initializing a String with a pointer to a character array, the String gets populated by the actual array contents itself, not just the first character. Now String has the final answer, saved on the heap where it is safe to return to the caller.
The +4 is because it needs to be at least 1 for the trailing null, and the compiler aligns to 4-byte alignment anyway, and this adds an extra buffer space so the buffer is not overwritten if I happened to have an off-by-one error somewhere and it doesn’t use any more stack space in reality.