Arduino RFID checksum calculation and key visualiz

2019-03-01 17:25发布

问题:

I'm using this RFID module for Arduino Ethernet R3 and I need to retrieve from the Software Serial the card (TAG) ID that is written outside the tag. The module's datasheet says that 14 bytes are sent to the Arduino. The first is the header, the last the footer, the 2 bytes before the footer are the checksum, and the other 10 bytes are the ASCII data that contains the tag ID.

How can I recreate the ID of the card, and control the checksum? For example with a tag that has this ID: 0013530444, the Arduino response is:

I received: 2
I received: 51
I received: 67
I received: 48
I received: 48
I received: 67
I received: 69
I received: 55
I received: 53
I received: 52
I received: 67
I received: 67
I received: 66
I received: 3

But I've no idea how to print on the screen the ID read by the Arduino. How to calculate the checksum?

http://www.seeedstudio.com/wiki/index.php?title=125Khz_RFID_module_-_UART

Can anyone help me?

回答1:

Here's a walkthrough of how to calculate the checksum.

Take your card number (this is just directly quoted from your text)

I received: 2
I received: 51
I received: 67
I received: 48
I received: 48
I received: 67
I received: 69
I received: 55
I received: 53
I received: 52
I received: 67
I received: 67
I received: 66
I received: 3

This would give you a number that is equivalent to the following:

2 51 67 48 48 67 69 55 53 52 67 67 66 3

The first numer (2) indicates that this is the beginning of a request.

The last number (3) indicates that this is the end of a request.

2 51 67 48 48 67 69 55 53 52 67 67 66 3

For the purposes of calculating the checksum, we are going to remove these two numbers. So your new number is now:

51 67 48 48 67 69 55 53 52 67 67 66

The last two numbers that you have are your checksum. The remaining numbers are your card number. So:

Your card number is:

51 67 48 48 67 69 55 53 52 67

And your checksum is:

67 66

Next you need to convert your Card Number and your Checksum to ASCII values:

Your card number is:

3 C 0 0 C E 7 5 4 C

And your checksum is:

C B

Next, grab each number into pairs:

Your card number is:

3C 00 CE 75 4C

And your checksum is:

CB

Then you need to treat each pair as a HEXIDECIMAL value and do an XOR against them. So basically you need to prove the following:

3C ^ 00 ^ CE ^ 75 ^ 4C == CB

(3C ^ 00) = 3C

3C ^ CE ^ 75 ^ 4C == CB

(3C ^ CE) = F2

F2 ^ 75 ^ 4C == CB

(3C ^ CE) = 87

87 ^ 4C == CB

(87 ^ 4C) = CB

CB == CB

Because CB == CB, this is a valid transaction.

No doubt someone else can come up with a better approach than this, but there should be enough pseudo code here for you to write it yourself.



回答2:

I found this blog which has an implementation in Arduino, I've adapted it to work in Java and results are good. Since there are a lot of bitwise operations - I used http://www.miniwebtool.com/bitwise-calculator/ to try to understand what's going on. I understand all of it except (val | (tempbyte << 4)), I mean I understand what the statement does, I just struggle to see how that produces the result I want.

void loop () {
  byte i = 0;
  byte val = 0;
  byte code[6];
  byte checksum = 0;
  byte bytesread = 0;
  byte tempbyte = 0;

  if(Serial.available() > 0) {
    if((val = Serial.read()) == 2) {
      // check for header 
      bytesread = 0; 
      while (bytesread < 12) {
        // read 10 digit code + 2 digit checksum
        if( Serial.available() > 0) {
          val = Serial.read();
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {
            // if header or stop bytes before the 10 digit reading
            break;
            // stop reading
          }
          // Do Ascii/Hex conversion:
          if ((val >= '0') && (val <= '9')) {
            val = val - '0';
          } else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }
          // Every two hex-digits, add byte to code:
          if (bytesread & 1 == 1) {
            // make some space for this hex-digit by
            // shifting the previous hex-digit with 4 bits to the left:
            code[bytesread >> 1] = (val | (tempbyte << 4));
            if (bytesread >> 1 != 5) {
              // If we're at the checksum byte,
              checksum ^= code[bytesread >> 1];
              // Calculate the checksum... (XOR)
            };
          } else {
            tempbyte = val;
            // Store the first hex digit first...
          };
          bytesread++;
          // ready to read next digit
        }
      }
      // Output to Serial:
      if (bytesread == 12) {
        // removed code for clarity
        LCD.print("Check:");
        LCD.print(code[5], HEX);
        LCD.print(code[5] == checksum ? "-passed" : "-error");
      }
      bytesread = 0;
    }
  }
}

My Java/Android port is listening over a BluetoothSocket. I'm using the code from BlueTerm as the base, this code goes in the ConnectedThread. Apologies for all silly comments, but I'm still learning Java).

//assume you have checksum as int and code as int array. it will overflow if bytes are used like above example
public void run() {
  Log.d(TAG, "BEGIN mConnectedThread");
  byte[] buffer = new byte[1024];
  int bytes;
  // Keep listening to the InputStream while connected
  while (true) {
    Log.d(TAG, "Running");
    try {
      // Read from the InputStream
      bytes = mmInStream.read(buffer);
      for (int i = 0; i < bytes; i++) {
        Log.d(TAG, "Reading: " + i + " of " + bytes + " from input stream");
        byte b = buffer[i];
        try {
          if(bytesread >= 0) {
            //just printing ASCII
            char printableB = (char) b;
            if (b < 32 || b > 126) printableB = ' ';
            Log.d(TAG, "'" + Character.toString(printableB) + "' (" + Integer.toString(b) + ")");
            if((b == 0x0D)||(b == 0x0A)||(b == 0x03)||(b == 0x02)) {
              // if header or stop bytes before the 10 digit reading
              Log.e(TAG, i + " Unexpected header while processing character " + Integer.toString(b));
            } else {
              // Do ASCII/Hex conversion
              if ((b >= '0') && (b <= '9')) {
                b = (byte) (b - '0');
              } else if ((b >= 'A') && (b <= 'F')) {
                b = (byte) (10 + b - 'A');
              }
              if ((bytesread & 1) == 1) {
                //if isOdd(bytesread)
              // make some space for this hex-digit by shifting the previous hex-digit with 4 bits to the left:
              code[bytesread >> 1] = (b | (tempbyte << 4));
              if (bytesread >> 1 != 5) {
                // If we're not at the checksum byte,
                checksum ^= code[bytesread >> 1];
                // Calculate the checksum... (XOR)
              }
            } else {
              // Store the first hex digit first
              tempbyte = b; 
            }
          }
          bytesread++;
        } else if(b == 2) {
          bytesread = 0;
          Log.d(TAG, "Header found!");
        }
        if(bytesread == 12) {
          String check = (code[5] == checksum ? "-passed" : "-error");
          String r = "";
          for(int j = 0; j < 5; j++){
            r += Integer.toString(code[i]);
          }
          Log.d(TAG, "Check:" + Integer.toString(code[5]) + check);
          init();
        } else if(bytesread > 12){
          Log.e(TAG, "Too many bytes!");
        }
      } catch (Exception e) {
        Log.e(TAG, i + " Exception while processing character " + Integer.toString(b), e);
      }
    }
    String a = buffer.toString();
    a = "";
  } catch (IOException e) {
    Log.e(TAG, "disconnected", e);
    connectionLost();
    break;
  }
}
Log.i(TAG, "END mConnectedThread");
}