Good day everyone and thank you in advance for your help
The sheer number of similar issues with this topic indicates that it's not straightforward, but despite many hours of reading and trying to work out what I'm doing wrong, I can not.
I am using an Arduino with an appropriate RFID reader module.
I can read the raw data, which is in "Data format: 16Hex ASCII code" according to the (extremely limited) info provided.
So for example, one of my chips has ID "990000005929238", and the data read from the module for it is "03DE00005A7916".
Now how in the name of g*&$%^£ does one convert from the second to the first?
According to the spec for FDX-B chips, the first 3 digits of the 15-digit decimal number are a country code if <900, or a manufacturer code if >=900. The second 3 digits are either the first three of the 12-digit animal ID, if the first three are a country code, or a "sub-manufacturer" code if it isn't, leaving 'only' 9 digits for the animal ID.
So for example:
970132004164479
970 = manuf. ID
132 = sub-manuf. ID
004164479 = 9-digit chip/animal ID.
788000006525677
788 = country ID (Tunisia)
000006525677 = 12-digit chip/animal ID.
I understand that there is also checksum information in there and an "animal?" flag, and maybe other bits and bobs, but I'm only really interested in the chip ID.
If anyone has successfully done this could they please point me in the right direction?
I know the algorithm exists, because when I scan the chip with a commercial chip scanner, it returns the correct number.
I can't believe how much time I've spent on this but I have finally got it working.
I was confused... and in fact it turns out the sub-manufacturer code is "the second three digits of the Chip ID if the first three digits are >=900" so there are only TWO conversions from hex to decimal required, not three. Once I'd sussed that, it was relatively straightforward but I did have some trouble using unsigned long longs because they break Serial.println, and in the end I decided to treat everything as a string and do it manually.
Here's the final code, which should work with any of the common 134.2kHz RFID modules.
Comments and criticism are welcome.
#include <Arduino.h>
#include <SoftwareSerial.h>
SoftwareSerial RFID(3, 4); // RX, TX
char buffer[32]; // Buffer for ASCII HEX input
uint8_t idx = 0;
bool started = false;
void setup() {
Serial.begin(9600);
RFID.begin(9600);
Serial.println(F("\nRFID Reader Ready..."));
}
void loop() {
while (RFID.available()) {
char b = RFID.read();
if (b == 0x02) { // Start of transmission (STX)
idx = 0;
started = true;
}
if (started) {
buffer[idx++] = b;
if (b == 0x03) { // End of transmission (ETX)
started = false;
buffer[idx] = '\0'; // Null terminate the string
// Extract and process hex data
processRFIDTag(buffer);
}
}
}
}
// Process the received RFID data
void processRFIDTag(const char* rawData) {
char countryHex[5] = {0};
char chipHex[11] = {0};
// Extract relevant HEX parts
strncpy(countryHex, &rawData[1], 4);
strncpy(chipHex, &rawData[5], 10);
// Convert HEX to Decimal with correct padding
char countryCode[4];
char chipID[13];
hexToPaddedDecimal(countryHex, countryCode, 3); // Country code needs 3-digit padding
hexToPaddedDecimal(chipHex, chipID, 12); // Chip ID needs 12-digit padding
// Final 15-digit ID
char fullID[16];
snprintf(fullID, sizeof(fullID), "%s%s", countryCode, chipID);
Serial.println(fullID);
}
// Convert hex string to zero-padded decimal string of specified length
void hexToPaddedDecimal(const char* hexStr, char* result, int padLength) {
uint64_t decimalValue = 0;
// Convert hex string to a 64-bit integer manually
for (int i = 0; i < strlen(hexStr); i++) {
char c = hexStr[i];
decimalValue *= 16; // Shift left in base 16
if (c >= '0' && c <= '9') {
decimalValue += c - '0';
} else if (c >= 'A' && c <= 'F') {
decimalValue += c - 'A' + 10;
} else if (c >= 'a' && c <= 'f') {
decimalValue += c - 'a' + 10;
} else {
strcpy(result, "ERROR"); // Return error if invalid character is found
return;
}
}
// Manually convert uint64_t to a zero-padded string
int i = padLength - 1;
result[padLength] = '\0'; // Null terminate the string
while (decimalValue > 0 && i >= 0) {
result[i--] = '0' + (decimalValue % 10);
decimalValue /= 10;
}
// Ensure correct padding
while (i >= 0) {
result[i--] = '0';
}
}