worked on RFID

worked on SPI
refactoring/changes to reduce RAM section size (.text)
This commit is contained in:
2017-09-16 19:11:17 +02:00
parent 2a3c4297cd
commit 72ed1a9125
3 changed files with 597 additions and 521 deletions

35
Debug.h
View File

@@ -3,19 +3,54 @@
#define DEBUG
#include <cstdint>
extern "C" {
#include "ets_sys.h"
#include "c_types.h"
#include "osapi.h"
//#include "gpio.h"
//#include "os_type.h"
//#include "user_config.h"
#include "user_interface.h"
//#include "wpa2_enterprise.h"
//#include "inttypes.h"
#include "mem.h"
#include "espconn.h"
#include "ESP8266lib/c++.h"
#include "driver/uart.h"
}
void hexdump(const uint8_t* buf, uint8_t len) {
for (int i = 0; i < len; ++i) {
os_printf("%02x ", buf[i]);
}
os_printf("\n");
}
#ifdef DEBUG
#define debug(str) os_printf(str)
#define debugMod(module, str) os_printf("[%s] %s\n", module, str)
#define debugMod1(module, str, val) os_printf("[%s] ", module); os_printf(str, val); os_printf("\n");
#define debugMod2(module, str, v1, v2) os_printf("[%s] ", module); os_printf(str, v1, v2); os_printf("\n");
#define debugMod3(module, str, v1, v2, v3) os_printf("[%s] ", module); os_printf(str, v1, v2, v3); os_printf("\n");
#define IF_DEBUG(a) a
#define debugShow(buf, len) hexdump(buf,len)
#else
#define debug(module, str)
#define debugMod(module, str)
#define debugMod1(module, str, val)
#define debugMod2(module, str, v1, v2)
#define debugMod3(module, str, v1, v2, v3)
#define IF_DEBUG(a)
#define debugShow(a, b)
#endif

View File

@@ -1,8 +1,8 @@
#ifndef MFRC522_H
#define MFRC522_H
#include "../../Debug.h"
#include "../../io/SoftSPI.h"
#define WITH_DEBUG
/**
@@ -20,19 +20,18 @@
*/
class MFRC522 {
typedef struct {
uint8_t size; // Number of bytes in the UID. 4, 7 or 10.
public:
static constexpr const char* NAME = "MFRC522";
struct UID {
uint8_t size = 0; // Number of bytes in the UID. 4, 7 or 10.
uint8_t uidByte[10];
uint8_t sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;
Uid uid;
struct OP {
uint8_t addr : 7; // bits 0-6
uint8_t rw : 1; // bit 7 [MSB] 1 = read, 0 = write
};
private:
enum class Register {
COMMAND_REG = 0x01 << 1,
@@ -66,8 +65,6 @@ class MFRC522 {
TEST_SEL_2_REG = 0x32 << 1,
VERSION_REG = 0x37 << 1, // software version
};
enum class Command {
@@ -109,6 +106,9 @@ class MFRC522 {
WRONG_BCC,
};
/** convert status-code to status string */
const char* getStatusStr(const Status s) const;
struct CommandReg {
uint8_t command : 4;
uint8_t power_down : 1;
@@ -129,28 +129,157 @@ class MFRC522 {
private:
SoftSPI spi;
public:
MFRC522() {
/** init */
void init();
/** check whether a RFID-reader is present or not */
bool isAvailable();
/** is there a card present? */
bool isCard();
/** yes, card is present -> read it */
bool select(UID* uidOut);
/** read the given 14-byte sector from the card */
void read(uint8_t address);
/** stop talking to the card */
void halt();
/** perform selftest */
void selftest();
private:
void stopCrypto1() {
clearRegBits(Register::STATUS2_REG, 0x08); // reset MFCrypto1On
}
/** init */
void init() {
os_printf("init MFRC522\n");
spi.init();
void antennaOn();
os_delay_us(5000);
// writeReg8(Register::T_MODE_REG, 0x8D);
// writeReg8(Register::T_PRESCALER_REG, 0x3E);
// writeReg8(Register::T_RELOAD_REG_L, 0x30);
// writeReg8(Register::T_RELOAD_REG_H, 0x00);
// writeReg8(Register::TX_AUTO_REG, 0x40);
// writeReg8(Register::T_MODE_REG, 0x3D);
// antennaOn();
Status requestA(uint8_t* bufferATQA, uint8_t* bufferSize) {
return piccREQAorWUPA(PICCComand::REQA, bufferATQA, bufferSize);
}
Status piccREQAorWUPA(const PICCComand cmd, uint8_t* buffer, uint8_t* bufferSize);
/** get card-type-name for the given 2-byte ATQA response */
const char* getCardType(const uint8_t* atqa) const;
Status anticol(int level, UID* uid);
Status select(int level, uint8_t* uidPart, UID* uid);
/**
* calculate the CRC for the given bytes and write them (2 bytes) to the given destination
* NOTE: the CRC depends on the settings of ModeReg (bit 0 and 1) which control
* the CRC-16's preset: 0x0000 0x6363 0xa671 0xffff
* 0x6363 seems to be the "correct" one?!
*/
Status calculateCRC(const uint8_t *data, const uint8_t length, uint8_t* result);
Status transceive(const uint8_t* srcData, const uint8_t srcDataLen, uint8_t* dstData, uint8_t* dstDataLen, uint8_t* validBits = nullptr, uint8_t rxAlign = 0, bool checkCRC = false) {
debugMod1(NAME, "transceive %d bytes", srcDataLen);
debugShow(srcData, srcDataLen);
const Status s = picc(Command::TRANSCEIVE, 0x30, srcData, srcDataLen, dstData, dstDataLen, validBits, rxAlign, checkCRC);
debugMod2(NAME, "transceive: %s, returned %d bytes", getStatusStr(s), *dstDataLen);
debugShow(dstData, *dstDataLen);
return s;
}
void fillFIFO(const uint8_t* srcData, const uint8_t srcDataLen) {
setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
if (readReg8(Register::FIFO_LEVEL_REG) != 0) {
debugMod(NAME, "!!!!!!!!!!!!!!!!! FIFO NOT EMPTY THOUGH IT SHOULD BE!\n");
}
writeReg(Register::FIFO_DATA_REG, srcData, srcDataLen); // write to-be-sent data to FIFO
if (readReg8(Register::FIFO_LEVEL_REG) != srcDataLen) {
debugMod(NAME, "!!!!!!!!!!!!!!!!!failed to fill fifo\n");
}
}
void ensureSane() {
setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
//writeReg8(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
writeReg8(Register::COMMAND_REG, (int) Command::IDLE); // stop previous commands
}
Status picc(Command cmd, const uint8_t waitIRQ, const uint8_t* srcData, const uint16_t srcDataLen, uint8_t* dstData, uint8_t* dstLen, uint8_t* validBits, uint8_t rxAlign, bool checkCRC);
private:
void writeReg8(const Register reg, const Command cmd) {
writeReg8(reg, (uint8_t) cmd);
}
void writeReg8(const Register reg, const uint8_t value) {
spi::chipSelect();
writeTo((int)reg);
spi::writeByte(value);
spi::chipDeselect();
}
void setRegBits(const Register reg, const uint8_t mask) {
const uint8_t tmp = readReg8(reg);
writeReg8(reg, tmp | mask);
}
void clearRegBits(const Register reg, const uint8_t mask) {
const uint8_t tmp = readReg8(reg);
writeReg8(reg, tmp & (~mask));
}
void writeReg(const Register reg, const uint8_t* data, const uint16_t len) {
spi::chipSelect();
writeTo((int)reg);
for (int i = 0; i < len; ++i){
spi::writeByte(data[i]);
}
spi::chipDeselect();
}
uint8_t readReg8(const Register reg) {
spi::chipSelect();
readFrom((int)reg);
const uint8_t res = spi::readByte();
spi::chipDeselect();
return res;
}
/** read multiple bytes from the same register (mainly FIFO) */
void readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign = 0);
// highest bit denotes whether reading or writing
void readFrom(uint8_t address) {
spi::writeByte(address | 0x80);
}
void writeTo(uint8_t address) {
spi::writeByte(address);
}
};
void ICACHE_FLASH_ATTR MFRC522::init() {
debugMod(NAME, "init");
spi::init();
//os_delay_us(5000);
// Reset baud rates
writeReg8(Register::TX_MODE_REG, 0x00);
@@ -169,310 +298,38 @@ public:
writeReg8(Register::COMMAND_REG, Command::IDLE);
}
}
void ICACHE_FLASH_ATTR MFRC522::readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign) {
spi::chipSelect();
void getStatus() {
// address for reading (MSB = 1)
const uint8_t address = (int) reg | 0x80;
spi::writeByte(address);
uint8_t s1 = readReg8(Register::STATUS1_REG);
uint8_t s2 = readReg8(Register::STATUS2_REG);
int i;
for (i = 0; i < count-1; ++i) {
os_printf("s1: %d, s2: %d \n", (int)s1, (int)s2);
}
/** is there a card present? */
bool isCard() {
os_printf("** is card?\n");
uint8_t bufferATQA[2];
uint8_t bufferSize = sizeof(bufferATQA);
// Reset baud rates
writeReg8(Register::TX_MODE_REG, 0x00);
writeReg8(Register::RX_MODE_REG, 0x00);
// Reset ModWidthReg
writeReg8(Register::MOD_WIDTH_REG, 0x26);
Status res = requestA(bufferATQA, &bufferSize);
os_printf("isCard: %d type: %s\n", (int)res, getCardType(bufferATQA));
return res == Status::OK;
}
/** yes, card is present -> read it */
bool select() {
os_printf("** select\n");
ensureSane();
Status res;
uint8_t uid[10] = {};
res = anticol(1, &uid[0]);
debugShow(uid, 10);
return (res == Status::OK);
}
/** read the given 14-byte sector from the card */
void read(uint8_t address) {
os_printf("** read block %d\n", address);
os_delay_us(1000*50);
clearRegBits(Register::COLL_REG, 0x80);
writeReg8(Register::BIT_FRAMING_REG, 0);
// READ command: 0x30 ADR CRC1 CRC2
uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_READ, address};
// calculate the CRC
calculateCRC(buffer, 2, &buffer[2]);
// response-buffer
uint8_t res[16];
uint8_t resLen = 16;
// send
transceive(buffer, 4, res, &resLen);
}
/** stop talking to the card */
void halt() {
os_printf("** halt the card\n");
// HALT command: 0x50 ADR CRC1 CRC2
uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_HLTA, 0x00};
// calculate the CRC
calculateCRC(buffer, 2, &buffer[2]);
// send
uint8_t resLen = 1;
transceive(buffer, 4, buffer, &resLen);
}
void selftest() {
os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG));
writeReg8(Register::MODE_REG, 61);
os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG));
uint8_t res[2];
// MUST BE 3c a2
uint8_t out2[9] = {0x93, 0x70, 0x12, 0x34, 0x56, 0x78, 0x08, 0x00, 0x00};
calculateCRC(out2, 7, res);
debugShow(res, 2);
}
private:
void stopCrypto1() {
clearRegBits(Register::STATUS2_REG, 0x08); // reset MFCrypto1On
}
void antennaOn() {
uint8_t val = readReg8(Register::TX_CONTROL_REG);
if ((val & 0x03) != 0x03) {
writeReg8(Register::TX_CONTROL_REG, val | 0x03);
}
val = readReg8(Register::TX_CONTROL_REG);
os_printf("antenna: %d\n", (int) val);
}
Status requestA(uint8_t* bufferATQA, uint8_t* bufferSize) {
return piccREQAorWUPA(PICCComand::REQA, bufferATQA, bufferSize);
}
Status piccREQAorWUPA(const PICCComand cmd, uint8_t* buffer, uint8_t* bufferSize) {
clearRegBits(Register::COLL_REG, 0x80);
uint8_t validBits = 7;
const uint8_t _cmd = (uint8_t) cmd;
const Status status = transceive(&_cmd, 1, buffer, bufferSize, &validBits);
if (status != Status::OK) {return status;}
os_printf("response-size: %d, valid bits: %d\n", (int)*bufferSize, (int)validBits);
// ATQA must be 16 bits
if ((*bufferSize != 2) || (validBits != 0)) {
return Status::INVALID_ATQA;
}
return Status::OK;
}
void debugShow(const uint8_t* buf, uint8_t len) {
for (int i = 0; i < len; ++i) {
os_printf("%02x ", buf[i]);
}
os_printf("\n");
}
/** get card-type-name for the given 2-byte ATQA response */
const char* getCardType(const uint8_t* atqa) {
const uint16_t resp = atqa[0] << 8 | atqa[1];
if (resp == 0x0400) {return "MFOne-S50";} // http://www.elechouse.com/elechouse/images/product/13.56MHZ_RFID_Module/mifare_S50.pdf
if (resp == 0x0200) {return "MFOne-S70";}
if (resp == 0x4400) {return "MF-UltraLight";}
if (resp == 0x0800) {return "MF-Pro";}
if (resp == 0x4403) {return "MF Desire";}
return "Unknown";
}
Status anticol(int level, uint8_t* uidDst) {
os_printf("** anticol level %d\n", level);
// Prepare MFRC522
clearRegBits(Register::COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared.
uint8_t out[9];
uint8_t resLen;
Status s;
// send 2 bytes: 0x93 0x20 and expect 5 bytes of response : 4 bytes UID + 1 byte BCC checksum
// the first byte of the UID might be 0x88 to indicate that there are more requests needed
// to get the full UID
resLen = 5;
out[0] = (uint8_t)PICCComand::PICC_CMD_SEL_CL1;
out[1] = 0x20;
writeReg8(Register::BIT_FRAMING_REG, 0);
s = transceive(out, 2, uidDst, &resLen);
if (s != Status::OK) {return s;}
// NOTES
// if the received UID starts with 0x88, then we have to read the next block (like UTF-8)
// if the received UID starts with 0x08, it is a random number that will change every time
// response is SN0 SN1 SN2 SN3 BCC where BCC = SN0^SN1^SN2^SN3 -> check this!
const uint8_t serNumCheck = uidDst[0] ^ uidDst[1] ^ uidDst[2] ^ uidDst[3];
if (serNumCheck != uidDst[4]) {return Status::WRONG_BCC;}
os_printf("** ser num check %d == %d ?\n", serNumCheck, uidDst[4]);
// go on with select
return select(level, uidDst);
}
Status select(int level, uint8_t* uidPart) {
os_printf("** select level %d\n", level);
uint8_t cmd = (uint8_t) PICCComand::PICC_CMD_SEL_CL1; // TODO: depends on level
uint8_t bcc = uidPart[0] ^ uidPart[1] ^ uidPart[2] ^ uidPart[3];
uint8_t out[9] = {cmd, 0x70, uidPart[0], uidPart[1], uidPart[2], uidPart[3], bcc, 0x00, 0x00};
// replace 0x00 0x00 with the crc
calculateCRC(out, 7, &out[7]);
// transmit
uint8_t res[3];
uint8_t resLen = 3;
Status status = transceive(out, 9, res, &resLen);
// NOTES on SAK (selective ACK)
// result starts with 0x04? -> UID not complete, go on reading!
// result starts with 0x08? -> UID complete,
// this one also contains some details on the card we see
uint8_t SAK = res[0];
// another UID part needs to be read? (max: 3)
if (SAK == 0x04) { return anticol(level+1, &uidPart[4]); }
// done
return status;
}
/**
* calculate the CRC for the given bytes and write them (2 bytes) to the given destination
* NOTE: the CRC depends on the settings of ModeReg (bit 0 and 1) which control
* the CRC-16's preset: 0x0000 0x6363 0xa671 0xffff
* 0x6363 seems to be the "correct" one?!
*/
Status calculateCRC(const uint8_t *data, const uint8_t length, uint8_t* result) {
os_printf("calculate CRC for %d bytes\n", length);
writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop any active command.
writeReg8(Register::DIV_IRQ_REG, 0x04); // Clear the CRCIRq interrupt request bit
fillFIFO(data, length); // fill the FIFO with the data to CRC
writeReg8(Register::COMMAND_REG, Command::CALC_CRC); // Start the calculation
// Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us.
for (int i = 0; i < 25; ++i) {
os_delay_us(1000*1);
// DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved
const uint8_t n = readReg8(Register::DIV_IRQ_REG);
// CRCIRq bit set - calculation done
if (n & 0x04) {
writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop calculating CRC for new content in the FIFO.
result[0] = readReg8(Register::CRC_RES_L);
result[1] = readReg8(Register::CRC_RES_H);
os_printf("crc calculation: OK!\n");
return Status::OK;
if ( (i == 0) && rxAlign ) {
uint8_t mask = (0xFF << rxAlign) & 0xFF;
const uint8_t value = spi::readWriteByte(address);
dst[0] = (dst[0] & ~mask) | (value & mask);
} else {
dst[i] = spi::readWriteByte(address);
}
}
os_printf("CRC: TIMEOUT!!!\n");
return Status::TIMEOUT_CRC;
// read last byte and stop reading
dst[i] = spi::readWriteByte(0);
}
spi::chipDeselect();
Status transceive(const uint8_t* srcData, const uint8_t srcDataLen, uint8_t* dstData, uint8_t* dstDataLen, uint8_t* validBits = nullptr, uint8_t rxAlign = 0, bool checkCRC = false) {
//os_printf("transceive %d bytes of data (valid bits: %d), expecting %d bytes of response\n", srcDataLen, *validBits, *dstDataLen);
os_printf("transceive %d bytes of data:", srcDataLen);
debugShow(srcData, srcDataLen);
const Status s = picc(Command::TRANSCEIVE, 0x30, srcData, srcDataLen, dstData, dstDataLen, validBits, rxAlign, checkCRC);
os_printf("transceive status: %d bytes: ", (int) s);
debugShow(dstData, *dstDataLen);
return s;
}
}
void fillFIFO(const uint8_t* srcData, const uint8_t srcDataLen) {
setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
if (readReg8(Register::FIFO_LEVEL_REG) != 0) {
os_printf("!!!!!!!!!!!!!!!!! FIFO NOT EMPTY THOUGH IT SHOULD BE!\n");
}
writeReg(Register::FIFO_DATA_REG, srcData, srcDataLen); // write to-be-sent data to FIFO
if (readReg8(Register::FIFO_LEVEL_REG) != srcDataLen) {
os_printf("!!!!!!!!!!!!!!!!!failed to fill fifo\n");
}
}
void ensureSane() {
setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
//writeReg8(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data)
writeReg8(Register::COMMAND_REG, (int) Command::IDLE); // stop previous commands
}
Status picc(Command cmd, const uint8_t waitIRQ, const uint8_t* srcData, const uint16_t srcDataLen, uint8_t* dstData, uint8_t* dstLen, uint8_t* validBits, uint8_t rxAlign, bool checkCRC) {
MFRC522::Status ICACHE_FLASH_ATTR MFRC522::picc(Command cmd, const uint8_t waitIRQ, const uint8_t* srcData, const uint16_t srcDataLen, uint8_t* dstData, uint8_t* dstLen, uint8_t* validBits, uint8_t rxAlign, bool checkCRC) {
const uint8_t txLastBits = validBits ? *validBits : 0;
const uint8_t bitFraming = (rxAlign << 4) + txLastBits;
@@ -501,7 +358,9 @@ private:
// received the interrupt we are waiting for?
if (res & waitIRQ) {
os_printf("got needed interrupt\n"); break;
//debugMod(NAME, "got needed interrupt -> done");
//os_printf("got needed interrupt\n");
break;
}
if (res & 0x01) {
@@ -509,7 +368,8 @@ private:
}
if (--maxRuns == 0) {
os_printf("picc() Timeout\n");
//debugMod(NAME, "TIMEOUT");
//os_printf("picc() Timeout\n");
return Status::TIMEOUT_MANUAL;
}
@@ -525,7 +385,8 @@ private:
if (dstData && dstLen) {
const uint8_t n = readReg8(Register::FIFO_LEVEL_REG);
os_printf("got %d bytes to read\n", (int) n);
debugMod1(NAME, "got %d bytes to read", (int)n);
//os_printf("got %d bytes to read\n", (int) n);
// not enough space for the response data?
if (n > *dstLen) { return Status::RESPONSE_TOO_LONG; }
@@ -542,7 +403,7 @@ private:
#ifdef WITH_DEBUG
// ensure fifo is now empty
if (readReg8(Register::FIFO_LEVEL_REG) != 0) {
os_printf("fifo not empty!\n");
debugMod(NAME, "!! FIFO is not empty though it should be!");
return Status::INTERNAL_ERROR;
}
#endif
@@ -557,110 +418,282 @@ private:
return Status::OK;
}
}
MFRC522::Status ICACHE_FLASH_ATTR MFRC522::calculateCRC(const uint8_t *data, const uint8_t length, uint8_t* result) {
debugMod1(NAME, "calculate CRC for %d bytes", length);
private:
writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop any active command.
writeReg8(Register::DIV_IRQ_REG, 0x04); // Clear the CRCIRq interrupt request bit
fillFIFO(data, length); // fill the FIFO with the data to CRC
writeReg8(Register::COMMAND_REG, Command::CALC_CRC); // Start the calculation
void writeReg8(const Register reg, const Command cmd) {
writeReg8(reg, (uint8_t) cmd);
}
// Wait for the CRC calculation to complete
for (int i = 0; i < 25; ++i) {
void writeReg8(const Register reg, const uint8_t value) {
spi.chipSelect();
writeTo((int)reg);
spi.writeByte(value);
spi.chipDeselect();
//uint8_t written = readReg8(reg);
//os_printf("write: %d to %d, re-read: %d \n", (int) value, (int) reg, (int) written);
}
os_delay_us(1000*1);
void setRegBits(const Register reg, const uint8_t mask) {
const uint8_t tmp = readReg8(reg);
writeReg8(reg, tmp | mask);
}
// wait for CRCIRq to be set
const uint8_t n = readReg8(Register::DIV_IRQ_REG);
void clearRegBits(const Register reg, const uint8_t mask) {
const uint8_t tmp = readReg8(reg);
writeReg8(reg, tmp & (~mask));
}
void writeReg(const Register reg, const uint8_t* data, const uint16_t len) {
//os_printf("writing %d bytes of data to %d\n", (int)len, (int)reg);
spi.chipSelect();
writeTo((int)reg);
for (int i = 0; i < len; ++i){
spi.writeByte(data[i]);
}
spi.chipDeselect();
}
uint8_t readReg8(const Register reg) {
spi.chipSelect();
readFrom((int)reg);
const uint8_t res = spi.readByte();
spi.chipDeselect();
return res;
}
// void readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign = 0) {
// if (!count) {return;}
// for (int i = 0; i < count; ++i) {
// dst[i] = readReg8(reg);
// }
// #ifdef WITH_DEBUG
// if (readReg8(Register::FIFO_LEVEL_REG) != 0) {
// os_printf("!!!!!!!!!!!!! fifo is not empty");
// }
// #endif
// }
/** read multiple bytes from the same register (mainly FIFO) */
void readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign = 0) {
spi.chipSelect();
// address for reading (MSB = 1)
const uint8_t address = (int) reg | 0x80;
spi.writeByte(address);
int i;
for (i = 0; i < count-1; ++i) {
if ( (i == 0) && rxAlign ) {
uint8_t mask = (0xFF << rxAlign) & 0xFF;
const uint8_t value = spi.readWriteByte(address);
dst[0] = (dst[0] & ~mask) | (value & mask);
} else {
dst[i] = spi.readWriteByte(address);
// CRCIRq bit set - calculation done
if (n & 0x04) {
writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop calculating CRC for new content in the FIFO.
result[0] = readReg8(Register::CRC_RES_L);
result[1] = readReg8(Register::CRC_RES_H);
return Status::OK;
}
}
// read last byte and stop reading
dst[i] = spi.readWriteByte(0);
debugMod(NAME, "CRC TIMEOUT");
return Status::TIMEOUT_CRC;
spi.chipDeselect();
}
const char* ICACHE_FLASH_ATTR MFRC522::getCardType(const uint8_t* atqa) const {
const uint16_t resp = atqa[0] << 8 | atqa[1];
if (resp == 0x0400) {return "MFOne-S50";} // http://www.elechouse.com/elechouse/images/product/13.56MHZ_RFID_Module/mifare_S50.pdf
if (resp == 0x0200) {return "MFOne-S70";}
if (resp == 0x4400) {return "MF-UltraLight";}
if (resp == 0x0800) {return "MF-Pro";}
if (resp == 0x4403) {return "MF Desire";}
return "Unknown";
}
MFRC522::Status ICACHE_FLASH_ATTR MFRC522::anticol(int level, UID* uid) {
debugMod1(NAME, "anticol(%d)", level);
// Prepare MFRC522
clearRegBits(Register::COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared.
uint8_t out[9];
uint8_t res[9];
uint8_t resLen;
Status s;
// send 2 bytes: 0x93 0x20 and expect 5 bytes of response : 4 bytes UID + 1 byte BCC checksum
// the first byte of the UID might be 0x88 to indicate that there are more requests needed
// to get the full UID
resLen = 5;
out[0] = (uint8_t)PICCComand::PICC_CMD_SEL_CL1;
out[1] = 0x20;
writeReg8(Register::BIT_FRAMING_REG, 0);
s = transceive(out, 2, res, &resLen);
// transceive failed?
if (s != Status::OK) {return s;}
// response is SN0 SN1 SN2 SN3 BCC where BCC = SN0^SN1^SN2^SN3 -> check this!
const uint8_t bcc = res[0] ^ res[1] ^ res[2] ^ res[3];
debugMod2(NAME, "check BCC: %02x == %02x ?", bcc, res[4]);
// NOTES
// if the received UID starts with SN0 = 0x88, then we have to read the next block (like UTF-8)
// if the received UID starts with SN0 = 0x08, it is a random number that will change every time
// adjust the UID-result accordingly
if (res[0] != 0x88) {uid->uidByte[uid->size] = res[0]; ++uid->size;}
{uid->uidByte[uid->size] = res[1]; ++uid->size;}
{uid->uidByte[uid->size] = res[2]; ++uid->size;}
{uid->uidByte[uid->size] = res[3]; ++uid->size;}
// go on with select
return select(level, res, uid);
}
MFRC522::Status ICACHE_FLASH_ATTR MFRC522::select(int level, uint8_t* uidPart, UID* uid) {
debugMod1(NAME, "select(%d)", level);
uint8_t cmd = (uint8_t) PICCComand::PICC_CMD_SEL_CL1; // TODO: depends on level
uint8_t bcc = uidPart[0] ^ uidPart[1] ^ uidPart[2] ^ uidPart[3];
uint8_t out[9] = {cmd, 0x70, uidPart[0], uidPart[1], uidPart[2], uidPart[3], bcc, 0x00, 0x00};
// replace 0x00 0x00 with the crc
calculateCRC(out, 7, &out[7]);
// transmit
uint8_t res[3];
uint8_t resLen = 3;
Status status = transceive(out, 9, res, &resLen);
// NOTES on SAK (selective ACK)
// result starts with 0x04? -> UID not complete, go on reading!
// result starts with 0x08? -> UID complete,
// this one also contains some details on the card we see
uint8_t SAK = res[0];
// another UID part needs to be read? (max: 3)
if (SAK == 0x04) { return anticol(level+1, uid); }
// done
return status;
}
/** is there a card present? */
bool ICACHE_FLASH_ATTR MFRC522::isCard() {
debugMod(NAME, "isCard()");
uint8_t bufferATQA[2] = {0x00, 0x00};
uint8_t bufferSize = sizeof(bufferATQA);
// Reset baud rates
writeReg8(Register::TX_MODE_REG, 0x00);
writeReg8(Register::RX_MODE_REG, 0x00);
// Reset ModWidthReg
writeReg8(Register::MOD_WIDTH_REG, 0x26);
// send REQA
Status res = requestA(bufferATQA, &bufferSize);
debugMod1(NAME, "isCard: %s", getStatusStr(res));
// card-type?
if (res == Status::OK) {
debugMod1(NAME, "card type: %s", getCardType(bufferATQA));
}
// done
return res == Status::OK;
// highest bit denotes whether reading or writing
void readFrom(uint8_t address) {
spi.writeByte(address | 0x80);
}
void writeTo(uint8_t address) {
spi.writeByte(address);
}
/** yes, card is present -> read it */
bool ICACHE_FLASH_ATTR MFRC522::select(UID* uidOut) {
debugMod(NAME, "select()");
ensureSane();
// reset UID
uidOut->size = 0;
Status res;
res = anticol(1, uidOut);
debugShow(uidOut->uidByte, 10);
return (res == Status::OK);
}
/** read the given 14-byte sector from the card */
void ICACHE_FLASH_ATTR MFRC522::read(uint8_t address) {
debugMod1(NAME, "read(%d)", address);
os_delay_us(1000*50);
clearRegBits(Register::COLL_REG, 0x80);
writeReg8(Register::BIT_FRAMING_REG, 0);
// READ command: 0x30 ADR CRC1 CRC2
uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_READ, address};
// calculate the CRC
calculateCRC(buffer, 2, &buffer[2]);
// response-buffer
uint8_t res[16];
uint8_t resLen = 16;
// send
transceive(buffer, 4, res, &resLen);
}
/** stop talking to the card */
void ICACHE_FLASH_ATTR MFRC522::halt() {
debugMod(NAME, "halt()");
// HALT command: 0x50 ADR CRC1 CRC2
uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_HLTA, 0x00};
// calculate the CRC
calculateCRC(buffer, 2, &buffer[2]);
// send
uint8_t resLen = 1;
transceive(buffer, 4, buffer, &resLen);
}
void ICACHE_FLASH_ATTR MFRC522::selftest() {
//os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG));
//writeReg8(Register::MODE_REG, 61);
//os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG));
uint8_t res[2];
// MUST BE 3c a2
uint8_t out2[9] = {0x93, 0x70, 0x12, 0x34, 0x56, 0x78, 0x08, 0x00, 0x00};
calculateCRC(out2, 7, res);
debugShow(res, 2);
}
bool ICACHE_FLASH_ATTR MFRC522::isAvailable() {
return readReg8(Register::MODE_REG) == 0x3D;
}
MFRC522::Status ICACHE_FLASH_ATTR MFRC522::piccREQAorWUPA(const PICCComand cmd, uint8_t* buffer, uint8_t* bufferSize) {
clearRegBits(Register::COLL_REG, 0x80);
uint8_t validBits = 7;
const uint8_t _cmd = (uint8_t) cmd;
const Status status = transceive(&_cmd, 1, buffer, bufferSize, &validBits);
if (status != Status::OK) {return status;}
//os_printf("response-size: %d, valid bits: %d\n", (int)*bufferSize, (int)validBits);
// ATQA must be 16 bits
if ((*bufferSize != 2) || (validBits != 0)) {
return Status::INVALID_ATQA;
}
return Status::OK;
};
}
/** convert status-code to status string */
const char* ICACHE_FLASH_ATTR MFRC522::getStatusStr(const Status s) const {
switch(s) {
case Status::OK: return "OK";
case Status::TIMEOUT_IRQ: return "TIMEOUT (IRQ)";
case Status::TIMEOUT_MANUAL: return "TIMEOUT (manual)";
case Status::TIMEOUT_CRC: return "TIMEOUT (crc)";
case Status::ERROR: return "ERROR";
case Status::RESPONSE_TOO_LONG: return "RESPONSE TOO LONG";
case Status::COLLISION: return "COLLISION";
case Status::INVALID: return "INVALID";
case Status::INVALID_ATQA: return "INVALID_ATQA";
case Status::INTERNAL_ERROR: return "INTERNAL_ERROR";
case Status::WRONG_CRC: return "WRONG_CRC";
case Status::WRONG_BCC: return "WRONG_BCC";
default: return "UNKNOWN STATUS";
}
}
void ICACHE_FLASH_ATTR MFRC522::antennaOn() {
uint8_t val = readReg8(Register::TX_CONTROL_REG);
if ((val & 0x03) != 0x03) {
writeReg8(Register::TX_CONTROL_REG, val | 0x03);
}
val = readReg8(Register::TX_CONTROL_REG);
}
#endif // MFRC522_H

View File

@@ -24,7 +24,7 @@
#define SPI_FAST
class SoftSPI {
namespace spi {
// MTDI GPIO12 MISO (DIN) D6
// MTCK GPIO13 MOSI (DOUT) D7
@@ -37,46 +37,102 @@ class SoftSPI {
// #define BIT(nr) (1 << 0)
public:
//public:
SoftSPI() {
// NOT CALLED!
// CALL INIT() manually!
// SoftSPI() {
// // NOT CALLED!
// // CALL INIT() manually!
// }
// THINGS THAT SHOULD RUN FAST AND THUS BE KEPT IN RAM
static inline void csLo() { SPI_CS_LO; } // D8
static inline void csHi() { SPI_CS_HI; } // D8
static inline void clkLo() { SPI_CLK_LO; } // D5
static inline void clkHi() { SPI_CLK_HI; } // D5
static inline bool getMISO() {return SPI_MISO_READ;} // D6
#ifdef SPI_FAST
static inline void wait() {
__asm__ __volatile__("nop");
}
void init() const {
SPI_MISO_INPUT; SPI_MISO_NO_PULLUP; // D6: MISO
SPI_MOSI_OUTPUT; // D7: MOSI
SPI_CLK_OUTPUT; // D5: CLK
SPI_CS_OUTPUT; // D8: CS
static inline void waitLong() {
os_delay_us(1);
}
#else
static inline void wait() {
os_delay_us(2);
}
static inline void waitLong() {
os_delay_us(50);
}
#endif
inline void chipSelect() const {
static void chipSelect() {
clkLo();
wait();
csLo();
waitLong();
}
inline void chipDeselect() const {
static void chipDeselect() {
clkLo();
wait();
csHi();
wait();
}
inline void csLo() const { SPI_CS_LO; } // D8
inline void csHi() const { SPI_CS_HI; } // D8
static inline uint8_t readWriteBit(const bool out) {
if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;}
wait();
clkHi();
wait();
const bool inp = getMISO();
wait();
clkLo();
wait();
return (inp) ? 1 : 0;
}
inline void clkLo() const { SPI_CLK_LO; } // D5
inline void clkHi() const { SPI_CLK_HI; } // D5
/** write one bit to the bus */
static inline void writeBit(const bool out) {
if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;}
wait();
clkHi();
wait();
clkLo();
wait();
}
inline bool getMISO() const {return SPI_MISO_READ;} // D6
/** read one bit from the bus */
static inline uint8_t readBit() {
clkHi();
wait();
const bool val = getMISO();
wait();
clkLo();
wait();
return (val) ? 1 : 0;
}
// THINGS THAT MAY RUN SLOWER FROM THE FLASH
static void ICACHE_FLASH_ATTR init() {
SPI_MISO_INPUT; SPI_MISO_NO_PULLUP; // D6: MISO
SPI_MOSI_OUTPUT; // D7: MOSI
SPI_CLK_OUTPUT; // D5: CLK
SPI_CS_OUTPUT; // D8: CS
}
/** read 16 bits */
inline uint16_t readWord() const {
static uint16_t ICACHE_FLASH_ATTR readWord() {
return
(readBit() << 15) |
(readBit() << 14) |
@@ -97,7 +153,7 @@ public:
}
/** read 8 bits */
inline uint8_t readByte() const {
static uint8_t ICACHE_FLASH_ATTR readByte() {
return
(readBit() << 7) |
(readBit() << 6) |
@@ -109,7 +165,9 @@ public:
(readBit() << 0);
}
inline void writeWord(const uint16_t word) const {
static void ICACHE_FLASH_ATTR writeWord(const uint16_t word) {
writeBit(word & BIT(15));
writeBit(word & BIT(14));
writeBit(word & BIT(13));
@@ -128,7 +186,7 @@ public:
writeBit(word & BIT( 0));
}
inline void writeByte(const uint8_t byte) const {
static void ICACHE_FLASH_ATTR writeByte(const uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
@@ -139,7 +197,7 @@ public:
writeBit(byte & BIT( 0));
}
inline uint16 readWriteWord(const uint16_t word) const {
static uint16 ICACHE_FLASH_ATTR readWriteWord(const uint16_t word) {
return
(readWriteBit(word & BIT(15)) << 15) |
(readWriteBit(word & BIT(14)) << 14) |
@@ -159,7 +217,7 @@ public:
(readWriteBit(word & BIT( 0)) << 0);
}
inline uint8 readWriteByte(const uint8_t byte) const {
static uint8 ICACHE_FLASH_ATTR readWriteByte(const uint8_t byte) {
return
(readWriteBit(byte & BIT( 7)) << 7) |
(readWriteBit(byte & BIT( 6)) << 6) |
@@ -171,62 +229,12 @@ public:
(readWriteBit(byte & BIT( 0)) << 0);
}
private:
}
inline uint8_t readWriteBit(const bool out) const {
if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;}
wait();
clkHi();
wait();
const bool inp = getMISO();
wait();
clkLo();
wait();
return (inp) ? 1 : 0;
}
// create an instance ONCE
//SoftSPI spi;
//using spi = SoftSPI;
/** write one bit to the bus */
inline void writeBit(const bool out) const {
if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;}
wait();
clkHi();
wait();
clkLo();
wait();
}
/** read one bit from the bus */
inline uint8_t readBit() const {
clkHi();
wait();
const bool val = getMISO();
wait();
clkLo();
wait();
return (val) ? 1 : 0;
}
#ifdef SPI_FAST
inline void wait() const {
__asm__ __volatile__("nop");
}
inline void waitLong() const {
os_delay_us(1);
}
#else
inline void wait() const {
os_delay_us(2);
}
inline void waitLong() const {
os_delay_us(50);
}
#endif
};
#endif // SOFTSPI_H