mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
4.6 KiB
Go
107 lines
4.6 KiB
Go
// 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"
|
|
|
|
// BlockAccess defines the block access bits.
|
|
type BlockAccess byte
|
|
|
|
// SectorTrailerAccess defines the sector trailing block access bits.
|
|
type SectorTrailerAccess byte
|
|
|
|
// Access bits for the sector data.
|
|
const (
|
|
AnyKeyRWID BlockAccess = 0x0 // Any key (A or B) can read, write, increment and decrement block.
|
|
RAB_WN_IN_DN BlockAccess = 0x02 // Read (A or B), Write (None), Increment (None), Decrement (None)
|
|
RAB_WB_IN_DN BlockAccess = 0x04 // Read (A orB), Write (B), Increment (None), Decrement (None)
|
|
RAB_WB_IB_DAB BlockAccess = 0x06 // Read (A or B), Write (B), Icrement (B), Decrement (A or B)
|
|
RAB_WN_IN_DAB BlockAccess = 0x01 // Read (A or B), Write (None), Increment (None), Decrment (A or B)
|
|
RB_WB_IN_DN BlockAccess = 0x03 // Read (B), Write (B), Increment (None), Decrement (None)
|
|
RB_WN_IN_DN BlockAccess = 0x05 // Read (B), Write (None), Increment (None), Decrement (None)
|
|
RN_WN_IN_DN BlockAccess = 0x07 // Read (None), Write (None), Increment (None), Decrement (None)
|
|
)
|
|
|
|
// Access bits for the sector trail.
|
|
// Every trail sector has the options for controlling the access to the trailing sector bits.
|
|
// For example :
|
|
//
|
|
// KeyA_R[Key]_W[Key]_BITS_R[Key]_W[Key]_KeyB_R[Key]_W[Key]
|
|
//
|
|
// - KeyA
|
|
// - could be Read by providing [Key] ( where [Key] could be KeyA or KeyB )
|
|
// - could be Written by Providing [Key] ( where [Key] is KeyA or KeyB )
|
|
// - access bits for the sector data (see above)
|
|
// - could be Read by providing [Key] ( where [Key] could be KeyA or KeyB )
|
|
// - could be Written by Providing [Key] ( where [Key] is KeyA or KeyB )
|
|
// - KeyB
|
|
// - could be Read by providing [Key] ( where [Key] could be KeyA or KeyB )
|
|
// - could be Written by Providing [Key] ( where [Key] is KeyA or KeyB )
|
|
//
|
|
// example:
|
|
//
|
|
// KeyA_RN_WA_BITS_RA_WA_KeyB_RA_WA means
|
|
// - KeyA could not be read but could be overwriten if KeyA is provided
|
|
// - Access bits could be read and overwritten if KeyA is provided during the card authentication
|
|
// - KeyB could be read and overriten if KeyA is provided during the card authentication
|
|
// more on the matter: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
|
|
const (
|
|
KeyA_RN_WA_BITS_RA_WN_KeyB_RA_WA SectorTrailerAccess = 0x0
|
|
KeyA_RN_WN_BITS_RA_WN_KeyB_RA_WN SectorTrailerAccess = 0x02
|
|
KeyA_RN_WB_BITS_RAB_WN_KeyB_RN_WB SectorTrailerAccess = 0x04
|
|
KeyA_RN_WN_BITS_RAB_WN_KeyB_RN_WN SectorTrailerAccess = 0x06
|
|
KeyA_RN_WA_BITS_RA_WA_KeyB_RA_WA SectorTrailerAccess = 0x01
|
|
KeyA_RN_WB_BITS_RAB_WB_KeyB_RN_WB SectorTrailerAccess = 0x03
|
|
KeyA_RN_WN_BITS_RAB_WB_KeyB_RN_WN SectorTrailerAccess = 0x05
|
|
KeyA_RN_WN_BITS_RAB_WN_KeyB_RN_WN_EXTRA SectorTrailerAccess = 0x07
|
|
)
|
|
|
|
// 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
|
|
}
|
|
|
|
func (ba *BlocksAccess) String() string {
|
|
return fmt.Sprintf("B0: %d, B1: %d, B2: %d, B3: %d", ba.B0, ba.B1, ba.B2, ba.B3)
|
|
}
|
|
|
|
// serialize calculates the block access and stores it into the passed slice, that must be at least 4 bytes wide.
|
|
func (ba *BlocksAccess) serialize(dst []byte) error {
|
|
if len(dst) != 4 {
|
|
return wrapf("serialized array must be of size at least 4")
|
|
}
|
|
dst[0] = ((^ba.getBits(2) & 0x0F) << 4) | (^ba.getBits(1) & 0x0F)
|
|
dst[1] = ((ba.getBits(1) & 0x0F) << 4) | (^ba.getBits(3) & 0x0F)
|
|
dst[2] = ((ba.getBits(3) & 0x0F) << 4) | (ba.getBits(2) & 0x0F)
|
|
dst[3] = dst[0] ^ dst[1] ^ dst[2]
|
|
return nil
|
|
}
|
|
|
|
// Init parses the given byte array into the block access structure.
|
|
func (ba *BlocksAccess) Init(ad []byte) {
|
|
ba.B0 = BlockAccess(((ad[1] & 0x10) >> 2) | ((ad[2] & 0x01) << 1) | ((ad[2] & 0x10) >> 5))
|
|
ba.B1 = BlockAccess(((ad[1] & 0x20) >> 3) | (ad[2] & 0x02) | ((ad[2] & 0x20) >> 5))
|
|
ba.B2 = BlockAccess(((ad[1] & 0x40) >> 4) | ((ad[2] & 0x04) >> 1) | ((ad[2] & 0x40) >> 6))
|
|
ba.B3 = SectorTrailerAccess(((ad[1] & 0x80) >> 5) | ((ad[2] & 0x08) >> 2) | ((ad[2] & 0x80) >> 7))
|
|
}
|
|
|
|
func (ba *BlocksAccess) getBits(bitNum uint) byte {
|
|
shift := 3 - bitNum
|
|
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 calcBlockAddress(sector int, block int) byte {
|
|
return byte(sector*4 + block)
|
|
}
|
|
|
|
var _ fmt.Stringer = &BlocksAccess{}
|