diff --git a/applications/lfrfid/helpers/decoder_ioprox.cpp b/applications/lfrfid/helpers/decoder_ioprox.cpp new file mode 100644 index 000000000..7b44d3cea --- /dev/null +++ b/applications/lfrfid/helpers/decoder_ioprox.cpp @@ -0,0 +1,107 @@ +#include "decoder_ioprox.h" +#include +#include +#include + +constexpr uint32_t clocks_in_us = 64; + +constexpr uint32_t jitter_time_us = 20; +constexpr uint32_t min_time_us = 64; +constexpr uint32_t max_time_us = 80; +constexpr uint32_t baud_time_us = 500; + +constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us; +constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us; +constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us; +constexpr uint32_t baud_time = baud_time_us * clocks_in_us; + +bool DecoderIoProx::read(uint8_t* data, uint8_t data_size) { + bool result = false; + furi_assert(data_size >= 4); + + if(ready) { + result = true; + ioprox.decode(raw_data, sizeof(raw_data), data, data_size); + ready = false; + } + + return result; +} + +void DecoderIoProx::process_front(bool is_rising_edge, uint32_t time) { + if(ready) { + return; + } + + // Always track the time that's gone by. + current_period_duration += time; + demodulation_sample_duration += time; + + // If a baud time has elapsed, we're at a sample point. + if(demodulation_sample_duration >= baud_time) { + // Start a new baud period... + demodulation_sample_duration = 0; + demodulated_value_invalid = false; + + // ... and if we didn't have any baud errors, capture a sample. + if(!demodulated_value_invalid) { + store_data(current_demodulated_value); + } + } + + // + // FSK demodulator. + // + + // If this isn't a rising edge, this isn't a pulse of interest. + // We're done. + if(!is_rising_edge) { + return; + } + + bool is_valid_low = (current_period_duration > min_time) && + (current_period_duration <= mid_time); + bool is_valid_high = (current_period_duration > mid_time) && + (current_period_duration < max_time); + + // If this is between the minimum and our threshold, this is a logical 0. + if(is_valid_low) { + current_demodulated_value = false; + } + // Otherwise, if between our threshold and the max time, it's a logical 1. + else if(is_valid_high) { + current_demodulated_value = true; + } + // Otherwise, invalidate this sample. + else { + demodulated_value_invalid = true; + } + + // We're starting a new period; track that. + current_period_duration = 0; +} + +DecoderIoProx::DecoderIoProx() { + reset_state(); +} + +void DecoderIoProx::store_data(bool data) { + for(int i = 0; i < 7; ++i) { + raw_data[i] = (raw_data[i] << 1) | ((raw_data[i + 1] >> 7) & 1); + } + raw_data[7] = (raw_data[7] << 1) | data; + + if(ioprox.can_be_decoded(raw_data, sizeof(raw_data))) { + ready = true; + } +} + +void DecoderIoProx::reset_state() { + current_demodulated_value = false; + demodulated_value_invalid = false; + + current_period_duration = 0; + demodulation_sample_duration = 0; + + ready = false; +} diff --git a/applications/lfrfid/helpers/decoder_ioprox.h b/applications/lfrfid/helpers/decoder_ioprox.h new file mode 100644 index 000000000..aff4a4778 --- /dev/null +++ b/applications/lfrfid/helpers/decoder_ioprox.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include "protocols/protocol_ioprox.h" + +class DecoderIoProx { +public: + bool read(uint8_t* data, uint8_t data_size); + void process_front(bool polarity, uint32_t time); + DecoderIoProx(); + +private: + uint32_t current_period_duration = 0; + uint32_t demodulation_sample_duration = 0; + + bool current_demodulated_value = false; + bool demodulated_value_invalid = false; + + uint8_t raw_data[8] = {0}; + void store_data(bool data); + + std::atomic ready; + + void reset_state(); + ProtocolIoProx ioprox; +}; diff --git a/applications/lfrfid/helpers/encoder_ioprox.cpp b/applications/lfrfid/helpers/encoder_ioprox.cpp new file mode 100644 index 000000000..417799186 --- /dev/null +++ b/applications/lfrfid/helpers/encoder_ioprox.cpp @@ -0,0 +1,32 @@ +#include "encoder_ioprox.h" +#include "protocols/protocol_ioprox.h" +#include + +void EncoderIoProx::init(const uint8_t* data, const uint8_t data_size) { + ProtocolIoProx ioprox; + ioprox.encode(data, data_size, card_data, sizeof(card_data)); + card_data_index = 0; +} + +void EncoderIoProx::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { + uint8_t bit = (card_data[card_data_index / 8] >> (7 - (card_data_index % 8))) & 1; + + bool advance = fsk->next(bit, period); + if(advance) { + card_data_index++; + if(card_data_index >= (8 * card_data_max)) { + card_data_index = 0; + } + } + + *polarity = true; + *pulse = *period / 2; +} + +EncoderIoProx::EncoderIoProx() { + fsk = new OscFSK(8, 10, 64); +} + +EncoderIoProx::~EncoderIoProx() { + delete fsk; +} diff --git a/applications/lfrfid/helpers/encoder_ioprox.h b/applications/lfrfid/helpers/encoder_ioprox.h new file mode 100644 index 000000000..568b40671 --- /dev/null +++ b/applications/lfrfid/helpers/encoder_ioprox.h @@ -0,0 +1,25 @@ +#pragma once +#include "encoder_generic.h" +#include "osc_fsk.h" + +class EncoderIoProx : public EncoderGeneric { +public: + /** + * @brief init data to emulate + * + * @param data 1 byte FC, 1 byte Version, 2 bytes code + * @param data_size must be 4 + */ + void init(const uint8_t* data, const uint8_t data_size) final; + void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; + EncoderIoProx(); + ~EncoderIoProx(); + +private: + static const uint8_t card_data_max = 8; + + uint8_t card_data[card_data_max]; + uint8_t card_data_index; + + OscFSK* fsk; +}; diff --git a/applications/lfrfid/helpers/key_info.cpp b/applications/lfrfid/helpers/key_info.cpp index ed2b20a90..4803cd6dc 100644 --- a/applications/lfrfid/helpers/key_info.cpp +++ b/applications/lfrfid/helpers/key_info.cpp @@ -12,6 +12,9 @@ const char* lfrfid_key_get_type_string(LfrfidKeyType type) { case LfrfidKeyType::KeyI40134: return "I40134"; break; + case LfrfidKeyType::KeyIoProxXSF: + return "IoProxXSF"; + break; } return "Unknown"; @@ -28,6 +31,8 @@ const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type) { case LfrfidKeyType::KeyI40134: return "Indala"; break; + case LfrfidKeyType::KeyIoProxXSF: + return "Kantech"; } return "Unknown"; @@ -42,6 +47,8 @@ bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type) { *type = LfrfidKeyType::KeyH10301; } else if(strcmp("I40134", string) == 0) { *type = LfrfidKeyType::KeyI40134; + } else if(strcmp("IoProxXSF", string) == 0) { + *type = LfrfidKeyType::KeyIoProxXSF; } else { result = false; } @@ -60,6 +67,9 @@ uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type) { case LfrfidKeyType::KeyI40134: return 3; break; + case LfrfidKeyType::KeyIoProxXSF: + return 4; + break; } return 0; diff --git a/applications/lfrfid/helpers/key_info.h b/applications/lfrfid/helpers/key_info.h index e465011d0..75a0a9406 100644 --- a/applications/lfrfid/helpers/key_info.h +++ b/applications/lfrfid/helpers/key_info.h @@ -8,6 +8,7 @@ enum class LfrfidKeyType : uint8_t { KeyEM4100, KeyH10301, KeyI40134, + KeyIoProxXSF, }; const char* lfrfid_key_get_type_string(LfrfidKeyType type); diff --git a/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp b/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp new file mode 100644 index 000000000..b3b6a0e59 --- /dev/null +++ b/applications/lfrfid/helpers/protocols/protocol_ioprox.cpp @@ -0,0 +1,193 @@ +#include "protocol_ioprox.h" +#include +#include + +/** + * Writes a bit into the output buffer. + */ +static void write_bit(bool bit, uint8_t position, uint8_t* data) { + if(bit) { + data[position / 8] |= 1UL << (7 - (position % 8)); + } else { + data[position / 8] &= ~(1UL << (7 - (position % 8))); + } +} + +/** + * Writes up to eight contiguous bits into the output buffer. + */ +static void write_bits(uint8_t byte, uint8_t position, uint8_t* data, uint8_t length) { + furi_check(length <= 8); + furi_check(length > 0); + + for(uint8_t i = 0; i < length; ++i) { + uint8_t shift = 7 - i; + write_bit((byte >> shift) & 1, position + i, data); + } +} + +uint8_t ProtocolIoProx::get_encoded_data_size() { + return 8; +} + +uint8_t ProtocolIoProx::get_decoded_data_size() { + return 4; +} + +void ProtocolIoProx::encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + // Packet to transmit: + // + // 0 10 20 30 40 50 60 + // v v v v v v v + // 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 + // ----------------------------------------------------------------------------- + // 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11 + + // Preamble. + write_bits(0b00000000, 0, encoded_data, 8); + write_bit(0, 8, encoded_data); + + write_bits(0b11110000, 9, encoded_data, 8); + write_bit(1, 17, encoded_data); + + // Facility code. + write_bits(decoded_data[0], 18, encoded_data, 8); + write_bit(1, 26, encoded_data); + + // Version + write_bits(decoded_data[1], 27, encoded_data, 8); + write_bit(1, 35, encoded_data); + + // Code one + write_bits(decoded_data[2], 36, encoded_data, 8); + write_bit(1, 44, encoded_data); + + // Code two + write_bits(decoded_data[3], 45, encoded_data, 8); + write_bit(1, 53, encoded_data); + + // Checksum + write_bits(compute_checksum(encoded_data, 8), 54, encoded_data, 8); + write_bit(1, 62, encoded_data); + write_bit(1, 63, encoded_data); +} + +void ProtocolIoProx::decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + // Packet structure: + // (Note: the second word seems fixed; but this may not be a guarantee; + // it currently has no meaning.) + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF + //----------------------------------------------------------------------- + //00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11 + // + // F = facility code + // V = version + // C = code + // X = checksum + + // Facility code + decoded_data[0] = (encoded_data[2] << 2) | (encoded_data[3] >> 6); + + // Version code. + decoded_data[1] = (encoded_data[3] << 3) | (encoded_data[4] >> 5); + + // Code bytes. + decoded_data[2] = (encoded_data[4] << 4) | (encoded_data[5] >> 4); + decoded_data[3] = (encoded_data[5] << 5) | (encoded_data[6] >> 3); +} + +bool ProtocolIoProx::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { + furi_check(encoded_data_size >= get_encoded_data_size()); + + // Packet framing + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF + //----------------------------------------------------------------------- + //00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11 + // + // _ = variable data + // 0 = preamble 0 + // 1 = framing 1 + // X = checksum + + // Validate the packet preamble is there... + if(encoded_data[0] != 0b00000000) { + return false; + } + if((encoded_data[1] >> 6) != 0b01) { + return false; + } + + // ... check for known ones... + if((encoded_data[2] & 0b01000000) == 0) { + return false; + } + if((encoded_data[3] & 0b00100000) == 0) { + return false; + } + if((encoded_data[4] & 0b00010000) == 0) { + return false; + } + if((encoded_data[5] & 0b00001000) == 0) { + return false; + } + if((encoded_data[6] & 0b00000100) == 0) { + return false; + } + if((encoded_data[7] & 0b00000011) == 0) { + return false; + } + + // ... and validate our checksums. + uint8_t checksum = compute_checksum(encoded_data, 8); + uint8_t checkval = (encoded_data[6] << 6) | (encoded_data[7] >> 2); + + if(checksum != checkval) { + return false; + } + + return true; +} + +uint8_t ProtocolIoProx::compute_checksum(const uint8_t* data, const uint8_t data_size) { + furi_check(data_size == get_encoded_data_size()); + + // Packet structure: + // + //0 1 2 3 4 5 6 7 + //v v v v v v v v + //01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF + //00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11 + // + // algorithm as observed by the proxmark3 folks + // CHECKSUM == 0xFF - (V + W + X + Y + Z) + + uint8_t checksum = 0; + + checksum += (data[1] << 1) | (data[2] >> 7); // VVVVVVVVV + checksum += (data[2] << 2) | (data[3] >> 6); // WWWWWWWWW + checksum += (data[3] << 3) | (data[4] >> 5); // XXXXXXXXX + checksum += (data[4] << 4) | (data[5] >> 4); // YYYYYYYYY + checksum += (data[5] << 5) | (data[6] >> 3); // ZZZZZZZZZ + + return 0xFF - checksum; +} diff --git a/applications/lfrfid/helpers/protocols/protocol_ioprox.h b/applications/lfrfid/helpers/protocols/protocol_ioprox.h new file mode 100644 index 000000000..2fff53b17 --- /dev/null +++ b/applications/lfrfid/helpers/protocols/protocol_ioprox.h @@ -0,0 +1,26 @@ +#pragma once +#include "protocol_generic.h" + +class ProtocolIoProx : public ProtocolGeneric { +public: + uint8_t get_encoded_data_size() final; + uint8_t get_decoded_data_size() final; + + void encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) final; + + void decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) final; + + bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; + +private: + /** Computes the IoProx checksum of the provided (decoded) data. */ + uint8_t compute_checksum(const uint8_t* data, const uint8_t data_size); +}; diff --git a/applications/lfrfid/helpers/rfid_reader.cpp b/applications/lfrfid/helpers/rfid_reader.cpp index 1a6ed5f70..fb837cb7a 100644 --- a/applications/lfrfid/helpers/rfid_reader.cpp +++ b/applications/lfrfid/helpers/rfid_reader.cpp @@ -25,10 +25,12 @@ void RfidReader::decode(bool polarity) { case Type::Normal: decoder_em.process_front(polarity, period); decoder_hid26.process_front(polarity, period); + decoder_ioprox.process_front(polarity, period); break; case Type::Indala: decoder_em.process_front(polarity, period); decoder_hid26.process_front(polarity, period); + decoder_ioprox.process_front(polarity, period); decoder_indala.process_front(polarity, period); break; } @@ -110,6 +112,11 @@ bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bo something_read = true; } + if(decoder_ioprox.read(data, data_size)) { + *_type = LfrfidKeyType::KeyIoProxXSF; + something_read = true; + } + if(decoder_indala.read(data, data_size)) { *_type = LfrfidKeyType::KeyI40134; something_read = true; diff --git a/applications/lfrfid/helpers/rfid_reader.h b/applications/lfrfid/helpers/rfid_reader.h index b3a93b89c..903bbecf9 100644 --- a/applications/lfrfid/helpers/rfid_reader.h +++ b/applications/lfrfid/helpers/rfid_reader.h @@ -4,6 +4,7 @@ #include "decoder_emmarin.h" #include "decoder_hid26.h" #include "decoder_indala.h" +#include "decoder_ioprox.h" #include "key_info.h" //#define RFID_GPIO_DEBUG 1 @@ -34,6 +35,7 @@ private: DecoderEMMarin decoder_em; DecoderHID26 decoder_hid26; DecoderIndala decoder_indala; + DecoderIoProx decoder_ioprox; uint32_t last_dwt_value; diff --git a/applications/lfrfid/helpers/rfid_timer_emulator.h b/applications/lfrfid/helpers/rfid_timer_emulator.h index 874a4c3dd..2129a1c7f 100644 --- a/applications/lfrfid/helpers/rfid_timer_emulator.h +++ b/applications/lfrfid/helpers/rfid_timer_emulator.h @@ -5,6 +5,7 @@ #include "encoder_emmarin.h" #include "encoder_hid_h10301.h" #include "encoder_indala_40134.h" +#include "encoder_ioprox.h" #include "pulse_joiner.h" #include @@ -22,6 +23,7 @@ private: {LfrfidKeyType::KeyEM4100, new EncoderEM()}, {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()}, {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()}, + {LfrfidKeyType::KeyIoProxXSF, new EncoderIoProx()}, }; PulseJoiner pulse_joiner; diff --git a/applications/lfrfid/helpers/rfid_worker.cpp b/applications/lfrfid/helpers/rfid_worker.cpp index 6e023cfbd..af15a340f 100644 --- a/applications/lfrfid/helpers/rfid_worker.cpp +++ b/applications/lfrfid/helpers/rfid_worker.cpp @@ -84,6 +84,11 @@ void RfidWorker::sq_write() { writer.write_indala(key.get_data()); writer.stop(); break; + case LfrfidKeyType::KeyIoProxXSF: + writer.start(); + writer.write_ioprox(key.get_data()); + writer.stop(); + break; } } } @@ -92,6 +97,7 @@ void RfidWorker::sq_write_start_validate() { switch(key.get_type()) { case LfrfidKeyType::KeyEM4100: case LfrfidKeyType::KeyH10301: + case LfrfidKeyType::KeyIoProxXSF: reader.start_forced(RfidReader::Type::Normal); break; case LfrfidKeyType::KeyI40134: diff --git a/applications/lfrfid/helpers/rfid_writer.cpp b/applications/lfrfid/helpers/rfid_writer.cpp index 996cb36ae..e85ab9361 100644 --- a/applications/lfrfid/helpers/rfid_writer.cpp +++ b/applications/lfrfid/helpers/rfid_writer.cpp @@ -1,4 +1,5 @@ #include "rfid_writer.h" +#include "protocols/protocol_ioprox.h" #include #include "protocols/protocol_emmarin.h" #include "protocols/protocol_hid_h10301.h" @@ -143,6 +144,28 @@ void RfidWriter::write_hid(const uint8_t hid_data[3]) { FURI_CRITICAL_EXIT(); } +/** Endian fixup. Translates an ioprox block into a t5577 block */ +static uint32_t ioprox_encode_block(const uint8_t block_data[4]) { + uint8_t raw_card_data[] = {block_data[3], block_data[2], block_data[1], block_data[0]}; + return *reinterpret_cast(&raw_card_data); +} + +void RfidWriter::write_ioprox(const uint8_t ioprox_data[4]) { + ProtocolIoProx ioprox_card; + + uint8_t encoded_data[8]; + ioprox_card.encode(ioprox_data, 4, encoded_data, sizeof(encoded_data)); + + const uint32_t ioprox_config_block_data = 0b00000000000101000111000001000000; + + FURI_CRITICAL_ENTER(); + write_block(0, 0, false, ioprox_config_block_data); + write_block(0, 1, false, ioprox_encode_block(&encoded_data[0])); + write_block(0, 2, false, ioprox_encode_block(&encoded_data[4])); + write_reset(); + FURI_CRITICAL_EXIT(); +} + void RfidWriter::write_indala(const uint8_t indala_data[3]) { ProtocolIndala40134 indala_card; uint32_t card_data[2]; diff --git a/applications/lfrfid/helpers/rfid_writer.h b/applications/lfrfid/helpers/rfid_writer.h index 38329877b..98d2bf955 100644 --- a/applications/lfrfid/helpers/rfid_writer.h +++ b/applications/lfrfid/helpers/rfid_writer.h @@ -9,6 +9,7 @@ public: void stop(); void write_em(const uint8_t em_data[5]); void write_hid(const uint8_t hid_data[3]); + void write_ioprox(const uint8_t ioprox_data[4]); void write_indala(const uint8_t indala_data[3]); private: diff --git a/applications/lfrfid/lfrfid_cli.cpp b/applications/lfrfid/lfrfid_cli.cpp index dbd37ddc8..451f10cef 100644 --- a/applications/lfrfid/lfrfid_cli.cpp +++ b/applications/lfrfid/lfrfid_cli.cpp @@ -28,6 +28,7 @@ void lfrfid_cli_print_usage() { printf("\tEM4100, EM-Marin (5 bytes key_data)\r\n"); printf("\tH10301, HID26 (3 bytes key_data)\r\n"); printf("\tI40134, Indala (3 bytes key_data)\r\n"); + printf("\tIoProxXSF, IoProx (4 bytes key_data)\r\n"); printf("\t are hex-formatted\r\n"); }; @@ -43,6 +44,9 @@ static bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) { } else if(string_cmp_str(data, "I40134") == 0 || string_cmp_str(data, "Indala") == 0) { result = true; *type = LfrfidKeyType::KeyI40134; + } else if(string_cmp_str(data, "IoProxXSF") == 0 || string_cmp_str(data, "IoProx") == 0) { + result = true; + *type = LfrfidKeyType::KeyIoProxXSF; } return result; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp index 40bd9e360..236ca8c29 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp @@ -50,6 +50,14 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore string_printf( string_decrypted, "FC: %u ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); break; + case LfrfidKeyType::KeyIoProxXSF: + string_printf( + string_decrypted, + "FC: %u VC: %u ID: %u", + data[0], + data[1], + (uint16_t)((data[2] << 8) | (data[3]))); + break; } line_3->set_text( string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp index 2b81a58a0..fd6f46a09 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp @@ -7,6 +7,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ string_init(string[0]); string_init(string[1]); string_init(string[2]); + string_init(string[3]); auto container = app->view_controller.get(); @@ -25,11 +26,13 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ header->set_text(app->worker.key.get_type_text(), 89, 3, 0, AlignCenter); auto line_1_text = container->add(); - auto line_2_text = container->add(); + auto line_2l_text = container->add(); + auto line_2r_text = container->add(); auto line_3_text = container->add(); auto line_1_value = container->add(); - auto line_2_value = container->add(); + auto line_2l_value = container->add(); + auto line_2r_value = container->add(); auto line_3_value = container->add(); const uint8_t* data = app->worker.key.get_data(); @@ -37,7 +40,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ switch(app->worker.key.get_type()) { case LfrfidKeyType::KeyEM4100: line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2_text->set_text("Mod:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_2l_text->set_text("Mod:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); line_3_text->set_text("ID:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { @@ -49,7 +52,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ line_1_value->set_text( string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2_value->set_text( + line_2l_value->set_text( string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); line_3_value->set_text( string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); @@ -57,7 +60,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ case LfrfidKeyType::KeyH10301: case LfrfidKeyType::KeyI40134: line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); - line_2_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_2l_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { @@ -69,11 +72,36 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ line_1_value->set_text( string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); - line_2_value->set_text( + line_2l_value->set_text( string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); line_3_value->set_text( string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); break; + + case LfrfidKeyType::KeyIoProxXSF: + line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); + line_2l_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_2r_text->set_text("V:", 95, 35, 0, AlignRight, AlignBottom, FontSecondary); + line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); + + for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { + string_cat_printf(string[0], "%02X", data[i]); + } + + string_printf(string[1], "%u", data[0]); + string_printf(string[2], "%u", (uint16_t)((data[2] << 8) | (data[3]))); + string_printf(string[3], "%u", data[1]); + + line_1_value->set_text( + string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary); + line_2l_value->set_text( + string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary); + line_2r_value->set_text( + string_get_cstr(string[3]), 98, 35, 0, AlignLeft, AlignBottom, FontSecondary); + line_3_value->set_text( + string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); + + break; } app->view_controller.switch_to(); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h index 1f6f6d742..847c0dabb 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_save_type.h +++ b/applications/lfrfid/scene/lfrfid_app_scene_save_type.h @@ -10,6 +10,6 @@ public: private: static void submenu_callback(void* context, uint32_t index); uint32_t submenu_item_selected = 0; - static const uint8_t keys_count = static_cast(LfrfidKeyType::KeyI40134); + static const uint8_t keys_count = static_cast(LfrfidKeyType::KeyIoProxXSF); string_t submenu_name[keys_count + 1]; }; diff --git a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp index 73c9a403e..dd4a3d4eb 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp @@ -43,6 +43,14 @@ void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) string_printf( string_decrypted, "FC: %u ID: %u", data[0], (uint16_t)((data[1] << 8) | (data[2]))); break; + case LfrfidKeyType::KeyIoProxXSF: + string_printf( + string_decrypted, + "FC: %u VC: %u ID: %u", + data[0], + data[1], + (uint16_t)((data[2] << 8) | (data[3]))); + break; } line_3->set_text( string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary);