Merge branch 'master' of https://git.frank-ebner.de/kazu/ESP8266lib
This commit is contained in:
60
CompileTime.h
Normal file
60
CompileTime.h
Normal file
@@ -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)
|
||||
43
Debug.h
43
Debug.h
@@ -1,21 +1,54 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#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 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
|
||||
|
||||
|
||||
26
c++.h
26
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);
|
||||
|
||||
30
ext/rfid/MFRC522.cpp
Normal file
30
ext/rfid/MFRC522.cpp
Normal file
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
6
io/IO.h
6
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
|
||||
|
||||
173
io/SoftSPI.h
173
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
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user