diff --git a/esphome/components/rc522/rc522.cpp b/esphome/components/rc522/rc522.cpp index 8182c1e8c9..ced58760ad 100644 --- a/esphome/components/rc522/rc522.cpp +++ b/esphome/components/rc522/rc522.cpp @@ -7,22 +7,38 @@ namespace esphome { namespace rc522 { +static const uint8_t WAIT_I_RQ = 0x30; // RxIRq and IdleIRq + static const char *TAG = "rc522"; static const uint8_t RESET_COUNT = 5; -void format_uid(char *buf, const uint8_t *uid, uint8_t uid_length) { +std::string format_buffer(uint8_t *b, uint8_t len) { + char buf[32]; int offset = 0; - for (uint8_t i = 0; i < uid_length; i++) { + for (uint8_t i = 0; i < len; i++) { const char *format = "%02X"; - if (i + 1 < uid_length) + if (i + 1 < len) + format = "%02X-"; + offset += sprintf(buf + offset, format, b[i]); + } + return std::string(buf); +} + +std::string format_uid(std::vector &uid) { + char buf[32]; + int offset = 0; + for (uint8_t i = 0; i < uid.size(); i++) { + const char *format = "%02X"; + if (i + 1 < uid.size()) format = "%02X-"; offset += sprintf(buf + offset, format, uid[i]); } + return std::string(buf); } void RC522::setup() { - initialize_pending_ = true; + state_ = STATE_SETUP; // Pull device out of power down / reset state. // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. @@ -48,7 +64,7 @@ void RC522::setup() { } void RC522::initialize_() { - // Per originall code, wait 50 ms + // Per original code, wait 50 ms if (millis() - reset_timeout_ < 50) return; @@ -75,9 +91,8 @@ void RC522::initialize_() { pcd_write_register(TX_ASK_REG, 0x40); pcd_write_register(MODE_REG, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC // command to 0x6363 (ISO 14443-3 part 6.2.4) - pcd_antenna_on_(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) - initialize_pending_ = false; + state_ = STATE_INIT; } void RC522::dump_config() { @@ -99,76 +114,163 @@ void RC522::dump_config() { } } +void RC522::update() { + if (state_ == STATE_INIT) { + pcd_antenna_on_(); + pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. + buffer_[0] = PICC_CMD_REQA; + pcd_transceive_data_(1); + state_ = STATE_PICC_REQUEST_A; + } else { + ESP_LOGW(TAG, "Communication takes longer than update interval: %d", state_); + } +} + void RC522::loop() { // First check reset is needed if (reset_count_ > 0) { pcd_reset_(); return; } - if (initialize_pending_) { + if (state_ == STATE_SETUP) { initialize_(); return; } - if (millis() - update_wait_ < this->update_interval_) - return; + StatusCode status = STATUS_ERROR; // For lint passing. TODO: refactor this + if (awaiting_comm_) { + if (state_ == STATE_SELECT_SERIAL_DONE) + status = await_crc_(); + else + status = await_transceive_(); - auto status = picc_is_new_card_present_(); - - static StatusCode LAST_STATUS = StatusCode::STATUS_OK; - - if (status != LAST_STATUS) { - ESP_LOGD(TAG, "Status is now: %d", status); - LAST_STATUS = status; - } - - if (status == STATUS_ERROR) // No card - { - // ESP_LOGE(TAG, "Error"); - // mark_failed(); - return; - } - - if (status != STATUS_OK) // We can receive STATUS_TIMEOUT when no card, or unexpected status. - return; - - // Try process card - if (!picc_read_card_serial_()) { - ESP_LOGW(TAG, "Requesting tag read failed!"); - return; - }; - - if (uid_.size < 4) { - return; - ESP_LOGW(TAG, "Read serial size: %d", uid_.size); - } - - update_wait_ = millis(); - - bool report = true; - // 1. Go through all triggers - for (auto *trigger : this->triggers_) - trigger->process(uid_.uiduint8_t, uid_.size); - - // 2. Find a binary sensor - for (auto *tag : this->binary_sensors_) { - if (tag->process(uid_.uiduint8_t, uid_.size)) { - // 2.1 if found, do not dump - report = false; + if (status == STATUS_WAITING) { + return; } + awaiting_comm_ = false; + ESP_LOGV(TAG, "finished communication status: %d, state: %d", status, state_); } - if (report) { - char buf[32]; - format_uid(buf, uid_.uiduint8_t, uid_.size); - ESP_LOGD(TAG, "Found new tag '%s'", buf); - } -} + switch (state_) { + case STATE_PICC_REQUEST_A: { + if (status == STATUS_TIMEOUT) { // no tag present + for (auto *obj : this->binary_sensors_) + obj->on_scan_end(); // reset the binary sensors + ESP_LOGV(TAG, "CMD_REQA -> TIMEOUT (no tag present) %d", status); + state_ = STATE_DONE; + } else if (status != STATUS_OK) { + ESP_LOGW(TAG, "CMD_REQA -> Not OK %d", status); + state_ = STATE_DONE; + } else if (back_length_ != 2) { // || *valid_bits_ != 0) { // ATQA must be exactly 16 bits. + ESP_LOGW(TAG, "CMD_REQA -> OK, but unexpacted back_length_ of %d", back_length_); + state_ = STATE_DONE; + } else { + state_ = STATE_READ_SERIAL; + } + if (state_ == STATE_DONE) { + // Don't wait another loop cycle + pcd_antenna_off_(); + } + break; + } + case STATE_READ_SERIAL: { + ESP_LOGV(TAG, "STATE_READ_SERIAL (%d)", status); + switch (uid_idx_) { + case 0: + buffer_[0] = PICC_CMD_SEL_CL1; + break; + case 3: + buffer_[0] = PICC_CMD_SEL_CL2; + break; + case 6: + buffer_[0] = PICC_CMD_SEL_CL3; + break; + default: + ESP_LOGE(TAG, "uid_idx_ invalid, uid_idx_ = %d", uid_idx_); + state_ = STATE_DONE; + } + buffer_[1] = 32; + pcd_transceive_data_(2); + state_ = STATE_SELECT_SERIAL; + break; + } + case STATE_SELECT_SERIAL: { + buffer_[1] = 0x70; // select + // todo: set CRC + buffer_[6] = buffer_[2] ^ buffer_[3] ^ buffer_[4] ^ buffer_[5]; + pcd_calculate_crc_(buffer_, 7); + state_ = STATE_SELECT_SERIAL_DONE; + break; + } + case STATE_SELECT_SERIAL_DONE: { + send_len_ = 6; + pcd_transceive_data_(9); + state_ = STATE_READ_SERIAL_DONE; + break; + } + case STATE_READ_SERIAL_DONE: { + if (status != STATUS_OK || back_length_ != 3) { + if (status == STATUS_TIMEOUT) + ESP_LOGV(TAG, "STATE_READ_SERIAL_DONE -> TIMEOUT (no tag present) %d", status); + else + ESP_LOGW(TAG, "Unexpected response. Read status is %d. Read bytes: %d (%s)", status, back_length_, + format_buffer(buffer_, 9).c_str()); -void RC522::update() { - for (auto *obj : this->binary_sensors_) - obj->on_scan_end(); -} + state_ = STATE_DONE; + uid_idx_ = 0; + + pcd_antenna_off_(); + return; + } + + // copy the uid + bool cascade = buffer_[2] == PICC_CMD_CT; // todo: should be determined based on select response (buffer[6]) + for (uint8_t i = 2 + cascade; i < 6; i++) + uid_buffer_[uid_idx_++] = buffer_[i]; + ESP_LOGVV(TAG, "copied uid to idx %d last byte is 0x%x, cascade is %d", uid_idx_, uid_buffer_[uid_idx_ - 1], + cascade); + + if (cascade) { // there is more bytes in the UID + state_ = STATE_READ_SERIAL; + return; + } + + std::vector rfid_uid(std::begin(uid_buffer_), std::begin(uid_buffer_) + uid_idx_); + uid_idx_ = 0; + // ESP_LOGD(TAG, "Processing '%s'", format_uid(rfid_uid).c_str()); + pcd_antenna_off_(); + state_ = STATE_INIT; // scan again on next update + bool report = true; + + for (auto *tag : this->binary_sensors_) { + if (tag->process(rfid_uid)) { + report = false; + } + } + + if (this->current_uid_ == rfid_uid) { + return; + } + + this->current_uid_ = rfid_uid; + + for (auto *trigger : this->triggers_) + trigger->process(rfid_uid); + + if (report) { + ESP_LOGD(TAG, "Found new tag '%s'", format_uid(rfid_uid).c_str()); + } + break; + } + case STATE_DONE: { + this->current_uid_ = {}; + state_ = STATE_INIT; + break; + } + default: + break; + } +} // namespace rc522 /** * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. @@ -176,14 +278,14 @@ void RC522::update() { void RC522::pcd_reset_() { // The datasheet does not mention how long the SoftRest command takes to complete. // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) - // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let - // us be generous: 50ms. + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. + // Let us be generous: 50ms. if (millis() - reset_timeout_ < 50) return; if (reset_count_ == RESET_COUNT) { - ESP_LOGV(TAG, "Soft reset..."); + ESP_LOGI(TAG, "Soft reset..."); // Issue the SoftReset command. pcd_write_register(COMMAND_REG, PCD_SOFT_RESET); } @@ -199,6 +301,7 @@ void RC522::pcd_reset_() { if (--reset_count_ == 0) { ESP_LOGE(TAG, "Unable to reset RC522."); + this->error_code_ = RESET_FAILED; mark_failed(); } } @@ -215,49 +318,13 @@ void RC522::pcd_antenna_on_() { } /** - * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or - * selection. 7 bit frame. Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - - * probably due do bad antenna design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. + * Turns the antenna off by disabling pins TX1 and TX2. */ -RC522::StatusCode RC522::picc_request_a_( - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. -) { - return picc_reqa_or_wupa_(PICC_CMD_REQA, buffer_atqa, buffer_size); -} - -/** - * Transmits REQA or WUPA commands. - * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna - * design. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_reqa_or_wupa_( - uint8_t command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. -) { - uint8_t valid_bits; - RC522::StatusCode status; - - if (buffer_atqa == nullptr || *buffer_size < 2) { // The ATQA response is 2 uint8_ts long. - return STATUS_NO_ROOM; +void RC522::pcd_antenna_off_() { + uint8_t value = pcd_read_register(TX_CONTROL_REG); + if ((value & 0x03) != 0x00) { + pcd_write_register(TX_CONTROL_REG, value & ~0x03); } - pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - valid_bits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) - // uint8_t. TxLastBits = BitFramingReg[2..0] - status = pcd_transceive_data_(&command, 1, buffer_atqa, buffer_size, &valid_bits); - if (status != STATUS_OK) - return status; - if (*buffer_size != 2 || valid_bits != 0) { // ATQA must be exactly 16 bits. - ESP_LOGVV(TAG, "picc_reqa_or_wupa_() -> STATUS_ERROR"); - return STATUS_ERROR; - } - - return STATUS_OK; } /** @@ -280,140 +347,86 @@ void RC522::pcd_clear_register_bit_mask_(PcdRegister reg, ///< The register to pcd_write_register(reg, tmp & (~mask)); // clear bit mask } -/** - * Executes the Transceive command. - * CRC validation can only be done if backData and backLen are specified. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::pcd_transceive_data_( - uint8_t *send_data, ///< Pointer to the data to transfer to the FIFO. - uint8_t send_len, ///< Number of uint8_ts to transfer to the FIFO. - uint8_t *back_data, ///< nullptr or pointer to buffer if data should be read back after executing the command. - uint8_t *back_len, ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. - uint8_t - *valid_bits, ///< In/Out: The number of valid bits in the last uint8_t. 0 for 8 valid bits. Default nullptr. - uint8_t rx_align, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool check_crc ///< In: True => The last two uint8_ts of the response is assumed to be a CRC_A that must be - ///< validated. -) { - uint8_t wait_i_rq = 0x30; // RxIRq and IdleIRq - auto ret = pcd_communicate_with_picc_(PCD_TRANSCEIVE, wait_i_rq, send_data, send_len, back_data, back_len, valid_bits, - rx_align, check_crc); - - if (ret == STATUS_OK && *back_len == 5) - ESP_LOGVV(TAG, "pcd_transceive_data_(..., %d, ) -> %d [%x, %x, %x, %x, %x]", send_len, ret, back_data[0], - back_data[1], back_data[2], back_data[3], back_data[4]); - else - ESP_LOGVV(TAG, "pcd_transceive_data_(..., %d, ... ) -> %d", send_len, ret); - return ret; -} - /** * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. * CRC validation can only be done if backData and backLen are specified. * * @return STATUS_OK on success, STATUS_??? otherwise. */ -RC522::StatusCode RC522::pcd_communicate_with_picc_( - uint8_t command, ///< The command to execute. One of the PCD_Command enums. - uint8_t wait_i_rq, ///< The bits in the ComIrqReg register that signals successful completion of the command. - uint8_t *send_data, ///< Pointer to the data to transfer to the FIFO. - uint8_t send_len, ///< Number of uint8_ts to transfer to the FIFO. - uint8_t *back_data, ///< nullptr or pointer to buffer if data should be read back after executing the command. - uint8_t *back_len, ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. - uint8_t *valid_bits, ///< In/Out: The number of valid bits in the last uint8_t. 0 for 8 valid bits. - uint8_t rx_align, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool check_crc ///< In: True => The last two uint8_ts of the response is assumed to be a CRC_A that must be - ///< validated. -) { - ESP_LOGVV(TAG, "pcd_communicate_with_picc_(%d, %d,... %d)", command, wait_i_rq, check_crc); - +void RC522::pcd_transceive_data_(uint8_t send_len) { + ESP_LOGV(TAG, "PCD TRANSCEIVE: RX: %s", format_buffer(buffer_, send_len).c_str()); + delayMicroseconds(1000); // we need 1 ms delay between antenna on and those communication commands + send_len_ = send_len; // Prepare values for BitFramingReg - uint8_t tx_last_bits = valid_bits ? *valid_bits : 0; - uint8_t bit_framing = - (rx_align << 4) + tx_last_bits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) + // uint8_t. TxLastBits = BitFramingReg[2..0] + uint8_t bit_framing = (buffer_[0] == PICC_CMD_REQA) ? 7 : 0; - pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. - pcd_write_register(COM_IRQ_REG, 0x7F); // Clear all seven interrupt request bits - pcd_write_register(FIFO_LEVEL_REG, 0x80); // FlushBuffer = 1, FIFO initialization - pcd_write_register(FIFO_DATA_REG, send_len, send_data); // Write sendData to the FIFO - pcd_write_register(BIT_FRAMING_REG, bit_framing); // Bit adjustments - pcd_write_register(COMMAND_REG, command); // Execute the command - if (command == PCD_TRANSCEIVE) { - pcd_set_register_bit_mask_(BIT_FRAMING_REG, 0x80); // StartSend=1, transmission of data starts - } + pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. + pcd_write_register(COM_IRQ_REG, 0x7F); // Clear all seven interrupt request bits + pcd_write_register(FIFO_LEVEL_REG, 0x80); // FlushBuffer = 1, FIFO initialization + pcd_write_register(FIFO_DATA_REG, send_len_, buffer_); // Write sendData to the FIFO + pcd_write_register(BIT_FRAMING_REG, bit_framing); // Bit adjustments + pcd_write_register(COMMAND_REG, PCD_TRANSCEIVE); // Execute the command + pcd_set_register_bit_mask_(BIT_FRAMING_REG, 0x80); // StartSend=1, transmission of data starts + awaiting_comm_ = true; + awaiting_comm_time_ = millis(); +} - // Wait for the command to complete. - // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops - // transmitting. Each iteration of the do-while-loop takes 17.86μs. - // TODO check/modify for other architectures than Arduino Uno 16bit - uint16_t i; - for (i = 2000; i > 0; i--) { - uint8_t n = pcd_read_register( - COM_IRQ_REG); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq - if (n & wait_i_rq) { // One of the interrupts that signal success has been set. - break; - } - if (n & 0x01) { // Timer interrupt - nothing received in 25ms - return STATUS_TIMEOUT; - } - } - // 35.7ms and nothing happend. Communication with the MFRC522 might be down. - if (i == 0) { +RC522::StatusCode RC522::await_transceive_() { + if (millis() - awaiting_comm_time_ < 2) // wait at least 2 ms + return STATUS_WAITING; + uint8_t n = pcd_read_register( + COM_IRQ_REG); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq + if (n & 0x01) { // Timer interrupt - nothing received in 25ms + back_length_ = 0; + error_counter_ = 0; // reset the error counter return STATUS_TIMEOUT; } + if (!(n & WAIT_I_RQ)) { // None of the interrupts that signal success has been set. + // Wait for the command to complete. + if (millis() - awaiting_comm_time_ < 40) + return STATUS_WAITING; + back_length_ = 0; + ESP_LOGW(TAG, "Communication with the MFRC522 might be down, reset in %d", + 10 - error_counter_); // todo: trigger reset? + if (error_counter_++ > 10) + setup(); + return STATUS_TIMEOUT; + } // Stop now if any errors except collisions were detected. uint8_t error_reg_value = pcd_read_register( ERROR_REG); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr if (error_reg_value & 0x13) { // BufferOvfl ParityErr ProtocolErr return STATUS_ERROR; } + error_counter_ = 0; // reset the error counter - uint8_t valid_bits_local = 0; - - // If the caller wants data back, get it from the MFRC522. - if (back_data && back_len) { - uint8_t n = pcd_read_register(FIFO_LEVEL_REG); // Number of uint8_ts in the FIFO - if (n > *back_len) { - return STATUS_NO_ROOM; - } - *back_len = n; // Number of uint8_ts returned - pcd_read_register(FIFO_DATA_REG, n, back_data, rx_align); // Get received data from FIFO - valid_bits_local = - pcd_read_register(CONTROL_REG) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last - // received uint8_t. If this value is 000b, the whole uint8_t is valid. - if (valid_bits) { - *valid_bits = valid_bits_local; - } - } + n = pcd_read_register(FIFO_LEVEL_REG); // Number of uint8_ts in the FIFO + if (n > sizeof(buffer_)) + return STATUS_NO_ROOM; + if (n > sizeof(buffer_) - send_len_) + send_len_ = sizeof(buffer_) - n; // simply overwrite the sent values + back_length_ = n; // Number of uint8_ts returned + pcd_read_register(FIFO_DATA_REG, n, buffer_ + send_len_, rx_align_); // Get received data from FIFO + uint8_t valid_bits_local = + pcd_read_register(CONTROL_REG) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last + // received uint8_t. If this value is 000b, the whole uint8_t is valid. // Tell about collisions if (error_reg_value & 0x08) { // CollErr + ESP_LOGW(TAG, "collision error, received %d bytes + %d bits (but anticollision not implemented)", + back_length_ - (valid_bits_local > 0), valid_bits_local); return STATUS_COLLISION; } - - // Perform CRC_A validation if requested. - if (back_data && back_len && check_crc) { - // In this case a MIFARE Classic NAK is not OK. - if (*back_len == 1 && valid_bits_local == 4) { - return STATUS_MIFARE_NACK; - } - // We need at least the CRC_A value and all 8 bits of the last uint8_t must be received. - if (*back_len < 2 || valid_bits_local != 0) { - return STATUS_CRC_WRONG; - } - // Verify CRC_A - do our own calculation and store the control in controlBuffer. - uint8_t control_buffer[2]; - RC522::StatusCode status = pcd_calculate_crc_(&back_data[0], *back_len - 2, &control_buffer[0]); - if (status != STATUS_OK) { - return status; - } - if ((back_data[*back_len - 2] != control_buffer[0]) || (back_data[*back_len - 1] != control_buffer[1])) { - return STATUS_CRC_WRONG; - } + // Tell about collisions + if (valid_bits_local) { + ESP_LOGW(TAG, "only %d valid bits received, tag distance to high? Error code is 0x%x", valid_bits_local, + error_reg_value); // TODO: is this always due to collissions? + return STATUS_ERROR; } + ESP_LOGV(TAG, "received %d bytes: %s", back_length_, format_buffer(buffer_ + send_len_, back_length_).c_str()); return STATUS_OK; } @@ -424,10 +437,8 @@ RC522::StatusCode RC522::pcd_communicate_with_picc_( * @return STATUS_OK on success, STATUS_??? otherwise. */ -RC522::StatusCode RC522::pcd_calculate_crc_( - uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - uint8_t length, ///< In: The number of uint8_ts to transfer. - uint8_t *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low uint8_t first. +void RC522::pcd_calculate_crc_(uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. + uint8_t length ///< In: The number of uint8_ts to transfer. ) { ESP_LOGVV(TAG, "pcd_calculate_crc_(..., %d, ...)", length); pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop any active command. @@ -436,323 +447,50 @@ RC522::StatusCode RC522::pcd_calculate_crc_( pcd_write_register(FIFO_DATA_REG, length, data); // Write data to the FIFO pcd_write_register(COMMAND_REG, PCD_CALC_CRC); // Start the calculation - // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73μs. - // TODO check/modify for other architectures than Arduino Uno 16bit + awaiting_comm_ = true; + awaiting_comm_time_ = millis(); +} - // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. - for (uint16_t i = 5000; i > 0; i--) { - // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved - uint8_t n = pcd_read_register(DIV_IRQ_REG); - if (n & 0x04) { // CRCIRq bit set - calculation done - pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop calculating CRC for new content in the FIFO. - // Transfer the result from the registers to the result buffer - result[0] = pcd_read_register(CRC_RESULT_REG_L); - result[1] = pcd_read_register(CRC_RESULT_REG_H); +RC522::StatusCode RC522::await_crc_() { + if (millis() - awaiting_comm_time_ < 2) // wait at least 2 ms + return STATUS_WAITING; - ESP_LOGVV(TAG, "pcd_calculate_crc_() STATUS_OK"); - return STATUS_OK; - } + // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved + uint8_t n = pcd_read_register(DIV_IRQ_REG); + if (n & 0x04) { // CRCIRq bit set - calculation done + pcd_write_register(COMMAND_REG, PCD_IDLE); // Stop calculating CRC for new content in the FIFO. + // Transfer the result from the registers to the result buffer + buffer_[7] = pcd_read_register(CRC_RESULT_REG_L); + buffer_[8] = pcd_read_register(CRC_RESULT_REG_H); + + ESP_LOGVV(TAG, "pcd_calculate_crc_() STATUS_OK"); + return STATUS_OK; } - ESP_LOGVV(TAG, "pcd_calculate_crc_() TIMEOUT"); + if (millis() - awaiting_comm_time_ < 89) + return STATUS_WAITING; + + ESP_LOGD(TAG, "pcd_calculate_crc_() TIMEOUT"); // 89ms passed and nothing happend. Communication with the MFRC522 might be down. return STATUS_TIMEOUT; } -/** - * Returns STATUS_OK if a PICC responds to PICC_CMD_REQA. - * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_is_new_card_present_() { - uint8_t buffer_atqa[2]; - uint8_t buffer_size = sizeof(buffer_atqa); - - // Reset baud rates - pcd_write_register(TX_MODE_REG, 0x00); - pcd_write_register(RX_MODE_REG, 0x00); - // Reset ModWidthReg - pcd_write_register(MOD_WIDTH_REG, 0x26); - - auto result = picc_request_a_(buffer_atqa, &buffer_size); - - ESP_LOGV(TAG, "picc_is_new_card_present_() -> %d", result); +bool RC522BinarySensor::process(std::vector &data) { + bool result = true; + if (data.size() != this->uid_.size()) + result = false; + else { + for (uint8_t i = 0; i < data.size(); i++) { + if (data[i] != this->uid_[i]) { + result = false; + break; + } + } + } + this->publish_state(result); + this->found_ = result; return result; } - -/** - * Simple wrapper around PICC_Select. - * Returns true if a UID could be read. - * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. - * The read UID is available in the class variable uid. - * - * @return bool - */ -bool RC522::picc_read_card_serial_() { - RC522::StatusCode result = picc_select_(&this->uid_); - ESP_LOGVV(TAG, "picc_select_(...) -> %d", result); - return (result == STATUS_OK); -} - -/** - * Transmits SELECT/ANTICOLLISION commands to select a single PICC. - * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or - * PICC_WakeupA(). On success: - * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the - * ISO/IEC 14443-3 draft.) - * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. - * - * A PICC UID consists of 4, 7 or 10 uint8_ts. - * Only 4 uint8_ts can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: - * UID size Number of UID uint8_ts Cascade levels Example of PICC - * ======== =================== ============== =============== - * single 4 1 MIFARE Classic - * double 7 2 MIFARE Ultralight - * triple 10 3 Not currently in use? - * - * @return STATUS_OK on success, STATUS_??? otherwise. - */ -RC522::StatusCode RC522::picc_select_( - Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - uint8_t valid_bits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply - ///< uid->size. -) { - bool uid_complete; - bool select_done; - bool use_cascade_tag; - uint8_t cascade_level = 1; - RC522::StatusCode result; - uint8_t count; - uint8_t check_bit; - uint8_t index; - uint8_t uid_index; // The first index in uid->uiduint8_t[] that is used in the current Cascade Level. - int8_t current_level_known_bits; // The number of known UID bits in the current Cascade Level. - uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 uint8_t standard frame + 2 uint8_ts CRC_A - uint8_t buffer_used; // The number of uint8_ts used in the buffer, ie the number of uint8_ts to transfer to the FIFO. - uint8_t rx_align; // Used in BitFramingReg. Defines the bit position for the first bit received. - uint8_t tx_last_bits; // Used in BitFramingReg. The number of valid bits in the last transmitted uint8_t. - uint8_t *response_buffer; - uint8_t response_length; - - // Description of buffer structure: - // uint8_t 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 - // uint8_t 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete - // uint8_ts, - // Low nibble: Extra bits. uint8_t 2: UID-data or CT See explanation below. CT means Cascade Tag. uint8_t - // 3: UID-data uint8_t 4: UID-data uint8_t 5: UID-data uint8_t 6: BCC Block Check Character - XOR of - // uint8_ts 2-5 uint8_t 7: CRC_A uint8_t 8: CRC_A The BCC and CRC_A are only transmitted if we know all the UID bits - // of the current Cascade Level. - // - // Description of uint8_ts 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) - // UID size Cascade level uint8_t2 uint8_t3 uint8_t4 uint8_t5 - // ======== ============= ===== ===== ===== ===== - // 4 uint8_ts 1 uid0 uid1 uid2 uid3 - // 7 uint8_ts 1 CT uid0 uid1 uid2 - // 2 uid3 uid4 uid5 uid6 - // 10 uint8_ts 1 CT uid0 uid1 uid2 - // 2 CT uid3 uid4 uid5 - // 3 uid6 uid7 uid8 uid9 - - // Sanity checks - if (valid_bits > 80) { - return STATUS_INVALID; - } - - ESP_LOGVV(TAG, "picc_select_(&, %d)", valid_bits); - - // Prepare MFRC522 - pcd_clear_register_bit_mask_(COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - - // Repeat Cascade Level loop until we have a complete UID. - uid_complete = false; - while (!uid_complete) { - // Set the Cascade Level in the SEL uint8_t, find out if we need to use the Cascade Tag in uint8_t 2. - switch (cascade_level) { - case 1: - buffer[0] = PICC_CMD_SEL_CL1; - uid_index = 0; - use_cascade_tag = valid_bits && uid->size > 4; // When we know that the UID has more than 4 uint8_ts - break; - - case 2: - buffer[0] = PICC_CMD_SEL_CL2; - uid_index = 3; - use_cascade_tag = valid_bits && uid->size > 7; // When we know that the UID has more than 7 uint8_ts - break; - - case 3: - buffer[0] = PICC_CMD_SEL_CL3; - uid_index = 6; - use_cascade_tag = false; // Never used in CL3. - break; - - default: - return STATUS_INTERNAL_ERROR; - break; - } - - // How many UID bits are known in this Cascade Level? - current_level_known_bits = valid_bits - (8 * uid_index); - if (current_level_known_bits < 0) { - current_level_known_bits = 0; - } - // Copy the known bits from uid->uiduint8_t[] to buffer[] - index = 2; // destination index in buffer[] - if (use_cascade_tag) { - buffer[index++] = PICC_CMD_CT; - } - uint8_t uint8_ts_to_copy = current_level_known_bits / 8 + - (current_level_known_bits % 8 - ? 1 - : 0); // The number of uint8_ts needed to represent the known bits for this level. - if (uint8_ts_to_copy) { - uint8_t maxuint8_ts = - use_cascade_tag ? 3 : 4; // Max 4 uint8_ts in each Cascade Level. Only 3 left if we use the Cascade Tag - if (uint8_ts_to_copy > maxuint8_ts) { - uint8_ts_to_copy = maxuint8_ts; - } - for (count = 0; count < uint8_ts_to_copy; count++) { - buffer[index++] = uid->uiduint8_t[uid_index + count]; - } - } - // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits - if (use_cascade_tag) { - current_level_known_bits += 8; - } - - // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. - select_done = false; - while (!select_done) { - // Find out how many bits and uint8_ts to send and receive. - if (current_level_known_bits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. - - if (response_length < 4) { - ESP_LOGW(TAG, "Not enough data received."); - return STATUS_INVALID; - } - - // Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole uint8_ts - // Calculate BCC - Block Check Character - buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; - // Calculate CRC_A - result = pcd_calculate_crc_(buffer, 7, &buffer[7]); - if (result != STATUS_OK) { - return result; - } - tx_last_bits = 0; // 0 => All 8 bits are valid. - buffer_used = 9; - // Store response in the last 3 uint8_ts of buffer (BCC and CRC_A - not needed after tx) - response_buffer = &buffer[6]; - response_length = 3; - } else { // This is an ANTICOLLISION. - // Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); - tx_last_bits = current_level_known_bits % 8; - count = current_level_known_bits / 8; // Number of whole uint8_ts in the UID part. - index = 2 + count; // Number of whole uint8_ts: SEL + NVB + UIDs - buffer[1] = (index << 4) + tx_last_bits; // NVB - Number of Valid Bits - buffer_used = index + (tx_last_bits ? 1 : 0); - // Store response in the unused part of buffer - response_buffer = &buffer[index]; - response_length = sizeof(buffer) - index; - } - - // Set bit adjustments - rx_align = tx_last_bits; // Having a separate variable is overkill. But it makes the next line easier to read. - pcd_write_register( - BIT_FRAMING_REG, - (rx_align << 4) + tx_last_bits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - - // Transmit the buffer and receive the response. - result = pcd_transceive_data_(buffer, buffer_used, response_buffer, &response_length, &tx_last_bits, rx_align); - if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. - uint8_t value_of_coll_reg = pcd_read_register( - COLL_REG); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] - if (value_of_coll_reg & 0x20) { // CollPosNotValid - return STATUS_COLLISION; // Without a valid collision position we cannot continue - } - uint8_t collision_pos = value_of_coll_reg & 0x1F; // Values 0-31, 0 means bit 32. - if (collision_pos == 0) { - collision_pos = 32; - } - if (collision_pos <= current_level_known_bits) { // No progress - should not happen - return STATUS_INTERNAL_ERROR; - } - // Choose the PICC with the bit set. - current_level_known_bits = collision_pos; - count = current_level_known_bits % 8; // The bit to modify - check_bit = (current_level_known_bits - 1) % 8; - index = 1 + (current_level_known_bits / 8) + (count ? 1 : 0); // First uint8_t is index 0. - if (response_length > 2) // Note: Otherwise buffer[index] might be not initialized - buffer[index] |= (1 << check_bit); - } else if (result != STATUS_OK) { - return result; - } else { // STATUS_OK - if (current_level_known_bits >= 32) { // This was a SELECT. - select_done = true; // No more anticollision - // We continue below outside the while. - } else { // This was an ANTICOLLISION. - // We now have all 32 bits of the UID in this Cascade Level - current_level_known_bits = 32; - // Run loop again to do the SELECT. - } - } - } // End of while (!selectDone) - - // We do not check the CBB - it was constructed by us above. - - // Copy the found UID uint8_ts from buffer[] to uid->uiduint8_t[] - index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] - uint8_ts_to_copy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; - for (count = 0; count < uint8_ts_to_copy; count++) { - uid->uiduint8_t[uid_index + count] = buffer[index++]; - } - - // Check response SAK (Select Acknowledge) - if (response_length != 3 || tx_last_bits != 0) { // SAK must be exactly 24 bits (1 uint8_t + CRC_A). - return STATUS_ERROR; - } - // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those uint8_ts are not needed - // anymore. - result = pcd_calculate_crc_(response_buffer, 1, &buffer[2]); - if (result != STATUS_OK) { - return result; - } - if ((buffer[2] != response_buffer[1]) || (buffer[3] != response_buffer[2])) { - return STATUS_CRC_WRONG; - } - if (response_buffer[0] & 0x04) { // Cascade bit set - UID not complete yes - cascade_level++; - } else { - uid_complete = true; - uid->sak = response_buffer[0]; - } - } // End of while (!uidComplete) - - // Set correct uid->size - uid->size = 3 * cascade_level + 1; - - return STATUS_OK; -} - -bool RC522BinarySensor::process(const uint8_t *data, uint8_t len) { - if (len != this->uid_.size()) - return false; - - for (uint8_t i = 0; i < len; i++) { - if (data[i] != this->uid_[i]) - return false; - } - - this->publish_state(true); - this->found_ = true; - return true; -} -void RC522Trigger::process(const uint8_t *uid, uint8_t uid_length) { - char buf[32]; - format_uid(buf, uid, uid_length); - this->trigger(std::string(buf)); -} +void RC522Trigger::process(std::vector &data) { this->trigger(format_uid(data)); } } // namespace rc522 } // namespace esphome diff --git a/esphome/components/rc522/rc522.h b/esphome/components/rc522/rc522.h index cabcf8db0b..7fb49e97fd 100644 --- a/esphome/components/rc522/rc522.h +++ b/esphome/components/rc522/rc522.h @@ -26,6 +26,33 @@ class RC522 : public PollingComponent { void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } protected: + // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. + // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered + enum StatusCode : uint8_t { + STATUS_OK, // Success + STATUS_WAITING, // Waiting result from RC522 chip + STATUS_ERROR, // Error in communication + STATUS_COLLISION, // Collission detected + STATUS_TIMEOUT, // Timeout in communication. + STATUS_NO_ROOM, // A buffer is not big enough. + STATUS_INTERNAL_ERROR, // Internal error in the code. Should not happen ;-) + STATUS_INVALID, // Invalid argument. + STATUS_CRC_WRONG, // The CRC_A does not match + STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. + }; + + enum State { + STATE_NONE = 0, + STATE_SETUP, + STATE_INIT, + STATE_PICC_REQUEST_A, + STATE_READ_SERIAL, + STATE_SELECT_SERIAL, + STATE_SELECT_SERIAL_DONE, + STATE_READ_SERIAL_DONE, + STATE_DONE, + } state_{STATE_NONE}; + enum PcdRegister : uint8_t { // Page 0: Command and status // 0x00 // reserved for future use @@ -150,33 +177,11 @@ class RC522 : public PollingComponent { PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 uint8_t page to the PICC. }; - // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. - // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered - enum StatusCode : uint8_t { - STATUS_OK, // Success - STATUS_ERROR, // Error in communication - STATUS_COLLISION, // Collission detected - STATUS_TIMEOUT, // Timeout in communication. - STATUS_NO_ROOM, // A buffer is not big enough. - STATUS_INTERNAL_ERROR, // Internal error in the code. Should not happen ;-) - STATUS_INVALID, // Invalid argument. - STATUS_CRC_WRONG, // The CRC_A does not match - STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. - }; - - // A struct used for passing the UID of a PICC. - using Uid = struct { - uint8_t size; // Number of uint8_ts in the UID. 4, 7 or 10. - uint8_t uiduint8_t[10]; - uint8_t sak; // The SAK (Select acknowledge) uint8_t returned from the PICC after successful selection. - }; - - Uid uid_; - uint32_t update_wait_{0}; - void pcd_reset_(); void initialize_(); void pcd_antenna_on_(); + void pcd_antenna_off_(); + virtual uint8_t pcd_read_register(PcdRegister reg ///< The register to read from. One of the PCD_Register enums. ) = 0; @@ -202,15 +207,6 @@ class RC522 : public PollingComponent { uint8_t *values ///< The values to write. uint8_t array. ) = 0; - StatusCode picc_request_a_( - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. - ); - StatusCode picc_reqa_or_wupa_( - uint8_t command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - uint8_t *buffer_atqa, ///< The buffer to store the ATQA (Answer to request) in - uint8_t *buffer_size ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. - ); void pcd_set_register_bit_mask_(PcdRegister reg, ///< The register to update. One of the PCD_Register enums. uint8_t mask ///< The bits to set. ); @@ -218,38 +214,33 @@ class RC522 : public PollingComponent { uint8_t mask ///< The bits to clear. ); - StatusCode pcd_transceive_data_(uint8_t *send_data, uint8_t send_len, uint8_t *back_data, uint8_t *back_len, - uint8_t *valid_bits = nullptr, uint8_t rx_align = 0, bool check_crc = false); - StatusCode pcd_communicate_with_picc_(uint8_t command, uint8_t wait_i_rq, uint8_t *send_data, uint8_t send_len, - uint8_t *back_data = nullptr, uint8_t *back_len = nullptr, - uint8_t *valid_bits = nullptr, uint8_t rx_align = 0, bool check_crc = false); - StatusCode pcd_calculate_crc_( - uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - uint8_t length, ///< In: The number of uint8_ts to transfer. - uint8_t *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low uint8_t first. - ); - RC522::StatusCode picc_is_new_card_present_(); - bool picc_read_card_serial_(); - StatusCode picc_select_( - Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - uint8_t valid_bits = 0 ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also - ///< supply uid->size. + void pcd_transceive_data_(uint8_t send_len); + + void pcd_calculate_crc_(uint8_t *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. + uint8_t length ///< In: The number of uint8_ts to transfer. ); - /** Read a data frame from the RC522 and return the result as a vector. - * - * Note that is_ready needs to be checked first before requesting this method. - * - * On failure, an empty vector is returned. - */ - std::vector r_c522_read_data_(); + bool awaiting_comm_; + uint32_t awaiting_comm_time_; + StatusCode await_transceive_(); + StatusCode await_crc_(); + + uint8_t buffer_[9]; ///< buffer for communication, the first bits [0..back_idx-1] are for tx , + ///< [back_idx..back_idx+back_len] for rx + uint8_t send_len_; // index of first byte for RX + uint8_t back_length_; ///< In: Max number of uint8_ts to write to *backData. Out: The number of uint8_ts returned. + uint8_t uid_buffer_[10]; // buffer to construct the uid (for 7 and 10 bit uids) + uint8_t uid_idx_ = 0; // number of read uid bytes e.g. index of the next available position in uid_buffer + uint8_t error_counter_ = 0; // to reset if unresponsive + uint8_t rx_align_; + uint8_t *valid_bits_; GPIOPin *reset_pin_{nullptr}; uint8_t reset_count_{0}; uint32_t reset_timeout_{0}; - bool initialize_pending_{false}; std::vector binary_sensors_; std::vector triggers_; + std::vector current_uid_; enum RC522Error { NONE = 0, @@ -261,7 +252,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { public: void set_uid(const std::vector &uid) { uid_ = uid; } - bool process(const uint8_t *data, uint8_t len); + bool process(std::vector &data); void on_scan_end() { if (!this->found_) { @@ -277,7 +268,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { class RC522Trigger : public Trigger { public: - void process(const uint8_t *uid, uint8_t uid_length); + void process(std::vector &data); }; } // namespace rc522 diff --git a/esphome/components/rc522_i2c/rc522_i2c.cpp b/esphome/components/rc522_i2c/rc522_i2c.cpp index 8248e79b50..fe88f567c0 100644 --- a/esphome/components/rc522_i2c/rc522_i2c.cpp +++ b/esphome/components/rc522_i2c/rc522_i2c.cpp @@ -36,10 +36,6 @@ void RC522I2C::pcd_read_register(PcdRegister reg, ///< The register to read fro return; } - std::string buf; - buf = "Rx"; - char cstrb[20]; - uint8_t b = values[0]; read_bytes(reg >> 1, values, count); @@ -69,31 +65,5 @@ void RC522I2C::pcd_write_register(PcdRegister reg, ///< The register to write t write_bytes(reg >> 1, values, count); } -// bool RC522I2C::write_data(const std::vector &data) { -// return this->write_bytes_raw(data.data(), data.size()); } - -// bool RC522I2C::read_data(std::vector &data, uint8_t len) { -// delay(5); - -// std::vector ready; -// ready.resize(1); -// uint32_t start_time = millis(); -// while (true) { -// if (this->read_bytes_raw(ready.data(), 1)) { -// if (ready[0] == 0x01) -// break; -// } - -// if (millis() - start_time > 100) { -// ESP_LOGV(TAG, "Timed out waiting for readiness from RC522!"); -// return false; -// } -// } - -// data.resize(len + 1); -// this->read_bytes_raw(data.data(), len + 1); -// return true; -// } - } // namespace rc522_i2c } // namespace esphome diff --git a/esphome/components/rc522_spi/rc522_spi.cpp b/esphome/components/rc522_spi/rc522_spi.cpp index 61236393e4..1865b36da6 100644 --- a/esphome/components/rc522_spi/rc522_spi.cpp +++ b/esphome/components/rc522_spi/rc522_spi.cpp @@ -32,7 +32,7 @@ uint8_t RC522Spi::pcd_read_register(PcdRegister reg ///< The register to read f transfer_byte(0x80 | reg); value = read_byte(); disable(); - ESP_LOGV(TAG, "read_register_(%x) -> %x", reg, value); + ESP_LOGVV(TAG, "read_register_(%d) -> %d", reg, value); return value; } @@ -45,9 +45,11 @@ void RC522Spi::pcd_read_register(PcdRegister reg, ///< The register to read fro uint8_t *values, ///< uint8_t array to store the values in. uint8_t rx_align ///< Only bit positions rxAlign..7 in values[0] are updated. ) { +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE std::string buf; buf = "Rx"; char cstrb[20]; +#endif if (count == 0) { return; } @@ -68,25 +70,30 @@ void RC522Spi::pcd_read_register(PcdRegister reg, ///< The register to read fro values[0] = (values[0] & ~mask) | (value & mask); index++; +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[0]); buf.append(cstrb); +#endif } while (index < count) { values[index] = transfer_byte(address); // Read value and tell that we want to read the same address again. +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[index]); buf.append(cstrb); +#endif index++; } values[index] = transfer_byte(0); // Read the final uint8_t. Send 0 to stop reading. +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE buf = buf + " "; sprintf(cstrb, "%x", values[index]); buf.append(cstrb); ESP_LOGVV(TAG, "read_register_array_(%x, %d, , %d) -> %s", reg, count, rx_align, buf.c_str()); - +#endif disable(); } @@ -108,21 +115,25 @@ void RC522Spi::pcd_write_register(PcdRegister reg, ///< The register to write t uint8_t count, ///< The number of uint8_ts to write to the register uint8_t *values ///< The values to write. uint8_t array. ) { +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE std::string buf; buf = "Tx"; + char cstrb[20]; +#endif enable(); transfer_byte(reg); - char cstrb[20]; for (uint8_t index = 0; index < count; index++) { transfer_byte(values[index]); +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE sprintf(cstrb, " %x", values[index]); buf.append(cstrb); +#endif } disable(); - ESP_LOGVV(TAG, "write_register_(%x, %d) -> %s", reg, count, buf.c_str()); + ESP_LOGVV(TAG, "write_register_(%d, %d) -> %s", reg, count, buf.c_str()); } } // namespace rc522_spi