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.
devices/mfrc522/blockaccess.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{}