From 72ed1a9125e28e7c0478e111181834c91606a47a Mon Sep 17 00:00:00 2001 From: kazu Date: Sat, 16 Sep 2017 19:11:17 +0200 Subject: [PATCH] worked on RFID worked on SPI refactoring/changes to reduce RAM section size (.text) --- Debug.h | 43 ++- ext/rfid/MFRC522.h | 909 +++++++++++++++++++++++---------------------- io/SoftSPI.h | 166 +++++---- 3 files changed, 597 insertions(+), 521 deletions(-) diff --git a/Debug.h b/Debug.h index ebc9338..33ec14e 100644 --- a/Debug.h +++ b/Debug.h @@ -3,19 +3,54 @@ #define DEBUG +#include + +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 IF_DEBUG(a) a + #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 diff --git a/ext/rfid/MFRC522.h b/ext/rfid/MFRC522.h index 75b30a5..df2ad69 100644 --- a/ext/rfid/MFRC522.h +++ b/ext/rfid/MFRC522.h @@ -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,152 +129,30 @@ class MFRC522 { private: - SoftSPI spi; + public: - MFRC522() { - - } - /** init */ - void init() { - os_printf("init MFRC522\n"); - spi.init(); + void init(); - 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(); - - // Reset baud rates - writeReg8(Register::TX_MODE_REG, 0x00); - writeReg8(Register::RX_MODE_REG, 0x00); - // Reset ModWidthReg - writeReg8(Register::MOD_WIDTH_REG, 0x26); - - writeReg8(Register::T_MODE_REG, 0x80); - writeReg8(Register::T_PRESCALER_REG, 0xA9); - writeReg8(Register::T_RELOAD_REG_L, 0xE8); - writeReg8(Register::T_RELOAD_REG_H, 0x03); - writeReg8(Register::TX_AUTO_REG, 0x40); - writeReg8(Register::MODE_REG, 0x3D); // very important. set CRC preset to 0x6363 by setting bit 0 and clearing bit 1 in MODE_REG - - antennaOn(); - - writeReg8(Register::COMMAND_REG, Command::IDLE); - - } - - - - void getStatus() { - - uint8_t s1 = readReg8(Register::STATUS1_REG); - uint8_t s2 = readReg8(Register::STATUS2_REG); - - os_printf("s1: %d, s2: %d \n", (int)s1, (int)s2); - - } + /** check whether a RFID-reader is present or not */ + bool isAvailable(); /** 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; - - } + bool isCard(); /** 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); - - } + bool select(UID* uidOut); /** 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); - - } + void read(uint8_t address); /** stop talking to the card */ - void halt() { + 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); - - } + /** perform selftest */ + void selftest(); private: @@ -282,128 +160,22 @@ private: 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); - } + void 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) { - - 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"); - } + 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 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"; - } + const char* getCardType(const uint8_t* atqa) const; - 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; - - } + Status anticol(int level, UID* uid); + Status select(int level, uint8_t* uidPart, UID* uid); /** @@ -412,45 +184,14 @@ private: * 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 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; - } - - } - - os_printf("CRC: TIMEOUT!!!\n"); - return Status::TIMEOUT_CRC; - - } 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); + debugMod1(NAME, "transceive %d bytes", 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); + debugMod2(NAME, "transceive: %s, returned %d bytes", getStatusStr(s), *dstDataLen); debugShow(dstData, *dstDataLen); return s; } @@ -458,11 +199,11 @@ private: 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"); + 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) { - os_printf("!!!!!!!!!!!!!!!!!failed to fill fifo\n"); + debugMod(NAME, "!!!!!!!!!!!!!!!!!failed to fill fifo\n"); } } @@ -472,94 +213,7 @@ private: 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) { - - const uint8_t txLastBits = validBits ? *validBits : 0; - const uint8_t bitFraming = (rxAlign << 4) + txLastBits; - - //os_printf("-- txLastBits: %d, bitFraming: %d \n", txLastBits, bitFraming); - - ensureSane(); - writeReg8(Register::COM_IRQ_REG, 0x7f); // clear interrupt flags - fillFIFO(srcData, srcDataLen); - writeReg8(Register::BIT_FRAMING_REG, bitFraming); - writeReg8(Register::COMMAND_REG, (int) cmd); - - if (cmd == Command::TRANSCEIVE) { - //os_printf("-- start seding...\n"); - setRegBits(Register::BIT_FRAMING_REG, 0x80); // startSend = 1 - } - - //const uint8_t _errReg = readReg8(Register::ERROR_REG); - //os_printf("cur err reg: %d\n", (int)_errReg); - - int maxRuns = 10; - while(true) { - - const uint8_t res = readReg8(Register::COM_IRQ_REG); - //os_printf("irq reg: %d\n", res); - - // received the interrupt we are waiting for? - if (res & waitIRQ) { - os_printf("got needed interrupt\n"); break; - } - - if (res & 0x01) { - return Status::TIMEOUT_IRQ; - } - - if (--maxRuns == 0) { - os_printf("picc() Timeout\n"); - return Status::TIMEOUT_MANUAL; - } - - os_delay_us(1000*5); - - } - - // buffer overflow? - const uint8_t errReg = readReg8(Register::ERROR_REG); - if (errReg & 0x13) {return Status::ERROR;} - - // caller wants to read a response? - if (dstData && dstLen) { - - const uint8_t n = readReg8(Register::FIFO_LEVEL_REG); - 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; } - - // read response - *dstLen = n; - readReg(Register::FIFO_DATA_REG, dstData, n, rxAlign); - - uint8_t _validBits = readReg8(Register::CONTROL_REG) & 0x07; - if (validBits) { - *validBits = _validBits; - } - - #ifdef WITH_DEBUG - // ensure fifo is now empty - if (readReg8(Register::FIFO_LEVEL_REG) != 0) { - os_printf("fifo not empty!\n"); - return Status::INTERNAL_ERROR; - } - #endif - - } - - if (errReg & 0x08) { - return Status::COLLISION; - } - - // TODO CRC - - return Status::OK; - - } - - + 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: @@ -569,12 +223,10 @@ private: } void writeReg8(const Register reg, const uint8_t value) { - spi.chipSelect(); + 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); + spi::writeByte(value); + spi::chipDeselect(); } void setRegBits(const Register reg, const uint8_t mask) { @@ -588,79 +240,460 @@ private: } 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(); + spi::chipSelect(); writeTo((int)reg); for (int i = 0; i < len; ++i){ - spi.writeByte(data[i]); + spi::writeByte(data[i]); } - spi.chipDeselect(); + spi::chipDeselect(); } uint8_t readReg8(const Register reg) { - spi.chipSelect(); + spi::chipSelect(); readFrom((int)reg); - const uint8_t res = spi.readByte(); - spi.chipDeselect(); + 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); - } - - } - - // read last byte and stop reading - dst[i] = spi.readWriteByte(0); - - spi.chipDeselect(); - - } + 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); + 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); + writeReg8(Register::RX_MODE_REG, 0x00); + // Reset ModWidthReg + writeReg8(Register::MOD_WIDTH_REG, 0x26); + + writeReg8(Register::T_MODE_REG, 0x80); + writeReg8(Register::T_PRESCALER_REG, 0xA9); + writeReg8(Register::T_RELOAD_REG_L, 0xE8); + writeReg8(Register::T_RELOAD_REG_H, 0x03); + writeReg8(Register::TX_AUTO_REG, 0x40); + writeReg8(Register::MODE_REG, 0x3D); // very important. set CRC preset to 0x6363 by setting bit 0 and clearing bit 1 in MODE_REG + + antennaOn(); + + 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(); + + // 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); + } + + } + + // read last byte and stop reading + dst[i] = spi::readWriteByte(0); + + spi::chipDeselect(); + +} + + +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; + + //os_printf("-- txLastBits: %d, bitFraming: %d \n", txLastBits, bitFraming); + + ensureSane(); + writeReg8(Register::COM_IRQ_REG, 0x7f); // clear interrupt flags + fillFIFO(srcData, srcDataLen); + writeReg8(Register::BIT_FRAMING_REG, bitFraming); + writeReg8(Register::COMMAND_REG, (int) cmd); + + if (cmd == Command::TRANSCEIVE) { + //os_printf("-- start seding...\n"); + setRegBits(Register::BIT_FRAMING_REG, 0x80); // startSend = 1 + } + + //const uint8_t _errReg = readReg8(Register::ERROR_REG); + //os_printf("cur err reg: %d\n", (int)_errReg); + + int maxRuns = 10; + while(true) { + + const uint8_t res = readReg8(Register::COM_IRQ_REG); + //os_printf("irq reg: %d\n", res); + + // received the interrupt we are waiting for? + if (res & waitIRQ) { + //debugMod(NAME, "got needed interrupt -> done"); + //os_printf("got needed interrupt\n"); + break; + } + + if (res & 0x01) { + return Status::TIMEOUT_IRQ; + } + + if (--maxRuns == 0) { + //debugMod(NAME, "TIMEOUT"); + //os_printf("picc() Timeout\n"); + return Status::TIMEOUT_MANUAL; + } + + os_delay_us(1000*5); + + } + + // buffer overflow? + const uint8_t errReg = readReg8(Register::ERROR_REG); + if (errReg & 0x13) {return Status::ERROR;} + + // caller wants to read a response? + if (dstData && dstLen) { + + const uint8_t n = readReg8(Register::FIFO_LEVEL_REG); + 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; } + + // read response + *dstLen = n; + readReg(Register::FIFO_DATA_REG, dstData, n, rxAlign); + + uint8_t _validBits = readReg8(Register::CONTROL_REG) & 0x07; + if (validBits) { + *validBits = _validBits; + } + + #ifdef WITH_DEBUG + // ensure fifo is now empty + if (readReg8(Register::FIFO_LEVEL_REG) != 0) { + debugMod(NAME, "!! FIFO is not empty though it should be!"); + return Status::INTERNAL_ERROR; + } + #endif + + } + + if (errReg & 0x08) { + return Status::COLLISION; + } + + // TODO CRC + + 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); + + 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 + for (int i = 0; i < 25; ++i) { + + os_delay_us(1000*1); + + // wait for CRCIRq to be set + 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); + return Status::OK; + } + + } + + debugMod(NAME, "CRC TIMEOUT"); + return Status::TIMEOUT_CRC; + +} + +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; + +} + +/** 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 diff --git a/io/SoftSPI.h b/io/SoftSPI.h index 7ab63a9..acc68c2 100644 --- a/io/SoftSPI.h +++ b/io/SoftSPI.h @@ -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