gobot.io/x/gobot/v2@v2.1.0/drivers/common/mfrc522/mfrc522_pcd.go (about)

     1  package mfrc522
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  )
     7  
     8  // PCD: proximity coupling device (reader unit)
     9  // PICC: proximity integrated circuit card (the card or chip)
    10  
    11  const (
    12  	pcdDebug = false
    13  	initTime = 50 * time.Millisecond
    14  	// at least 5 ms are needed after switch on, see AN10834
    15  	antennaOnTime = 10 * time.Millisecond
    16  )
    17  
    18  type busConnection interface {
    19  	ReadByteData(reg byte) (byte, error)
    20  	WriteByteData(reg byte, data byte) error
    21  }
    22  
    23  var versions = map[uint8]string{0x12: "Counterfeit", 0x88: "FM17522", 0x89: "FM17522E",
    24  	0x90: "MFRC522 0.0", 0x91: "MFRC522 1.0", 0x92: "MFRC522 2.0", 0xB2: "FM17522 1"}
    25  
    26  // MFRC522Common is the Gobot Driver for MFRC522 RFID.
    27  // datasheet:
    28  // https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
    29  //
    30  // reference implementations:
    31  // * https://github.com/OSSLibraries/ArduinoRegMFRC522v2
    32  // * https://github.com/jdevelop/golang-rpi-extras
    33  // * https://github.com/pimylifeup/MFRC522-python
    34  // * https://periph.io/device/mf-rc522/
    35  type MFRC522Common struct {
    36  	connection      busConnection
    37  	firstCardAccess bool
    38  }
    39  
    40  // NewMFRC522Common creates a new Gobot Driver for MFRC522 RFID with specified bus connection
    41  // The device supports SPI, I2C and UART (not implemented yet at gobot system level).
    42  //
    43  // Params:
    44  //      c BusConnection - the bus connection to use with this driver
    45  func NewMFRC522Common() *MFRC522Common {
    46  	d := &MFRC522Common{}
    47  	return d
    48  }
    49  
    50  // Initialize sets the connection and initializes the driver.
    51  func (d *MFRC522Common) Initialize(c busConnection) error {
    52  	d.connection = c
    53  
    54  	if err := d.softReset(); err != nil {
    55  		return err
    56  	}
    57  
    58  	initSequence := [][]byte{
    59  		{regTxMode, rxtxModeRegReset},
    60  		{regRxMode, rxtxModeRegReset},
    61  		{regModWidth, modWidthRegReset},
    62  		{regTMode, tModeRegTAutoBit | 0x0F}, // timer starts automatically at the end of the transmission
    63  		{regTPrescaler, 0xFF},
    64  		{regTReloadL, tReloadRegValue25ms & 0xFF},
    65  		{regTReloadH, tReloadRegValue25ms >> 8},
    66  		{regTxASK, txASKRegForce100ASKBit},
    67  		{regMode, modeRegTxWaitRFBit | modeRegPolMFinBit | modeRegCRCPreset6363},
    68  	}
    69  	for _, init := range initSequence {
    70  		d.writeByteData(init[0], init[1])
    71  	}
    72  
    73  	if err := d.switchAntenna(true); err != nil {
    74  		return err
    75  	}
    76  	if err := d.setAntennaGain(rfcCfgRegRxGain38dB); err != nil {
    77  		return err
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  // PrintReaderVersion gets and prints the reader (pcd) version.
    84  func (d *MFRC522Common) PrintReaderVersion() error {
    85  	version, err := d.getVersion()
    86  	if err != nil {
    87  		return err
    88  	}
    89  	fmt.Printf("PCD version: '%s' (0x%X)\n", versions[version], version)
    90  	return nil
    91  }
    92  
    93  func (d *MFRC522Common) getVersion() (uint8, error) {
    94  	return d.readByteData(regVersion)
    95  }
    96  
    97  func (d *MFRC522Common) switchAntenna(targetState bool) error {
    98  	val, err := d.readByteData(regTxControl)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	maskForOn := uint8(txControlRegTx2RFEn1outputBit | txControlRegTx1RFEn1outputBit)
   103  	currentState := val&maskForOn == maskForOn
   104  
   105  	if targetState == currentState {
   106  		return nil
   107  	}
   108  
   109  	if targetState {
   110  		val = val | maskForOn
   111  	} else {
   112  		val = val & ^maskForOn
   113  	}
   114  
   115  	if err := d.writeByteData(regTxControl, val); err != nil {
   116  		return err
   117  	}
   118  
   119  	if targetState {
   120  		time.Sleep(antennaOnTime)
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  func (d *MFRC522Common) setAntennaGain(val uint8) error {
   127  	return d.writeByteData(regRFCfg, val)
   128  }
   129  
   130  func (d *MFRC522Common) softReset() error {
   131  	if err := d.writeByteData(regCommand, commandRegSoftReset); err != nil {
   132  		return err
   133  	}
   134  
   135  	// The datasheet does not mention how long the SoftReset command takes to complete. According to section 8.8.2 of the
   136  	// datasheet the oscillator start-up time is the start up time of the crystal + 37.74 us.
   137  	// TODO: this can be done better by wait until the power down bit is cleared
   138  	time.Sleep(initTime)
   139  	val, err := d.readByteData(regCommand)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	if val&commandRegPowerDownBit > 1 {
   145  		return fmt.Errorf("initialization takes longer than %s", initTime)
   146  	}
   147  	return nil
   148  }
   149  
   150  func (d *MFRC522Common) stopCrypto1() error {
   151  	return d.clearRegisterBitMask(regStatus2, status2RegMFCrypto1OnBit)
   152  }
   153  
   154  func (d *MFRC522Common) communicateWithPICC(command uint8, sendData []byte, backData []byte, txLastBits uint8,
   155  	checkCRC bool) error {
   156  	irqEn := 0x00
   157  	waitIRq := uint8(0x00)
   158  	switch command {
   159  	case commandRegMFAuthent:
   160  		irqEn = comIEnRegIdleIEnBit | comIEnRegErrIEnBit
   161  		waitIRq = comIrqRegIdleIRqBit
   162  	case commandRegTransceive:
   163  		irqEn = comIEnRegTimerIEnBit | comIEnRegErrIEnBit | comIEnRegLoAlertIEnBit
   164  		irqEn = irqEn | comIEnRegIdleIEnBit | comIEnRegRxIEnBit | comIEnRegTxIEnBit
   165  		waitIRq = uint8(comIrqRegIdleIRqBit | comIrqRegRxIRqBit)
   166  	}
   167  
   168  	// TODO: this is not used at the moment (propagation of IRQ pin)
   169  	if err := d.writeByteData(regComIEn, uint8(irqEn|comIEnRegIRqInv)); err != nil {
   170  		return err
   171  	}
   172  	if err := d.writeByteData(regComIrq, comIrqRegClearAll); err != nil {
   173  		return err
   174  	}
   175  	if err := d.writeByteData(regFIFOLevel, fifoLevelRegFlushBufferBit); err != nil {
   176  		return err
   177  	}
   178  	// stop any active command
   179  	if err := d.writeByteData(regCommand, commandRegIdle); err != nil {
   180  		return err
   181  	}
   182  	// prepare and start communication
   183  	if err := d.writeFifo(sendData); err != nil {
   184  		return err
   185  	}
   186  	if err := d.writeByteData(regBitFraming, txLastBits); err != nil {
   187  		return err
   188  	}
   189  	if err := d.writeByteData(regCommand, command); err != nil {
   190  		return err
   191  	}
   192  	if command == commandRegTransceive {
   193  		if err := d.setRegisterBitMask(regBitFraming, bitFramingRegStartSendBit); err != nil {
   194  			return err
   195  		}
   196  	}
   197  
   198  	// Wait for the command to complete. On initialization the TAuto flag in TMode register is set. This means the timer
   199  	// automatically starts when the PCD stops transmitting.
   200  	const maxTries = 5
   201  	i := 0
   202  	for ; i < maxTries; i++ {
   203  		irqs, err := d.readByteData(regComIrq)
   204  		if err != nil {
   205  			return err
   206  		}
   207  		if irqs&waitIRq > 0 {
   208  			// One of the interrupts that signal success has been set.
   209  			break
   210  		}
   211  		if irqs&comIrqRegTimerIRqBit == comIrqRegTimerIRqBit {
   212  			return fmt.Errorf("the timer interrupt occurred")
   213  		}
   214  		time.Sleep(time.Millisecond)
   215  	}
   216  
   217  	if err := d.clearRegisterBitMask(regBitFraming, bitFramingRegStartSendBit); err != nil {
   218  		return err
   219  	}
   220  
   221  	if i >= maxTries {
   222  		return fmt.Errorf("no data available after %d tries", maxTries)
   223  	}
   224  
   225  	errorRegValue, err := d.readByteData(regError)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	// stop if any errors except collisions were detected.
   230  	if err := d.getFirstError(errorRegValue &^ errorRegCollErrBit); err != nil {
   231  		return err
   232  	}
   233  
   234  	backLen := len(backData)
   235  	var rxLastBits uint8
   236  	if backLen > 0 {
   237  		rxLastBits, err = d.readFifo(backData)
   238  		if err != nil {
   239  			return err
   240  		}
   241  		if pcdDebug {
   242  			fmt.Printf("rxLastBits: 0x%02x\n", rxLastBits)
   243  		}
   244  	}
   245  
   246  	if err := d.getFirstError(errorRegValue & errorRegCollErrBit); err != nil {
   247  		return err
   248  	}
   249  
   250  	if backLen > 2 && checkCRC {
   251  		// the last 2 bytes of data contains the CRC
   252  		if backLen == 3 && rxLastBits == 0x04 {
   253  			return fmt.Errorf("CRC: MIFARE Classic NAK is not OK")
   254  		}
   255  		if backLen < 4 || backLen == 4 && rxLastBits != 0 {
   256  			return fmt.Errorf("CRC: at least the 2 byte CRCRegA value and all 8 bits of the last byte must be received")
   257  		}
   258  
   259  		crcResult := []byte{0x00, 0x00}
   260  		crcData := backData[:backLen-2]
   261  		dataCrc := backData[backLen-2:]
   262  		err := d.calculateCRC(crcData, crcResult)
   263  		if err != nil {
   264  			return err
   265  		}
   266  		if dataCrc[0] != crcResult[0] || dataCrc[1] != crcResult[1] {
   267  			return fmt.Errorf("CRC: values not match %v - %v", crcResult, dataCrc)
   268  		}
   269  	}
   270  
   271  	return nil
   272  }
   273  
   274  // 16 bit CRC will be calculated for the given data
   275  func (d *MFRC522Common) calculateCRC(data []byte, result []byte) error {
   276  	// Stop any active command.
   277  	if err := d.writeByteData(regCommand, commandRegIdle); err != nil {
   278  		return err
   279  	}
   280  	if err := d.writeByteData(regDivIrq, divIrqRegCRCIRqBit); err != nil {
   281  		return err
   282  	}
   283  	if err := d.writeByteData(regFIFOLevel, fifoLevelRegFlushBufferBit); err != nil {
   284  		return err
   285  	}
   286  	if err := d.writeFifo(data); err != nil {
   287  		return err
   288  	}
   289  	if err := d.writeByteData(regCommand, commandRegCalcCRC); err != nil {
   290  		return err
   291  	}
   292  
   293  	const maxTries = 3
   294  	for i := 0; i < maxTries; i++ {
   295  		irqs, err := d.readByteData(regDivIrq)
   296  		if err != nil {
   297  			return err
   298  		}
   299  		if irqs&divIrqRegCRCIRqBit == divIrqRegCRCIRqBit {
   300  			if err := d.writeByteData(regCommand, commandRegIdle); err != nil {
   301  				return err
   302  			}
   303  			result[0], err = d.readByteData(regCRCResultL)
   304  			if err != nil {
   305  				return err
   306  			}
   307  			result[1], err = d.readByteData(regCRCResultH)
   308  			if err != nil {
   309  				return err
   310  			}
   311  			return nil
   312  		}
   313  		time.Sleep(time.Millisecond)
   314  	}
   315  
   316  	return fmt.Errorf("no CRC available after %d tries", maxTries)
   317  }
   318  
   319  func (d *MFRC522Common) writeFifo(fifoData []byte) error {
   320  	// the register command is always the same, the pointer in FIFO is incremented automatically after each write
   321  	for _, b := range fifoData {
   322  		if err := d.writeByteData(regFIFOData, b); err != nil {
   323  			return err
   324  		}
   325  	}
   326  	return nil
   327  }
   328  
   329  func (d *MFRC522Common) readFifo(backData []byte) (uint8, error) {
   330  	n, err := d.readByteData(regFIFOLevel) // Number of bytes in the FIFO
   331  	if err != nil {
   332  		return 0, err
   333  	}
   334  	if n > uint8(len(backData)) {
   335  		return 0, fmt.Errorf("more data in FIFO (%d) than expected (%d)", n, len(backData))
   336  	}
   337  
   338  	if n < uint8(len(backData)) {
   339  		return 0, fmt.Errorf("less data in FIFO (%d) than expected (%d)", n, len(backData))
   340  	}
   341  
   342  	// the register command is always the same, the pointer in FIFO is incremented automatically after each read
   343  	for i := 0; i < int(n); i++ {
   344  		byteVal, err := d.readByteData(regFIFOData)
   345  		if err != nil {
   346  			return 0, err
   347  		}
   348  		backData[i] = byteVal
   349  	}
   350  
   351  	rxLastBits, err := d.readByteData(regControl)
   352  	if err != nil {
   353  		return 0, err
   354  	}
   355  	return rxLastBits & controlRegRxLastBits, nil
   356  }
   357  
   358  func (d *MFRC522Common) getFirstError(errorRegValue uint8) error {
   359  	if errorRegValue == 0 {
   360  		return nil
   361  	}
   362  
   363  	if errorRegValue&errorRegProtocolErrBit == errorRegProtocolErrBit {
   364  		return fmt.Errorf("a protocol error occurred")
   365  	}
   366  	if errorRegValue&errorRegParityErrBit == errorRegParityErrBit {
   367  		return fmt.Errorf("a parity error occurred")
   368  	}
   369  	if errorRegValue&errorRegCRCErrBit == errorRegCRCErrBit {
   370  		return fmt.Errorf("a CRC error occurred")
   371  	}
   372  	if errorRegValue&errorRegCollErrBit == errorRegCollErrBit {
   373  		return fmt.Errorf("a collision error occurred")
   374  	}
   375  	if errorRegValue&errorRegBufferOvflBit == errorRegBufferOvflBit {
   376  		return fmt.Errorf("a buffer overflow error occurred")
   377  	}
   378  	if errorRegValue&errorRegTempErrBit == errorRegTempErrBit {
   379  		return fmt.Errorf("a temperature error occurred")
   380  	}
   381  	if errorRegValue&errorRegWrErrBit == errorRegWrErrBit {
   382  		return fmt.Errorf("a temperature error occurred")
   383  	}
   384  	return fmt.Errorf("an unknown error occurred")
   385  }