Initial support for the Mifare MFRC522 RFID Reader (#220)

Signed-off-by: Eugene Dzhurinsky <jdevelop@gmail.com>
pull/1/head
Eugene 8 years ago committed by M-A
parent 1f328237e7
commit ddf7ca2519

@ -27,6 +27,7 @@
# Please keep the list sorted.
Cássio Botaro <cassiobotaro@gmail.com>
Eugene Dzhurynsky <jdevelop@gmail.com>
Hidetoshi Shimokawa <smkwhdts@gmail.com>
Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com>

@ -0,0 +1,30 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package commands
// Operation constants
const (
PCD_IDLE = 0x00
PCD_AUTHENT = 0x0E
PCD_RECEIVE = 0x08
PCD_TRANSMIT = 0x04
PCD_TRANSCEIVE = 0x0C
PCD_RESETPHASE = 0x0F
PCD_CALCCRC = 0x03
PICC_REQIDL = 0x26
PICC_REQALL = 0x52
PICC_ANTICOLL = 0x93
PICC_SElECTTAG = 0x93
PICC_AUTHENT1A = 0x60
PICC_AUTHENT1B = 0x61
PICC_READ = 0x30
PICC_WRITE = 0xA0
PICC_DECREMENT = 0xC0
PICC_INCREMENT = 0xC1
PICC_RESTORE = 0xC2
PICC_TRANSFER = 0xB0
PICC_HALT = 0x50
)

@ -0,0 +1,61 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package commands
// Command register constants
const (
CommandReg = 0x01
CommIEnReg = 0x02
DivlEnReg = 0x03
CommIrqReg = 0x04
DivIrqReg = 0x05
ErrorReg = 0x06
Status1Reg = 0x07
Status2Reg = 0x08
FIFODataReg = 0x09
FIFOLevelReg = 0x0A
WaterLevelReg = 0x0B
ControlReg = 0x0C
BitFramingReg = 0x0D
CollReg = 0x0E
ModeReg = 0x11
TxModeReg = 0x12
RxModeReg = 0x13
TxControlReg = 0x14
TxAutoReg = 0x15
TxSelReg = 0x16
RxSelReg = 0x17
RxThresholdReg = 0x18
DemodReg = 0x19
MifareReg = 0x1C
SerialSpeedReg = 0x1F
CRCResultRegM = 0x21
CRCResultRegL = 0x22
ModWidthReg = 0x24
RFCfgReg = 0x26
GsNReg = 0x27
CWGsPReg = 0x28
ModGsPReg = 0x29
TModeReg = 0x2A
TPrescalerReg = 0x2B
TReloadRegH = 0x2C
TReloadRegL = 0x2D
TCounterValueRegH = 0x2E
TCounterValueRegL = 0x2F
TestSel1Reg = 0x31
TestSel2Reg = 0x32
TestPinEnReg = 0x33
TestPinValueReg = 0x34
TestBusReg = 0x35
AutoTestReg = 0x36
VersionReg = 0x37
AnalogTestReg = 0x38
TestDAC1Reg = 0x39
TestDAC2Reg = 0x3A
TestADCReg = 0x3B
)

@ -0,0 +1,757 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package mfrc522 controls a Mifare RFID card reader.
//
// Datasheet
//
// https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
package mfrc522
import (
"fmt"
"time"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/spi"
"periph.io/x/periph/experimental/devices/mfrc522/commands"
)
// BlockAccess defines the block access bits.
type BlockAccess byte
// SectorTrailerAccess defines the sector trailing block access bits.
type SectorTrailerAccess byte
// Access bits.
const (
AnyKeyRWID BlockAccess = iota
RAB_WN_IN_DN = 0x02 // Read (A|B), Write (None), Increment (None), Decrement(None)
RAB_WB_IN_DN = 0x04
RAB_WB_IB_DAB = 0x06
RAB_WN_IN_DAB = 0x01
RB_WB_IN_DN = 0x03
RB_WN_IN_DN = 0x05
RN_WN_IN_DN = 0x07
KeyA_RN_WA_BITS_RA_WN_KeyB_RA_WA SectorTrailerAccess = iota
KeyA_RN_WN_BITS_RA_WN_KeyB_RA_WN = 0x02
KeyA_RN_WB_BITS_RAB_WN_KeyB_RN_WB = 0x04
KeyA_RN_WN_BITS_RAB_WN_KeyB_RN_WN = 0x06
KeyA_RN_WA_BITS_RA_WA_KeyB_RA_WA = 0x01
KeyA_RN_WB_BITS_RAB_WB_KeyB_RN_WB = 0x03
KeyA_RN_WN_BITS_RAB_WB_KeyB_RN_WN = 0x05
KeyA_RN_WN_BITS_RAB_WN_KeyB_RN_WN_EXTRA = 0x07
)
// AuthStatus indicates the authentication response, could be one of AuthOk, AuthReadFailure or AuthFailure
type AuthStatus byte
// Card authentication status enum.
const (
AuthOk AuthStatus = iota
AuthReadFailure
AuthFailure
)
// BlocksAccess defines the access structure for first 3 blocks of the sector and the access bits for the
// sector trail.
type BlocksAccess struct {
B0, B1, B2 BlockAccess
B3 SectorTrailerAccess
}
// DefaultKey provides the default bytes for card authentication for method B.
var DefaultKey = []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
// Dev is an handle to an MFRC522 RFID reader.
type Dev struct {
resetPin gpio.PinOut
irqPin gpio.PinIn
operationTimeout time.Duration
spiDev spi.Conn
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// MFRC522 SPI Dev public API
//
///////////////////////////////////////////////////////////////////////////////////////////
// NewSPI creates and initializes the RFID card reader attached to SPI.
//
// spiPort - the SPI device to use.
// resetPin - reset GPIO pin.
// irqPin - irq GPIO pin.
func NewSPI(spiPort spi.Port, resetPin gpio.PinOut, irqPin gpio.PinIn) (*Dev, error) {
if resetPin == nil {
return nil, wrapf("reset pin is not set")
}
if irqPin == nil {
return nil, wrapf("IRQ pin is not set")
}
spiDev, err := spiPort.Connect(10000000, spi.Mode0, 8)
if err != nil {
return nil, err
}
dev := &Dev{
spiDev: spiDev,
operationTimeout: 30 * time.Second,
}
if err := resetPin.Out(gpio.High); err != nil {
return nil, err
}
dev.resetPin = resetPin
if err := irqPin.In(gpio.PullUp, gpio.FallingEdge); err != nil {
return nil, err
}
dev.irqPin = irqPin
if err := dev.Init(); err != nil {
return nil, err
}
return dev, nil
}
// SetOperationtimeout updates the device timeout for card operations.
// Effectively that sets the maximum time the RFID device will wait for IRQ from the proximity card detection.
//
// timeout the duration to wait for IRQ strobe.
func (r *Dev) SetOperationtimeout(timeout time.Duration) {
r.operationTimeout = timeout
}
// Init initializes the RFID chip.
func (r *Dev) Init() error {
if err := r.Reset(); err != nil {
return err
}
if err := r.writeCommandSequence(sequenceCommands.init); err != nil {
return err
}
return r.SetAntenna(true)
}
// Reset resets the RFID chip to initial state.
func (r *Dev) Reset() error {
return r.devWrite(commands.CommandReg, commands.PCD_RESETPHASE)
}
// Halt soft-stops the chip - PowerDown bit set, command IDLE
func (r *Dev) Halt() error {
return r.devWrite(commands.CommandReg, 16)
}
// SetAntenna configures the antenna state, on/off.
func (r *Dev) SetAntenna(state bool) error {
if state {
current, err := r.devRead(commands.TxControlReg)
if err != nil {
return err
}
if current&0x03 != 0 {
return wrapf("can not set the bitmask for antenna")
}
return r.setBitmask(commands.TxControlReg, 0x03)
}
return r.clearBitmask(commands.TxControlReg, 0x03)
}
// CardWrite the low-level interface to write some raw commands to the card.
//
// command - the command register
// data - the data to write out to the card using the authenticated sector.
func (r *Dev) CardWrite(command byte, data []byte) ([]byte, int, error) {
var backData []byte
backLength := -1
irqEn := byte(0x00)
irqWait := byte(0x00)
switch command {
case commands.PCD_AUTHENT:
irqEn = 0x12
irqWait = 0x10
case commands.PCD_TRANSCEIVE:
irqEn = 0x77
irqWait = 0x30
}
r.devWrite(commands.CommIEnReg, irqEn|0x80)
r.clearBitmask(commands.CommIrqReg, 0x80)
r.setBitmask(commands.FIFOLevelReg, 0x80)
r.devWrite(commands.CommandReg, commands.PCD_IDLE)
for _, v := range data {
r.devWrite(commands.FIFODataReg, v)
}
r.devWrite(commands.CommandReg, command)
if command == commands.PCD_TRANSCEIVE {
r.setBitmask(commands.BitFramingReg, 0x80)
}
i := 2000
n := byte(0)
for ; i > 0; i-- {
n, err := r.devRead(commands.CommIrqReg)
if err != nil {
return nil, -1, err
}
if n&(irqWait|1) != 0 {
break
}
}
r.clearBitmask(commands.BitFramingReg, 0x80)
if i == 0 {
return nil, -1, wrapf("can't read data after 2000 loops")
}
if d, err := r.devRead(commands.ErrorReg); err != nil || d&0x1B != 0 {
return nil, -1, err
}
if n&irqEn&0x01 == 1 {
return nil, -1, wrapf("IRQ error")
}
if command == commands.PCD_TRANSCEIVE {
n, err := r.devRead(commands.FIFOLevelReg)
if err != nil {
return nil, -1, err
}
lastBits, err := r.devRead(commands.ControlReg)
if err != nil {
return nil, -1, err
}
lastBits = lastBits & 0x07
if lastBits != 0 {
backLength = (int(n)-1)*8 + int(lastBits)
} else {
backLength = int(n) * 8
}
if n == 0 {
n = 1
}
if n > 16 {
n = 16
}
backData = make([]byte, n)
for i := byte(0); i < n; i++ {
byteVal, err := r.devRead(commands.FIFODataReg)
if err != nil {
return nil, -1, err
}
backData[i] = byteVal
}
}
return backData, backLength, nil
}
// Request the card information. Returns number of blocks available on the card.
func (r *Dev) Request() (int, error) {
backBits := -1
if err := r.devWrite(commands.BitFramingReg, 0x07); err != nil {
return backBits, err
}
_, backBits, err := r.CardWrite(commands.PCD_TRANSCEIVE, []byte{0x26})
if err != nil {
return -1, err
}
if backBits != 0x10 {
return -1, wrapf("wrong number of bits %d", backBits)
}
return backBits, nil
}
// Wait wait for IRQ to strobe on the IRQ pin when the card is detected.
func (r *Dev) Wait() error {
irqChannel := make(chan bool)
go func() {
irqChannel <- r.irqPin.WaitForEdge(r.operationTimeout)
}()
defer func() {
close(irqChannel)
}()
if err := r.Init(); err != nil {
return err
}
if err := r.writeCommandSequence(sequenceCommands.waitInit); err != nil {
return err
}
for {
if err := r.writeCommandSequence(sequenceCommands.waitLoop); err != nil {
return err
}
select {
case irqResult := <-irqChannel:
if !irqResult {
return wrapf("timeout waitinf for IRQ edge: %v", r.operationTimeout)
}
return nil
case <-time.After(100 * time.Millisecond):
// do nothing
}
}
}
// AntiColl performs the collision check for different cards.
func (r *Dev) AntiColl() ([]byte, error) {
if err := r.devWrite(commands.BitFramingReg, 0x00); err != nil {
return nil, err
}
backData, _, err := r.CardWrite(commands.PCD_TRANSCEIVE, []byte{commands.PICC_ANTICOLL, 0x20}[:])
if err != nil {
return nil, err
}
if len(backData) != 5 {
return nil, wrapf("back data expected 5, actual %d", len(backData))
}
crc := byte(0)
for _, v := range backData[:4] {
crc = crc ^ v
}
if crc != backData[4] {
return nil, wrapf("CRC mismatch, expected %02x actual %02x", crc, backData[4])
}
return backData, nil
}
// CRC calculates the CRC of the data using the card chip.
func (r *Dev) CRC(inData []byte) ([]byte, error) {
if err := r.clearBitmask(commands.DivIrqReg, 0x04); err != nil {
return nil, err
}
if err := r.setBitmask(commands.FIFOLevelReg, 0x80); err != nil {
return nil, err
}
for _, v := range inData {
if err := r.devWrite(commands.FIFODataReg, v); err != nil {
return nil, err
}
}
if err := r.devWrite(commands.CommandReg, commands.PCD_CALCCRC); err != nil {
return nil, err
}
for i := byte(0xFF); i > 0; i-- {
n, err := r.devRead(commands.DivIrqReg)
if err != nil {
return nil, err
}
if n&0x04 > 0 {
break
}
}
lsb, err := r.devRead(commands.CRCResultRegL)
if err != nil {
return nil, err
}
msb, err := r.devRead(commands.CRCResultRegM)
if err != nil {
return nil, err
}
return []byte{lsb, msb}, nil
}
// SelectTag selects the FOB device by device UUID.
func (r *Dev) SelectTag(serial []byte) (byte, error) {
dataBuf := make([]byte, len(serial)+2)
dataBuf[0] = commands.PICC_SElECTTAG
dataBuf[1] = 0x70
copy(dataBuf[2:], serial)
crc, err := r.CRC(dataBuf)
if err != nil {
return 0, err
}
dataBuf = append(dataBuf, crc[0], crc[1])
backData, backLen, err := r.CardWrite(commands.PCD_TRANSCEIVE, dataBuf)
if err != nil {
return 0, err
}
var blocks byte
if backLen == 0x18 {
blocks = backData[0]
} else {
blocks = 0
}
return blocks, nil
}
// StopCrypto stops the crypto chip.
func (r *Dev) StopCrypto() error {
return r.clearBitmask(commands.Status2Reg, 0x08)
}
// ReadBlock reads the block from the card.
//
// sector - card sector to read from
// block - the block within the sector (0-3 tor Mifare 4K)
func (r *Dev) ReadBlock(sector int, block int) ([]byte, error) {
return r.read(calcBlockAddress(sector, block%3))
}
// WriteBlock writes the data into the card block.
//
// auth - the authentiction mode.
// sector - the sector on the card to write to.
// block - the block within the sector to write into.
// data - 16 bytes if data to write
// key - the key used to authenticate the card - depends on the used auth method.
func (r *Dev) WriteBlock(auth byte, sector int, block int, data [16]byte, key []byte) (err error) {
defer func() {
if err == nil {
err = r.StopCrypto()
}
}()
uuid, err := r.selectCard()
if err != nil {
return
}
state, err := r.Auth(auth, sector, 3, key, uuid)
if err != nil {
return
}
if state != AuthOk {
err = wrapf("authentication failed")
return
}
return r.write(calcBlockAddress(sector, block%3), data[:])
}
/*
ReadSectorTrail reads the sector trail (the last sector that contains the sector access bits)
sector - the sector number to read the data from.
*/
func (r *Dev) ReadSectorTrail(sector int) ([]byte, error) {
return r.read(calcBlockAddress(sector&0xFF, 3))
}
// WriteSectorTrail writes the sector trait with sector access bits.
//
// auth - authentication mode.
// sector - sector to set authentication.
// keyA - the key used for AuthA authentication scheme.
// keyB - the key used for AuthB authentication schemd.
// access - the block access structure.
// key - the current key used to authenticate the provided sector.
func (r *Dev) WriteSectorTrail(auth byte, sector int, keyA [6]byte, keyB [6]byte, access *BlocksAccess, key []byte) (err error) {
defer func() {
if err == nil {
err = r.StopCrypto()
}
}()
uuid, err := r.selectCard()
if err != nil {
return
}
state, err := r.Auth(auth, sector, 3, key, uuid)
if err != nil {
return
}
if state != AuthOk {
err = wrapf("failed to authenticate")
return
}
data := make([]byte, 16)
copy(data, keyA[:])
accessData := CalculateBlockAccess(access)
copy(data[6:], accessData[:4])
copy(data[10:], keyB[:])
return r.write(calcBlockAddress(sector&0xFF, 3), data)
}
// Auth authenticate the card fof the sector/block using the provided data.
//
// mode - the authentication mode.
// sector - the sector to authenticate on.
// block - the block within sector to authenticate.
// sectorKey - the key to be used for accessing the sector data.
// serial - the serial of the card.
func (r *Dev) Auth(mode byte, sector, block int, sectorKey []byte, serial []byte) (AuthStatus, error) {
return r.auth(mode, calcBlockAddress(sector, block), sectorKey, serial)
}
// ReadCard reads the card sector/block.
//
// auth - the authentication mode.
// sector - the sector to authenticate on.
// block - the block within sector to authenticate.
// key - the key to be used for accessing the sector data.
func (r *Dev) ReadCard(auth byte, sector int, block int, key []byte) (data []byte, err error) {
defer func() {
if err == nil {
err = r.StopCrypto()
}
}()
uuid, err := r.selectCard()
if err != nil {
return
}
state, err := r.Auth(auth, sector, block, key, uuid)
if err != nil {
return
}
if state != AuthOk {
err = wrapf("can not authenticate")
return
}
return r.ReadBlock(sector, block)
}
// ReadAuth - read the card authentication data.
//
// sector - the sector to authenticate on.
// key - the key to be used for accessing the sector data.
func (r *Dev) ReadAuth(auth byte, sector int, key []byte) (data []byte, err error) {
defer func() {
if err == nil {
err = r.StopCrypto()
}
}()
uuid, err := r.selectCard()
if err != nil {
return
}
state, err := r.Auth(auth, sector, 3, key, uuid)
if err != nil {
return
}
if state != AuthOk {
return nil, wrapf("can not authenticate")
}
return r.read(calcBlockAddress(sector, 3))
}
// CalculateBlockAccess calculates the block access.
func CalculateBlockAccess(ba *BlocksAccess) []byte {
res := make([]byte, 4)
res[0] = (^ba.getBits(1) & 0x0F) | ((^ba.getBits(2) & 0x0F) << 4)
res[1] = (^ba.getBits(3) & 0x0F) | (ba.getBits(1) & 0x0F << 4)
res[2] = (ba.getBits(2) & 0x0F) | (ba.getBits(3) & 0x0F << 4)
res[3] = res[0] ^ res[1] ^ res[2]
return res
}
// ParseBlockAccess parses the given byte array into the block access structure.
func ParseBlockAccess(ad []byte) *BlocksAccess {
ba := new(BlocksAccess)
ba.B0 = BlockAccess(ad[1]&0x10>>4 | ad[2]&0x01<<1 | ad[2]&0x10>>2)
ba.B1 = BlockAccess(ad[1]&0x20>>5 | ad[2]&0x02 | ad[2]&0x20>>3)
ba.B2 = BlockAccess(ad[1]&0x40>>6 | ad[2]&0x04>>1 | ad[2]&0x40>>4)
ba.B3 = SectorTrailerAccess(ad[1]&0x80>>7 | ad[2]&0x08>>2 | ad[2]&0x80>>5)
return ba
}
func (r *Dev) String() string {
return fmt.Sprintf("Mifare MFRC522 [bus: %v, reset pin: %s, irq pin: %s]",
r.spiDev, r.resetPin.Name(), r.irqPin.Name())
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// MFRC522 SPI Dev private/helper functions
//
///////////////////////////////////////////////////////////////////////////////////////////
func (ba *BlocksAccess) getBits(bitNum uint) byte {
shift := bitNum - 1
bit := byte(1 << shift)
return (byte(ba.B0)&bit)>>shift | ((byte(ba.B1)&bit)>>shift)<<1 | ((byte(ba.B2)&bit)>>shift)<<2 | ((byte(ba.B3)&bit)>>shift)<<3
}
func (r *Dev) writeCommandSequence(commands [][]byte) error {
for _, cmdData := range commands {
if err := r.devWrite(int(cmdData[0]), cmdData[1]); err != nil {
return err
}
}
return nil
}
func (r *Dev) selectCard() ([]byte, error) {
if err := r.Wait(); err != nil {
return nil, err
}
if err := r.Init(); err != nil {
return nil, err
}
if _, err := r.Request(); err != nil {
return nil, err
}
uuid, err := r.AntiColl()
if err != nil {
return nil, err
}
if _, err := r.SelectTag(uuid); err != nil {
return nil, err
}
return uuid, nil
}
func calcBlockAddress(sector int, block int) byte {
return byte(sector*4 + block)
}
func (r *Dev) write(blockAddr byte, data []byte) error {
read, backLen, err := r.preAccess(blockAddr, commands.PICC_WRITE)
if err != nil || backLen != 4 {
return err
}
if read[0]&0x0F != 0x0A {
return wrapf("can't authorize write")
}
var newData [18]byte
copy(newData[:], data[:16])
crc, err := r.CRC(newData[:16])
if err != nil {
return err
}
newData[16] = crc[0]
newData[17] = crc[1]
read, backLen, err = r.CardWrite(commands.PCD_TRANSCEIVE, newData[:])
if err != nil {
return err
}
if backLen != 4 || read[0]&0x0F != 0x0A {
err = wrapf("can't write data")
}
return nil
}
func (r *Dev) auth(mode byte, blockAddress byte, sectorKey []byte, serial []byte) (AuthStatus, error) {
buffer := make([]byte, 2)
buffer[0] = mode
buffer[1] = blockAddress
buffer = append(buffer, sectorKey...)
buffer = append(buffer, serial[:4]...)
_, _, err := r.CardWrite(commands.PCD_AUTHENT, buffer)
if err != nil {
return AuthReadFailure, err
}
if n, err := r.devRead(commands.Status2Reg); err != nil || n&0x08 == 0 {
return AuthFailure, err
}
return AuthOk, nil
}
func (r *Dev) devWrite(address int, data byte) error {
newData := []byte{(byte(address) << 1) & 0x7E, data}
return r.spiDev.Tx(newData, nil)
}
func (r *Dev) devRead(address int) (byte, error) {
data := []byte{((byte(address) << 1) & 0x7E) | 0x80, 0}
out := make([]byte, len(data))
if err := r.spiDev.Tx(data, out); err != nil {
return 0, err
}
return out[1], nil
}
func (r *Dev) setBitmask(address, mask int) error {
current, err := r.devRead(address)
if err != nil {
return err
}
return r.devWrite(address, current|byte(mask))
}
func (r *Dev) clearBitmask(address, mask int) error {
current, err := r.devRead(address)
if err != nil {
return err
}
return r.devWrite(address, current&^byte(mask))
}
func (r *Dev) preAccess(blockAddr byte, cmd byte) ([]byte, int, error) {
send := make([]byte, 4)
send[0] = cmd
send[1] = blockAddr
crc, err := r.CRC(send[:2])
if err != nil {
return nil, -1, err
}
send[2] = crc[0]
send[3] = crc[1]
return r.CardWrite(commands.PCD_TRANSCEIVE, send)
}
func (r *Dev) read(blockAddr byte) ([]byte, error) {
data, _, err := r.preAccess(blockAddr, commands.PICC_READ)
if err != nil {
return nil, err
}
if len(data) != 16 {
return nil, wrapf("expected 16 bytes, actual %d", len(data))
}
return data, nil
}
// the command batches for card init and wait loop.
var sequenceCommands = struct {
init [][]byte
waitInit [][]byte
waitLoop [][]byte
}{
init: [][]byte{
{commands.TModeReg, 0x8D},
{commands.TPrescalerReg, 0x3E},
{commands.TReloadRegL, 30},
{commands.TReloadRegH, 0},
{commands.TxAutoReg, 0x40},
{commands.ModeReg, 0x3D},
},
waitInit: [][]byte{
{commands.CommIrqReg, 0x00},
{commands.CommIEnReg, 0xA0},
},
waitLoop: [][]byte{
{commands.FIFODataReg, 0x26},
{commands.CommandReg, 0x0C},
{commands.BitFramingReg, 0x87},
},
}
var _ conn.Resource = &Dev{}
var _ fmt.Stringer = &Dev{}
func wrapf(format string, a ...interface{}) error {
return fmt.Errorf("mfrc522: "+format, a...)
}

@ -0,0 +1,56 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package mfrc522
import (
"bytes"
"reflect"
"strconv"
"testing"
)
func TestBitCalc(t *testing.T) {
ba := BlocksAccess{
B3: KeyA_RN_WB_BITS_RAB_WN_KeyB_RN_WB, // 100
B2: RAB_WN_IN_DAB, // 001
B1: RB_WN_IN_DN, // 101
B0: RAB_WB_IB_DAB, // 110
}
access := CalculateBlockAccess(&ba)
reader := func(s string) (res byte) {
d, err := strconv.ParseUint(s, 2, 8)
if err != nil {
t.Fatal(err)
}
res = byte(d & 0xFF)
return
}
if reader("0110") != ba.getBits(1) {
t.Fatalf("0110 is not equal to %d", ba.getBits(1))
}
expected := []byte{
reader("11101001"),
reader("01100100"),
reader("10110001"),
0,
}
expected[3] = expected[0] ^ expected[1] ^ expected[2]
if !bytes.Equal(expected, access) {
t.Fatal("Access is incorrect")
}
parsedAccess := ParseBlockAccess(access)
if !reflect.DeepEqual(ba, *parsedAccess) {
t.Fatal("Parsed access mismatch")
}
}
Loading…
Cancel
Save