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 }