mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	RC522 fixes (#1479)
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							4d7c1ae143
						
					
				
				
					commit
					a7c648b60b
				
			| @@ -7,22 +7,38 @@ | |||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace rc522 { | namespace rc522 { | ||||||
|  |  | ||||||
|  | static const uint8_t WAIT_I_RQ = 0x30;  // RxIRq and IdleIRq | ||||||
|  |  | ||||||
| static const char *TAG = "rc522"; | static const char *TAG = "rc522"; | ||||||
|  |  | ||||||
| static const uint8_t RESET_COUNT = 5; | 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; |   int offset = 0; | ||||||
|   for (uint8_t i = 0; i < uid_length; i++) { |   for (uint8_t i = 0; i < len; i++) { | ||||||
|     const char *format = "%02X"; |     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<uint8_t> &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-"; |       format = "%02X-"; | ||||||
|     offset += sprintf(buf + offset, format, uid[i]); |     offset += sprintf(buf + offset, format, uid[i]); | ||||||
|   } |   } | ||||||
|  |   return std::string(buf); | ||||||
| } | } | ||||||
|  |  | ||||||
| void RC522::setup() { | void RC522::setup() { | ||||||
|   initialize_pending_ = true; |   state_ = STATE_SETUP; | ||||||
|   // Pull device out of power down / reset state. |   // Pull device out of power down / reset state. | ||||||
|  |  | ||||||
|   // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. |   // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. | ||||||
| @@ -48,7 +64,7 @@ void RC522::setup() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void RC522::initialize_() { | void RC522::initialize_() { | ||||||
|   // Per originall code, wait 50 ms |   // Per original code, wait 50 ms | ||||||
|   if (millis() - reset_timeout_ < 50) |   if (millis() - reset_timeout_ < 50) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
| @@ -75,9 +91,8 @@ void RC522::initialize_() { | |||||||
|   pcd_write_register(TX_ASK_REG, 0x40); |   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 |   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) |                                        // 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() { | 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() { | void RC522::loop() { | ||||||
|   // First check reset is needed |   // First check reset is needed | ||||||
|   if (reset_count_ > 0) { |   if (reset_count_ > 0) { | ||||||
|     pcd_reset_(); |     pcd_reset_(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   if (initialize_pending_) { |   if (state_ == STATE_SETUP) { | ||||||
|     initialize_(); |     initialize_(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (millis() - update_wait_ < this->update_interval_) |   StatusCode status = STATUS_ERROR;  // For lint passing. TODO: refactor this | ||||||
|     return; |   if (awaiting_comm_) { | ||||||
|  |     if (state_ == STATE_SELECT_SERIAL_DONE) | ||||||
|  |       status = await_crc_(); | ||||||
|  |     else | ||||||
|  |       status = await_transceive_(); | ||||||
|  |  | ||||||
|   auto status = picc_is_new_card_present_(); |     if (status == STATUS_WAITING) { | ||||||
|  |       return; | ||||||
|   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; |  | ||||||
|     } |     } | ||||||
|  |     awaiting_comm_ = false; | ||||||
|  |     ESP_LOGV(TAG, "finished communication status: %d, state: %d", status, state_); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (report) { |   switch (state_) { | ||||||
|     char buf[32]; |     case STATE_PICC_REQUEST_A: { | ||||||
|     format_uid(buf, uid_.uiduint8_t, uid_.size); |       if (status == STATUS_TIMEOUT) {  // no tag present | ||||||
|     ESP_LOGD(TAG, "Found new tag '%s'", buf); |         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() { |         state_ = STATE_DONE; | ||||||
|   for (auto *obj : this->binary_sensors_) |         uid_idx_ = 0; | ||||||
|     obj->on_scan_end(); |  | ||||||
| } |         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<uint8_t> 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. |  * 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_() { | void RC522::pcd_reset_() { | ||||||
|   // The datasheet does not mention how long the SoftRest command takes to complete. |   // 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) |   // 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 |   // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. | ||||||
|   // us be generous: 50ms. |   // Let us be generous: 50ms. | ||||||
|  |  | ||||||
|   if (millis() - reset_timeout_ < 50) |   if (millis() - reset_timeout_ < 50) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   if (reset_count_ == RESET_COUNT) { |   if (reset_count_ == RESET_COUNT) { | ||||||
|     ESP_LOGV(TAG, "Soft reset..."); |     ESP_LOGI(TAG, "Soft reset..."); | ||||||
|     // Issue the SoftReset command. |     // Issue the SoftReset command. | ||||||
|     pcd_write_register(COMMAND_REG, PCD_SOFT_RESET); |     pcd_write_register(COMMAND_REG, PCD_SOFT_RESET); | ||||||
|   } |   } | ||||||
| @@ -199,6 +301,7 @@ void RC522::pcd_reset_() { | |||||||
|  |  | ||||||
|   if (--reset_count_ == 0) { |   if (--reset_count_ == 0) { | ||||||
|     ESP_LOGE(TAG, "Unable to reset RC522."); |     ESP_LOGE(TAG, "Unable to reset RC522."); | ||||||
|  |     this->error_code_ = RESET_FAILED; | ||||||
|     mark_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 |  * Turns the antenna off by disabling pins TX1 and TX2. | ||||||
|  * 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. |  | ||||||
|  */ |  */ | ||||||
| RC522::StatusCode RC522::picc_request_a_( | void RC522::pcd_antenna_off_() { | ||||||
|     uint8_t *buffer_atqa,  ///< The buffer to store the ATQA (Answer to request) in |   uint8_t value = pcd_read_register(TX_CONTROL_REG); | ||||||
|     uint8_t *buffer_size   ///< Buffer size, at least two uint8_ts. Also number of uint8_ts returned if STATUS_OK. |   if ((value & 0x03) != 0x00) { | ||||||
| ) { |     pcd_write_register(TX_CONTROL_REG, value & ~0x03); | ||||||
|   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; |  | ||||||
|   } |   } | ||||||
|   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 |   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. |  * 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. |  * CRC validation can only be done if backData and backLen are specified. | ||||||
|  * |  * | ||||||
|  * @return STATUS_OK on success, STATUS_??? otherwise. |  * @return STATUS_OK on success, STATUS_??? otherwise. | ||||||
|  */ |  */ | ||||||
| RC522::StatusCode RC522::pcd_communicate_with_picc_( | void RC522::pcd_transceive_data_(uint8_t send_len) { | ||||||
|     uint8_t command,      ///< The command to execute. One of the PCD_Command enums. |   ESP_LOGV(TAG, "PCD TRANSCEIVE: RX: %s", format_buffer(buffer_, send_len).c_str()); | ||||||
|     uint8_t wait_i_rq,    ///< The bits in the ComIrqReg register that signals successful completion of the command. |   delayMicroseconds(1000);  // we need 1 ms delay between antenna on and those communication commands | ||||||
|     uint8_t *send_data,   ///< Pointer to the data to transfer to the FIFO. |   send_len_ = send_len; | ||||||
|     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); |  | ||||||
|  |  | ||||||
|   // Prepare values for BitFramingReg |   // Prepare values for BitFramingReg | ||||||
|   uint8_t tx_last_bits = valid_bits ? *valid_bits : 0; |   // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) | ||||||
|   uint8_t bit_framing = |   // uint8_t. TxLastBits = BitFramingReg[2..0] | ||||||
|       (rx_align << 4) + tx_last_bits;  // RxAlign = BitFramingReg[6..4]. 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(COMMAND_REG, PCD_IDLE);              // Stop any active command. | ||||||
|   pcd_write_register(COM_IRQ_REG, 0x7F);                   // Clear all seven interrupt request bits |   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_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(FIFO_DATA_REG, send_len_, buffer_);  // Write sendData to the FIFO | ||||||
|   pcd_write_register(BIT_FRAMING_REG, bit_framing);        // Bit adjustments |   pcd_write_register(BIT_FRAMING_REG, bit_framing);       // Bit adjustments | ||||||
|   pcd_write_register(COMMAND_REG, command);                // Execute the command |   pcd_write_register(COMMAND_REG, PCD_TRANSCEIVE);        // Execute the command | ||||||
|   if (command == PCD_TRANSCEIVE) { |   pcd_set_register_bit_mask_(BIT_FRAMING_REG, 0x80);      // StartSend=1, transmission of data starts | ||||||
|     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. | RC522::StatusCode RC522::await_transceive_() { | ||||||
|   // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops |   if (millis() - awaiting_comm_time_ < 2)  // wait at least 2 ms | ||||||
|   // transmitting. Each iteration of the do-while-loop takes 17.86μs. |     return STATUS_WAITING; | ||||||
|   // TODO check/modify for other architectures than Arduino Uno 16bit |   uint8_t n = pcd_read_register( | ||||||
|   uint16_t i; |       COM_IRQ_REG);  // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq | ||||||
|   for (i = 2000; i > 0; i--) { |   if (n & 0x01) {    // Timer interrupt - nothing received in 25ms | ||||||
|     uint8_t n = pcd_read_register( |     back_length_ = 0; | ||||||
|         COM_IRQ_REG);     // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq |     error_counter_ = 0;  // reset the error counter | ||||||
|     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) { |  | ||||||
|     return STATUS_TIMEOUT; |     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. |   // Stop now if any errors except collisions were detected. | ||||||
|   uint8_t error_reg_value = pcd_read_register( |   uint8_t error_reg_value = pcd_read_register( | ||||||
|       ERROR_REG);  // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr |       ERROR_REG);  // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr | ||||||
|   if (error_reg_value & 0x13) {  // BufferOvfl ParityErr ProtocolErr |   if (error_reg_value & 0x13) {  // BufferOvfl ParityErr ProtocolErr | ||||||
|     return STATUS_ERROR; |     return STATUS_ERROR; | ||||||
|   } |   } | ||||||
|  |   error_counter_ = 0;  // reset the error counter | ||||||
|  |  | ||||||
|   uint8_t valid_bits_local = 0; |   n = pcd_read_register(FIFO_LEVEL_REG);  // Number of uint8_ts in the FIFO | ||||||
|  |   if (n > sizeof(buffer_)) | ||||||
|   // If the caller wants data back, get it from the MFRC522. |     return STATUS_NO_ROOM; | ||||||
|   if (back_data && back_len) { |   if (n > sizeof(buffer_) - send_len_) | ||||||
|     uint8_t n = pcd_read_register(FIFO_LEVEL_REG);  // Number of uint8_ts in the FIFO |     send_len_ = sizeof(buffer_) - n;                                    // simply overwrite the sent values | ||||||
|     if (n > *back_len) { |   back_length_ = n;                                                     // Number of uint8_ts returned | ||||||
|       return STATUS_NO_ROOM; |   pcd_read_register(FIFO_DATA_REG, n, buffer_ + send_len_, rx_align_);  // Get received data from FIFO | ||||||
|     } |   uint8_t valid_bits_local = | ||||||
|     *back_len = n;                                             // Number of uint8_ts returned |       pcd_read_register(CONTROL_REG) & 0x07;  // RxLastBits[2:0] indicates the number of valid bits in the last | ||||||
|     pcd_read_register(FIFO_DATA_REG, n, back_data, rx_align);  // Get received data from FIFO |                                               // received uint8_t. If this value is 000b, the whole uint8_t is valid. | ||||||
|     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; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Tell about collisions |   // Tell about collisions | ||||||
|   if (error_reg_value & 0x08) {  // CollErr |   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; |     return STATUS_COLLISION; | ||||||
|   } |   } | ||||||
|  |   // Tell about collisions | ||||||
|   // Perform CRC_A validation if requested. |   if (valid_bits_local) { | ||||||
|   if (back_data && back_len && check_crc) { |     ESP_LOGW(TAG, "only %d valid bits received, tag distance to high? Error code is 0x%x", valid_bits_local, | ||||||
|     // In this case a MIFARE Classic NAK is not OK. |              error_reg_value);  // TODO: is this always due to collissions? | ||||||
|     if (*back_len == 1 && valid_bits_local == 4) { |     return STATUS_ERROR; | ||||||
|       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; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |   ESP_LOGV(TAG, "received %d bytes: %s", back_length_, format_buffer(buffer_ + send_len_, back_length_).c_str()); | ||||||
|  |  | ||||||
|   return STATUS_OK; |   return STATUS_OK; | ||||||
| } | } | ||||||
| @@ -424,10 +437,8 @@ RC522::StatusCode RC522::pcd_communicate_with_picc_( | |||||||
|  * @return STATUS_OK on success, STATUS_??? otherwise. |  * @return STATUS_OK on success, STATUS_??? otherwise. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| RC522::StatusCode RC522::pcd_calculate_crc_( | void RC522::pcd_calculate_crc_(uint8_t *data,  ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. | ||||||
|     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 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. |  | ||||||
| ) { | ) { | ||||||
|   ESP_LOGVV(TAG, "pcd_calculate_crc_(..., %d, ...)", length); |   ESP_LOGVV(TAG, "pcd_calculate_crc_(..., %d, ...)", length); | ||||||
|   pcd_write_register(COMMAND_REG, PCD_IDLE);        // Stop any active command. |   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(FIFO_DATA_REG, length, data);  // Write data to the FIFO | ||||||
|   pcd_write_register(COMMAND_REG, PCD_CALC_CRC);    // Start the calculation |   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. |   awaiting_comm_ = true; | ||||||
|   // TODO check/modify for other architectures than Arduino Uno 16bit |   awaiting_comm_time_ = millis(); | ||||||
|  | } | ||||||
|  |  | ||||||
|   // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. | RC522::StatusCode RC522::await_crc_() { | ||||||
|   for (uint16_t i = 5000; i > 0; i--) { |   if (millis() - awaiting_comm_time_ < 2)  // wait at least 2 ms | ||||||
|     // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved |     return STATUS_WAITING; | ||||||
|     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); |  | ||||||
|  |  | ||||||
|       ESP_LOGVV(TAG, "pcd_calculate_crc_() STATUS_OK"); |   // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved | ||||||
|       return STATUS_OK; |   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. |   // 89ms passed and nothing happend. Communication with the MFRC522 might be down. | ||||||
|   return STATUS_TIMEOUT; |   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_() { | bool RC522BinarySensor::process(std::vector<uint8_t> &data) { | ||||||
|   uint8_t buffer_atqa[2]; |   bool result = true; | ||||||
|   uint8_t buffer_size = sizeof(buffer_atqa); |   if (data.size() != this->uid_.size()) | ||||||
|  |     result = false; | ||||||
|   // Reset baud rates |   else { | ||||||
|   pcd_write_register(TX_MODE_REG, 0x00); |     for (uint8_t i = 0; i < data.size(); i++) { | ||||||
|   pcd_write_register(RX_MODE_REG, 0x00); |       if (data[i] != this->uid_[i]) { | ||||||
|   // Reset ModWidthReg |         result = false; | ||||||
|   pcd_write_register(MOD_WIDTH_REG, 0x26); |         break; | ||||||
|  |       } | ||||||
|   auto result = picc_request_a_(buffer_atqa, &buffer_size); |     } | ||||||
|  |   } | ||||||
|   ESP_LOGV(TAG, "picc_is_new_card_present_() -> %d", result); |   this->publish_state(result); | ||||||
|  |   this->found_ = result; | ||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  | void RC522Trigger::process(std::vector<uint8_t> &data) { this->trigger(format_uid(data)); } | ||||||
| /** |  | ||||||
|  * 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)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace rc522 | }  // namespace rc522 | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -26,6 +26,33 @@ class RC522 : public PollingComponent { | |||||||
|   void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } |   void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } | ||||||
|  |  | ||||||
|  protected: |  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 { |   enum PcdRegister : uint8_t { | ||||||
|     // Page 0: Command and status |     // Page 0: Command and status | ||||||
|     // 0x00      // reserved for future use |     // 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. |     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 pcd_reset_(); | ||||||
|   void initialize_(); |   void initialize_(); | ||||||
|   void pcd_antenna_on_(); |   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. |   virtual uint8_t pcd_read_register(PcdRegister reg  ///< The register to read from. One of the PCD_Register enums. | ||||||
|                                     ) = 0; |                                     ) = 0; | ||||||
|  |  | ||||||
| @@ -202,15 +207,6 @@ class RC522 : public PollingComponent { | |||||||
|                                   uint8_t *values   ///< The values to write. uint8_t array. |                                   uint8_t *values   ///< The values to write. uint8_t array. | ||||||
|                                   ) = 0; |                                   ) = 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. |   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. |                                   uint8_t mask      ///< The bits to set. | ||||||
|   ); |   ); | ||||||
| @@ -218,38 +214,33 @@ class RC522 : public PollingComponent { | |||||||
|                                     uint8_t mask      ///< The bits to clear. |                                     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, |   void pcd_transceive_data_(uint8_t send_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, |   void pcd_calculate_crc_(uint8_t *data,  ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. | ||||||
|                                         uint8_t *back_data = nullptr, uint8_t *back_len = nullptr, |                           uint8_t length  ///< In: The number of uint8_ts to transfer. | ||||||
|                                         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. |  | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   /** Read a data frame from the RC522 and return the result as a vector. |   bool awaiting_comm_; | ||||||
|    * |   uint32_t awaiting_comm_time_; | ||||||
|    * Note that is_ready needs to be checked first before requesting this method. |   StatusCode await_transceive_(); | ||||||
|    * |   StatusCode await_crc_(); | ||||||
|    * On failure, an empty vector is returned. |  | ||||||
|    */ |   uint8_t buffer_[9];       ///< buffer for communication, the first bits [0..back_idx-1] are for tx , | ||||||
|   std::vector<uint8_t> r_c522_read_data_(); |                             ///< [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}; |   GPIOPin *reset_pin_{nullptr}; | ||||||
|   uint8_t reset_count_{0}; |   uint8_t reset_count_{0}; | ||||||
|   uint32_t reset_timeout_{0}; |   uint32_t reset_timeout_{0}; | ||||||
|   bool initialize_pending_{false}; |  | ||||||
|   std::vector<RC522BinarySensor *> binary_sensors_; |   std::vector<RC522BinarySensor *> binary_sensors_; | ||||||
|   std::vector<RC522Trigger *> triggers_; |   std::vector<RC522Trigger *> triggers_; | ||||||
|  |   std::vector<uint8_t> current_uid_; | ||||||
|  |  | ||||||
|   enum RC522Error { |   enum RC522Error { | ||||||
|     NONE = 0, |     NONE = 0, | ||||||
| @@ -261,7 +252,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { | |||||||
|  public: |  public: | ||||||
|   void set_uid(const std::vector<uint8_t> &uid) { uid_ = uid; } |   void set_uid(const std::vector<uint8_t> &uid) { uid_ = uid; } | ||||||
|  |  | ||||||
|   bool process(const uint8_t *data, uint8_t len); |   bool process(std::vector<uint8_t> &data); | ||||||
|  |  | ||||||
|   void on_scan_end() { |   void on_scan_end() { | ||||||
|     if (!this->found_) { |     if (!this->found_) { | ||||||
| @@ -277,7 +268,7 @@ class RC522BinarySensor : public binary_sensor::BinarySensor { | |||||||
|  |  | ||||||
| class RC522Trigger : public Trigger<std::string> { | class RC522Trigger : public Trigger<std::string> { | ||||||
|  public: |  public: | ||||||
|   void process(const uint8_t *uid, uint8_t uid_length); |   void process(std::vector<uint8_t> &data); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace rc522 | }  // namespace rc522 | ||||||
|   | |||||||
| @@ -36,10 +36,6 @@ void RC522I2C::pcd_read_register(PcdRegister reg,  ///< The register to read fro | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   std::string buf; |  | ||||||
|   buf = "Rx"; |  | ||||||
|   char cstrb[20]; |  | ||||||
|  |  | ||||||
|   uint8_t b = values[0]; |   uint8_t b = values[0]; | ||||||
|   read_bytes(reg >> 1, values, count); |   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); |   write_bytes(reg >> 1, values, count); | ||||||
| } | } | ||||||
|  |  | ||||||
| // bool RC522I2C::write_data(const std::vector<uint8_t> &data) { |  | ||||||
| // return this->write_bytes_raw(data.data(), data.size()); } |  | ||||||
|  |  | ||||||
| // bool RC522I2C::read_data(std::vector<uint8_t> &data, uint8_t len) { |  | ||||||
| //   delay(5); |  | ||||||
|  |  | ||||||
| //   std::vector<uint8_t> 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 rc522_i2c | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ uint8_t RC522Spi::pcd_read_register(PcdRegister reg  ///< The register to read f | |||||||
|   transfer_byte(0x80 | reg); |   transfer_byte(0x80 | reg); | ||||||
|   value = read_byte(); |   value = read_byte(); | ||||||
|   disable(); |   disable(); | ||||||
|   ESP_LOGV(TAG, "read_register_(%x) -> %x", reg, value); |   ESP_LOGVV(TAG, "read_register_(%d) -> %d", reg, value); | ||||||
|   return 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 *values,  ///< uint8_t array to store the values in. | ||||||
|                                  uint8_t rx_align  ///< Only bit positions rxAlign..7 in values[0] are updated. |                                  uint8_t rx_align  ///< Only bit positions rxAlign..7 in values[0] are updated. | ||||||
| ) { | ) { | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|   std::string buf; |   std::string buf; | ||||||
|   buf = "Rx"; |   buf = "Rx"; | ||||||
|   char cstrb[20]; |   char cstrb[20]; | ||||||
|  | #endif | ||||||
|   if (count == 0) { |   if (count == 0) { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| @@ -68,25 +70,30 @@ void RC522Spi::pcd_read_register(PcdRegister reg,  ///< The register to read fro | |||||||
|     values[0] = (values[0] & ~mask) | (value & mask); |     values[0] = (values[0] & ~mask) | (value & mask); | ||||||
|     index++; |     index++; | ||||||
|  |  | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|     sprintf(cstrb, " %x", values[0]); |     sprintf(cstrb, " %x", values[0]); | ||||||
|     buf.append(cstrb); |     buf.append(cstrb); | ||||||
|  | #endif | ||||||
|   } |   } | ||||||
|   while (index < count) { |   while (index < count) { | ||||||
|     values[index] = transfer_byte(address);  // Read value and tell that we want to read the same address again. |     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]); |     sprintf(cstrb, " %x", values[index]); | ||||||
|     buf.append(cstrb); |     buf.append(cstrb); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     index++; |     index++; | ||||||
|   } |   } | ||||||
|   values[index] = transfer_byte(0);  // Read the final uint8_t. Send 0 to stop reading. |   values[index] = transfer_byte(0);  // Read the final uint8_t. Send 0 to stop reading. | ||||||
|  |  | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|   buf = buf + " "; |   buf = buf + " "; | ||||||
|   sprintf(cstrb, "%x", values[index]); |   sprintf(cstrb, "%x", values[index]); | ||||||
|   buf.append(cstrb); |   buf.append(cstrb); | ||||||
|  |  | ||||||
|   ESP_LOGVV(TAG, "read_register_array_(%x, %d, , %d) -> %s", reg, count, rx_align, buf.c_str()); |   ESP_LOGVV(TAG, "read_register_array_(%x, %d, , %d) -> %s", reg, count, rx_align, buf.c_str()); | ||||||
|  | #endif | ||||||
|   disable(); |   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 count,    ///< The number of uint8_ts to write to the register | ||||||
|                                   uint8_t *values   ///< The values to write. uint8_t array. |                                   uint8_t *values   ///< The values to write. uint8_t array. | ||||||
| ) { | ) { | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|   std::string buf; |   std::string buf; | ||||||
|   buf = "Tx"; |   buf = "Tx"; | ||||||
|  |   char cstrb[20]; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   enable(); |   enable(); | ||||||
|   transfer_byte(reg); |   transfer_byte(reg); | ||||||
|   char cstrb[20]; |  | ||||||
|  |  | ||||||
|   for (uint8_t index = 0; index < count; index++) { |   for (uint8_t index = 0; index < count; index++) { | ||||||
|     transfer_byte(values[index]); |     transfer_byte(values[index]); | ||||||
|  |  | ||||||
|  | #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||||
|     sprintf(cstrb, " %x", values[index]); |     sprintf(cstrb, " %x", values[index]); | ||||||
|     buf.append(cstrb); |     buf.append(cstrb); | ||||||
|  | #endif | ||||||
|   } |   } | ||||||
|   disable(); |   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 | }  // namespace rc522_spi | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user