Guest User

RC522 ISO15693 Dirty test sketch

a guest
Feb 1st, 2020
62
65 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include<MFRC522.h>
  2. #include<SPI.h>
  3.  
  4. MFRC522 mfrc522(3, 2);
  5.  
  6. byte txBuffer [384];
  7. int txlen;
  8.  
  9. byte rxBuffer [896];
  10.  
  11. byte dataBuffer [12];
  12.  
  13. const byte cmd [5] = {0x26, 0x01, 0x00, 0xF6, 0x0A};
  14. //Flags 0   0   1   0   0   1   1   0
  15. //      RFU Opt Nb  AFI PE  In  DR  Sc
  16. //RFU= 0 : RFU bits only deserves zeroes.
  17. //Opt= 0 : Not needed
  18. //Nb = 1 : One time slot (Not anticollision-friendly).
  19. //AFI= 0 : Tags responds no matter their AFI
  20. //PE = 0 : No protocol extension
  21. //In = 1 : Inventory Flag is set
  22. //Dr = 1 : High data rate.
  23. //Sc = 0 : One Subcarrier
  24. //
  25. //Command : 0x01 (INVENTORY)
  26. //
  27. //Parameter : 0x00 (Mask length = 0, Any tag should respond immediately.)
  28. //
  29. //CRC 0xF6 0x0A
  30.  
  31. bool generateRXBuffer(byte buf [], int len)
  32. {
  33.   for(int i=0; i<len; i++)
  34.   {
  35.     buf[i] = 0xF6;//READ TestADCReg's address (digitized complex baseband signal)
  36.   }
  37.   buf[len - 1] = 0x00;//End by zero to end the transmission
  38.   return 1;
  39. }
  40.  
  41. void transmitBuffer(byte buffer [], int len)//Transfer a len bytes buffer with the RC522 at 231 kSa/s
  42. {
  43.   noInterrupts();
  44.   SPI.setClockDivider(SPI_CLOCK_DIV8);
  45.   digitalWrite(3, LOW);
  46.   SPI.transfer(buffer, len);
  47.   digitalWrite(3, HIGH);
  48.   SPI.setClockDivider(SPI_CLOCK_DIV4);
  49.   interrupts();
  50. }
  51.  
  52. int getBitPair(byte buf [], int idx)//Get a bit pair from the tx command buffer (idx is the BIT PAIR's index)
  53. {
  54.   return (buf[idx >> 2] >> (2 * (idx & 0b11))) & 0b11;
  55. }
  56.  
  57. void addETUs(byte buf [], int &idx, int nbETUs)//Add a delay of nbETUs in the buffer at index idx
  58. {
  59.   float nbSamples;
  60.   int nbSamplesInteger;
  61.   nbSamples = nbETUs * 2.18;//Calculate a number of samples
  62.   nbSamplesInteger = roundf(nbSamples);//Round to the nearest integer
  63.   for(int cnt = 0; cnt < nbSamplesInteger; cnt++)//Add 0x00s (no carrier invert = carrier on)
  64.   {
  65.     buf[idx] = 0x00;
  66.     idx++;
  67.   }
  68. }
  69.  
  70. void addPause(byte buf [], int &idx)//Add a pause at index idx in the transmit buffer
  71. {
  72.   buf[idx] = 0x08;//Add two 0x08s (carrier invert = carrier off)
  73.   buf[idx + 1] = 0x08;
  74.   idx += 2;
  75. }
  76.  
  77. //SAMPLE RATE 231 kSa/s
  78. //1 ETU = 9.44us = 2.18 samples (not official)
  79. int generateTXBuffer(byte cmd[], int cmdLen, byte buf[], int buflen)//Generate a transmit buffer from the command buffer
  80. {
  81.   if(2.18 * (8 * cmdLen + 12) + 1 < buflen)
  82.   {
  83.     int numBitPairs = 4 * cmdLen;
  84.     int idx = 0;//Reset idx
  85.     buf[0] = 0x24;//Write to TxModeReg register
  86.     idx = 1;
  87.     addPause(buf, idx);//Add the start of frame
  88.     addETUs(buf, idx, 4);
  89.     addPause(buf, idx);
  90.     addETUs(buf, idx, 3 + (2 * getBitPair(cmd, 0)));//Add the delay between the start of fraame's pulse and the first bit pair's pulse
  91.     addPause(buf, idx);
  92.     for(int bitPairIdx = 1; bitPairIdx < numBitPairs; bitPairIdx++)//For each 2-bit pair
  93.     {
  94.       addETUs(buf, idx, 7 + (2 * (getBitPair(cmd, bitPairIdx) - getBitPair(cmd, bitPairIdx - 1))));//Add the proper delay according to the current and previous bit pait
  95.       addPause(buf, idx);//And finally add a pause
  96.     }
  97.     addETUs(buf, idx, 8 - (2 * getBitPair(cmd, numBitPairs   - 1)));//Add the delay between the last bit's pulse and the end of frame's pause
  98.     addPause(buf, idx);//Add a pause
  99.     addETUs(buf, idx, 1);//Turn the carrier back on
  100.     return idx;
  101.   }
  102. }
  103.  
  104. void comp2amp(byte buf [], int len)//Converts I/Q samples to amplitudes
  105. {
  106.   int i;
  107.   int q;
  108.   for(int idx = 0; idx < len; idx++)//Read the entire buffer
  109.   {
  110.     i = (buf[idx] >> 4) & 0b1111;//Get the Inphase & Quadrature samples
  111.     q = buf[idx] & 0b1111;
  112.     if(i > 7)//Convert them from 4 bit two's complement signed to signed ints.
  113.       i -= 16;
  114.     if(q > 7)
  115.       q -= 16;
  116.     buf[idx] = sqrt((i * i) + (q * q));//Calculate the resulting amplitude.
  117.   }
  118. }
  119.  
  120. void discretize(byte buf [], int len, int discrPeriod)//Discretize the buffer by comparing the signal averaged over 3 samples with itself averaged over discrPeriod samples
  121. {
  122.   int rollingAverage = 0;//Reset the rolling average
  123.   int ampFactor = discrPeriod / 3;//Amp factor to get the 3-samples averaged signal at the same level as the discrPeriod averaged signal.
  124.   bool discretizedSample;//To hold the disscretized sample
  125.   for(int idx = 0; idx < discrPeriod; idx++)//Init the rolling average as the sum of the first discrPeriod samples
  126.   {
  127.     rollingAverage += buf[idx];
  128.   }
  129.   for(int idx = 0; idx < len; idx++)//For each of the samples
  130.   {
  131.     discretizedSample = (buf[idx] + buf[idx + 1] + buf[idx + 2]) * ampFactor > rollingAverage;//The sample is discretized as one if the amplitude value multiplied by the amp factor exceeeds the rolling average
  132.     if(idx < len - discrPeriod)//If we can still shift our rolling average to the right
  133.     {
  134.       rollingAverage -= buf[idx];//We shift it
  135.       rollingAverage += buf[idx + discrPeriod];
  136.     }
  137.     buf[idx] = discretizedSample;//We overwrite the sample with the discretized one
  138.   }
  139. }
  140.  
  141. bool lowToHigh(byte buf [], int idx)//Returns true if transition from zero to one wetween indexes idx and idx+1
  142. {
  143.   return buf[idx] == 0 && buf[idx + 1] == 1;
  144. }
  145.  
  146. bool highToLow(byte buf [], int idx)//Returns true if transition from one to zero between indexes idx and idx+1
  147. {
  148.   return buf[idx] == 1 && buf[idx + 1] == 0;
  149. }
  150.  
  151. //I have decided that 1 ETU (Elementary Timing Unit) = 9.44 microseconds = 2.18 samples at 231kSa/s
  152. bool detectPattern(byte buf [], int bufIdx, bool pattern [], int patternLen)//Search for a pattern from an index. First element starts at idx+1ETU, next elements every 2 ETUs
  153. {
  154.   int nbDetected = 0;
  155.   for(int patternIdx = 0; patternIdx < patternLen; patternIdx++)
  156.   {
  157.     if(buf[roundf(bufIdx + (2 * patternIdx + 1) * 2.18)] == pattern[patternIdx])//If the element at the aforementioned position matvhes the pattern
  158.       nbDetected++;//We increment a counter
  159.   }
  160.   return nbDetected == patternLen;//We return whether the counter matches the length of the pattern
  161. }
  162.  
  163. bool detectSF(byte buf [], int len, int &SFidx)//Returns true if an start of frame was detected. If yes, SFidx is set to the index where the LOW TO HIGH transition of the start of frame is.
  164. {
  165.   const bool SFPattern [5] = {1, 1, 1, 0, 1};
  166.   bool detected = false;
  167.   int idx = 0;
  168.   do//Read the buffer until we haven't detected anything or reached the end of the buffer
  169.   {
  170.     if(lowToHigh(buf, idx))//If we found a transition
  171.     {
  172.       if(detectPattern(buf, idx, SFPattern, 5))//If we have a proper pattern.
  173.       {
  174.         detected = true;//We mark as detected
  175.         SFidx = idx;//We set SFidx to the transition's index
  176.       }
  177.     }
  178.     idx++;
  179.   }
  180.   while(!detected  && idx < len);
  181.   return detected;//Return wether we've detected a start of frame or not
  182. }
  183.  
  184. bool detectEF(byte buf [], int len, int &EFidx)//Returns true if an end of frame was detected. If yes, EFidx is set to the index where the HIGH TO LOW transition of the end of fraame is.
  185. {
  186.   const bool EFPattern [5] = {0, 1, 1, 1, 0};
  187.   bool detected = false;
  188.   int idx = 0;
  189.   do
  190.   {
  191.     if(highToLow(buf, idx))
  192.     {
  193.       if(detectPattern(buf, idx, EFPattern, 5))
  194.       {
  195.         detected = true;
  196.         EFidx = idx;
  197.       }
  198.     }
  199.     idx++;
  200.   }
  201.   while(!detected  && idx < len);
  202.   return detected;
  203. }
  204.  
  205. void setBit(byte buf [], int bitIdx, bool bitValue)//Set BIT at index bitIdx if bitValue equals one. THIS CANNOT SET BITS TO ZERO! BUFFER MUST BE CLEARED FIRST!
  206. {
  207.   buf[bitIdx >> 3] |= bitValue << (bitIdx & 0b111);
  208. }
  209.  
  210. bool searchForTransition(byte buf [], int len, int &idx, bool &bitValue)//Search for a low to high or high to low transition in a discretized len bytes buffer.
  211. {
  212.   bool transitionDetected = false;
  213.   do//Read the buffer while we haven't detected any transition AND we haven't reached the end of the buffer
  214.   {
  215.     if(lowToHigh(buf, idx))//If we have a LTH transition
  216.     {
  217.       transitionDetected = true;//We note that a transition was detected
  218.       bitValue = true;//A low to high transition is a logical one
  219.     }
  220.     else if(highToLow(buf, idx))//If we have a HTL transition
  221.     {
  222.       transitionDetected = true;//We note that a transition was detected
  223.       bitValue = false;//A high to low transitio is a logical zero.
  224.     }
  225.     else//If we have'nt found anything we go to the next sample.
  226.       idx++;
  227.   }
  228.   while(!transitionDetected && idx < len);
  229.   return transitionDetected;//Return whether a transiton was detected or not.
  230. }
  231.  
  232. int decodeBuffer(byte rxBuffer [], int rxlen, byte dataBuffer [], int nbDataBytes)//Decode a rxlen bytes discretized buffer into a nbDataBytes data buffer
  233. {
  234.   int bufIdx = 0;//Discretized buffer index
  235.   int dataIdx = 0;//Data buffer index
  236.   int SFidx;//Start of frme index
  237.   int EFidx;//End of frame index
  238.   bool transitionDetected = true;//True if we got a transition last time we searched for one
  239.   bool bitValue;//Value of the bit being decoded
  240.   int nbDataBits = 8 * nbDataBytes;//Calculate the max number of bits
  241.   for(int i = 0; i < nbDataBytes; i++)//Clear the buffer
  242.     dataBuffer[i] = 0;
  243.   if(detectSF(rxBuffer, rxlen, SFidx))//If we found a start of frame
  244.   {
  245.     if(detectEF(rxBuffer, rxlen, EFidx))//And an end of frame
  246.     {
  247.       bufIdx = SFidx + 24;//We start 24 samples after the start of frame
  248.       while(bufIdx < EFidx - 4 && dataIdx < nbDataBits && transitionDetected)//We continue scanning as long as we haven't reached the end of frame AND we haven't filled the buffer AND we got a transition.
  249.       {
  250.         transitionDetected = searchForTransition(rxBuffer, rxlen, bufIdx, bitValue);//We search for the next high to low or low to high transition
  251.         if(transitionDetected)//If we got one
  252.         {
  253.           setBit(dataBuffer, dataIdx, bitValue);//We set the corresponding bit in the data buffer
  254.           dataIdx++;//We go to the next BIT in the data buffer
  255.           bufIdx += 7;//We go 7 samples further to get to the first part of the next bit.
  256.         }
  257.       }
  258.     }
  259.   }
  260.   if(!transitionDetected || dataIdx > nbDataBits || dataIdx % 8 != 0)//If we ran out of transitions OR we reached the end of the data buffer OR we didn't receive an integer multiple of 8 bits
  261.     return 0;//We return 0 because the result is invalid
  262.   else
  263.     return dataIdx / 8;//Else we return the number of data bits we got divided by 8.
  264. }
  265.  
  266. int calculateCRC(byte data [], int len)//Returns the ISO15693 CRC over a len bytes buffer.
  267. {
  268.   const unsigned int POLYNOMIAL = 0x8408;//Define a polynomial
  269.   unsigned int current_crc_value = 0xFFFF;//Preset the LFSR
  270.   for (int i = 0; i < len; i++)//For each byte
  271.   {
  272.     current_crc_value = current_crc_value ^ ((unsigned int)data[i]);//Xor LFSR with data
  273.     for (int j = 0; j < 8; j++)
  274.     {
  275.       if (current_crc_value & 0x0001)//If LSB = 1
  276.       {
  277.         current_crc_value = (current_crc_value >> 1) ^ POLYNOMIAL;//Shift to the right with feedback thru the polynomial
  278.       }
  279.       else
  280.       {
  281.         current_crc_value = (current_crc_value >> 1);//Else just shift to the right
  282.       }
  283.     }
  284.   }
  285.   return current_crc_value;
  286. }
  287.  
  288. bool verifyCRC(byte data [], int len)//Returns true if the two last bytes of the buffer are a valid CRC.
  289. {
  290.   return calculateCRC(data, len) == 0xF0B8;
  291. }
  292.  
  293. void appendCRC(byte data [], int len)//Calculate the ISO15693 CRC oven len-2 bytes and append it as the two last bytes of the buffer.
  294. {
  295.   if(len > 2)
  296.   {
  297.     unsigned int calculatedCRC = calculateCRC(data, len - 2);
  298.     data[len - 2] = ~calculatedCRC & 0xFF;
  299.     data[len - 1] = ~(calculatedCRC >> 8) & 0xFF;
  300.   }
  301. }
  302.  
  303. void setup() {
  304.  
  305.   Serial.begin(115200);//Init the serial port
  306.  
  307.   SPI.begin();//Init the SPI
  308.   mfrc522.PCD_Init();//Init the reader
  309. }
  310.  
  311. void loop() {
  312.   txlen = generateTXBuffer(cmd, sizeof(cmd), txBuffer, sizeof(txBuffer));//Fill the transmit buffer
  313.   generateRXBuffer(rxBuffer, 896);//Prepare the receive buffer
  314.   transmitBuffer(txBuffer, txlen);//Transmit the TX buffer at 231kSa/s to modulate the carrier
  315.   mfrc522.PCD_WriteRegister(MFRC522::RFCfgReg, 0x70);//Set the sensitivity to the maximum
  316.   mfrc522.PCD_WriteRegister(MFRC522::CommandReg, MFRC522::PCD_Receive);//Enable the RC522's receiver
  317.   transmitBuffer(rxBuffer, 896);//Transmit the RX buffer at 231kSa/s to get the Inphase/Quadrature samples
  318.   comp2amp(rxBuffer, 896);//Convert the I/Q samples to amplitude
  319.   discretize(rxBuffer, 896, 24);//Discretize the signal by comparing it when averaged over 3 samples vss averaged over 24 samples.
  320.   if(decodeBuffer(rxBuffer, 896, dataBuffer, 12) == 12 && verifyCRC(dataBuffer, 12))//If we got a 12-byte buffer and a proper CRC
  321.   {
  322.     Serial.print("UID: ");//Print the card's UID. The UID is from byte 2 to 9 and has to be read in reverse.
  323.     for(int i = 9; i > 1; i--)
  324.     {
  325.       if(dataBuffer[i] < 16)
  326.         Serial.print('0');
  327.       Serial.print(dataBuffer[i], HEX);
  328.       Serial.print(' ');
  329.     }
  330.     Serial.println();
  331.     delay(1000);//Wait
  332.   }
  333. }
RAW Paste Data