diff --git a/CompileTime.h b/CompileTime.h new file mode 100644 index 0000000..7f8d1b2 --- /dev/null +++ b/CompileTime.h @@ -0,0 +1,60 @@ +#define COMPUTE_BUILD_YEAR ( \ + (__DATE__[ 7] - '0') * 1000 + \ + (__DATE__[ 8] - '0') * 100 + \ + (__DATE__[ 9] - '0') * 10 + \ + (__DATE__[10] - '0') \ +) + + +#define COMPUTE_BUILD_DAY ( \ + ((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \ + (__DATE__[5] - '0') \ +) + + +#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n') +#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F') +#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r') +#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p') +#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y') +#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n') +#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l') +#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u') +#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S') +#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O') +#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N') +#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D') + + +#define COMPUTE_BUILD_MONTH ( \ + (BUILD_MONTH_IS_JAN) ? 1 : \ + (BUILD_MONTH_IS_FEB) ? 2 : \ + (BUILD_MONTH_IS_MAR) ? 3 : \ + (BUILD_MONTH_IS_APR) ? 4 : \ + (BUILD_MONTH_IS_MAY) ? 5 : \ + (BUILD_MONTH_IS_JUN) ? 6 : \ + (BUILD_MONTH_IS_JUL) ? 7 : \ + (BUILD_MONTH_IS_AUG) ? 8 : \ + (BUILD_MONTH_IS_SEP) ? 9 : \ + (BUILD_MONTH_IS_OCT) ? 10 : \ + (BUILD_MONTH_IS_NOV) ? 11 : \ + (BUILD_MONTH_IS_DEC) ? 12 : \ + /* error default */ 99 \ +) + +#define COMPUTE_BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0') +#define COMPUTE_BUILD_MIN ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0') +#define COMPUTE_BUILD_SEC ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0') + + +#define BUILD_DATE_IS_BAD (__DATE__[0] == '?') + +#define BUILD_YEAR ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_YEAR) +#define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH) +#define BUILD_DAY ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY) + +#define BUILD_TIME_IS_BAD (__TIME__[0] == '?') + +#define BUILD_HOUR ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_HOUR) +#define BUILD_MIN ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_MIN) +#define BUILD_SEC ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_SEC) diff --git a/Debug.h b/Debug.h index ebc9338..d781631 100644 --- a/Debug.h +++ b/Debug.h @@ -1,21 +1,54 @@ #ifndef DEBUG_H #define DEBUG_H -#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/c++.h b/c++.h index 52c4af3..cf8b428 100644 --- a/c++.h +++ b/c++.h @@ -4,7 +4,7 @@ #define FALSE false typedef void (*int_handler_t)(void*); - +/* void *pvPortMalloc(size_t xWantedSize, const char* file, int line) __attribute__((malloc, alloc_size(1))); void *pvPortRealloc(void* ptr, size_t xWantedSize, const char* file, int line) __attribute__((alloc_size(2))); void vPortFree(void *ptr, const char* file, int line); @@ -29,7 +29,6 @@ void ets_install_putc1(void* routine); void uart_div_modify(int no, int freq); //STATUS uart_tx_one_char(uint8_t uart, uint8_t TxChar); - void ets_isr_mask(int intr); void ets_isr_unmask(int intr); void ets_isr_attach(int intr, int_handler_t handler, void *arg); @@ -54,7 +53,7 @@ typedef void (*int_handler_t)(void*); #define ETS_CCOMPARE0_INUM 6 #define ETS_SOFT_INUM 7 #define ETS_WDT_INUM 8 -#define ETS_FRC_TIMER1_INUM 9 /* use edge*/ +#define ETS_FRC_TIMER1_INUM 9 // use edge #define ETS_INTR_LOCK() \ ets_intr_lock() @@ -99,18 +98,18 @@ inline uint32_t ETS_INTR_PENDING(void) #define ETS_CCOMPARE0_DISABLE() \ ETS_INTR_DISABLE(ETS_CCOMPARE0_INUM) -/* + //#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \ // ets_isr_attach(ETS_FRC_TIMER1_INUM, (int_handler_t)(func), (void *)(arg)) -*/ + #define ETS_FRC_TIMER1_NMI_INTR_ATTACH(func) \ NmiTimSetFunc(func) -/* + //#define ETS_GPIO_INTR_ATTACH(func, arg) \ // ets_isr_attach(ETS_GPIO_INUM, (int_handler_t)(func), (void *)(arg)) -*/ + #define ETS_GPIO_INTR_ENABLE() \ ETS_INTR_ENABLE(ETS_GPIO_INUM) @@ -118,10 +117,10 @@ inline uint32_t ETS_INTR_PENDING(void) #define ETS_GPIO_INTR_DISABLE() \ ETS_INTR_DISABLE(ETS_GPIO_INUM) -/* + //#define ETS_UART_INTR_ATTACH(func, arg) \ // ets_isr_attach(ETS_UART_INUM, (int_handler_t)(func), (void *)(arg)) -*/ + #define ETS_UART_INTR_ENABLE() \ ETS_INTR_ENABLE(ETS_UART_INUM) @@ -135,10 +134,10 @@ inline uint32_t ETS_INTR_PENDING(void) #define ETS_FRC1_INTR_DISABLE() \ ETS_INTR_DISABLE(ETS_FRC_TIMER1_INUM) -/* + //#define ETS_SPI_INTR_ATTACH(func, arg) \ // ets_isr_attach(ETS_SPI_INUM, (int_handler_t)(func), (void *)(arg)) -*/ + #define ETS_SPI_INTR_ENABLE() \ ETS_INTR_ENABLE(ETS_SPI_INUM) @@ -156,10 +155,9 @@ inline uint32_t ETS_INTR_PENDING(void) #define ETS_SLC_INTR_DISABLE() \ ETS_INTR_DISABLE(ETS_SLC_INUM) -/* + //#define ETS_SDIO_INTR_ATTACH(func, arg) \ // ets_isr_attach(ETS_SDIO_INUM, (int_handler_t)(func), (void *)(arg)) -*/ #define ETS_SDIO_INTR_ENABLE() \ ETS_INTR_ENABLE(ETS_SDIO_INUM) @@ -185,7 +183,7 @@ extern void ets_delay_us(uint32_t us); extern int os_printf_plus(const char * format, ...) __attribute__ ((format (printf, 1, 2))); - +*/ /* bool wifi_station_get_config(struct station_config *config); diff --git a/ext/rfid/MFRC522.cpp b/ext/rfid/MFRC522.cpp new file mode 100644 index 0000000..0dcdee6 --- /dev/null +++ b/ext/rfid/MFRC522.cpp @@ -0,0 +1,30 @@ +#include "MFRC522.h" + +void 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); + + +} diff --git a/ext/rfid/MFRC522.h b/ext/rfid/MFRC522.h index b3577b1..df2ad69 100644 --- a/ext/rfid/MFRC522.h +++ b/ext/rfid/MFRC522.h @@ -1,40 +1,114 @@ #ifndef MFRC522_H #define MFRC522_H +#include "../../Debug.h" #include "../../io/SoftSPI.h" + /** * RFID reader based on MFRC522 * attached via SPI * * http://www.nxp.com/documents/data_sheet/MFRC522.pdf * + * http://www.gorferay.com/initialization-and-anticollision-iso-iec-14433-3/ + * https://community.nxp.com/thread/437908 + * https://www.nxp.com/docs/en/application-note/AN10833.pdf + * https://www.slideshare.net/contactsarbjeet/architecture-development-of-nfc-applications + * http://www.gorferay.com/mifare-and-handling-of-uids/ + * http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20MIFARE%20Classic/MIFARE%20Classic%20clones/ISSI_IS23SC4439_User_Manual.pdf */ class MFRC522 { - struct OP { - uint8_t addr : 7; // bits 0-6 - uint8_t rw : 1; // bit 7 [MSB] 1 = read, 0 = write +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. }; +private: + enum class Register { - COMMAND_REG = 0x01, - INTERRUPTS_REG = 0x02, - ERROR_REG = 0x06, - STATUS1_REG = 0x07, - STATUS2_REG = 0x08, - FIFI_DATA_REG = 0x09, // access fifo buffer - FIFO_SIZE_REG = 0x0A, // number of available fifo data - MOD_REG = 0x11, - DEMOG_REG = 0x19, + COMMAND_REG = 0x01 << 1, + INTERRUPTS_REG = 0x02 << 1, + COM_IRQ_REG = 0x04 << 1, + DIV_IRQ_REG = 0x05 << 1, + ERROR_REG = 0x06 << 1, + STATUS1_REG = 0x07 << 1, + STATUS2_REG = 0x08 << 1, + FIFO_DATA_REG = 0x09 << 1, // access fifo buffer + FIFO_LEVEL_REG = 0x0A << 1, // number of available fifo data + CONTROL_REG = 0x0C << 1, + BIT_FRAMING_REG = 0x0D << 1, + COLL_REG = 0x0E << 1, + MODE_REG = 0x11 << 1, + TX_MODE_REG = 0x12 << 1, + RX_MODE_REG = 0x13 << 1, + TX_CONTROL_REG = 0x14 << 1, + TX_AUTO_REG = 0x15 << 1, + DEMOG_REG = 0x19 << 1, - TEST_SEL_1_REG = 0x31, - TEST_SEL_2_REG = 0x32, - VERSION_REG = 0x37, // software version + CRC_RES_H = 0x21 << 1, + CRC_RES_L = 0x22 << 1, + MOD_WIDTH_REG = 0x24 << 1, + T_MODE_REG = 0x2A << 1, + T_PRESCALER_REG = 0x2B << 1, + T_RELOAD_REG_H = 0x2C << 1, + T_RELOAD_REG_L = 0x2D << 1, + + TEST_SEL_1_REG = 0x31 << 1, + TEST_SEL_2_REG = 0x32 << 1, + VERSION_REG = 0x37 << 1, // software version }; + enum class Command { + IDLE = 0x00, + MEM = 0x01, + GEN_RANDOM_ID = 0x02, + CALC_CRC = 0x03, + TRANSMIT = 0x04, + NO_CMD_CHANGE = 0x07, + RECEIVE = 0x08, + TRANSCEIVE = 0x0C, + MF_AUTHENT = 0x0E, + SOFT_RESET = 0x0F, + }; + + enum class PICCComand { + REQA = 0x26, + PICC_CMD_READ = 0x30, + PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. + PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 + PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 + PICC_CMD_HLTA = 0x50, // HaLT command, Typ + }; + + enum class Status { + OK, + TIMEOUT_IRQ, + TIMEOUT_MANUAL, + TIMEOUT_CRC, + ERROR, + RESPONSE_TOO_LONG, + COLLISION, + INVALID, + INVALID_ATQA, + INTERNAL_ERROR, + WRONG_CRC, + 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; @@ -55,20 +129,571 @@ class MFRC522 { private: - SoftSPI spi; + public: - MFRC522() { - ; - } - /** init */ - void init() { - spi.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 } + 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); + + /** 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); + 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/IO.h b/io/IO.h index e74352b..8813ea4 100644 --- a/io/IO.h +++ b/io/IO.h @@ -72,6 +72,8 @@ public: #elif PLATFORM == NODE_MCU GPIO16_OUTPUT_SET; if (on) {GPIO16_H;} else {GPIO16_L;} + GPIO2_OUTPUT_SET; + if (on) {GPIO2_H;} else {GPIO2_L;} #else #error "NO PLATFORM" #endif @@ -79,6 +81,10 @@ public: } + + + + }; #endif // IO_H diff --git a/io/SoftSPI.h b/io/SoftSPI.h index 6dcb47d..acc68c2 100644 --- a/io/SoftSPI.h +++ b/io/SoftSPI.h @@ -4,7 +4,27 @@ //#include "IO.h" #include "fastGPIO.h" -class SoftSPI { +// wemos D1 mini +#define SPI_CS_OUTPUT GPIO15_OUTPUT_SET +#define SPI_MOSI_OUTPUT GPIO13_OUTPUT_SET +#define SPI_MISO_INPUT GPIO12_INPUT_SET +#define SPI_MISO_NO_PULLUP GPIO12_INPUT_PULLUP_UNSET +#define SPI_CLK_OUTPUT GPIO14_OUTPUT_SET + +#define SPI_CS_LO GPIO15_L +#define SPI_CS_HI GPIO15_H + +#define SPI_CLK_LO GPIO14_L +#define SPI_CLK_HI GPIO14_H + +#define SPI_MOSI_LO GPIO13_L +#define SPI_MOSI_HI GPIO13_H + +#define SPI_MISO_READ GPIO12_IN + +#define SPI_FAST + +namespace spi { // MTDI GPIO12 MISO (DIN) D6 // MTCK GPIO13 MOSI (DOUT) D7 @@ -17,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 { - GPIO12_INPUT_SET; GPIO12_INPUT_PULLUP_UNSET; // D6: MISO - GPIO13_OUTPUT_SET; // D7: MOSI - GPIO14_OUTPUT_SET; // D5: CLK - GPIO15_OUTPUT_SET; // 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 { GPIO15_L; } // D8 - inline void csHi() const { GPIO15_H; } // 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 clkHi() const { GPIO14_H; } // D5 - inline void clkLo() const { GPIO14_L; } // 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 GPIO12_IN;} // 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) | @@ -77,7 +153,7 @@ public: } /** read 8 bits */ - inline uint16_t readByte() const { + static uint8_t ICACHE_FLASH_ATTR readByte() { return (readBit() << 7) | (readBit() << 6) | @@ -89,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)); @@ -108,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)); @@ -119,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) | @@ -139,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) | @@ -151,49 +229,12 @@ public: (readWriteBit(byte & BIT( 0)) << 0); } - -private: +} - inline uint8_t readWriteBit(const bool out) const { - if(out) {GPIO13_H;} else {GPIO13_L;} - wait(); - clkHi(); - wait(); - const bool inp = getMISO(); - wait(); - clkLo(); - 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) {GPIO13_H;} else {GPIO13_L;} - wait(); - clkHi(); - wait(); - clkLo(); - } - - /** read one bit from the bus */ - inline uint8_t readBit() const { - clkHi(); - wait(); - const bool val = getMISO(); - wait(); - clkLo(); - wait(); - return (val) ? 1 : 0; - } - - inline void wait() const { - __asm__ __volatile__("nop"); - } - - inline void waitLong() const { - os_delay_us(1); - } - -}; #endif // SOFTSPI_H diff --git a/net/Promiscuous.h b/net/Promiscuous.h index 9f6435c..c318542 100644 --- a/net/Promiscuous.h +++ b/net/Promiscuous.h @@ -25,7 +25,7 @@ struct RxControl { unsigned rxend_state:8; unsigned ampdu_cnt:8; unsigned channel:4; //which channel this packet in. - unsigned:12; + unsigned unknown3:12; }; struct LenSeq{