[FL-2529][FL-1628] New LF-RFID subsystem (#1601)
* Makefile: unit tests pack * RFID: pulse joiner and its unit test * Move pulse protocol helpers to appropriate place * Drop pulse_joiner tests * Generic protocol, protocols dictionary, unit test * Protocol dict unit test * iButton: protocols dictionary * Lib: varint * Lib: profiler * Unit test: varint * rfid: worker mockup * LFRFID: em4100 unit test * Storage: file_exist function * rfid: fsk osc * rfid: generic fsk demodulator * rfid: protocol em4100 * rfid: protocol h10301 * rfid: protocol io prox xsf * Unit test: rfid protocols * rfid: new hal * rfid: raw worker * Unit test: fix error output * rfid: worker * rfid: plain c cli * fw: migrate to scons * lfrfid: full io prox support * unit test: io prox protocol * SubGHZ: move bit defines to source * FSK oscillator: level duration compability * libs: bit manipulation library * lfrfid: ioprox protocol, use bit library and new level duration method of FSK ocillator * bit lib: unit tests * Bit lib: parity tests, remove every nth bit, copy bits * Lfrfid: awid protocol * bit lib: uint16 and uint32 getters, unit tests * lfrfid: FDX-B read, draft version * Minunit: better memeq assert * bit lib: reverse, print, print regions * Protocol dict: get protocol features, get protocol validate count * lfrfid worker: improved read * lfrfid raw worker: psk support * Cli: rfid plain C cli * protocol AWID: render * protocol em4100: render * protocol h10301: render * protocol indala26: support every indala 26 scramble * Protocol IO Prox: render * Protocol FDX-B: advanced read * lfrfid: remove unused test function * lfrfid: fix os primitives * bit lib: crc16 and unit tests * FDX-B: save data * lfrfid worker: increase stream size. Alloc raw worker only when needed. * lfrfid: indala26 emulation * lfrfid: prepare to write * lfrfid: fdx-b emulation * lfrfid: awid, ioprox write * lfrfid: write t55xx w\o validation * lfrfid: better t55xx block0 handling * lfrfid: use new t5577 functions in worker * lfrfid: improve protocol description * lfrfid: write and verify * lfrfid: delete cpp cli * lfrfid: improve worker usage * lfrfid-app: step to new worker * lfrfid: old indala (I40134) load fallback * lfrfid: indala26, recover wrong synced data * lfrfid: remove old worker * lfrfid app: dummy read screen * lfrfid app: less dummy read screen * lfrfid: generic 96-bit HID protocol (covers up to HID 37-bit) * rename * lfrfid: improve indala26 read * lfrfid: generic 192-bit HID protocol (covers all HID extended) * lfrfid: TODO about HID render * lfrfid: new protocol FDX-A * lfrfid-app: correct worker stop on exit * misc fixes * lfrfid: FDX-A and HID distinguishability has been fixed. * lfrfid: decode HID size header and render it (#1612) * lfrfid: rename HID96 and HID192 to HIDProx and HIDExt * lfrfid: extra actions scene * lfrfid: decode generic HID Proximity size lazily (#1618) * lib: stream of data buffers concept * lfrfid: raw file helper * lfrfid: changed raw worker api * lfrfid: packed varint pair * lfrfid: read stream speedup * lfrfid app: show read mode * Documentation * lfrfid app: raw read gui * lfrfid app: storage check for raw read * memleak fix * review fixes * lfrfid app: read blink color * lfrfid app: reset key name after read * review fixes * lfrfid app: fix copypasted text * review fixes * lfrfid: disable debug gpio * lfrfid: card detection events * lfrfid: change validation color from magenta to green * Update core_defines. * lfrfid: prefix fdx-b id by zeroes * lfrfid: parse up to 43-bit HID Proximity keys (#1640) * Fbt: downgrade toolchain and fix PS1 * lfrfid: fix unit tests * lfrfid app: remove printf * lfrfid: indala26, use bit 55 as data * lfrfid: indala26, better brief format * lfrfid: indala26, loading fallback * lfrfid: read timing tuning Co-authored-by: James Ide <ide@users.noreply.github.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									f92127c0a7
								
							
						
					
					
						commit
						9bfb641d3e
					
				| @ -29,23 +29,13 @@ bool archive_app_is_available(void* context, const char* path) { | |||||||
| 
 | 
 | ||||||
|     if(app == ArchiveAppTypeU2f) { |     if(app == ArchiveAppTypeU2f) { | ||||||
|         bool file_exists = false; |         bool file_exists = false; | ||||||
|         Storage* fs_api = furi_record_open(RECORD_STORAGE); |         Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|         File* file = storage_file_alloc(fs_api); |  | ||||||
| 
 | 
 | ||||||
|         file_exists = |         if(storage_file_exists(storage, ANY_PATH("u2f/key.u2f"))) { | ||||||
|             storage_file_open(file, ANY_PATH("u2f/key.u2f"), FSAM_READ, FSOM_OPEN_EXISTING); |             file_exists = storage_file_exists(storage, ANY_PATH("u2f/cnt.u2f")); | ||||||
|         if(file_exists) { |  | ||||||
|             storage_file_close(file); |  | ||||||
|             file_exists = |  | ||||||
|                 storage_file_open(file, ANY_PATH("u2f/cnt.u2f"), FSAM_READ, FSOM_OPEN_EXISTING); |  | ||||||
|             if(file_exists) { |  | ||||||
|                 storage_file_close(file); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         storage_file_free(file); |  | ||||||
|         furi_record_close(RECORD_STORAGE); |         furi_record_close(RECORD_STORAGE); | ||||||
| 
 |  | ||||||
|         return file_exists; |         return file_exists; | ||||||
|     } else { |     } else { | ||||||
|         return false; |         return false; | ||||||
|  | |||||||
| @ -82,9 +82,8 @@ uint16_t archive_favorites_count(void* context) { | |||||||
| static bool archive_favourites_rescan() { | static bool archive_favourites_rescan() { | ||||||
|     string_t buffer; |     string_t buffer; | ||||||
|     string_init(buffer); |     string_init(buffer); | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(storage); | ||||||
|     File* fav_item_file = storage_file_alloc(fs_api); |  | ||||||
| 
 | 
 | ||||||
|     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); |     bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|     if(result) { |     if(result) { | ||||||
| @ -101,13 +100,8 @@ static bool archive_favourites_rescan() { | |||||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); |                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 bool file_exists = storage_file_open( |                 if(storage_file_exists(storage, string_get_cstr(buffer))) { | ||||||
|                     fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING); |  | ||||||
|                 if(file_exists) { |  | ||||||
|                     storage_file_close(fav_item_file); |  | ||||||
|                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); |                     archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); | ||||||
|                 } else { |  | ||||||
|                     storage_file_close(fav_item_file); |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -116,12 +110,11 @@ static bool archive_favourites_rescan() { | |||||||
|     string_clear(buffer); |     string_clear(buffer); | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_common_remove(fs_api, ARCHIVE_FAV_PATH); |     storage_common_remove(storage, ARCHIVE_FAV_PATH); | ||||||
|     storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); |     storage_common_rename(storage, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); | ||||||
|     storage_common_remove(fs_api, ARCHIVE_FAV_TEMP_PATH); |     storage_common_remove(storage, ARCHIVE_FAV_TEMP_PATH); | ||||||
| 
 | 
 | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|     storage_file_free(fav_item_file); |  | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| @ -131,9 +124,8 @@ bool archive_favorites_read(void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| 
 | 
 | ||||||
|     ArchiveBrowserView* browser = context; |     ArchiveBrowserView* browser = context; | ||||||
|     Storage* fs_api = furi_record_open(RECORD_STORAGE); |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|     File* file = storage_file_alloc(fs_api); |     File* file = storage_file_alloc(storage); | ||||||
|     File* fav_item_file = storage_file_alloc(fs_api); |  | ||||||
| 
 | 
 | ||||||
|     string_t buffer; |     string_t buffer; | ||||||
|     FileInfo file_info; |     FileInfo file_info; | ||||||
| @ -163,16 +155,12 @@ bool archive_favorites_read(void* context) { | |||||||
|                     need_refresh = true; |                     need_refresh = true; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 bool file_exists = storage_file_open( |                 if(storage_file_exists(storage, string_get_cstr(buffer))) { | ||||||
|                     fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING); |                     storage_common_stat(storage, string_get_cstr(buffer), &file_info); | ||||||
|                 if(file_exists) { |  | ||||||
|                     storage_common_stat(fs_api, string_get_cstr(buffer), &file_info); |  | ||||||
|                     storage_file_close(fav_item_file); |  | ||||||
|                     archive_add_file_item( |                     archive_add_file_item( | ||||||
|                         browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer)); |                         browser, (file_info.flags & FSF_DIRECTORY), string_get_cstr(buffer)); | ||||||
|                     file_count++; |                     file_count++; | ||||||
|                 } else { |                 } else { | ||||||
|                     storage_file_close(fav_item_file); |  | ||||||
|                     need_refresh = true; |                     need_refresh = true; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -183,7 +171,6 @@ bool archive_favorites_read(void* context) { | |||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     string_clear(buffer); |     string_clear(buffer); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|     storage_file_free(fav_item_file); |  | ||||||
|     furi_record_close(RECORD_STORAGE); |     furi_record_close(RECORD_STORAGE); | ||||||
| 
 | 
 | ||||||
|     archive_set_item_count(browser, file_count); |     archive_set_item_count(browser, file_count); | ||||||
|  | |||||||
| @ -220,8 +220,7 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager | |||||||
|             furi_assert(blocking_animation); |             furi_assert(blocking_animation); | ||||||
|             animation_manager->sd_shown_sd_ok = true; |             animation_manager->sd_shown_sd_ok = true; | ||||||
|         } else if(!animation_manager->sd_shown_no_db) { |         } else if(!animation_manager->sd_shown_no_db) { | ||||||
|             bool db_exists = storage_common_stat(storage, EXT_PATH("Manifest"), NULL) == FSE_OK; |             if(!storage_file_exists(storage, EXT_PATH("Manifest"))) { | ||||||
|             if(!db_exists) { |  | ||||||
|                 blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME); |                 blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME); | ||||||
|                 furi_assert(blocking_animation); |                 furi_assert(blocking_animation); | ||||||
|                 animation_manager->sd_shown_no_db = true; |                 animation_manager->sd_shown_no_db = true; | ||||||
|  | |||||||
| @ -1,50 +0,0 @@ | |||||||
| #include "decoder_analyzer.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal.h> |  | ||||||
| 
 |  | ||||||
| // FIXME: unused args?
 |  | ||||||
| bool DecoderAnalyzer::read(uint8_t* /* _data */, uint8_t /* _data_size */) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     if(ready) { |  | ||||||
|         result = true; |  | ||||||
| 
 |  | ||||||
|         for(size_t i = 0; i < data_size; i++) { |  | ||||||
|             printf("%lu ", data[i]); |  | ||||||
|             if((i + 1) % 8 == 0) printf("\r\n"); |  | ||||||
|         } |  | ||||||
|         printf("\r\n--------\r\n"); |  | ||||||
| 
 |  | ||||||
|         ready = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderAnalyzer::process_front(bool polarity, uint32_t time) { |  | ||||||
|     UNUSED(polarity); |  | ||||||
|     if(ready) return; |  | ||||||
| 
 |  | ||||||
|     data[data_index] = time; |  | ||||||
| 
 |  | ||||||
|     if(data_index < data_size) { |  | ||||||
|         data_index++; |  | ||||||
|     } else { |  | ||||||
|         data_index = 0; |  | ||||||
|         ready = true; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderAnalyzer::DecoderAnalyzer() { |  | ||||||
|     data = reinterpret_cast<uint32_t*>(calloc(data_size, sizeof(uint32_t))); |  | ||||||
|     furi_check(data); |  | ||||||
|     data_index = 0; |  | ||||||
|     ready = false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderAnalyzer::~DecoderAnalyzer() { |  | ||||||
|     free(data); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderAnalyzer::reset_state() { |  | ||||||
| } |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <atomic> |  | ||||||
| 
 |  | ||||||
| class DecoderAnalyzer { |  | ||||||
| public: |  | ||||||
|     bool read(uint8_t* data, uint8_t data_size); |  | ||||||
|     void process_front(bool polarity, uint32_t time); |  | ||||||
| 
 |  | ||||||
|     DecoderAnalyzer(); |  | ||||||
|     ~DecoderAnalyzer(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void reset_state(); |  | ||||||
| 
 |  | ||||||
|     std::atomic<bool> ready; |  | ||||||
| 
 |  | ||||||
|     static const uint32_t data_size = 2048; |  | ||||||
|     uint32_t data_index = 0; |  | ||||||
|     uint32_t* data; |  | ||||||
| }; |  | ||||||
| @ -1,72 +0,0 @@ | |||||||
| #include "emmarin.h" |  | ||||||
| #include "decoder_emmarin.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal.h> |  | ||||||
| 
 |  | ||||||
| constexpr uint32_t clocks_in_us = 64; |  | ||||||
| constexpr uint32_t short_time = 255 * clocks_in_us; |  | ||||||
| constexpr uint32_t long_time = 510 * clocks_in_us; |  | ||||||
| constexpr uint32_t jitter_time = 100 * clocks_in_us; |  | ||||||
| 
 |  | ||||||
| constexpr uint32_t short_time_low = short_time - jitter_time; |  | ||||||
| constexpr uint32_t short_time_high = short_time + jitter_time; |  | ||||||
| constexpr uint32_t long_time_low = long_time - jitter_time; |  | ||||||
| constexpr uint32_t long_time_high = long_time + jitter_time; |  | ||||||
| 
 |  | ||||||
| void DecoderEMMarin::reset_state() { |  | ||||||
|     ready = false; |  | ||||||
|     read_data = 0; |  | ||||||
|     manchester_advance( |  | ||||||
|         manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DecoderEMMarin::read(uint8_t* data, uint8_t data_size) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     if(ready) { |  | ||||||
|         result = true; |  | ||||||
|         em_marin.decode( |  | ||||||
|             reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t), data, data_size); |  | ||||||
|         ready = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderEMMarin::process_front(bool polarity, uint32_t time) { |  | ||||||
|     if(ready) return; |  | ||||||
|     if(time < short_time_low) return; |  | ||||||
| 
 |  | ||||||
|     ManchesterEvent event = ManchesterEventReset; |  | ||||||
| 
 |  | ||||||
|     if(time > short_time_low && time < short_time_high) { |  | ||||||
|         if(polarity) { |  | ||||||
|             event = ManchesterEventShortHigh; |  | ||||||
|         } else { |  | ||||||
|             event = ManchesterEventShortLow; |  | ||||||
|         } |  | ||||||
|     } else if(time > long_time_low && time < long_time_high) { |  | ||||||
|         if(polarity) { |  | ||||||
|             event = ManchesterEventLongHigh; |  | ||||||
|         } else { |  | ||||||
|             event = ManchesterEventLongLow; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(event != ManchesterEventReset) { |  | ||||||
|         bool data; |  | ||||||
|         bool data_ok = |  | ||||||
|             manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); |  | ||||||
| 
 |  | ||||||
|         if(data_ok) { |  | ||||||
|             read_data = (read_data << 1) | data; |  | ||||||
| 
 |  | ||||||
|             ready = em_marin.can_be_decoded( |  | ||||||
|                 reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderEMMarin::DecoderEMMarin() { |  | ||||||
|     reset_state(); |  | ||||||
| } |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <atomic> |  | ||||||
| #include <lib/toolbox/manchester_decoder.h> |  | ||||||
| #include "protocols/protocol_emmarin.h" |  | ||||||
| class DecoderEMMarin { |  | ||||||
| public: |  | ||||||
|     bool read(uint8_t* data, uint8_t data_size); |  | ||||||
|     void process_front(bool polarity, uint32_t time); |  | ||||||
| 
 |  | ||||||
|     DecoderEMMarin(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void reset_state(); |  | ||||||
| 
 |  | ||||||
|     uint64_t read_data = 0; |  | ||||||
|     std::atomic<bool> ready; |  | ||||||
| 
 |  | ||||||
|     ManchesterState manchester_saved_state; |  | ||||||
|     ProtocolEMMarin em_marin; |  | ||||||
| }; |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| #include "decoder_gpio_out.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal.h> |  | ||||||
| 
 |  | ||||||
| void DecoderGpioOut::process_front(bool polarity, uint32_t /* time */) { |  | ||||||
|     furi_hal_gpio_write(&gpio_ext_pa7, polarity); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderGpioOut::DecoderGpioOut() { |  | ||||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderGpioOut::~DecoderGpioOut() { |  | ||||||
|     furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); |  | ||||||
| } |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <atomic> |  | ||||||
| 
 |  | ||||||
| class DecoderGpioOut { |  | ||||||
| public: |  | ||||||
|     void process_front(bool polarity, uint32_t time); |  | ||||||
| 
 |  | ||||||
|     DecoderGpioOut(); |  | ||||||
|     ~DecoderGpioOut(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void reset_state(); |  | ||||||
| }; |  | ||||||
| @ -1,98 +0,0 @@ | |||||||
| #include "decoder_hid26.h" |  | ||||||
| #include <furi_hal.h> |  | ||||||
| 
 |  | ||||||
| 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 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; |  | ||||||
| 
 |  | ||||||
| bool DecoderHID26::read(uint8_t* data, uint8_t data_size) { |  | ||||||
|     bool result = false; |  | ||||||
|     furi_assert(data_size >= 3); |  | ||||||
| 
 |  | ||||||
|     if(ready) { |  | ||||||
|         result = true; |  | ||||||
|         hid.decode( |  | ||||||
|             reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3, data, data_size); |  | ||||||
|         ready = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderHID26::process_front(bool polarity, uint32_t time) { |  | ||||||
|     if(ready) return; |  | ||||||
| 
 |  | ||||||
|     if(polarity == true) { |  | ||||||
|         last_pulse_time = time; |  | ||||||
|     } else { |  | ||||||
|         last_pulse_time += time; |  | ||||||
| 
 |  | ||||||
|         if(last_pulse_time > min_time && last_pulse_time < max_time) { |  | ||||||
|             bool pulse; |  | ||||||
| 
 |  | ||||||
|             if(last_pulse_time < mid_time) { |  | ||||||
|                 // 6 pulses
 |  | ||||||
|                 pulse = false; |  | ||||||
|             } else { |  | ||||||
|                 // 5 pulses
 |  | ||||||
|                 pulse = true; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if(last_pulse == pulse) { |  | ||||||
|                 pulse_count++; |  | ||||||
| 
 |  | ||||||
|                 if(pulse) { |  | ||||||
|                     if(pulse_count > 4) { |  | ||||||
|                         pulse_count = 0; |  | ||||||
|                         store_data(1); |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     if(pulse_count > 5) { |  | ||||||
|                         pulse_count = 0; |  | ||||||
|                         store_data(0); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 if(last_pulse) { |  | ||||||
|                     if(pulse_count > 2) { |  | ||||||
|                         store_data(1); |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     if(pulse_count > 3) { |  | ||||||
|                         store_data(0); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 pulse_count = 0; |  | ||||||
|                 last_pulse = pulse; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderHID26::DecoderHID26() { |  | ||||||
|     reset_state(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderHID26::store_data(bool data) { |  | ||||||
|     stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); |  | ||||||
|     stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); |  | ||||||
|     stored_data[2] = (stored_data[2] << 1) | data; |  | ||||||
| 
 |  | ||||||
|     if(hid.can_be_decoded(reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3)) { |  | ||||||
|         ready = true; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderHID26::reset_state() { |  | ||||||
|     last_pulse = false; |  | ||||||
|     pulse_count = 0; |  | ||||||
|     ready = false; |  | ||||||
|     last_pulse_time = 0; |  | ||||||
| } |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <atomic> |  | ||||||
| #include "protocols/protocol_hid_h10301.h" |  | ||||||
| 
 |  | ||||||
| class DecoderHID26 { |  | ||||||
| public: |  | ||||||
|     bool read(uint8_t* data, uint8_t data_size); |  | ||||||
|     void process_front(bool polarity, uint32_t time); |  | ||||||
|     DecoderHID26(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     uint32_t last_pulse_time = 0; |  | ||||||
|     bool last_pulse; |  | ||||||
|     uint8_t pulse_count; |  | ||||||
| 
 |  | ||||||
|     uint32_t stored_data[3] = {0, 0, 0}; |  | ||||||
|     void store_data(bool data); |  | ||||||
| 
 |  | ||||||
|     std::atomic<bool> ready; |  | ||||||
| 
 |  | ||||||
|     void reset_state(); |  | ||||||
|     ProtocolHID10301 hid; |  | ||||||
| }; |  | ||||||
| @ -1,76 +0,0 @@ | |||||||
| #include "decoder_indala.h" |  | ||||||
| #include <furi_hal.h> |  | ||||||
| 
 |  | ||||||
| constexpr uint32_t clocks_in_us = 64; |  | ||||||
| constexpr uint32_t us_per_bit = 255; |  | ||||||
| 
 |  | ||||||
| bool DecoderIndala::read(uint8_t* data, uint8_t data_size) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     if(ready) { |  | ||||||
|         result = true; |  | ||||||
|         if(cursed_data_valid) { |  | ||||||
|             indala.decode( |  | ||||||
|                 reinterpret_cast<const uint8_t*>(&cursed_raw_data), |  | ||||||
|                 sizeof(uint64_t), |  | ||||||
|                 data, |  | ||||||
|                 data_size); |  | ||||||
|         } else { |  | ||||||
|             indala.decode( |  | ||||||
|                 reinterpret_cast<const uint8_t*>(&raw_data), sizeof(uint64_t), data, data_size); |  | ||||||
|         } |  | ||||||
|         reset_state(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderIndala::process_front(bool polarity, uint32_t time) { |  | ||||||
|     if(ready) return; |  | ||||||
| 
 |  | ||||||
|     process_internal(polarity, time, &raw_data); |  | ||||||
|     if(ready) return; |  | ||||||
| 
 |  | ||||||
|     if(polarity) { |  | ||||||
|         time = time + 110; |  | ||||||
|     } else { |  | ||||||
|         time = time - 110; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     process_internal(!polarity, time, &cursed_raw_data); |  | ||||||
|     if(ready) { |  | ||||||
|         cursed_data_valid = true; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderIndala::process_internal(bool polarity, uint32_t time, uint64_t* data) { |  | ||||||
|     time /= clocks_in_us; |  | ||||||
|     time += (us_per_bit / 2); |  | ||||||
| 
 |  | ||||||
|     uint32_t bit_count = (time / us_per_bit); |  | ||||||
| 
 |  | ||||||
|     if(bit_count < 64) { |  | ||||||
|         for(uint32_t i = 0; i < bit_count; i++) { |  | ||||||
|             *data = (*data << 1) | polarity; |  | ||||||
| 
 |  | ||||||
|             if((*data >> 32) == 0xa0000000ULL) { |  | ||||||
|                 if(indala.can_be_decoded( |  | ||||||
|                        reinterpret_cast<const uint8_t*>(data), sizeof(uint64_t))) { |  | ||||||
|                     ready = true; |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DecoderIndala::DecoderIndala() { |  | ||||||
|     reset_state(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DecoderIndala::reset_state() { |  | ||||||
|     raw_data = 0; |  | ||||||
|     cursed_raw_data = 0; |  | ||||||
|     ready = false; |  | ||||||
|     cursed_data_valid = false; |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <limits.h> |  | ||||||
| #include <atomic> |  | ||||||
| #include "protocols/protocol_indala_40134.h" |  | ||||||
| 
 |  | ||||||
| class DecoderIndala { |  | ||||||
| public: |  | ||||||
|     bool read(uint8_t* data, uint8_t data_size); |  | ||||||
|     void process_front(bool polarity, uint32_t time); |  | ||||||
| 
 |  | ||||||
|     void process_internal(bool polarity, uint32_t time, uint64_t* data); |  | ||||||
| 
 |  | ||||||
|     DecoderIndala(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     void reset_state(); |  | ||||||
| 
 |  | ||||||
|     uint64_t raw_data; |  | ||||||
|     uint64_t cursed_raw_data; |  | ||||||
| 
 |  | ||||||
|     std::atomic<bool> ready; |  | ||||||
|     std::atomic<bool> cursed_data_valid; |  | ||||||
|     ProtocolIndala40134 indala; |  | ||||||
| }; |  | ||||||
| @ -1,107 +0,0 @@ | |||||||
| #include "decoder_ioprox.h" |  | ||||||
| #include <furi_hal.h> |  | ||||||
| #include <cli/cli.h> |  | ||||||
| #include <utility> |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <atomic> |  | ||||||
| #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<bool> ready; |  | ||||||
| 
 |  | ||||||
|     void reset_state(); |  | ||||||
|     ProtocolIoProx ioprox; |  | ||||||
| }; |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| #define EM_HEADER_POS 55 |  | ||||||
| #define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) |  | ||||||
| 
 |  | ||||||
| #define EM_FIRST_ROW_POS 50 |  | ||||||
| #define EM_ROW_COUNT 10 |  | ||||||
| 
 |  | ||||||
| #define EM_COLUMN_POS 4 |  | ||||||
| #define EM_STOP_POS 0 |  | ||||||
| #define EM_STOP_MASK (0x1LLU << EM_STOP_POS) |  | ||||||
| 
 |  | ||||||
| #define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) |  | ||||||
| #define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| #include "encoder_emmarin.h" |  | ||||||
| #include "protocols/protocol_emmarin.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| void EncoderEM::init(const uint8_t* data, const uint8_t data_size) { |  | ||||||
|     ProtocolEMMarin em_marin; |  | ||||||
|     em_marin.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(uint64_t)); |  | ||||||
| 
 |  | ||||||
|     card_data_index = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // data transmitted as manchester encoding
 |  | ||||||
| // 0 - high2low
 |  | ||||||
| // 1 - low2high
 |  | ||||||
| void EncoderEM::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { |  | ||||||
|     *period = clocks_per_bit; |  | ||||||
|     *pulse = clocks_per_bit / 2; |  | ||||||
|     *polarity = (card_data >> (63 - card_data_index)) & 1; |  | ||||||
| 
 |  | ||||||
|     card_data_index++; |  | ||||||
|     if(card_data_index >= 64) { |  | ||||||
|         card_data_index = 0; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "encoder_generic.h" |  | ||||||
| 
 |  | ||||||
| class EncoderEM : public EncoderGeneric { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief init data to emulate |  | ||||||
|      *  |  | ||||||
|      * @param data 1 byte FC, next 4 byte SN |  | ||||||
|      * @param data_size must be 5 |  | ||||||
|      */ |  | ||||||
|     void init(const uint8_t* data, const uint8_t data_size) final; |  | ||||||
| 
 |  | ||||||
|     void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     // clock pulses per bit
 |  | ||||||
|     static const uint8_t clocks_per_bit = 64; |  | ||||||
| 
 |  | ||||||
|     uint64_t card_data; |  | ||||||
|     uint8_t card_data_index; |  | ||||||
| }; |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| class EncoderGeneric { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief init encoder |  | ||||||
|      *  |  | ||||||
|      * @param data data array |  | ||||||
|      * @param data_size data array size |  | ||||||
|      */ |  | ||||||
|     virtual void init(const uint8_t* data, const uint8_t data_size) = 0; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief Get the next timer pulse |  | ||||||
|      *  |  | ||||||
|      * @param polarity pulse polarity true = high2low, false = low2high |  | ||||||
|      * @param period overall period time in timer clicks |  | ||||||
|      * @param pulse pulse time in timer clicks |  | ||||||
|      */ |  | ||||||
|     virtual void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) = 0; |  | ||||||
| 
 |  | ||||||
|     virtual ~EncoderGeneric(){}; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| }; |  | ||||||
| @ -1,46 +0,0 @@ | |||||||
| #include "encoder_hid_h10301.h" |  | ||||||
| #include "protocols/protocol_hid_h10301.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) { |  | ||||||
|     ProtocolHID10301 hid; |  | ||||||
|     hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3); |  | ||||||
| 
 |  | ||||||
|     card_data_index = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EncoderHID_H10301::write_bit(bool bit, uint8_t position) { |  | ||||||
|     write_raw_bit(bit, position + 0); |  | ||||||
|     write_raw_bit(!bit, position + 1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EncoderHID_H10301::write_raw_bit(bool bit, uint8_t position) { |  | ||||||
|     if(bit) { |  | ||||||
|         card_data[position / 32] |= 1UL << (31 - (position % 32)); |  | ||||||
|     } else { |  | ||||||
|         card_data[position / 32] &= ~(1UL << (31 - (position % 32))); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EncoderHID_H10301::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { |  | ||||||
|     uint8_t bit = (card_data[card_data_index / 32] >> (31 - (card_data_index % 32))) & 1; |  | ||||||
| 
 |  | ||||||
|     bool advance = fsk->next(bit, period); |  | ||||||
|     if(advance) { |  | ||||||
|         card_data_index++; |  | ||||||
|         if(card_data_index >= (32 * card_data_max)) { |  | ||||||
|             card_data_index = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     *polarity = true; |  | ||||||
|     *pulse = *period / 2; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| EncoderHID_H10301::EncoderHID_H10301() { |  | ||||||
|     fsk = new OscFSK(8, 10, 50); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| EncoderHID_H10301::~EncoderHID_H10301() { |  | ||||||
|     delete fsk; |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "encoder_generic.h" |  | ||||||
| #include "osc_fsk.h" |  | ||||||
| 
 |  | ||||||
| class EncoderHID_H10301 : public EncoderGeneric { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief init data to emulate |  | ||||||
|      *  |  | ||||||
|      * @param data 1 byte FC, next 2 byte SN |  | ||||||
|      * @param data_size must be 3 |  | ||||||
|      */ |  | ||||||
|     void init(const uint8_t* data, const uint8_t data_size) final; |  | ||||||
|     void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; |  | ||||||
|     EncoderHID_H10301(); |  | ||||||
|     ~EncoderHID_H10301(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     static const uint8_t card_data_max = 3; |  | ||||||
|     uint32_t card_data[card_data_max]; |  | ||||||
|     uint8_t card_data_index; |  | ||||||
|     void write_bit(bool bit, uint8_t position); |  | ||||||
|     void write_raw_bit(bool bit, uint8_t position); |  | ||||||
| 
 |  | ||||||
|     OscFSK* fsk; |  | ||||||
| }; |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| #include "encoder_indala_40134.h" |  | ||||||
| #include "protocols/protocol_indala_40134.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) { |  | ||||||
|     ProtocolIndala40134 indala; |  | ||||||
|     indala.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data)); |  | ||||||
| 
 |  | ||||||
|     last_bit = card_data & 1; |  | ||||||
|     card_data_index = 0; |  | ||||||
|     current_polarity = true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { |  | ||||||
|     *period = 2; |  | ||||||
|     *pulse = 1; |  | ||||||
|     *polarity = current_polarity; |  | ||||||
| 
 |  | ||||||
|     bit_clock_index++; |  | ||||||
|     if(bit_clock_index >= clock_per_bit) { |  | ||||||
|         bit_clock_index = 0; |  | ||||||
| 
 |  | ||||||
|         bool current_bit = (card_data >> (63 - card_data_index)) & 1; |  | ||||||
| 
 |  | ||||||
|         if(current_bit != last_bit) { |  | ||||||
|             current_polarity = !current_polarity; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         last_bit = current_bit; |  | ||||||
| 
 |  | ||||||
|         card_data_index++; |  | ||||||
|         if(card_data_index >= 64) { |  | ||||||
|             card_data_index = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,23 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "encoder_generic.h" |  | ||||||
| 
 |  | ||||||
| class EncoderIndala_40134 : public EncoderGeneric { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief init data to emulate |  | ||||||
|      *  |  | ||||||
|      * @param data indala raw data |  | ||||||
|      * @param data_size must be 5 |  | ||||||
|      */ |  | ||||||
|     void init(const uint8_t* data, const uint8_t data_size) final; |  | ||||||
| 
 |  | ||||||
|     void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     uint64_t card_data; |  | ||||||
|     uint8_t card_data_index; |  | ||||||
|     uint8_t bit_clock_index; |  | ||||||
|     bool last_bit; |  | ||||||
|     bool current_polarity; |  | ||||||
|     static const uint8_t clock_per_bit = 16; |  | ||||||
| }; |  | ||||||
| @ -1,32 +0,0 @@ | |||||||
| #include "encoder_ioprox.h" |  | ||||||
| #include "protocols/protocol_ioprox.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| #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; |  | ||||||
| }; |  | ||||||
| @ -1,76 +0,0 @@ | |||||||
| #include "key_info.h" |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| const char* lfrfid_key_get_type_string(LfrfidKeyType type) { |  | ||||||
|     switch(type) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         return "EM4100"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|         return "H10301"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         return "I40134"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyIoProxXSF: |  | ||||||
|         return "IoProxXSF"; |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return "Unknown"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type) { |  | ||||||
|     switch(type) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         return "EM-Marin"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|         return "HID"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         return "Indala"; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyIoProxXSF: |  | ||||||
|         return "Kantech"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return "Unknown"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type) { |  | ||||||
|     bool result = true; |  | ||||||
| 
 |  | ||||||
|     if(strcmp("EM4100", string) == 0) { |  | ||||||
|         *type = LfrfidKeyType::KeyEM4100; |  | ||||||
|     } else if(strcmp("H10301", string) == 0) { |  | ||||||
|         *type = LfrfidKeyType::KeyH10301; |  | ||||||
|     } else if(strcmp("I40134", string) == 0) { |  | ||||||
|         *type = LfrfidKeyType::KeyI40134; |  | ||||||
|     } else if(strcmp("IoProxXSF", string) == 0) { |  | ||||||
|         *type = LfrfidKeyType::KeyIoProxXSF; |  | ||||||
|     } else { |  | ||||||
|         result = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type) { |  | ||||||
|     switch(type) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         return 5; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|         return 3; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         return 3; |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyIoProxXSF: |  | ||||||
|         return 4; |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| @ -1,17 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| static const uint8_t LFRFID_KEY_SIZE = 8; |  | ||||||
| static const uint8_t LFRFID_KEY_NAME_SIZE = 22; |  | ||||||
| 
 |  | ||||||
| enum class LfrfidKeyType : uint8_t { |  | ||||||
|     KeyEM4100, |  | ||||||
|     KeyH10301, |  | ||||||
|     KeyI40134, |  | ||||||
|     KeyIoProxXSF, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const char* lfrfid_key_get_type_string(LfrfidKeyType type); |  | ||||||
| const char* lfrfid_key_get_manufacturer_string(LfrfidKeyType type); |  | ||||||
| bool lfrfid_key_get_string_type(const char* string, LfrfidKeyType* type); |  | ||||||
| uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); |  | ||||||
| @ -1,20 +0,0 @@ | |||||||
| #include "osc_fsk.h" |  | ||||||
| 
 |  | ||||||
| OscFSK::OscFSK(uint16_t _freq_low, uint16_t _freq_hi, uint16_t _osc_phase_max) |  | ||||||
|     : freq{_freq_low, _freq_hi} |  | ||||||
|     , osc_phase_max(_osc_phase_max) { |  | ||||||
|     osc_phase_current = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool OscFSK::next(bool bit, uint16_t* period) { |  | ||||||
|     bool advance = false; |  | ||||||
|     *period = freq[bit]; |  | ||||||
|     osc_phase_current += *period; |  | ||||||
| 
 |  | ||||||
|     if(osc_phase_current > osc_phase_max) { |  | ||||||
|         advance = true; |  | ||||||
|         osc_phase_current -= osc_phase_max; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return advance; |  | ||||||
| } |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * This code tries to fit the periods into a given number of cycles (phases) by taking cycles from the next cycle of periods. |  | ||||||
|  */ |  | ||||||
| class OscFSK { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * Get next period |  | ||||||
|      * @param bit bit value |  | ||||||
|      * @param period return period |  | ||||||
|      * @return bool whether to advance to the next bit |  | ||||||
|      */ |  | ||||||
|     bool next(bool bit, uint16_t* period); |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * FSK ocillator constructor |  | ||||||
|      *  |  | ||||||
|      * @param freq_low bit 0 freq |  | ||||||
|      * @param freq_hi bit 1 freq |  | ||||||
|      * @param osc_phase_max max oscillator phase |  | ||||||
|      */ |  | ||||||
|     OscFSK(uint16_t freq_low, uint16_t freq_hi, uint16_t osc_phase_max); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     const uint16_t freq[2]; |  | ||||||
|     const uint16_t osc_phase_max; |  | ||||||
|     int32_t osc_phase_current; |  | ||||||
| }; |  | ||||||
| @ -1,150 +0,0 @@ | |||||||
| #include "protocol_emmarin.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #define EM_HEADER_POS 55 |  | ||||||
| #define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) |  | ||||||
| 
 |  | ||||||
| #define EM_FIRST_ROW_POS 50 |  | ||||||
| 
 |  | ||||||
| #define EM_ROW_COUNT 10 |  | ||||||
| #define EM_COLUMN_COUNT 4 |  | ||||||
| #define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) |  | ||||||
| 
 |  | ||||||
| #define EM_COLUMN_POS 4 |  | ||||||
| #define EM_STOP_POS 0 |  | ||||||
| #define EM_STOP_MASK (0x1LLU << EM_STOP_POS) |  | ||||||
| 
 |  | ||||||
| #define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) |  | ||||||
| #define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) |  | ||||||
| 
 |  | ||||||
| typedef uint64_t EMMarinCardData; |  | ||||||
| 
 |  | ||||||
| void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) { |  | ||||||
|     uint8_t parity_sum = 0; |  | ||||||
|     uint8_t start = 0; |  | ||||||
|     if(!low_nibble) start = 4; |  | ||||||
| 
 |  | ||||||
|     for(int8_t i = (start + 3); i >= start; i--) { |  | ||||||
|         parity_sum += (data >> i) & 1; |  | ||||||
|         *card_data = (*card_data << 1) | ((data >> i) & 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     *card_data = (*card_data << 1) | ((parity_sum % 2) & 1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolEMMarin::get_encoded_data_size() { |  | ||||||
|     return sizeof(EMMarinCardData); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolEMMarin::get_decoded_data_size() { |  | ||||||
|     return 5; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolEMMarin::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()); |  | ||||||
| 
 |  | ||||||
|     EMMarinCardData card_data; |  | ||||||
| 
 |  | ||||||
|     // header
 |  | ||||||
|     card_data = 0b111111111; |  | ||||||
| 
 |  | ||||||
|     // data
 |  | ||||||
|     for(uint8_t i = 0; i < get_decoded_data_size(); i++) { |  | ||||||
|         write_nibble(false, decoded_data[i], &card_data); |  | ||||||
|         write_nibble(true, decoded_data[i], &card_data); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // column parity and stop bit
 |  | ||||||
|     uint8_t parity_sum; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { |  | ||||||
|         parity_sum = 0; |  | ||||||
|         for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { |  | ||||||
|             uint8_t parity_bit = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; |  | ||||||
|             parity_sum += parity_bit; |  | ||||||
|         } |  | ||||||
|         card_data = (card_data << 1) | ((parity_sum % 2) & 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // stop bit
 |  | ||||||
|     card_data = (card_data << 1) | 0; |  | ||||||
| 
 |  | ||||||
|     memcpy(encoded_data, &card_data, get_encoded_data_size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolEMMarin::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()); |  | ||||||
| 
 |  | ||||||
|     uint8_t decoded_data_index = 0; |  | ||||||
|     EMMarinCardData card_data = *(reinterpret_cast<const EMMarinCardData*>(encoded_data)); |  | ||||||
| 
 |  | ||||||
|     // clean result
 |  | ||||||
|     memset(decoded_data, 0, decoded_data_size); |  | ||||||
| 
 |  | ||||||
|     // header
 |  | ||||||
|     for(uint8_t i = 0; i < 9; i++) { |  | ||||||
|         card_data = card_data << 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // nibbles
 |  | ||||||
|     uint8_t value = 0; |  | ||||||
|     for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { |  | ||||||
|         uint8_t nibble = 0; |  | ||||||
|         for(uint8_t i = 0; i < 5; i++) { |  | ||||||
|             if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); |  | ||||||
|             card_data = card_data << 1; |  | ||||||
|         } |  | ||||||
|         value = (value << 4) | nibble; |  | ||||||
|         if(r % 2) { |  | ||||||
|             decoded_data[decoded_data_index] |= value; |  | ||||||
|             decoded_data_index++; |  | ||||||
|             value = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { |  | ||||||
|     furi_check(encoded_data_size >= get_encoded_data_size()); |  | ||||||
|     const EMMarinCardData* card_data = reinterpret_cast<const EMMarinCardData*>(encoded_data); |  | ||||||
| 
 |  | ||||||
|     // check header and stop bit
 |  | ||||||
|     if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; |  | ||||||
| 
 |  | ||||||
|     // check row parity
 |  | ||||||
|     for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { |  | ||||||
|         uint8_t parity_sum = 0; |  | ||||||
| 
 |  | ||||||
|         for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { |  | ||||||
|             parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if((parity_sum % 2)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // check columns parity
 |  | ||||||
|     for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { |  | ||||||
|         uint8_t parity_sum = 0; |  | ||||||
| 
 |  | ||||||
|         for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { |  | ||||||
|             parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if((parity_sum % 2)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "protocol_generic.h" |  | ||||||
| 
 |  | ||||||
| class ProtocolEMMarin : 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; |  | ||||||
| }; |  | ||||||
| @ -1,60 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "stdint.h" |  | ||||||
| #include "stdbool.h" |  | ||||||
| 
 |  | ||||||
| class ProtocolGeneric { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief Get the encoded data size |  | ||||||
|      *  |  | ||||||
|      * @return uint8_t size of encoded data in bytes |  | ||||||
|      */ |  | ||||||
|     virtual uint8_t get_encoded_data_size() = 0; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief Get the decoded data size |  | ||||||
|      *  |  | ||||||
|      * @return uint8_t size of decoded data in bytes |  | ||||||
|      */ |  | ||||||
|     virtual uint8_t get_decoded_data_size() = 0; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief encode decoded data |  | ||||||
|      *  |  | ||||||
|      * @param decoded_data  |  | ||||||
|      * @param decoded_data_size  |  | ||||||
|      * @param encoded_data  |  | ||||||
|      * @param encoded_data_size  |  | ||||||
|      */ |  | ||||||
|     virtual void encode( |  | ||||||
|         const uint8_t* decoded_data, |  | ||||||
|         const uint8_t decoded_data_size, |  | ||||||
|         uint8_t* encoded_data, |  | ||||||
|         const uint8_t encoded_data_size) = 0; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief decode encoded data |  | ||||||
|      *  |  | ||||||
|      * @param encoded_data  |  | ||||||
|      * @param encoded_data_size  |  | ||||||
|      * @param decoded_data  |  | ||||||
|      * @param decoded_data_size  |  | ||||||
|      */ |  | ||||||
|     virtual void decode( |  | ||||||
|         const uint8_t* encoded_data, |  | ||||||
|         const uint8_t encoded_data_size, |  | ||||||
|         uint8_t* decoded_data, |  | ||||||
|         const uint8_t decoded_data_size) = 0; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief fast check that data can be correctly decoded |  | ||||||
|      *  |  | ||||||
|      * @param encoded_data  |  | ||||||
|      * @param encoded_data_size  |  | ||||||
|      * @return true - can be correctly decoded |  | ||||||
|      * @return false - cannot be correctly decoded |  | ||||||
|      */ |  | ||||||
|     virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0; |  | ||||||
| 
 |  | ||||||
|     virtual ~ProtocolGeneric(){}; |  | ||||||
| }; |  | ||||||
| @ -1,238 +0,0 @@ | |||||||
| #include "protocol_hid_h10301.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| typedef uint32_t HID10301CardData; |  | ||||||
| constexpr uint8_t HID10301Count = 3; |  | ||||||
| constexpr uint8_t HID10301BitSize = sizeof(HID10301CardData) * 8; |  | ||||||
| 
 |  | ||||||
| static void write_raw_bit(bool bit, uint8_t position, HID10301CardData* card_data) { |  | ||||||
|     if(bit) { |  | ||||||
|         card_data[position / HID10301BitSize] |= |  | ||||||
|             1UL << (HID10301BitSize - (position % HID10301BitSize) - 1); |  | ||||||
|     } else { |  | ||||||
|         card_data[position / (sizeof(HID10301CardData) * 8)] &= |  | ||||||
|             ~(1UL << (HID10301BitSize - (position % HID10301BitSize) - 1)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void write_bit(bool bit, uint8_t position, HID10301CardData* card_data) { |  | ||||||
|     write_raw_bit(bit, position + 0, card_data); |  | ||||||
|     write_raw_bit(!bit, position + 1, card_data); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolHID10301::get_encoded_data_size() { |  | ||||||
|     return sizeof(HID10301CardData) * HID10301Count; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolHID10301::get_decoded_data_size() { |  | ||||||
|     return 3; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolHID10301::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()); |  | ||||||
| 
 |  | ||||||
|     HID10301CardData card_data[HID10301Count] = {0, 0, 0}; |  | ||||||
| 
 |  | ||||||
|     uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; |  | ||||||
| 
 |  | ||||||
|     // even parity sum calculation (high 12 bits of data)
 |  | ||||||
|     uint8_t even_parity_sum = 0; |  | ||||||
|     for(int8_t i = 12; i < 24; i++) { |  | ||||||
|         if(((fc_cn >> i) & 1) == 1) { |  | ||||||
|             even_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity sum calculation (low 12 bits of data)
 |  | ||||||
|     uint8_t odd_parity_sum = 1; |  | ||||||
|     for(int8_t i = 0; i < 12; i++) { |  | ||||||
|         if(((fc_cn >> i) & 1) == 1) { |  | ||||||
|             odd_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // 0x1D preamble
 |  | ||||||
|     write_raw_bit(0, 0, card_data); |  | ||||||
|     write_raw_bit(0, 1, card_data); |  | ||||||
|     write_raw_bit(0, 2, card_data); |  | ||||||
|     write_raw_bit(1, 3, card_data); |  | ||||||
|     write_raw_bit(1, 4, card_data); |  | ||||||
|     write_raw_bit(1, 5, card_data); |  | ||||||
|     write_raw_bit(0, 6, card_data); |  | ||||||
|     write_raw_bit(1, 7, card_data); |  | ||||||
| 
 |  | ||||||
|     // company / OEM code 1
 |  | ||||||
|     write_bit(0, 8, card_data); |  | ||||||
|     write_bit(0, 10, card_data); |  | ||||||
|     write_bit(0, 12, card_data); |  | ||||||
|     write_bit(0, 14, card_data); |  | ||||||
|     write_bit(0, 16, card_data); |  | ||||||
|     write_bit(0, 18, card_data); |  | ||||||
|     write_bit(1, 20, card_data); |  | ||||||
| 
 |  | ||||||
|     // card format / length 1
 |  | ||||||
|     write_bit(0, 22, card_data); |  | ||||||
|     write_bit(0, 24, card_data); |  | ||||||
|     write_bit(0, 26, card_data); |  | ||||||
|     write_bit(0, 28, card_data); |  | ||||||
|     write_bit(0, 30, card_data); |  | ||||||
|     write_bit(0, 32, card_data); |  | ||||||
|     write_bit(0, 34, card_data); |  | ||||||
|     write_bit(0, 36, card_data); |  | ||||||
|     write_bit(0, 38, card_data); |  | ||||||
|     write_bit(0, 40, card_data); |  | ||||||
|     write_bit(1, 42, card_data); |  | ||||||
| 
 |  | ||||||
|     // even parity bit
 |  | ||||||
|     write_bit((even_parity_sum % 2), 44, card_data); |  | ||||||
| 
 |  | ||||||
|     // data
 |  | ||||||
|     for(uint8_t i = 0; i < 24; i++) { |  | ||||||
|         write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity bit
 |  | ||||||
|     write_bit((odd_parity_sum % 2), 94, card_data); |  | ||||||
| 
 |  | ||||||
|     memcpy(encoded_data, &card_data, get_encoded_data_size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolHID10301::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()); |  | ||||||
| 
 |  | ||||||
|     const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_data); |  | ||||||
| 
 |  | ||||||
|     // data decoding
 |  | ||||||
|     uint32_t result = 0; |  | ||||||
| 
 |  | ||||||
|     // decode from word 1
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 9; i >= 0; i--) { |  | ||||||
|         switch((*(card_data + 1) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // decode from word 2
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 15; i >= 0; i--) { |  | ||||||
|         switch((*(card_data + 2) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint8_t data[3] = {(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)}; |  | ||||||
| 
 |  | ||||||
|     memcpy(decoded_data, &data, get_decoded_data_size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool ProtocolHID10301::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { |  | ||||||
|     furi_check(encoded_data_size >= get_encoded_data_size()); |  | ||||||
| 
 |  | ||||||
|     const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_data); |  | ||||||
| 
 |  | ||||||
|     // packet preamble
 |  | ||||||
|     // raw data
 |  | ||||||
|     if(*(encoded_data + 3) != 0x1D) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // encoded company/oem
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     // stored in word 0
 |  | ||||||
|     if((*card_data >> 10 & 0x3FFF) != 0x1556) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // encoded format/length
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     // stored in word 0 and word 1
 |  | ||||||
|     if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // data decoding
 |  | ||||||
|     uint32_t result = 0; |  | ||||||
| 
 |  | ||||||
|     // decode from word 1
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 9; i >= 0; i--) { |  | ||||||
|         switch((*(card_data + 1) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             return false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // decode from word 2
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 15; i >= 0; i--) { |  | ||||||
|         switch((*(card_data + 2) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             return false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // trailing parity (odd) test
 |  | ||||||
|     uint8_t parity_sum = 0; |  | ||||||
|     for(int8_t i = 0; i < 13; i++) { |  | ||||||
|         if(((result >> i) & 1) == 1) { |  | ||||||
|             parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((parity_sum % 2) != 1) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // leading parity (even) test
 |  | ||||||
|     parity_sum = 0; |  | ||||||
|     for(int8_t i = 13; i < 26; i++) { |  | ||||||
|         if(((result >> i) & 1) == 1) { |  | ||||||
|             parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((parity_sum % 2) == 1) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "protocol_generic.h" |  | ||||||
| 
 |  | ||||||
| class ProtocolHID10301 : 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; |  | ||||||
| }; |  | ||||||
| @ -1,237 +0,0 @@ | |||||||
| #include "protocol_indala_40134.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| typedef uint64_t Indala40134CardData; |  | ||||||
| 
 |  | ||||||
| static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) { |  | ||||||
|     position = (sizeof(Indala40134CardData) * 8) - 1 - position; |  | ||||||
|     if(bit) { |  | ||||||
|         *card_data |= 1ull << position; |  | ||||||
|     } else { |  | ||||||
|         *card_data &= ~(1ull << position); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool get_bit(uint8_t position, const Indala40134CardData* card_data) { |  | ||||||
|     position = (sizeof(Indala40134CardData) * 8) - 1 - position; |  | ||||||
|     return (*card_data >> position) & 1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolIndala40134::get_encoded_data_size() { |  | ||||||
|     return sizeof(Indala40134CardData); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t ProtocolIndala40134::get_decoded_data_size() { |  | ||||||
|     return 3; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolIndala40134::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()); |  | ||||||
| 
 |  | ||||||
|     uint32_t fc_and_card = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; |  | ||||||
|     Indala40134CardData card_data = 0; |  | ||||||
| 
 |  | ||||||
|     // preamble
 |  | ||||||
|     set_bit(1, 0, &card_data); |  | ||||||
|     set_bit(1, 2, &card_data); |  | ||||||
|     set_bit(1, 32, &card_data); |  | ||||||
| 
 |  | ||||||
|     // factory code
 |  | ||||||
|     set_bit(((fc_and_card >> 23) & 1), 57, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 22) & 1), 49, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 21) & 1), 44, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 20) & 1), 47, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 19) & 1), 48, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 18) & 1), 53, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 17) & 1), 39, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 16) & 1), 58, &card_data); |  | ||||||
| 
 |  | ||||||
|     // card number
 |  | ||||||
|     set_bit(((fc_and_card >> 15) & 1), 42, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 14) & 1), 45, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 13) & 1), 43, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 12) & 1), 40, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 11) & 1), 52, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 10) & 1), 36, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 9) & 1), 35, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 8) & 1), 51, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 7) & 1), 46, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 6) & 1), 33, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 5) & 1), 37, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 4) & 1), 54, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 3) & 1), 56, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 2) & 1), 59, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 1) & 1), 50, &card_data); |  | ||||||
|     set_bit(((fc_and_card >> 0) & 1), 41, &card_data); |  | ||||||
| 
 |  | ||||||
|     // checksum
 |  | ||||||
|     uint8_t checksum = 0; |  | ||||||
|     checksum += ((fc_and_card >> 14) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 12) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 9) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 8) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 6) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 5) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 2) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 0) & 1); |  | ||||||
| 
 |  | ||||||
|     // wiegand parity bits
 |  | ||||||
|     // even parity sum calculation (high 12 bits of data)
 |  | ||||||
|     uint8_t even_parity_sum = 0; |  | ||||||
|     for(int8_t i = 12; i < 24; i++) { |  | ||||||
|         if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|             even_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity sum calculation (low 12 bits of data)
 |  | ||||||
|     uint8_t odd_parity_sum = 1; |  | ||||||
|     for(int8_t i = 0; i < 12; i++) { |  | ||||||
|         if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|             odd_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // even parity bit
 |  | ||||||
|     set_bit((even_parity_sum % 2), 34, &card_data); |  | ||||||
| 
 |  | ||||||
|     // odd parity bit
 |  | ||||||
|     set_bit((odd_parity_sum % 2), 38, &card_data); |  | ||||||
| 
 |  | ||||||
|     // checksum
 |  | ||||||
|     if((checksum & 1) == 1) { |  | ||||||
|         set_bit(0, 62, &card_data); |  | ||||||
|         set_bit(1, 63, &card_data); |  | ||||||
|     } else { |  | ||||||
|         set_bit(1, 62, &card_data); |  | ||||||
|         set_bit(0, 63, &card_data); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     memcpy(encoded_data, &card_data, get_encoded_data_size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // factory code
 |  | ||||||
| static uint8_t get_fc(const Indala40134CardData* card_data) { |  | ||||||
|     uint8_t fc = 0; |  | ||||||
| 
 |  | ||||||
|     fc = fc << 1 | get_bit(57, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(49, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(44, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(47, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(48, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(53, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(39, card_data); |  | ||||||
|     fc = fc << 1 | get_bit(58, card_data); |  | ||||||
| 
 |  | ||||||
|     return fc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // card number
 |  | ||||||
| static uint16_t get_cn(const Indala40134CardData* card_data) { |  | ||||||
|     uint16_t cn = 0; |  | ||||||
| 
 |  | ||||||
|     cn = cn << 1 | get_bit(42, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(45, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(43, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(40, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(52, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(36, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(35, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(51, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(46, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(33, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(37, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(54, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(56, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(59, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(50, card_data); |  | ||||||
|     cn = cn << 1 | get_bit(41, card_data); |  | ||||||
| 
 |  | ||||||
|     return cn; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ProtocolIndala40134::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()); |  | ||||||
| 
 |  | ||||||
|     const Indala40134CardData* card_data = |  | ||||||
|         reinterpret_cast<const Indala40134CardData*>(encoded_data); |  | ||||||
| 
 |  | ||||||
|     uint8_t fc = get_fc(card_data); |  | ||||||
|     uint16_t card = get_cn(card_data); |  | ||||||
| 
 |  | ||||||
|     decoded_data[0] = fc; |  | ||||||
|     decoded_data[1] = card >> 8; |  | ||||||
|     decoded_data[2] = card; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool ProtocolIndala40134::can_be_decoded( |  | ||||||
|     const uint8_t* encoded_data, |  | ||||||
|     const uint8_t encoded_data_size) { |  | ||||||
|     furi_check(encoded_data_size >= get_encoded_data_size()); |  | ||||||
|     bool can_be_decoded = false; |  | ||||||
| 
 |  | ||||||
|     const Indala40134CardData* card_data = |  | ||||||
|         reinterpret_cast<const Indala40134CardData*>(encoded_data); |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         // preambula
 |  | ||||||
|         if((*card_data >> 32) != 0xa0000000UL) break; |  | ||||||
| 
 |  | ||||||
|         // data
 |  | ||||||
|         const uint32_t fc_and_card = get_fc(card_data) << 16 | get_cn(card_data); |  | ||||||
| 
 |  | ||||||
|         // checksum
 |  | ||||||
|         const uint8_t checksum = get_bit(62, card_data) << 1 | get_bit(63, card_data); |  | ||||||
|         uint8_t checksum_sum = 0; |  | ||||||
|         checksum_sum += ((fc_and_card >> 14) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 12) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 9) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 8) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 6) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 5) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 2) & 1); |  | ||||||
|         checksum_sum += ((fc_and_card >> 0) & 1); |  | ||||||
|         checksum_sum = checksum_sum & 0b1; |  | ||||||
| 
 |  | ||||||
|         if(checksum_sum == 1 && checksum == 0b01) { |  | ||||||
|         } else if(checksum_sum == 0 && checksum == 0b10) { |  | ||||||
|         } else { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // wiegand parity bits
 |  | ||||||
|         // even parity sum calculation (high 12 bits of data)
 |  | ||||||
|         const bool even_parity = get_bit(34, card_data); |  | ||||||
|         uint8_t even_parity_sum = 0; |  | ||||||
|         for(int8_t i = 12; i < 24; i++) { |  | ||||||
|             if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|                 even_parity_sum++; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if(even_parity_sum % 2 != even_parity) break; |  | ||||||
| 
 |  | ||||||
|         // odd parity sum calculation (low 12 bits of data)
 |  | ||||||
|         const bool odd_parity = get_bit(38, card_data); |  | ||||||
|         uint8_t odd_parity_sum = 1; |  | ||||||
|         for(int8_t i = 0; i < 12; i++) { |  | ||||||
|             if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|                 odd_parity_sum++; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if(odd_parity_sum % 2 != odd_parity) break; |  | ||||||
| 
 |  | ||||||
|         can_be_decoded = true; |  | ||||||
|     } while(false); |  | ||||||
| 
 |  | ||||||
|     return can_be_decoded; |  | ||||||
| } |  | ||||||
| @ -1,22 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "protocol_generic.h" |  | ||||||
| 
 |  | ||||||
| class ProtocolIndala40134 : 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; |  | ||||||
| }; |  | ||||||
| @ -1,193 +0,0 @@ | |||||||
| #include "protocol_ioprox.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <cli/cli.h> |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * 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; |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| #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); |  | ||||||
| }; |  | ||||||
| @ -1,95 +0,0 @@ | |||||||
| #include "pulse_joiner.h" |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| bool PulseJoiner::push_pulse(bool polarity, uint16_t period, uint16_t pulse) { |  | ||||||
|     bool result = false; |  | ||||||
|     furi_check((pulse_index + 1) < pulse_max); |  | ||||||
| 
 |  | ||||||
|     if(polarity == false && pulse_index == 0) { |  | ||||||
|         // first negative pulse is ommited
 |  | ||||||
| 
 |  | ||||||
|     } else { |  | ||||||
|         pulses[pulse_index].polarity = polarity; |  | ||||||
|         pulses[pulse_index].time = pulse; |  | ||||||
|         pulse_index++; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(period > pulse) { |  | ||||||
|         pulses[pulse_index].polarity = !polarity; |  | ||||||
|         pulses[pulse_index].time = period - pulse; |  | ||||||
|         pulse_index++; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(pulse_index >= 4) { |  | ||||||
|         // we know that first pulse is always high
 |  | ||||||
|         // so we wait 2 edges, hi2low and next low2hi
 |  | ||||||
| 
 |  | ||||||
|         uint8_t edges_count = 0; |  | ||||||
|         bool last_polarity = pulses[0].polarity; |  | ||||||
| 
 |  | ||||||
|         for(uint8_t i = 1; i < pulse_index; i++) { |  | ||||||
|             if(pulses[i].polarity != last_polarity) { |  | ||||||
|                 edges_count++; |  | ||||||
|                 last_polarity = pulses[i].polarity; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(edges_count >= 2) { |  | ||||||
|             result = true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PulseJoiner::pop_pulse(uint16_t* period, uint16_t* pulse) { |  | ||||||
|     furi_check(pulse_index <= (pulse_max + 1)); |  | ||||||
| 
 |  | ||||||
|     uint16_t tmp_period = 0; |  | ||||||
|     uint16_t tmp_pulse = 0; |  | ||||||
|     uint8_t edges_count = 0; |  | ||||||
|     bool last_polarity = pulses[0].polarity; |  | ||||||
|     uint8_t next_fist_pulse = 0; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < pulse_max; i++) { |  | ||||||
|         // count edges
 |  | ||||||
|         if(pulses[i].polarity != last_polarity) { |  | ||||||
|             edges_count++; |  | ||||||
|             last_polarity = pulses[i].polarity; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // wait for 2 edges
 |  | ||||||
|         if(edges_count == 2) { |  | ||||||
|             next_fist_pulse = i; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // sum pulse time
 |  | ||||||
|         if(pulses[i].polarity) { |  | ||||||
|             tmp_period += pulses[i].time; |  | ||||||
|             tmp_pulse += pulses[i].time; |  | ||||||
|         } else { |  | ||||||
|             tmp_period += pulses[i].time; |  | ||||||
|         } |  | ||||||
|         pulse_index--; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     *period = tmp_period; |  | ||||||
|     *pulse = tmp_pulse; |  | ||||||
| 
 |  | ||||||
|     // remove counted periods and shift data
 |  | ||||||
|     for(uint8_t i = 0; i < pulse_max; i++) { |  | ||||||
|         if((next_fist_pulse + i) < pulse_max) { |  | ||||||
|             pulses[i].polarity = pulses[next_fist_pulse + i].polarity; |  | ||||||
|             pulses[i].time = pulses[next_fist_pulse + i].time; |  | ||||||
|         } else { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| PulseJoiner::PulseJoiner() { |  | ||||||
|     for(uint8_t i = 0; i < pulse_max; i++) { |  | ||||||
|         pulses[i] = {false, 0}; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "stdint.h" |  | ||||||
| 
 |  | ||||||
| class PulseJoiner { |  | ||||||
| public: |  | ||||||
|     /**
 |  | ||||||
|      * @brief Push timer pulse. First negative pulse is ommited. |  | ||||||
|      *  |  | ||||||
|      * @param polarity pulse polarity: true = high2low, false = low2high |  | ||||||
|      * @param period overall period time in timer clicks |  | ||||||
|      * @param pulse pulse time in timer clicks |  | ||||||
|      *  |  | ||||||
|      * @return true - next pulse can and must be popped immediatly |  | ||||||
|      */ |  | ||||||
|     bool push_pulse(bool polarity, uint16_t period, uint16_t pulse); |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * @brief Get the next timer pulse. Call only if push_pulse returns true. |  | ||||||
|      *  |  | ||||||
|      * @param period overall period time in timer clicks |  | ||||||
|      * @param pulse pulse time in timer clicks |  | ||||||
|      */ |  | ||||||
|     void pop_pulse(uint16_t* period, uint16_t* pulse); |  | ||||||
| 
 |  | ||||||
|     PulseJoiner(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     struct Pulse { |  | ||||||
|         bool polarity; |  | ||||||
|         uint16_t time; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     uint8_t pulse_index = 0; |  | ||||||
|     static const uint8_t pulse_max = 6; |  | ||||||
|     Pulse pulses[pulse_max]; |  | ||||||
| }; |  | ||||||
| @ -1,65 +0,0 @@ | |||||||
| #include "rfid_key.h" |  | ||||||
| #include <core/check.h> |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| RfidKey::RfidKey() { |  | ||||||
|     clear(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidKey::~RfidKey() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidKey::set_type(LfrfidKeyType _type) { |  | ||||||
|     type = _type; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidKey::set_data(const uint8_t* _data, const uint8_t _data_size) { |  | ||||||
|     furi_assert(_data_size <= data.size()); |  | ||||||
|     for(uint8_t i = 0; i < _data_size; i++) { |  | ||||||
|         data[i] = _data[i]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidKey::set_name(const char* _name) { |  | ||||||
|     strlcpy(name, _name, get_name_length()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| LfrfidKeyType RfidKey::get_type() { |  | ||||||
|     return type; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const uint8_t* RfidKey::get_data() { |  | ||||||
|     return &data[0]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const char* RfidKey::get_type_text() { |  | ||||||
|     return lfrfid_key_get_type_string(type); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t RfidKey::get_type_data_count() const { |  | ||||||
|     return lfrfid_key_get_type_data_count(type); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| char* RfidKey::get_name() { |  | ||||||
|     return name; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t RfidKey::get_name_length() { |  | ||||||
|     return LFRFID_KEY_NAME_SIZE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidKey::clear() { |  | ||||||
|     set_name(""); |  | ||||||
|     set_type(LfrfidKeyType::KeyEM4100); |  | ||||||
|     data.fill(0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidKey& RfidKey::operator=(const RfidKey& rhs) { |  | ||||||
|     if(this == &rhs) return *this; |  | ||||||
| 
 |  | ||||||
|     set_type(rhs.type); |  | ||||||
|     set_name(rhs.name); |  | ||||||
|     set_data(&rhs.data[0], get_type_data_count()); |  | ||||||
| 
 |  | ||||||
|     return *this; |  | ||||||
| } |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "key_info.h" |  | ||||||
| #include <array> |  | ||||||
| 
 |  | ||||||
| class RfidKey { |  | ||||||
| public: |  | ||||||
|     RfidKey(); |  | ||||||
|     ~RfidKey(); |  | ||||||
| 
 |  | ||||||
|     void set_type(LfrfidKeyType type); |  | ||||||
|     void set_data(const uint8_t* data, const uint8_t data_size); |  | ||||||
|     void set_name(const char* name); |  | ||||||
| 
 |  | ||||||
|     LfrfidKeyType get_type(); |  | ||||||
|     const uint8_t* get_data(); |  | ||||||
|     const char* get_type_text(); |  | ||||||
|     uint8_t get_type_data_count() const; |  | ||||||
|     char* get_name(); |  | ||||||
|     uint8_t get_name_length(); |  | ||||||
|     void clear(); |  | ||||||
|     RfidKey& operator=(const RfidKey& rhs); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     std::array<uint8_t, LFRFID_KEY_SIZE> data; |  | ||||||
|     LfrfidKeyType type; |  | ||||||
|     char name[LFRFID_KEY_NAME_SIZE + 1]; |  | ||||||
| }; |  | ||||||
| @ -1,175 +0,0 @@ | |||||||
| #include "rfid_reader.h" |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal.h> |  | ||||||
| #include <stm32wbxx_ll_cortex.h> |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @brief private violation assistant for RfidReader |  | ||||||
|  */ |  | ||||||
| struct RfidReaderAccessor { |  | ||||||
|     static void decode(RfidReader& rfid_reader, bool polarity) { |  | ||||||
|         rfid_reader.decode(polarity); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void RfidReader::decode(bool polarity) { |  | ||||||
|     uint32_t current_dwt_value = DWT->CYCCNT; |  | ||||||
|     uint32_t period = current_dwt_value - last_dwt_value; |  | ||||||
|     last_dwt_value = current_dwt_value; |  | ||||||
| 
 |  | ||||||
| #ifdef RFID_GPIO_DEBUG |  | ||||||
|     decoder_gpio_out.process_front(polarity, period); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     switch(type) { |  | ||||||
|     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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     detect_ticks++; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidReader::switch_timer_elapsed() { |  | ||||||
|     const uint32_t seconds_to_switch = furi_kernel_get_tick_frequency() * 2.0f; |  | ||||||
|     return (furi_get_tick() - switch_os_tick_last) > seconds_to_switch; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::switch_timer_reset() { |  | ||||||
|     switch_os_tick_last = furi_get_tick(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::switch_mode() { |  | ||||||
|     switch(type) { |  | ||||||
|     case Type::Normal: |  | ||||||
|         type = Type::Indala; |  | ||||||
|         furi_hal_rfid_change_read_config(62500.0f, 0.25f); |  | ||||||
|         break; |  | ||||||
|     case Type::Indala: |  | ||||||
|         type = Type::Normal; |  | ||||||
|         furi_hal_rfid_change_read_config(125000.0f, 0.5f); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     switch_timer_reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void comparator_trigger_callback(bool level, void* comp_ctx) { |  | ||||||
|     RfidReader* _this = static_cast<RfidReader*>(comp_ctx); |  | ||||||
| 
 |  | ||||||
|     RfidReaderAccessor::decode(*_this, !level); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidReader::RfidReader() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::start() { |  | ||||||
|     type = Type::Normal; |  | ||||||
| 
 |  | ||||||
|     furi_hal_rfid_pins_read(); |  | ||||||
|     furi_hal_rfid_tim_read(125000, 0.5); |  | ||||||
|     furi_hal_rfid_tim_read_start(); |  | ||||||
|     start_comparator(); |  | ||||||
| 
 |  | ||||||
|     switch_timer_reset(); |  | ||||||
|     last_read_count = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::start_forced(RfidReader::Type _type) { |  | ||||||
|     start(); |  | ||||||
|     if(_type == Type::Indala) { |  | ||||||
|         switch_mode(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::stop() { |  | ||||||
|     furi_hal_rfid_pins_reset(); |  | ||||||
|     furi_hal_rfid_tim_read_stop(); |  | ||||||
|     furi_hal_rfid_tim_reset(); |  | ||||||
|     stop_comparator(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) { |  | ||||||
|     bool result = false; |  | ||||||
|     bool something_read = false; |  | ||||||
| 
 |  | ||||||
|     // reading
 |  | ||||||
|     if(decoder_em.read(data, data_size)) { |  | ||||||
|         *_type = LfrfidKeyType::KeyEM4100; |  | ||||||
|         something_read = true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(decoder_hid26.read(data, data_size)) { |  | ||||||
|         *_type = LfrfidKeyType::KeyH10301; |  | ||||||
|         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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // validation
 |  | ||||||
|     if(something_read) { |  | ||||||
|         switch_timer_reset(); |  | ||||||
| 
 |  | ||||||
|         if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) { |  | ||||||
|             last_read_count = last_read_count + 1; |  | ||||||
| 
 |  | ||||||
|             if(last_read_count > 2) { |  | ||||||
|                 result = true; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             last_read_type = *_type; |  | ||||||
|             memcpy(last_read_data, data, data_size); |  | ||||||
|             last_read_count = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // mode switching
 |  | ||||||
|     if(switch_enable && switch_timer_elapsed()) { |  | ||||||
|         switch_mode(); |  | ||||||
|         last_read_count = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidReader::detect() { |  | ||||||
|     bool detected = false; |  | ||||||
|     if(detect_ticks > 10) { |  | ||||||
|         detected = true; |  | ||||||
|     } |  | ||||||
|     detect_ticks = 0; |  | ||||||
| 
 |  | ||||||
|     return detected; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidReader::any_read() { |  | ||||||
|     return last_read_count > 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::start_comparator(void) { |  | ||||||
|     furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); |  | ||||||
|     last_dwt_value = DWT->CYCCNT; |  | ||||||
| 
 |  | ||||||
|     furi_hal_rfid_comp_start(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidReader::stop_comparator(void) { |  | ||||||
|     furi_hal_rfid_comp_stop(); |  | ||||||
|     furi_hal_rfid_comp_set_callback(NULL, NULL); |  | ||||||
| } |  | ||||||
| @ -1,59 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| //#include "decoder_analyzer.h"
 |  | ||||||
| #include "decoder_gpio_out.h" |  | ||||||
| #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
 |  | ||||||
| 
 |  | ||||||
| class RfidReader { |  | ||||||
| public: |  | ||||||
|     enum class Type : uint8_t { |  | ||||||
|         Normal, |  | ||||||
|         Indala, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     RfidReader(); |  | ||||||
|     void start(); |  | ||||||
|     void start_forced(RfidReader::Type type); |  | ||||||
|     void stop(); |  | ||||||
|     bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size, bool switch_enable = true); |  | ||||||
| 
 |  | ||||||
|     bool detect(); |  | ||||||
|     bool any_read(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     friend struct RfidReaderAccessor; |  | ||||||
| 
 |  | ||||||
|     //DecoderAnalyzer decoder_analyzer;
 |  | ||||||
| #ifdef RFID_GPIO_DEBUG |  | ||||||
|     DecoderGpioOut decoder_gpio_out; |  | ||||||
| #endif |  | ||||||
|     DecoderEMMarin decoder_em; |  | ||||||
|     DecoderHID26 decoder_hid26; |  | ||||||
|     DecoderIndala decoder_indala; |  | ||||||
|     DecoderIoProx decoder_ioprox; |  | ||||||
| 
 |  | ||||||
|     uint32_t last_dwt_value; |  | ||||||
| 
 |  | ||||||
|     void start_comparator(void); |  | ||||||
|     void stop_comparator(void); |  | ||||||
| 
 |  | ||||||
|     void decode(bool polarity); |  | ||||||
| 
 |  | ||||||
|     uint32_t detect_ticks; |  | ||||||
| 
 |  | ||||||
|     uint32_t switch_os_tick_last; |  | ||||||
|     bool switch_timer_elapsed(); |  | ||||||
|     void switch_timer_reset(); |  | ||||||
|     void switch_mode(); |  | ||||||
| 
 |  | ||||||
|     LfrfidKeyType last_read_type; |  | ||||||
|     uint8_t last_read_data[LFRFID_KEY_SIZE]; |  | ||||||
|     uint8_t last_read_count; |  | ||||||
| 
 |  | ||||||
|     Type type = Type::Normal; |  | ||||||
| }; |  | ||||||
| @ -1,56 +0,0 @@ | |||||||
| #include "rfid_timer_emulator.h" |  | ||||||
| 
 |  | ||||||
| RfidTimerEmulator::RfidTimerEmulator() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidTimerEmulator::~RfidTimerEmulator() { |  | ||||||
|     std::map<LfrfidKeyType, EncoderGeneric*>::iterator it; |  | ||||||
| 
 |  | ||||||
|     for(it = encoders.begin(); it != encoders.end(); ++it) { |  | ||||||
|         delete it->second; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     encoders.clear(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidTimerEmulator::start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size) { |  | ||||||
|     if(encoders.count(type)) { |  | ||||||
|         current_encoder = encoders.find(type)->second; |  | ||||||
| 
 |  | ||||||
|         if(data_size >= lfrfid_key_get_type_data_count(type)) { |  | ||||||
|             current_encoder->init(data, data_size); |  | ||||||
| 
 |  | ||||||
|             furi_hal_rfid_tim_emulate(125000); |  | ||||||
|             furi_hal_rfid_pins_emulate(); |  | ||||||
| 
 |  | ||||||
|             furi_hal_rfid_tim_emulate_start(RfidTimerEmulator::timer_update_callback, this); |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // not found
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidTimerEmulator::stop() { |  | ||||||
|     furi_hal_rfid_tim_emulate_stop(); |  | ||||||
|     furi_hal_rfid_tim_reset(); |  | ||||||
|     furi_hal_rfid_pins_reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidTimerEmulator::timer_update_callback(void* ctx) { |  | ||||||
|     RfidTimerEmulator* _this = static_cast<RfidTimerEmulator*>(ctx); |  | ||||||
| 
 |  | ||||||
|     bool result; |  | ||||||
|     bool polarity; |  | ||||||
|     uint16_t period; |  | ||||||
|     uint16_t pulse; |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         _this->current_encoder->get_next(&polarity, &period, &pulse); |  | ||||||
|         result = _this->pulse_joiner.push_pulse(polarity, period, pulse); |  | ||||||
|     } while(result == false); |  | ||||||
| 
 |  | ||||||
|     _this->pulse_joiner.pop_pulse(&period, &pulse); |  | ||||||
| 
 |  | ||||||
|     furi_hal_rfid_set_emulate_period(period - 1); |  | ||||||
|     furi_hal_rfid_set_emulate_pulse(pulse); |  | ||||||
| } |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <furi_hal.h> |  | ||||||
| #include "key_info.h" |  | ||||||
| #include "encoder_generic.h" |  | ||||||
| #include "encoder_emmarin.h" |  | ||||||
| #include "encoder_hid_h10301.h" |  | ||||||
| #include "encoder_indala_40134.h" |  | ||||||
| #include "encoder_ioprox.h" |  | ||||||
| #include "pulse_joiner.h" |  | ||||||
| #include <map> |  | ||||||
| 
 |  | ||||||
| class RfidTimerEmulator { |  | ||||||
| public: |  | ||||||
|     RfidTimerEmulator(); |  | ||||||
|     ~RfidTimerEmulator(); |  | ||||||
|     void start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size); |  | ||||||
|     void stop(); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     EncoderGeneric* current_encoder = nullptr; |  | ||||||
| 
 |  | ||||||
|     std::map<LfrfidKeyType, EncoderGeneric*> encoders = { |  | ||||||
|         {LfrfidKeyType::KeyEM4100, new EncoderEM()}, |  | ||||||
|         {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()}, |  | ||||||
|         {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()}, |  | ||||||
|         {LfrfidKeyType::KeyIoProxXSF, new EncoderIoProx()}, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     PulseJoiner pulse_joiner; |  | ||||||
|     static void timer_update_callback(void* ctx); |  | ||||||
| }; |  | ||||||
| @ -1,136 +0,0 @@ | |||||||
| #include "rfid_worker.h" |  | ||||||
| 
 |  | ||||||
| RfidWorker::RfidWorker() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidWorker::~RfidWorker() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::start_read() { |  | ||||||
|     reader.start(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidWorker::read() { |  | ||||||
|     static const uint8_t data_size = LFRFID_KEY_SIZE; |  | ||||||
|     uint8_t data[data_size] = {0}; |  | ||||||
|     LfrfidKeyType type; |  | ||||||
| 
 |  | ||||||
|     bool result = reader.read(&type, data, data_size); |  | ||||||
| 
 |  | ||||||
|     if(result) { |  | ||||||
|         key.set_type(type); |  | ||||||
|         key.set_data(data, data_size); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidWorker::detect() { |  | ||||||
|     return reader.detect(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool RfidWorker::any_read() { |  | ||||||
|     return reader.any_read(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::stop_read() { |  | ||||||
|     reader.stop(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::start_write() { |  | ||||||
|     write_result = WriteResult::Nothing; |  | ||||||
|     write_sequence = new TickSequencer(); |  | ||||||
|     validate_counts = 0; |  | ||||||
| 
 |  | ||||||
|     write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write, this)); |  | ||||||
|     write_sequence->do_after_tick(2, std::bind(&RfidWorker::sq_write_start_validate, this)); |  | ||||||
|     write_sequence->do_every_tick(30, std::bind(&RfidWorker::sq_write_validate, this)); |  | ||||||
|     write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write_stop_validate, this)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidWorker::WriteResult RfidWorker::write() { |  | ||||||
|     write_sequence->tick(); |  | ||||||
|     return write_result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::stop_write() { |  | ||||||
|     delete write_sequence; |  | ||||||
|     reader.stop(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::start_emulate() { |  | ||||||
|     emulator.start(key.get_type(), key.get_data(), key.get_type_data_count()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::stop_emulate() { |  | ||||||
|     emulator.stop(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::sq_write() { |  | ||||||
|     for(size_t i = 0; i < 5; i++) { |  | ||||||
|         switch(key.get_type()) { |  | ||||||
|         case LfrfidKeyType::KeyEM4100: |  | ||||||
|             writer.start(); |  | ||||||
|             writer.write_em(key.get_data()); |  | ||||||
|             writer.stop(); |  | ||||||
|             break; |  | ||||||
|         case LfrfidKeyType::KeyH10301: |  | ||||||
|             writer.start(); |  | ||||||
|             writer.write_hid(key.get_data()); |  | ||||||
|             writer.stop(); |  | ||||||
|             break; |  | ||||||
|         case LfrfidKeyType::KeyI40134: |  | ||||||
|             writer.start(); |  | ||||||
|             writer.write_indala(key.get_data()); |  | ||||||
|             writer.stop(); |  | ||||||
|             break; |  | ||||||
|         case LfrfidKeyType::KeyIoProxXSF: |  | ||||||
|             writer.start(); |  | ||||||
|             writer.write_ioprox(key.get_data()); |  | ||||||
|             writer.stop(); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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: |  | ||||||
|         reader.start_forced(RfidReader::Type::Indala); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::sq_write_validate() { |  | ||||||
|     static const uint8_t data_size = LFRFID_KEY_SIZE; |  | ||||||
|     uint8_t data[data_size] = {0}; |  | ||||||
|     LfrfidKeyType type; |  | ||||||
| 
 |  | ||||||
|     bool result = reader.read(&type, data, data_size); |  | ||||||
| 
 |  | ||||||
|     if(result && (write_result != WriteResult::Ok)) { |  | ||||||
|         if(validate_counts > (5 * 60)) { |  | ||||||
|             write_result = WriteResult::NotWritable; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(type == key.get_type()) { |  | ||||||
|             if(memcmp(data, key.get_data(), key.get_type_data_count()) == 0) { |  | ||||||
|                 write_result = WriteResult::Ok; |  | ||||||
|                 validate_counts = 0; |  | ||||||
|             } else { |  | ||||||
|                 validate_counts++; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             validate_counts++; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWorker::sq_write_stop_validate() { |  | ||||||
|     reader.stop(); |  | ||||||
| } |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "key_info.h" |  | ||||||
| #include "rfid_reader.h" |  | ||||||
| #include "rfid_writer.h" |  | ||||||
| #include "rfid_timer_emulator.h" |  | ||||||
| #include "rfid_key.h" |  | ||||||
| #include "state_sequencer.h" |  | ||||||
| 
 |  | ||||||
| class RfidWorker { |  | ||||||
| public: |  | ||||||
|     RfidWorker(); |  | ||||||
|     ~RfidWorker(); |  | ||||||
| 
 |  | ||||||
|     void start_read(); |  | ||||||
|     bool read(); |  | ||||||
|     bool detect(); |  | ||||||
|     bool any_read(); |  | ||||||
|     void stop_read(); |  | ||||||
| 
 |  | ||||||
|     enum class WriteResult : uint8_t { |  | ||||||
|         Ok, |  | ||||||
|         NotWritable, |  | ||||||
|         Nothing, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     void start_write(); |  | ||||||
|     WriteResult write(); |  | ||||||
|     void stop_write(); |  | ||||||
| 
 |  | ||||||
|     void start_emulate(); |  | ||||||
|     void stop_emulate(); |  | ||||||
| 
 |  | ||||||
|     RfidKey key; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     RfidWriter writer; |  | ||||||
|     RfidReader reader; |  | ||||||
|     RfidTimerEmulator emulator; |  | ||||||
| 
 |  | ||||||
|     WriteResult write_result; |  | ||||||
|     TickSequencer* write_sequence; |  | ||||||
| 
 |  | ||||||
|     void sq_write(); |  | ||||||
|     void sq_write_start_validate(); |  | ||||||
|     void sq_write_validate(); |  | ||||||
|     uint16_t validate_counts; |  | ||||||
|     void sq_write_stop_validate(); |  | ||||||
| }; |  | ||||||
| @ -1,183 +0,0 @@ | |||||||
| #include "rfid_writer.h" |  | ||||||
| #include "protocols/protocol_ioprox.h" |  | ||||||
| #include <furi_hal.h> |  | ||||||
| #include "protocols/protocol_emmarin.h" |  | ||||||
| #include "protocols/protocol_hid_h10301.h" |  | ||||||
| #include "protocols/protocol_indala_40134.h" |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us) |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| class T55xxTiming { |  | ||||||
| public: |  | ||||||
|     constexpr static const uint16_t wait_time = 400; |  | ||||||
|     constexpr static const uint8_t start_gap = 30; |  | ||||||
|     constexpr static const uint8_t write_gap = 18; |  | ||||||
|     constexpr static const uint8_t data_0 = 24; |  | ||||||
|     constexpr static const uint8_t data_1 = 56; |  | ||||||
|     constexpr static const uint16_t program = 700; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class T55xxCmd { |  | ||||||
| public: |  | ||||||
|     constexpr static const uint8_t opcode_page_0 = 0b10; |  | ||||||
|     constexpr static const uint8_t opcode_page_1 = 0b11; |  | ||||||
|     constexpr static const uint8_t opcode_reset = 0b00; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| RfidWriter::RfidWriter() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RfidWriter::~RfidWriter() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::start() { |  | ||||||
|     furi_hal_rfid_tim_read(125000, 0.5); |  | ||||||
|     furi_hal_rfid_pins_read(); |  | ||||||
|     furi_hal_rfid_tim_read_start(); |  | ||||||
| 
 |  | ||||||
|     // do not ground the antenna
 |  | ||||||
|     furi_hal_rfid_pin_pull_release(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::stop() { |  | ||||||
|     furi_hal_rfid_tim_read_stop(); |  | ||||||
|     furi_hal_rfid_tim_reset(); |  | ||||||
|     furi_hal_rfid_pins_reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_gap(uint32_t gap_time) { |  | ||||||
|     furi_hal_rfid_tim_read_stop(); |  | ||||||
|     furi_delay_us(gap_time * 8); |  | ||||||
|     furi_hal_rfid_tim_read_start(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_bit(bool value) { |  | ||||||
|     if(value) { |  | ||||||
|         furi_delay_us(T55xxTiming::data_1 * 8); |  | ||||||
|     } else { |  | ||||||
|         furi_delay_us(T55xxTiming::data_0 * 8); |  | ||||||
|     } |  | ||||||
|     write_gap(T55xxTiming::write_gap); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_byte(uint8_t value) { |  | ||||||
|     for(uint8_t i = 0; i < 8; i++) { |  | ||||||
|         write_bit((value >> i) & 1); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data) { |  | ||||||
|     furi_delay_us(T55xxTiming::wait_time * 8); |  | ||||||
| 
 |  | ||||||
|     // start gap
 |  | ||||||
|     write_gap(T55xxTiming::start_gap); |  | ||||||
| 
 |  | ||||||
|     // opcode
 |  | ||||||
|     switch(page) { |  | ||||||
|     case 0: |  | ||||||
|         write_bit(1); |  | ||||||
|         write_bit(0); |  | ||||||
|         break; |  | ||||||
|     case 1: |  | ||||||
|         write_bit(1); |  | ||||||
|         write_bit(1); |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         furi_check(false); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // lock bit
 |  | ||||||
|     write_bit(lock_bit); |  | ||||||
| 
 |  | ||||||
|     // data
 |  | ||||||
|     for(uint8_t i = 0; i < 32; i++) { |  | ||||||
|         write_bit((data >> (31 - i)) & 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // block address
 |  | ||||||
|     write_bit((block >> 2) & 1); |  | ||||||
|     write_bit((block >> 1) & 1); |  | ||||||
|     write_bit((block >> 0) & 1); |  | ||||||
| 
 |  | ||||||
|     furi_delay_us(T55xxTiming::program * 8); |  | ||||||
| 
 |  | ||||||
|     furi_delay_us(T55xxTiming::wait_time * 8); |  | ||||||
|     write_reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_reset() { |  | ||||||
|     write_gap(T55xxTiming::start_gap); |  | ||||||
|     write_bit(1); |  | ||||||
|     write_bit(0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_em(const uint8_t em_data[5]) { |  | ||||||
|     ProtocolEMMarin em_card; |  | ||||||
|     uint64_t em_encoded_data; |  | ||||||
|     em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t)); |  | ||||||
|     const uint32_t em_config_block_data = 0b00000000000101001000000001000000; |  | ||||||
| 
 |  | ||||||
|     FURI_CRITICAL_ENTER(); |  | ||||||
|     write_block(0, 0, false, em_config_block_data); |  | ||||||
|     write_block(0, 1, false, em_encoded_data); |  | ||||||
|     write_block(0, 2, false, em_encoded_data >> 32); |  | ||||||
|     write_reset(); |  | ||||||
|     FURI_CRITICAL_EXIT(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void RfidWriter::write_hid(const uint8_t hid_data[3]) { |  | ||||||
|     ProtocolHID10301 hid_card; |  | ||||||
|     uint32_t card_data[3]; |  | ||||||
|     hid_card.encode(hid_data, 3, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3); |  | ||||||
| 
 |  | ||||||
|     const uint32_t hid_config_block_data = 0b00000000000100000111000001100000; |  | ||||||
| 
 |  | ||||||
|     FURI_CRITICAL_ENTER(); |  | ||||||
|     write_block(0, 0, false, hid_config_block_data); |  | ||||||
|     write_block(0, 1, false, card_data[0]); |  | ||||||
|     write_block(0, 2, false, card_data[1]); |  | ||||||
|     write_block(0, 3, false, card_data[2]); |  | ||||||
|     write_reset(); |  | ||||||
|     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<uint32_t*>(&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]; |  | ||||||
|     indala_card.encode( |  | ||||||
|         indala_data, 3, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 2); |  | ||||||
| 
 |  | ||||||
|     const uint32_t indala_config_block_data = 0b00000000000010000001000001000000; |  | ||||||
| 
 |  | ||||||
|     FURI_CRITICAL_ENTER(); |  | ||||||
|     write_block(0, 0, false, indala_config_block_data); |  | ||||||
|     write_block(0, 1, false, card_data[0]); |  | ||||||
|     write_block(0, 2, false, card_data[1]); |  | ||||||
|     write_reset(); |  | ||||||
|     FURI_CRITICAL_EXIT(); |  | ||||||
| } |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "stdint.h" |  | ||||||
| 
 |  | ||||||
| class RfidWriter { |  | ||||||
| public: |  | ||||||
|     RfidWriter(); |  | ||||||
|     ~RfidWriter(); |  | ||||||
|     void start(); |  | ||||||
|     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: |  | ||||||
|     void write_gap(uint32_t gap_time); |  | ||||||
|     void write_bit(bool value); |  | ||||||
|     void write_byte(uint8_t value); |  | ||||||
|     void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data); |  | ||||||
|     void write_reset(); |  | ||||||
| }; |  | ||||||
| @ -1,50 +0,0 @@ | |||||||
| #include "state_sequencer.h" |  | ||||||
| #include "stdio.h" |  | ||||||
| 
 |  | ||||||
| TickSequencer::TickSequencer() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| TickSequencer::~TickSequencer() { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::tick() { |  | ||||||
|     if(tick_count == list_it->first) { |  | ||||||
|         tick_count = 0; |  | ||||||
| 
 |  | ||||||
|         list_it++; |  | ||||||
|         if(list_it == list.end()) { |  | ||||||
|             list_it = list.begin(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     list_it->second(); |  | ||||||
|     tick_count++; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::reset() { |  | ||||||
|     list_it = list.begin(); |  | ||||||
|     tick_count = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::clear() { |  | ||||||
|     list.clear(); |  | ||||||
|     reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::do_every_tick(uint32_t tick_count, std::function<void(void)> fn) { |  | ||||||
|     list.push_back(std::make_pair(tick_count, fn)); |  | ||||||
|     reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::do_after_tick(uint32_t tick_count, std::function<void(void)> fn) { |  | ||||||
|     if(tick_count > 1) { |  | ||||||
|         list.push_back( |  | ||||||
|             std::make_pair(tick_count - 1, std::bind(&TickSequencer::do_nothing, this))); |  | ||||||
|     } |  | ||||||
|     list.push_back(std::make_pair(1, fn)); |  | ||||||
| 
 |  | ||||||
|     reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void TickSequencer::do_nothing() { |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "stdint.h" |  | ||||||
| #include <list> |  | ||||||
| #include <functional> |  | ||||||
| 
 |  | ||||||
| class TickSequencer { |  | ||||||
| public: |  | ||||||
|     TickSequencer(); |  | ||||||
|     ~TickSequencer(); |  | ||||||
| 
 |  | ||||||
|     void tick(); |  | ||||||
|     void reset(); |  | ||||||
|     void clear(); |  | ||||||
| 
 |  | ||||||
|     void do_every_tick(uint32_t tick_count, std::function<void(void)> fn); |  | ||||||
|     void do_after_tick(uint32_t tick_count, std::function<void(void)> fn); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     std::list<std::pair<uint32_t, std::function<void(void)> > > list; |  | ||||||
|     std::list<std::pair<uint32_t, std::function<void(void)> > >::iterator list_it; |  | ||||||
| 
 |  | ||||||
|     uint32_t tick_count; |  | ||||||
| 
 |  | ||||||
|     void do_nothing(); |  | ||||||
| }; |  | ||||||
| @ -21,6 +21,11 @@ | |||||||
| #include "scene/lfrfid_app_scene_delete_confirm.h" | #include "scene/lfrfid_app_scene_delete_confirm.h" | ||||||
| #include "scene/lfrfid_app_scene_delete_success.h" | #include "scene/lfrfid_app_scene_delete_success.h" | ||||||
| #include "scene/lfrfid_app_scene_rpc.h" | #include "scene/lfrfid_app_scene_rpc.h" | ||||||
|  | #include "scene/lfrfid_app_scene_extra_actions.h" | ||||||
|  | #include "scene/lfrfid_app_scene_raw_info.h" | ||||||
|  | #include "scene/lfrfid_app_scene_raw_name.h" | ||||||
|  | #include "scene/lfrfid_app_scene_raw_read.h" | ||||||
|  | #include "scene/lfrfid_app_scene_raw_success.h" | ||||||
| 
 | 
 | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| @ -28,24 +33,44 @@ | |||||||
| #include <rpc/rpc_app.h> | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); | const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); | ||||||
|  | const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid"); | ||||||
| const char* LfRfidApp::app_extension = ".rfid"; | const char* LfRfidApp::app_extension = ".rfid"; | ||||||
| const char* LfRfidApp::app_filetype = "Flipper RFID key"; | const char* LfRfidApp::app_filetype = "Flipper RFID key"; | ||||||
| 
 | 
 | ||||||
| LfRfidApp::LfRfidApp() | LfRfidApp::LfRfidApp() | ||||||
|     : scene_controller{this} |     : scene_controller{this} | ||||||
|     , notification{"notification"} |     , notification{RECORD_NOTIFICATION} | ||||||
|     , storage{"storage"} |     , storage{RECORD_STORAGE} | ||||||
|     , dialogs{"dialogs"} |     , dialogs{RECORD_DIALOGS} | ||||||
|     , text_store(40) { |     , text_store(40) { | ||||||
|  |     string_init(file_name); | ||||||
|  |     string_init(raw_file_name); | ||||||
|     string_init_set_str(file_path, app_folder); |     string_init_set_str(file_path, app_folder); | ||||||
|  | 
 | ||||||
|  |     dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  | 
 | ||||||
|  |     size_t size = protocol_dict_get_max_data_size(dict); | ||||||
|  |     new_key_data = (uint8_t*)malloc(size); | ||||||
|  |     old_key_data = (uint8_t*)malloc(size); | ||||||
|  | 
 | ||||||
|  |     lfworker = lfrfid_worker_alloc(dict); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| LfRfidApp::~LfRfidApp() { | LfRfidApp::~LfRfidApp() { | ||||||
|  |     string_clear(raw_file_name); | ||||||
|  |     string_clear(file_name); | ||||||
|     string_clear(file_path); |     string_clear(file_path); | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_free(lfworker); | ||||||
|  | 
 | ||||||
|     if(rpc_ctx) { |     if(rpc_ctx) { | ||||||
|         rpc_system_app_set_callback(rpc_ctx, NULL, NULL); |         rpc_system_app_set_callback(rpc_ctx, NULL, NULL); | ||||||
|         rpc_system_app_send_exited(rpc_ctx); |         rpc_system_app_send_exited(rpc_ctx); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     free(new_key_data); | ||||||
|  |     free(old_key_data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { | static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { | ||||||
| @ -88,7 +113,7 @@ void LfRfidApp::run(void* _args) { | |||||||
|             scene_controller.process(100, SceneType::Rpc); |             scene_controller.process(100, SceneType::Rpc); | ||||||
|         } else { |         } else { | ||||||
|             string_set_str(file_path, args); |             string_set_str(file_path, args); | ||||||
|             load_key_data(file_path, &worker.key, true); |             load_key_data(file_path, true); | ||||||
|             view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); |             view_controller.attach_to_gui(ViewDispatcherTypeFullscreen); | ||||||
|             scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); |             scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); | ||||||
|             scene_controller.process(100, SceneType::Emulate); |             scene_controller.process(100, SceneType::Emulate); | ||||||
| @ -114,11 +139,16 @@ void LfRfidApp::run(void* _args) { | |||||||
|         scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo()); |         scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo()); | ||||||
|         scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm()); |         scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm()); | ||||||
|         scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess()); |         scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess()); | ||||||
|  |         scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions()); | ||||||
|  |         scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo()); | ||||||
|  |         scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName()); | ||||||
|  |         scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead()); | ||||||
|  |         scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess()); | ||||||
|         scene_controller.process(100); |         scene_controller.process(100); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidApp::save_key(RfidKey* key) { | bool LfRfidApp::save_key() { | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     make_app_folder(); |     make_app_folder(); | ||||||
| @ -128,9 +158,9 @@ bool LfRfidApp::save_key(RfidKey* key) { | |||||||
|         string_left(file_path, filename_start); |         string_left(file_path, filename_start); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_cat_printf(file_path, "/%s%s", key->get_name(), app_extension); |     string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension); | ||||||
| 
 | 
 | ||||||
|     result = save_key_data(file_path, key); |     result = save_key_data(file_path); | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -143,56 +173,27 @@ bool LfRfidApp::load_key_from_file_select(bool need_restore) { | |||||||
|         dialogs, file_path, file_path, app_extension, true, &I_125_10px, true); |         dialogs, file_path, file_path, app_extension, true, &I_125_10px, true); | ||||||
| 
 | 
 | ||||||
|     if(result) { |     if(result) { | ||||||
|         result = load_key_data(file_path, &worker.key, true); |         result = load_key_data(file_path, true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidApp::delete_key(RfidKey* key) { | bool LfRfidApp::delete_key() { | ||||||
|     UNUSED(key); |  | ||||||
|     return storage_simply_remove(storage, string_get_cstr(file_path)); |     return storage_simply_remove(storage, string_get_cstr(file_path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidApp::load_key_data(string_t path, RfidKey* key, bool show_dialog) { | bool LfRfidApp::load_key_data(string_t path, bool show_dialog) { | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); |  | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     string_t str_result; |  | ||||||
|     string_init(str_result); |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_file_open_existing(file, string_get_cstr(path))) break; |         protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path)); | ||||||
|  |         if(protocol_id == PROTOCOL_NO) break; | ||||||
| 
 | 
 | ||||||
|         // header
 |         path_extract_filename(path, file_name, true); | ||||||
|         uint32_t version; |  | ||||||
|         if(!flipper_format_read_header(file, str_result, &version)) break; |  | ||||||
|         if(string_cmp_str(str_result, app_filetype) != 0) break; |  | ||||||
|         if(version != 1) break; |  | ||||||
| 
 |  | ||||||
|         // key type
 |  | ||||||
|         LfrfidKeyType type; |  | ||||||
|         RfidKey loaded_key; |  | ||||||
| 
 |  | ||||||
|         if(!flipper_format_read_string(file, "Key type", str_result)) break; |  | ||||||
|         if(!lfrfid_key_get_string_type(string_get_cstr(str_result), &type)) break; |  | ||||||
|         loaded_key.set_type(type); |  | ||||||
| 
 |  | ||||||
|         // key data
 |  | ||||||
|         uint8_t key_data[loaded_key.get_type_data_count()] = {}; |  | ||||||
|         if(!flipper_format_read_hex(file, "Data", key_data, loaded_key.get_type_data_count())) |  | ||||||
|             break; |  | ||||||
|         loaded_key.set_data(key_data, loaded_key.get_type_data_count()); |  | ||||||
| 
 |  | ||||||
|         path_extract_filename(path, str_result, true); |  | ||||||
|         loaded_key.set_name(string_get_cstr(str_result)); |  | ||||||
| 
 |  | ||||||
|         *key = loaded_key; |  | ||||||
|         result = true; |         result = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     flipper_format_free(file); |  | ||||||
|     string_clear(str_result); |  | ||||||
| 
 |  | ||||||
|     if((!result) && (show_dialog)) { |     if((!result) && (show_dialog)) { | ||||||
|         dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); |         dialog_message_show_storage_error(dialogs, "Cannot load\nkey file"); | ||||||
|     } |     } | ||||||
| @ -200,27 +201,8 @@ bool LfRfidApp::load_key_data(string_t path, RfidKey* key, bool show_dialog) { | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidApp::save_key_data(string_t path, RfidKey* key) { | bool LfRfidApp::save_key_data(string_t path) { | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(storage); |     bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path)); | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         if(!flipper_format_file_open_always(file, string_get_cstr(path))) break; |  | ||||||
|         if(!flipper_format_write_header_cstr(file, app_filetype, 1)) break; |  | ||||||
|         if(!flipper_format_write_comment_cstr(file, "Key type can be EM4100, H10301 or I40134")) |  | ||||||
|             break; |  | ||||||
|         if(!flipper_format_write_string_cstr( |  | ||||||
|                file, "Key type", lfrfid_key_get_type_string(key->get_type()))) |  | ||||||
|             break; |  | ||||||
|         if(!flipper_format_write_comment_cstr( |  | ||||||
|                file, "Data size for EM4100 is 5, for H10301 is 3, for I40134 is 3")) |  | ||||||
|             break; |  | ||||||
|         if(!flipper_format_write_hex(file, "Data", key->get_data(), key->get_type_data_count())) |  | ||||||
|             break; |  | ||||||
|         result = true; |  | ||||||
|     } while(0); |  | ||||||
| 
 |  | ||||||
|     flipper_format_free(file); |  | ||||||
| 
 | 
 | ||||||
|     if(!result) { |     if(!result) { | ||||||
|         dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); |         dialog_message_show_storage_error(dialogs, "Cannot save\nkey file"); | ||||||
|  | |||||||
| @ -20,9 +20,15 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <dialogs/dialogs.h> | #include <dialogs/dialogs.h> | ||||||
| 
 | 
 | ||||||
| #include "helpers/rfid_worker.h" |  | ||||||
| #include "rpc/rpc_app.h" | #include "rpc/rpc_app.h" | ||||||
| 
 | 
 | ||||||
|  | #include <toolbox/protocols/protocol_dict.h> | ||||||
|  | #include <lfrfid/lfrfid_dict_file.h> | ||||||
|  | #include <lfrfid/protocols/lfrfid_protocols.h> | ||||||
|  | #include <lfrfid/lfrfid_worker.h> | ||||||
|  | 
 | ||||||
|  | #define LFRFID_KEY_NAME_SIZE 22 | ||||||
|  | 
 | ||||||
| class LfRfidApp { | class LfRfidApp { | ||||||
| public: | public: | ||||||
|     enum class EventType : uint8_t { |     enum class EventType : uint8_t { | ||||||
| @ -32,7 +38,19 @@ public: | |||||||
|         Stay, |         Stay, | ||||||
|         Retry, |         Retry, | ||||||
|         Exit, |         Exit, | ||||||
|         EmulateStart, |         ReadEventSenseStart, | ||||||
|  |         ReadEventSenseEnd, | ||||||
|  |         ReadEventSenseCardStart, | ||||||
|  |         ReadEventSenseCardEnd, | ||||||
|  |         ReadEventStartASK, | ||||||
|  |         ReadEventStartPSK, | ||||||
|  |         ReadEventDone, | ||||||
|  |         ReadEventOverrun, | ||||||
|  |         ReadEventError, | ||||||
|  |         WriteEventOK, | ||||||
|  |         WriteEventProtocolCannotBeWritten, | ||||||
|  |         WriteEventFobCannotBeWritten, | ||||||
|  |         WriteEventTooLongToWrite, | ||||||
|         RpcLoadFile, |         RpcLoadFile, | ||||||
|         RpcSessionClose, |         RpcSessionClose, | ||||||
|     }; |     }; | ||||||
| @ -57,12 +75,17 @@ public: | |||||||
|         DeleteConfirm, |         DeleteConfirm, | ||||||
|         DeleteSuccess, |         DeleteSuccess, | ||||||
|         Rpc, |         Rpc, | ||||||
|  |         ExtraActions, | ||||||
|  |         RawInfo, | ||||||
|  |         RawName, | ||||||
|  |         RawRead, | ||||||
|  |         RawSuccess, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     class Event { |     class Event { | ||||||
|     public: |     public: | ||||||
|         union { |         union { | ||||||
|             int32_t menu_index; |             int32_t signed_int; | ||||||
|         } payload; |         } payload; | ||||||
| 
 | 
 | ||||||
|         EventType type; |         EventType type; | ||||||
| @ -79,8 +102,6 @@ public: | |||||||
|     RecordController<Storage> storage; |     RecordController<Storage> storage; | ||||||
|     RecordController<DialogsApp> dialogs; |     RecordController<DialogsApp> dialogs; | ||||||
| 
 | 
 | ||||||
|     RfidWorker worker; |  | ||||||
| 
 |  | ||||||
|     TextStore text_store; |     TextStore text_store; | ||||||
| 
 | 
 | ||||||
|     string_t file_path; |     string_t file_path; | ||||||
| @ -90,15 +111,27 @@ public: | |||||||
|     void run(void* args); |     void run(void* args); | ||||||
| 
 | 
 | ||||||
|     static const char* app_folder; |     static const char* app_folder; | ||||||
|  |     static const char* app_sd_folder; | ||||||
|     static const char* app_extension; |     static const char* app_extension; | ||||||
|     static const char* app_filetype; |     static const char* app_filetype; | ||||||
| 
 | 
 | ||||||
|     bool save_key(RfidKey* key); |     bool save_key(); | ||||||
|     bool load_key_from_file_select(bool need_restore); |     bool load_key_from_file_select(bool need_restore); | ||||||
|     bool delete_key(RfidKey* key); |     bool delete_key(); | ||||||
| 
 | 
 | ||||||
|     bool load_key_data(string_t path, RfidKey* key, bool show_dialog); |     bool load_key_data(string_t path, bool show_dialog); | ||||||
|     bool save_key_data(string_t path, RfidKey* key); |     bool save_key_data(string_t path); | ||||||
| 
 | 
 | ||||||
|     void make_app_folder(); |     void make_app_folder(); | ||||||
|  | 
 | ||||||
|  |     ProtocolDict* dict; | ||||||
|  |     LFRFIDWorker* lfworker; | ||||||
|  |     string_t file_name; | ||||||
|  |     ProtocolId protocol_id; | ||||||
|  |     LFRFIDWorkerReadType read_type; | ||||||
|  | 
 | ||||||
|  |     uint8_t* old_key_data; | ||||||
|  |     uint8_t* new_key_data; | ||||||
|  | 
 | ||||||
|  |     string_t raw_file_name; | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										575
									
								
								applications/lfrfid/lfrfid_cli.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										575
									
								
								applications/lfrfid/lfrfid_cli.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,575 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <cli/cli.h> | ||||||
|  | #include <lib/toolbox/args.h> | ||||||
|  | #include <lib/lfrfid/lfrfid_worker.h> | ||||||
|  | #include <storage/storage.h> | ||||||
|  | #include <toolbox/stream/file_stream.h> | ||||||
|  | 
 | ||||||
|  | #include <toolbox/varint.h> | ||||||
|  | 
 | ||||||
|  | #include <toolbox/protocols/protocol_dict.h> | ||||||
|  | #include <lfrfid/protocols/lfrfid_protocols.h> | ||||||
|  | #include <lfrfid/lfrfid_raw_file.h> | ||||||
|  | #include <toolbox/pulse_protocols/pulse_glue.h> | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli(Cli* cli, string_t args, void* context); | ||||||
|  | 
 | ||||||
|  | // app cli function
 | ||||||
|  | void lfrfid_on_system_start() { | ||||||
|  |     Cli* cli = furi_record_open(RECORD_CLI); | ||||||
|  |     cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL); | ||||||
|  |     furi_record_close(RECORD_CLI); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_print_usage() { | ||||||
|  |     printf("Usage:\r\n"); | ||||||
|  |     printf("rfid read <optional: normal | indala>\r\n"); | ||||||
|  |     printf("rfid <write | emulate> <key_type> <key_data>\r\n"); | ||||||
|  |     printf("rfid raw_read <ask | psk> <filename>\r\n"); | ||||||
|  |     printf("rfid raw_emulate <filename>\r\n"); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     ProtocolId protocol; | ||||||
|  |     FuriEventFlag* event; | ||||||
|  | } LFRFIDCliReadContext; | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_read_callback(LFRFIDWorkerReadResult result, ProtocolId proto, void* ctx) { | ||||||
|  |     furi_assert(ctx); | ||||||
|  |     LFRFIDCliReadContext* context = ctx; | ||||||
|  |     if(result == LFRFIDWorkerReadDone) { | ||||||
|  |         context->protocol = proto; | ||||||
|  |         FURI_SW_MEMBARRIER(); | ||||||
|  |     } | ||||||
|  |     furi_event_flag_set(context->event, 1 << result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_read(Cli* cli, string_t args) { | ||||||
|  |     string_t type_string; | ||||||
|  |     string_init(type_string); | ||||||
|  |     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||||
|  | 
 | ||||||
|  |     if(args_read_string_and_trim(args, type_string)) { | ||||||
|  |         if(string_cmp_str(type_string, "normal") == 0 || string_cmp_str(type_string, "ask") == 0) { | ||||||
|  |             // ask
 | ||||||
|  |             type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|  |         } else if( | ||||||
|  |             string_cmp_str(type_string, "indala") == 0 || | ||||||
|  |             string_cmp_str(type_string, "psk") == 0) { | ||||||
|  |             // psk
 | ||||||
|  |             type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|  |         } else { | ||||||
|  |             lfrfid_cli_print_usage(); | ||||||
|  |             string_clear(type_string); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     string_clear(type_string); | ||||||
|  | 
 | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
|  |     LFRFIDCliReadContext context; | ||||||
|  |     context.protocol = PROTOCOL_NO; | ||||||
|  |     context.event = furi_event_flag_alloc(); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_start_thread(worker); | ||||||
|  | 
 | ||||||
|  |     printf("Reading RFID...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|  | 
 | ||||||
|  |     const uint32_t available_flags = (1 << LFRFIDWorkerReadDone); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_read_start(worker, type, lfrfid_cli_read_callback, &context); | ||||||
|  | 
 | ||||||
|  |     while(true) { | ||||||
|  |         uint32_t flags = | ||||||
|  |             furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100); | ||||||
|  | 
 | ||||||
|  |         if(flags != FuriFlagErrorTimeout) { | ||||||
|  |             if(FURI_BIT(flags, LFRFIDWorkerReadDone)) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(cli_cmd_interrupt_received(cli)) break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_stop(worker); | ||||||
|  |     lfrfid_worker_stop_thread(worker); | ||||||
|  |     lfrfid_worker_free(worker); | ||||||
|  | 
 | ||||||
|  |     if(context.protocol != PROTOCOL_NO) { | ||||||
|  |         printf("%s ", protocol_dict_get_name(dict, context.protocol)); | ||||||
|  | 
 | ||||||
|  |         size_t size = protocol_dict_get_data_size(dict, context.protocol); | ||||||
|  |         uint8_t* data = malloc(size); | ||||||
|  |         protocol_dict_get_data(dict, context.protocol, data, size); | ||||||
|  |         for(size_t i = 0; i < size; i++) { | ||||||
|  |             printf("%02X", data[i]); | ||||||
|  |         } | ||||||
|  |         printf("\r\n"); | ||||||
|  |         free(data); | ||||||
|  | 
 | ||||||
|  |         string_t info; | ||||||
|  |         string_init(info); | ||||||
|  |         protocol_dict_render_data(dict, info, context.protocol); | ||||||
|  |         if(string_size(info) > 0) { | ||||||
|  |             printf("%s\r\n", string_get_cstr(info)); | ||||||
|  |         } | ||||||
|  |         string_clear(info); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     printf("Reading stopped\r\n"); | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | 
 | ||||||
|  |     furi_event_flag_free(context.event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* protocol) { | ||||||
|  |     bool result = false; | ||||||
|  |     string_t protocol_name, data_text; | ||||||
|  |     string_init(protocol_name); | ||||||
|  |     string_init(data_text); | ||||||
|  |     size_t data_size = protocol_dict_get_max_data_size(dict); | ||||||
|  |     uint8_t* data = malloc(data_size); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // load args
 | ||||||
|  |         if(!args_read_string_and_trim(args, protocol_name) || | ||||||
|  |            !args_read_string_and_trim(args, data_text)) { | ||||||
|  |             lfrfid_cli_print_usage(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // check protocol arg
 | ||||||
|  |         *protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(protocol_name)); | ||||||
|  |         if(*protocol == PROTOCOL_NO) { | ||||||
|  |             printf( | ||||||
|  |                 "Unknown protocol: %s\r\n" | ||||||
|  |                 "Available protocols:\r\n", | ||||||
|  |                 string_get_cstr(protocol_name)); | ||||||
|  | 
 | ||||||
|  |             for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) { | ||||||
|  |                 printf( | ||||||
|  |                     "\t%s, %d bytes long\r\n", | ||||||
|  |                     protocol_dict_get_name(dict, i), | ||||||
|  |                     protocol_dict_get_data_size(dict, i)); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         data_size = protocol_dict_get_data_size(dict, *protocol); | ||||||
|  | 
 | ||||||
|  |         // check data arg
 | ||||||
|  |         if(!args_read_hex_bytes(data_text, data, data_size)) { | ||||||
|  |             printf( | ||||||
|  |                 "%s data needs to be %d bytes long\r\n", | ||||||
|  |                 protocol_dict_get_name(dict, *protocol), | ||||||
|  |                 data_size); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // load data to protocol
 | ||||||
|  |         protocol_dict_set_data(dict, *protocol, data, data_size); | ||||||
|  | 
 | ||||||
|  |         result = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     free(data); | ||||||
|  |     string_clear(protocol_name); | ||||||
|  |     string_clear(data_text); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { | ||||||
|  |     furi_assert(ctx); | ||||||
|  |     FuriEventFlag* events = ctx; | ||||||
|  |     furi_event_flag_set(events, 1 << result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_write(Cli* cli, string_t args) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     ProtocolId protocol; | ||||||
|  | 
 | ||||||
|  |     if(!lfrfid_cli_parse_args(args, dict, &protocol)) { | ||||||
|  |         protocol_dict_free(dict); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
|  |     FuriEventFlag* event = furi_event_flag_alloc(); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_start_thread(worker); | ||||||
|  |     lfrfid_worker_write_start(worker, protocol, lfrfid_cli_write_callback, event); | ||||||
|  | 
 | ||||||
|  |     printf("Writing RFID...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|  |     const uint32_t available_flags = (1 << LFRFIDWorkerWriteOK) | | ||||||
|  |                                      (1 << LFRFIDWorkerWriteProtocolCannotBeWritten) | | ||||||
|  |                                      (1 << LFRFIDWorkerWriteFobCannotBeWritten); | ||||||
|  | 
 | ||||||
|  |     while(!cli_cmd_interrupt_received(cli)) { | ||||||
|  |         uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||||
|  |         if(flags != FuriFlagErrorTimeout) { | ||||||
|  |             if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) { | ||||||
|  |                 printf("Written!\r\n"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(FURI_BIT(flags, LFRFIDWorkerWriteProtocolCannotBeWritten)) { | ||||||
|  |                 printf("This protocol cannot be written.\r\n"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(FURI_BIT(flags, LFRFIDWorkerWriteFobCannotBeWritten)) { | ||||||
|  |                 printf("Seems this fob cannot be written.\r\n"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     printf("Writing stopped\r\n"); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_stop(worker); | ||||||
|  |     lfrfid_worker_stop_thread(worker); | ||||||
|  |     lfrfid_worker_free(worker); | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  |     furi_event_flag_free(event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_emulate(Cli* cli, string_t args) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     ProtocolId protocol; | ||||||
|  | 
 | ||||||
|  |     if(!lfrfid_cli_parse_args(args, dict, &protocol)) { | ||||||
|  |         protocol_dict_free(dict); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_start_thread(worker); | ||||||
|  |     lfrfid_worker_emulate_start(worker, protocol); | ||||||
|  | 
 | ||||||
|  |     printf("Emulating RFID...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|  |     while(!cli_cmd_interrupt_received(cli)) { | ||||||
|  |         furi_delay_ms(100); | ||||||
|  |     } | ||||||
|  |     printf("Emulation stopped\r\n"); | ||||||
|  | 
 | ||||||
|  |     lfrfid_worker_stop(worker); | ||||||
|  |     lfrfid_worker_stop_thread(worker); | ||||||
|  |     lfrfid_worker_free(worker); | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) { | ||||||
|  |     UNUSED(cli); | ||||||
|  |     string_t filepath, info_string; | ||||||
|  |     string_init(filepath); | ||||||
|  |     string_init(info_string); | ||||||
|  |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|  |     LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         float frequency = 0; | ||||||
|  |         float duty_cycle = 0; | ||||||
|  | 
 | ||||||
|  |         if(!args_read_probably_quoted_string_and_trim(args, filepath)) { | ||||||
|  |             lfrfid_cli_print_usage(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!lfrfid_raw_file_open_read(file, string_get_cstr(filepath))) { | ||||||
|  |             printf("Failed to open file\r\n"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!lfrfid_raw_file_read_header(file, &frequency, &duty_cycle)) { | ||||||
|  |             printf("Invalid header\r\n"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool file_end = false; | ||||||
|  |         uint32_t total_warns = 0; | ||||||
|  |         uint32_t total_duration = 0; | ||||||
|  |         uint32_t total_pulse = 0; | ||||||
|  |         ProtocolId total_protocol = PROTOCOL_NO; | ||||||
|  | 
 | ||||||
|  |         ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |         protocol_dict_decoders_start(dict); | ||||||
|  | 
 | ||||||
|  |         while(!file_end) { | ||||||
|  |             uint32_t pulse = 0; | ||||||
|  |             uint32_t duration = 0; | ||||||
|  |             if(lfrfid_raw_file_read_pair(file, &duration, &pulse, &file_end)) { | ||||||
|  |                 bool warn = false; | ||||||
|  | 
 | ||||||
|  |                 if(pulse > duration || pulse <= 0 || duration <= 0) { | ||||||
|  |                     total_warns += 1; | ||||||
|  |                     warn = true; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 string_printf(info_string, "[%ld %ld]", pulse, duration); | ||||||
|  |                 printf("%-16s", string_get_cstr(info_string)); | ||||||
|  |                 string_printf(info_string, "[%ld %ld]", pulse, duration - pulse); | ||||||
|  |                 printf("%-16s", string_get_cstr(info_string)); | ||||||
|  | 
 | ||||||
|  |                 if(warn) { | ||||||
|  |                     printf(" <<----"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(total_protocol == PROTOCOL_NO) { | ||||||
|  |                     total_protocol = protocol_dict_decoders_feed(dict, true, pulse); | ||||||
|  |                     if(total_protocol == PROTOCOL_NO) { | ||||||
|  |                         total_protocol = | ||||||
|  |                             protocol_dict_decoders_feed(dict, false, duration - pulse); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if(total_protocol != PROTOCOL_NO) { | ||||||
|  |                         printf(" <FOUND %s>", protocol_dict_get_name(dict, total_protocol)); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 printf("\r\n"); | ||||||
|  | 
 | ||||||
|  |                 total_pulse += pulse; | ||||||
|  |                 total_duration += duration; | ||||||
|  | 
 | ||||||
|  |                 if(total_protocol != PROTOCOL_NO) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 printf("Failed to read pair\r\n"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         printf("   Frequency: %f\r\n", (double)frequency); | ||||||
|  |         printf("  Duty Cycle: %f\r\n", (double)duty_cycle); | ||||||
|  |         printf("       Warns: %ld\r\n", total_warns); | ||||||
|  |         printf("   Pulse sum: %ld\r\n", total_pulse); | ||||||
|  |         printf("Duration sum: %ld\r\n", total_duration); | ||||||
|  |         printf("     Average: %f\r\n", (double)((float)total_pulse / (float)total_duration)); | ||||||
|  |         printf("    Protocol: "); | ||||||
|  | 
 | ||||||
|  |         if(total_protocol != PROTOCOL_NO) { | ||||||
|  |             size_t data_size = protocol_dict_get_data_size(dict, total_protocol); | ||||||
|  |             uint8_t* data = malloc(data_size); | ||||||
|  |             protocol_dict_get_data(dict, total_protocol, data, data_size); | ||||||
|  | 
 | ||||||
|  |             printf("%s [", protocol_dict_get_name(dict, total_protocol)); | ||||||
|  |             for(size_t i = 0; i < data_size; i++) { | ||||||
|  |                 printf("%02X", data[i]); | ||||||
|  |                 if(i < data_size - 1) { | ||||||
|  |                     printf(" "); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             printf("]\r\n"); | ||||||
|  | 
 | ||||||
|  |             protocol_dict_render_data(dict, info_string, total_protocol); | ||||||
|  |             printf("%s\r\n", string_get_cstr(info_string)); | ||||||
|  | 
 | ||||||
|  |             free(data); | ||||||
|  |         } else { | ||||||
|  |             printf("not found\r\n"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protocol_dict_free(dict); | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(filepath); | ||||||
|  |     string_clear(info_string); | ||||||
|  |     lfrfid_raw_file_free(file); | ||||||
|  |     furi_record_close(RECORD_STORAGE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_raw_read_callback(LFRFIDWorkerReadRawResult result, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     FuriEventFlag* event = context; | ||||||
|  |     furi_event_flag_set(event, 1 << result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_raw_read(Cli* cli, string_t args) { | ||||||
|  |     UNUSED(cli); | ||||||
|  | 
 | ||||||
|  |     string_t filepath, type_string; | ||||||
|  |     string_init(filepath); | ||||||
|  |     string_init(type_string); | ||||||
|  |     LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(args_read_string_and_trim(args, type_string)) { | ||||||
|  |             if(string_cmp_str(type_string, "normal") == 0 || | ||||||
|  |                string_cmp_str(type_string, "ask") == 0) { | ||||||
|  |                 // ask
 | ||||||
|  |                 type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|  |             } else if( | ||||||
|  |                 string_cmp_str(type_string, "indala") == 0 || | ||||||
|  |                 string_cmp_str(type_string, "psk") == 0) { | ||||||
|  |                 // psk
 | ||||||
|  |                 type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|  |             } else { | ||||||
|  |                 lfrfid_cli_print_usage(); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!args_read_probably_quoted_string_and_trim(args, filepath)) { | ||||||
|  |             lfrfid_cli_print_usage(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |         LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
|  |         FuriEventFlag* event = furi_event_flag_alloc(); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_start_thread(worker); | ||||||
|  | 
 | ||||||
|  |         bool overrun = false; | ||||||
|  | 
 | ||||||
|  |         const uint32_t available_flags = (1 << LFRFIDWorkerReadRawFileError) | | ||||||
|  |                                          (1 << LFRFIDWorkerReadRawOverrun); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_read_raw_start( | ||||||
|  |             worker, string_get_cstr(filepath), type, lfrfid_cli_raw_read_callback, event); | ||||||
|  |         while(true) { | ||||||
|  |             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||||
|  | 
 | ||||||
|  |             if(flags != FuriFlagErrorTimeout) { | ||||||
|  |                 if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) { | ||||||
|  |                     printf("File is not RFID raw file\r\n"); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(FURI_BIT(flags, LFRFIDWorkerReadRawOverrun)) { | ||||||
|  |                     if(!overrun) { | ||||||
|  |                         printf("Overrun\r\n"); | ||||||
|  |                         overrun = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(cli_cmd_interrupt_received(cli)) break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(overrun) { | ||||||
|  |             printf("An overrun occurred during read\r\n"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_stop(worker); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_stop_thread(worker); | ||||||
|  |         lfrfid_worker_free(worker); | ||||||
|  |         protocol_dict_free(dict); | ||||||
|  | 
 | ||||||
|  |         furi_event_flag_free(event); | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(filepath); | ||||||
|  |     string_clear(type_string); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     FuriEventFlag* event = context; | ||||||
|  |     furi_event_flag_set(event, 1 << result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) { | ||||||
|  |     UNUSED(cli); | ||||||
|  | 
 | ||||||
|  |     string_t filepath; | ||||||
|  |     string_init(filepath); | ||||||
|  |     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(!args_read_probably_quoted_string_and_trim(args, filepath)) { | ||||||
|  |             lfrfid_cli_print_usage(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!storage_file_exists(storage, string_get_cstr(filepath))) { | ||||||
|  |             printf("File not found: \"%s\"\r\n", string_get_cstr(filepath)); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |         LFRFIDWorker* worker = lfrfid_worker_alloc(dict); | ||||||
|  |         FuriEventFlag* event = furi_event_flag_alloc(); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_start_thread(worker); | ||||||
|  | 
 | ||||||
|  |         bool overrun = false; | ||||||
|  | 
 | ||||||
|  |         const uint32_t available_flags = (1 << LFRFIDWorkerEmulateRawFileError) | | ||||||
|  |                                          (1 << LFRFIDWorkerEmulateRawOverrun); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_emulate_raw_start( | ||||||
|  |             worker, string_get_cstr(filepath), lfrfid_cli_raw_emulate_callback, event); | ||||||
|  |         while(true) { | ||||||
|  |             uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100); | ||||||
|  | 
 | ||||||
|  |             if(flags != FuriFlagErrorTimeout) { | ||||||
|  |                 if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) { | ||||||
|  |                     printf("File is not RFID raw file\r\n"); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(FURI_BIT(flags, LFRFIDWorkerEmulateRawOverrun)) { | ||||||
|  |                     if(!overrun) { | ||||||
|  |                         printf("Overrun\r\n"); | ||||||
|  |                         overrun = true; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(cli_cmd_interrupt_received(cli)) break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(overrun) { | ||||||
|  |             printf("An overrun occurred during emulation\r\n"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_stop(worker); | ||||||
|  | 
 | ||||||
|  |         lfrfid_worker_stop_thread(worker); | ||||||
|  |         lfrfid_worker_free(worker); | ||||||
|  |         protocol_dict_free(dict); | ||||||
|  | 
 | ||||||
|  |         furi_event_flag_free(event); | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     furi_record_close(RECORD_STORAGE); | ||||||
|  |     string_clear(filepath); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lfrfid_cli(Cli* cli, string_t args, void* context) { | ||||||
|  |     UNUSED(context); | ||||||
|  |     string_t cmd; | ||||||
|  |     string_init(cmd); | ||||||
|  | 
 | ||||||
|  |     if(!args_read_string_and_trim(args, cmd)) { | ||||||
|  |         string_clear(cmd); | ||||||
|  |         lfrfid_cli_print_usage(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(string_cmp_str(cmd, "read") == 0) { | ||||||
|  |         lfrfid_cli_read(cli, args); | ||||||
|  |     } else if(string_cmp_str(cmd, "write") == 0) { | ||||||
|  |         lfrfid_cli_write(cli, args); | ||||||
|  |     } else if(string_cmp_str(cmd, "emulate") == 0) { | ||||||
|  |         lfrfid_cli_emulate(cli, args); | ||||||
|  |     } else if(string_cmp_str(cmd, "raw_read") == 0) { | ||||||
|  |         lfrfid_cli_raw_read(cli, args); | ||||||
|  |     } else if(string_cmp_str(cmd, "raw_emulate") == 0) { | ||||||
|  |         lfrfid_cli_raw_emulate(cli, args); | ||||||
|  |     } else if(string_cmp_str(cmd, "raw_analyze") == 0) { | ||||||
|  |         lfrfid_cli_raw_analyze(cli, args); | ||||||
|  |     } else { | ||||||
|  |         lfrfid_cli_print_usage(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(cmd); | ||||||
|  | } | ||||||
| @ -1,177 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| #include <furi_hal.h> |  | ||||||
| #include <stdarg.h> |  | ||||||
| #include <cli/cli.h> |  | ||||||
| #include <lib/toolbox/args.h> |  | ||||||
| 
 |  | ||||||
| #include "helpers/rfid_reader.h" |  | ||||||
| #include "helpers/rfid_timer_emulator.h" |  | ||||||
| 
 |  | ||||||
| static void lfrfid_cli(Cli* cli, string_t args, void* context); |  | ||||||
| 
 |  | ||||||
| // app cli function
 |  | ||||||
| extern "C" void lfrfid_on_system_start() { |  | ||||||
| #ifdef SRV_CLI |  | ||||||
|     Cli* cli = static_cast<Cli*>(furi_record_open("cli")); |  | ||||||
|     cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL); |  | ||||||
|     furi_record_close("cli"); |  | ||||||
| #else |  | ||||||
|     UNUSED(lfrfid_cli); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void lfrfid_cli_print_usage() { |  | ||||||
|     printf("Usage:\r\n"); |  | ||||||
|     printf("rfid read <optional: normal | indala>\r\n"); |  | ||||||
|     printf("rfid <write | emulate> <key_type> <key_data>\r\n"); |  | ||||||
|     printf("\t<key_type> choose from:\r\n"); |  | ||||||
|     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<key_data> are hex-formatted\r\n"); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) { |  | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     if(string_cmp_str(data, "EM4100") == 0 || string_cmp_str(data, "EM-Marin") == 0) { |  | ||||||
|         result = true; |  | ||||||
|         *type = LfrfidKeyType::KeyEM4100; |  | ||||||
|     } else if(string_cmp_str(data, "H10301") == 0 || string_cmp_str(data, "HID26") == 0) { |  | ||||||
|         result = true; |  | ||||||
|         *type = LfrfidKeyType::KeyH10301; |  | ||||||
|     } 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lfrfid_cli_read(Cli* cli, string_t args) { |  | ||||||
|     RfidReader reader; |  | ||||||
|     string_t type_string; |  | ||||||
|     string_init(type_string); |  | ||||||
|     bool simple_mode = true; |  | ||||||
|     LfrfidKeyType type; |  | ||||||
|     RfidReader::Type reader_type = RfidReader::Type::Normal; |  | ||||||
|     static const uint8_t data_size = LFRFID_KEY_SIZE; |  | ||||||
|     uint8_t data[data_size] = {0}; |  | ||||||
| 
 |  | ||||||
|     if(args_read_string_and_trim(args, type_string)) { |  | ||||||
|         simple_mode = false; |  | ||||||
| 
 |  | ||||||
|         if(string_cmp_str(type_string, "normal") == 0) { |  | ||||||
|             reader_type = RfidReader::Type::Normal; |  | ||||||
|         } else if(string_cmp_str(type_string, "indala") == 0) { |  | ||||||
|             reader_type = RfidReader::Type::Indala; |  | ||||||
|         } else { |  | ||||||
|             lfrfid_cli_print_usage(); |  | ||||||
|             string_clear(type_string); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(simple_mode) { |  | ||||||
|         reader.start(); |  | ||||||
|     } else { |  | ||||||
|         reader.start_forced(reader_type); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     printf("Reading RFID...\r\nPress Ctrl+C to abort\r\n"); |  | ||||||
|     while(!cli_cmd_interrupt_received(cli)) { |  | ||||||
|         if(reader.read(&type, data, data_size, simple_mode)) { |  | ||||||
|             printf("%s", lfrfid_key_get_type_string(type)); |  | ||||||
|             printf(" "); |  | ||||||
| 
 |  | ||||||
|             for(uint8_t i = 0; i < lfrfid_key_get_type_data_count(type); i++) { |  | ||||||
|                 printf("%02X", data[i]); |  | ||||||
|             } |  | ||||||
|             printf("\r\n"); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         furi_delay_ms(100); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     printf("Reading stopped\r\n"); |  | ||||||
|     reader.stop(); |  | ||||||
| 
 |  | ||||||
|     string_clear(type_string); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lfrfid_cli_write(Cli* cli, string_t args) { |  | ||||||
|     UNUSED(cli); |  | ||||||
|     UNUSED(args); |  | ||||||
|     // TODO implement rfid write
 |  | ||||||
|     printf("Not Implemented :(\r\n"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lfrfid_cli_emulate(Cli* cli, string_t args) { |  | ||||||
|     string_t data; |  | ||||||
|     string_init(data); |  | ||||||
|     RfidTimerEmulator emulator; |  | ||||||
| 
 |  | ||||||
|     static const uint8_t data_size = LFRFID_KEY_SIZE; |  | ||||||
|     uint8_t key_data[data_size] = {0}; |  | ||||||
|     uint8_t key_data_size = 0; |  | ||||||
|     LfrfidKeyType type; |  | ||||||
| 
 |  | ||||||
|     if(!args_read_string_and_trim(args, data)) { |  | ||||||
|         lfrfid_cli_print_usage(); |  | ||||||
|         string_clear(data); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(!lfrfid_cli_get_key_type(data, &type)) { |  | ||||||
|         lfrfid_cli_print_usage(); |  | ||||||
|         string_clear(data); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     key_data_size = lfrfid_key_get_type_data_count(type); |  | ||||||
| 
 |  | ||||||
|     if(!args_read_hex_bytes(args, key_data, key_data_size)) { |  | ||||||
|         lfrfid_cli_print_usage(); |  | ||||||
|         string_clear(data); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     emulator.start(type, key_data, key_data_size); |  | ||||||
| 
 |  | ||||||
|     printf("Emulating RFID...\r\nPress Ctrl+C to abort\r\n"); |  | ||||||
|     while(!cli_cmd_interrupt_received(cli)) { |  | ||||||
|         furi_delay_ms(100); |  | ||||||
|     } |  | ||||||
|     printf("Emulation stopped\r\n"); |  | ||||||
|     emulator.stop(); |  | ||||||
| 
 |  | ||||||
|     string_clear(data); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lfrfid_cli(Cli* cli, string_t args, void* context) { |  | ||||||
|     UNUSED(context); |  | ||||||
|     string_t cmd; |  | ||||||
|     string_init(cmd); |  | ||||||
| 
 |  | ||||||
|     if(!args_read_string_and_trim(args, cmd)) { |  | ||||||
|         string_clear(cmd); |  | ||||||
|         lfrfid_cli_print_usage(); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(string_cmp_str(cmd, "read") == 0) { |  | ||||||
|         lfrfid_cli_read(cli, args); |  | ||||||
|     } else if(string_cmp_str(cmd, "write") == 0) { |  | ||||||
|         lfrfid_cli_write(cli, args); |  | ||||||
|     } else if(string_cmp_str(cmd, "emulate") == 0) { |  | ||||||
|         lfrfid_cli_emulate(cli, args); |  | ||||||
|     } else { |  | ||||||
|         lfrfid_cli_print_usage(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     string_clear(cmd); |  | ||||||
| } |  | ||||||
| @ -5,7 +5,6 @@ | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     string_init(string_data); |     string_init(string_data); | ||||||
|     string_init(string_decrypted); |  | ||||||
|     string_init(string_header); |     string_init(string_header); | ||||||
| 
 | 
 | ||||||
|     auto container = app->view_controller.get<ContainerVM>(); |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
| @ -21,49 +20,26 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore | |||||||
|     auto line_1 = container->add<StringElement>(); |     auto line_1 = container->add<StringElement>(); | ||||||
|     auto line_2 = container->add<StringElement>(); |     auto line_2 = container->add<StringElement>(); | ||||||
|     auto line_3 = container->add<StringElement>(); |     auto line_3 = container->add<StringElement>(); | ||||||
|     auto line_4 = container->add<StringElement>(); |  | ||||||
| 
 | 
 | ||||||
|     RfidKey& key = app->worker.key; |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|     const uint8_t* data = key.get_data(); |     uint8_t* data = (uint8_t*)malloc(size); | ||||||
| 
 |     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||||
|     for(uint8_t i = 0; i < key.get_type_data_count(); i++) { |     for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) { | ||||||
|         if(i != 0) { |         if(i != 0) { | ||||||
|             string_cat_printf(string_data, " "); |             string_cat_printf(string_data, " "); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         string_cat_printf(string_data, "%02X", data[i]); |         string_cat_printf(string_data, "%02X", data[i]); | ||||||
|     } |     } | ||||||
|  |     free(data); | ||||||
| 
 | 
 | ||||||
|     string_printf(string_header, "Delete %s?", key.get_name()); |     string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name)); | ||||||
|     line_1->set_text( |     line_1->set_text( | ||||||
|         string_get_cstr(string_header), 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary); |         string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary); | ||||||
|     line_2->set_text( |     line_2->set_text( | ||||||
|         string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontSecondary); |         string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary); | ||||||
| 
 |  | ||||||
|     switch(key.get_type()) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         string_printf( |  | ||||||
|             string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); |  | ||||||
| 
 |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         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( |     line_3->set_text( | ||||||
|         string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary); |         protocol_dict_get_name(app->dict, app->protocol_id), | ||||||
| 
 |  | ||||||
|     line_4->set_text( |  | ||||||
|         lfrfid_key_get_type_string(key.get_type()), |  | ||||||
|         64, |         64, | ||||||
|         49, |         49, | ||||||
|         0, |         0, | ||||||
| @ -78,7 +54,7 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Next) { |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|         app->delete_key(&app->worker.key); |         app->delete_key(); | ||||||
|         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } else if(event->type == LfRfidApp::EventType::Stay) { |     } else if(event->type == LfRfidApp::EventType::Stay) { | ||||||
| @ -94,7 +70,6 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve | |||||||
| void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { | void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) { | ||||||
|     app->view_controller.get<ContainerVM>()->clean(); |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|     string_clear(string_data); |     string_clear(string_data); | ||||||
|     string_clear(string_decrypted); |  | ||||||
|     string_clear(string_header); |     string_clear(string_header); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,5 +13,4 @@ private: | |||||||
| 
 | 
 | ||||||
|     string_t string_header; |     string_t string_header; | ||||||
|     string_t string_data; |     string_t string_data; | ||||||
|     string_t string_decrypted; |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -3,28 +3,21 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     string_init(data_string); |  | ||||||
| 
 |  | ||||||
|     DOLPHIN_DEED(DolphinDeedRfidEmulate); |     DOLPHIN_DEED(DolphinDeedRfidEmulate); | ||||||
|     const uint8_t* data = app->worker.key.get_data(); |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { |  | ||||||
|         string_cat_printf(data_string, "%02X", data[i]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop); |     popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop); | ||||||
|     if(strlen(app->worker.key.get_name())) { |     if(string_size(app->file_name)) { | ||||||
|         popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); |         popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||||
|     } else { |     } else { | ||||||
|         popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); |         popup->set_text( | ||||||
|  |             protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); | ||||||
|     } |     } | ||||||
|     popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); |     popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
|     app->worker.start_emulate(); |     lfrfid_worker_start_thread(app->lfworker); | ||||||
| 
 |     lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); | ||||||
|     notification_message(app->notification, &sequence_blink_start_magenta); |     notification_message(app->notification, &sequence_blink_start_magenta); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -37,7 +30,7 @@ bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) { | void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) { | ||||||
|     app->view_controller.get<PopupVM>()->clean(); |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|     app->worker.stop_emulate(); |     lfrfid_worker_stop(app->lfworker); | ||||||
|     string_clear(data_string); |     lfrfid_worker_stop_thread(app->lfworker); | ||||||
|     notification_message(app->notification, &sequence_blink_stop); |     notification_message(app->notification, &sequence_blink_stop); | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,7 +6,4 @@ public: | |||||||
|     void on_enter(LfRfidApp* app, bool need_restore) final; |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|     void on_exit(LfRfidApp* app) final; |     void on_exit(LfRfidApp* app) final; | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     string_t data_string; |  | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | #include "lfrfid_app_scene_extra_actions.h" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubmenuASK, | ||||||
|  |     SubmenuPSK, | ||||||
|  |     SubmenuRAW, | ||||||
|  | } SubmenuIndex; | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|  |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
|  | 
 | ||||||
|  |     submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app); | ||||||
|  |     submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app); | ||||||
|  | 
 | ||||||
|  |     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||||
|  |         submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         submenu->set_selected_item(submenu_item_selected); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|  |         submenu_item_selected = event->payload.signed_int; | ||||||
|  |         switch(event->payload.signed_int) { | ||||||
|  |         case SubmenuASK: | ||||||
|  |             app->read_type = LFRFIDWorkerReadTypeASKOnly; | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); | ||||||
|  |             break; | ||||||
|  |         case SubmenuPSK: | ||||||
|  |             app->read_type = LFRFIDWorkerReadTypePSKOnly; | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); | ||||||
|  |             break; | ||||||
|  |         case SubmenuRAW: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<SubmenuVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  | 
 | ||||||
|  |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|  |     event.payload.signed_int = index; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid_app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneExtraActions : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void submenu_callback(void* context, uint32_t index); | ||||||
|  |     uint32_t submenu_item_selected = 0; | ||||||
|  | }; | ||||||
							
								
								
									
										77
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | #include "lfrfid_app_scene_raw_info.h" | ||||||
|  | #include "../view/elements/button_element.h" | ||||||
|  | #include "../view/elements/icon_element.h" | ||||||
|  | #include "../view/elements/string_element.h" | ||||||
|  | 
 | ||||||
|  | static void ok_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Next; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void back_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Back; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|  |     string_init(string_info); | ||||||
|  | 
 | ||||||
|  |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
|  | 
 | ||||||
|  |     bool sd_exist = storage_sd_status(app->storage) == FSE_OK; | ||||||
|  |     if(!sd_exist) { | ||||||
|  |         auto icon = container->add<IconElement>(); | ||||||
|  |         icon->set_icon(0, 0, &I_SDQuestion_35x43); | ||||||
|  |         auto line = container->add<StringElement>(); | ||||||
|  |         line->set_text( | ||||||
|  |             "No SD card found.\nThis function will not\nwork without\nSD card.", | ||||||
|  |             81, | ||||||
|  |             4, | ||||||
|  |             0, | ||||||
|  |             AlignCenter, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary); | ||||||
|  | 
 | ||||||
|  |         auto button = container->add<ButtonElement>(); | ||||||
|  |         button->set_type(ButtonElement::Type::Left, "Back"); | ||||||
|  |         button->set_callback(app, back_callback); | ||||||
|  |     } else { | ||||||
|  |         string_printf( | ||||||
|  |             string_info, | ||||||
|  |             "RAW RFID data reader\r\n" | ||||||
|  |             "1) Put the Flipper on your card\r\n" | ||||||
|  |             "2) Press OK\r\n" | ||||||
|  |             "3) Wait until data is read"); | ||||||
|  | 
 | ||||||
|  |         auto line = container->add<StringElement>(); | ||||||
|  |         line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); | ||||||
|  | 
 | ||||||
|  |         auto button = container->add<ButtonElement>(); | ||||||
|  |         button->set_type(ButtonElement::Type::Center, "OK"); | ||||||
|  |         button->set_callback(app, ok_callback); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ContainerVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|  |         app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead}); | ||||||
|  |         consumed = true; | ||||||
|  |     } else if(event->type == LfRfidApp::EventType::Back) { | ||||||
|  |         app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|  |             {LfRfidApp::SceneType::ExtraActions}); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|  |     string_clear(string_info); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_info.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_info.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid_app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneRawInfo : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     string_t string_info; | ||||||
|  | }; | ||||||
							
								
								
									
										46
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | 
 | ||||||
|  | #include "lfrfid_app_scene_raw_name.h" | ||||||
|  | #include "m-string.h" | ||||||
|  | #include <lib/toolbox/random_name.h> | ||||||
|  | #include <lib/toolbox/path.h> | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|  |     const char* key_name = string_get_cstr(app->raw_file_name); | ||||||
|  | 
 | ||||||
|  |     bool key_name_empty = (string_size(app->raw_file_name) == 0); | ||||||
|  |     if(key_name_empty) { | ||||||
|  |         app->text_store.set("RfidRecord"); | ||||||
|  |     } else { | ||||||
|  |         app->text_store.set("%s", key_name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto text_input = app->view_controller.get<TextInputVM>(); | ||||||
|  |     text_input->set_header_text("Name the raw file"); | ||||||
|  | 
 | ||||||
|  |     text_input->set_result_callback( | ||||||
|  |         save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<TextInputVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|  |         string_set_str(app->raw_file_name, app->text_store.text); | ||||||
|  |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<TextInputVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawName::save_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Next; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_name.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_name.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid_app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneRawName : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static void save_callback(void* context); | ||||||
|  | }; | ||||||
							
								
								
									
										107
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | #include "lfrfid_app_scene_raw_read.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | #define RAW_READ_TIME 5000 | ||||||
|  | 
 | ||||||
|  | static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(ctx); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  | 
 | ||||||
|  |     switch(result) { | ||||||
|  |     case LFRFIDWorkerReadRawFileError: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventError; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadRawOverrun: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventOverrun; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void timer_callback(void* ctx) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(ctx); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::ReadEventDone; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|  |     string_init(string_file_name); | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
|  |     popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
|  |     app->view_controller.switch_to<PopupVM>(); | ||||||
|  |     lfrfid_worker_start_thread(app->lfworker); | ||||||
|  |     app->make_app_folder(); | ||||||
|  | 
 | ||||||
|  |     timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app); | ||||||
|  |     furi_timer_start(timer, RAW_READ_TIME); | ||||||
|  |     string_printf( | ||||||
|  |         string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name)); | ||||||
|  |     popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); | ||||||
|  |     lfrfid_worker_read_raw_start( | ||||||
|  |         app->lfworker, | ||||||
|  |         string_get_cstr(string_file_name), | ||||||
|  |         LFRFIDWorkerReadTypeASKOnly, | ||||||
|  |         lfrfid_read_callback, | ||||||
|  |         app); | ||||||
|  | 
 | ||||||
|  |     notification_message(app->notification, &sequence_blink_start_cyan); | ||||||
|  | 
 | ||||||
|  |     is_psk = false; | ||||||
|  |     error = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     UNUSED(app); | ||||||
|  |     bool consumed = true; | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
|  | 
 | ||||||
|  |     switch(event->type) { | ||||||
|  |     case LfRfidApp::EventType::ReadEventError: | ||||||
|  |         error = true; | ||||||
|  |         popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); | ||||||
|  |         notification_message(app->notification, &sequence_blink_start_red); | ||||||
|  |         furi_timer_stop(timer); | ||||||
|  |         break; | ||||||
|  |     case LfRfidApp::EventType::ReadEventDone: | ||||||
|  |         if(!error) { | ||||||
|  |             if(is_psk) { | ||||||
|  |                 notification_message(app->notification, &sequence_success); | ||||||
|  |                 app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess); | ||||||
|  |             } else { | ||||||
|  |                 popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop); | ||||||
|  |                 notification_message(app->notification, &sequence_blink_start_yellow); | ||||||
|  |                 lfrfid_worker_stop(app->lfworker); | ||||||
|  |                 string_printf( | ||||||
|  |                     string_file_name, | ||||||
|  |                     "%s/%s.psk.raw", | ||||||
|  |                     app->app_sd_folder, | ||||||
|  |                     string_get_cstr(app->raw_file_name)); | ||||||
|  |                 lfrfid_worker_read_raw_start( | ||||||
|  |                     app->lfworker, | ||||||
|  |                     string_get_cstr(string_file_name), | ||||||
|  |                     LFRFIDWorkerReadTypePSKOnly, | ||||||
|  |                     lfrfid_read_callback, | ||||||
|  |                     app); | ||||||
|  |                 furi_timer_start(timer, RAW_READ_TIME); | ||||||
|  |                 is_psk = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         consumed = false; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) { | ||||||
|  |     notification_message(app->notification, &sequence_blink_stop); | ||||||
|  |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|  |     lfrfid_worker_stop(app->lfworker); | ||||||
|  |     lfrfid_worker_stop_thread(app->lfworker); | ||||||
|  |     furi_timer_free(timer); | ||||||
|  |     string_clear(string_file_name); | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_read.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_read.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid_app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneRawRead : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     string_t string_file_name; | ||||||
|  |     FuriTimer* timer; | ||||||
|  |     bool is_psk; | ||||||
|  |     bool error; | ||||||
|  | }; | ||||||
							
								
								
									
										45
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | #include "lfrfid_app_scene_raw_success.h" | ||||||
|  | #include "../view/elements/button_element.h" | ||||||
|  | #include "../view/elements/icon_element.h" | ||||||
|  | #include "../view/elements/string_element.h" | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|  |     string_init(string_info); | ||||||
|  | 
 | ||||||
|  |     string_printf(string_info, "RAW RFID read success!\r\n"); | ||||||
|  |     string_cat_printf(string_info, "Now you can analyze files\r\n"); | ||||||
|  |     string_cat_printf(string_info, "Or send them to developers"); | ||||||
|  | 
 | ||||||
|  |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
|  | 
 | ||||||
|  |     auto line = container->add<StringElement>(); | ||||||
|  |     line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     auto button = container->add<ButtonElement>(); | ||||||
|  |     button->set_type(ButtonElement::Type::Center, "OK"); | ||||||
|  |     button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ContainerVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|  |         app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|  |             {LfRfidApp::SceneType::ExtraActions}); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) { | ||||||
|  |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|  |     string_clear(string_info); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneRawSuccess::ok_callback(void* context) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  |     event.type = LfRfidApp::EventType::Next; | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_success.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								applications/lfrfid/scene/lfrfid_app_scene_raw_success.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../lfrfid_app.h" | ||||||
|  | 
 | ||||||
|  | class LfRfidAppSceneRawSuccess : public GenericScene<LfRfidApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|  |     void on_exit(LfRfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     string_t string_info; | ||||||
|  |     static void ok_callback(void* context); | ||||||
|  | }; | ||||||
| @ -1,40 +1,100 @@ | |||||||
| #include "lfrfid_app_scene_read.h" | #include "lfrfid_app_scene_read.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
|  | static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) { | ||||||
|  |     LfRfidApp* app = static_cast<LfRfidApp*>(ctx); | ||||||
|  |     LfRfidApp::Event event; | ||||||
|  | 
 | ||||||
|  |     switch(result) { | ||||||
|  |     case LFRFIDWorkerReadSenseStart: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventSenseStart; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadSenseEnd: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventSenseEnd; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadSenseCardStart: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventSenseCardStart; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadSenseCardEnd: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventSenseCardEnd; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadDone: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventDone; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadStartASK: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventStartASK; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerReadStartPSK: | ||||||
|  |         event.type = LfRfidApp::EventType::ReadEventStartPSK; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     event.payload.signed_int = protocol; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedRfidRead); |     DOLPHIN_DEED(DolphinDeedRfidRead); | ||||||
|     popup->set_header("Reading\nLF RFID", 89, 34, AlignCenter, AlignTop); |     if(app->read_type == LFRFIDWorkerReadTypePSKOnly) { | ||||||
|  |         popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); | ||||||
|  |     } else { | ||||||
|  |         popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); |     popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
|     app->worker.start_read(); |     lfrfid_worker_start_thread(app->lfworker); | ||||||
|  |     lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app); | ||||||
|  | 
 | ||||||
|  |     notification_message(app->notification, &sequence_blink_start_cyan); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|     bool consumed = false; |     bool consumed = true; | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Tick) { |     switch(event->type) { | ||||||
|         if(app->worker.read()) { |     case LfRfidApp::EventType::ReadEventSenseStart: | ||||||
|  |         notification_message(app->notification, &sequence_blink_stop); | ||||||
|  |         notification_message(app->notification, &sequence_blink_start_yellow); | ||||||
|  |         break; | ||||||
|  |     case LfRfidApp::EventType::ReadEventSenseCardStart: | ||||||
|  |         notification_message(app->notification, &sequence_blink_stop); | ||||||
|  |         notification_message(app->notification, &sequence_blink_start_green); | ||||||
|  |         break; | ||||||
|  |     case LfRfidApp::EventType::ReadEventSenseEnd: | ||||||
|  |     case LfRfidApp::EventType::ReadEventSenseCardEnd: | ||||||
|  |         notification_message(app->notification, &sequence_blink_stop); | ||||||
|  |         notification_message(app->notification, &sequence_blink_start_cyan); | ||||||
|  |         break; | ||||||
|  |     case LfRfidApp::EventType::ReadEventDone: | ||||||
|  |         app->protocol_id = event->payload.signed_int; | ||||||
|         DOLPHIN_DEED(DolphinDeedRfidReadSuccess); |         DOLPHIN_DEED(DolphinDeedRfidReadSuccess); | ||||||
|         notification_message(app->notification, &sequence_success); |         notification_message(app->notification, &sequence_success); | ||||||
|  |         string_reset(app->file_name); | ||||||
|         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); | ||||||
|         } else { |         break; | ||||||
|             if(app->worker.any_read()) { |     case LfRfidApp::EventType::ReadEventStartPSK: | ||||||
|                 notification_message(app->notification, &sequence_blink_yellow_10); |         popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop); | ||||||
|             } else if(app->worker.detect()) { |         break; | ||||||
|                 notification_message(app->notification, &sequence_blink_yellow_10); |     case LfRfidApp::EventType::ReadEventStartASK: | ||||||
|             } else { |         popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop); | ||||||
|                 notification_message(app->notification, &sequence_blink_cyan_10); |         break; | ||||||
|             } |     default: | ||||||
|         } |         consumed = false; | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneRead::on_exit(LfRfidApp* app) { | void LfRfidAppSceneRead::on_exit(LfRfidApp* app) { | ||||||
|  |     notification_message(app->notification, &sequence_blink_stop); | ||||||
|     app->view_controller.get<PopupVM>()->clean(); |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|     app->worker.stop_read(); |     lfrfid_worker_stop(app->lfworker); | ||||||
|  |     lfrfid_worker_stop_thread(app->lfworker); | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,8 +24,8 @@ bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::MenuSelected) { |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|         submenu_item_selected = event->payload.menu_index; |         submenu_item_selected = event->payload.signed_int; | ||||||
|         switch(event->payload.menu_index) { |         switch(event->payload.signed_int) { | ||||||
|         case SubmenuWrite: |         case SubmenuWrite: | ||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write); | ||||||
|             break; |             break; | ||||||
| @ -54,7 +54,7 @@ void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) | |||||||
|     LfRfidApp::Event event; |     LfRfidApp::Event event; | ||||||
| 
 | 
 | ||||||
|     event.type = LfRfidApp::EventType::MenuSelected; |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|     event.payload.menu_index = index; |     event.payload.signed_int = index; | ||||||
| 
 | 
 | ||||||
|     app->view_controller.send_event(&event); |     app->view_controller.send_event(&event); | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,10 +4,37 @@ | |||||||
| #include "../view/elements/string_element.h" | #include "../view/elements/string_element.h" | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     string_init(string[0]); |     string_init(string_info); | ||||||
|     string_init(string[1]); |     string_init(string_header); | ||||||
|     string_init(string[2]); | 
 | ||||||
|     string_init(string[3]); |     string_init_printf( | ||||||
|  |         string_header, | ||||||
|  |         "%s[%s]", | ||||||
|  |         protocol_dict_get_name(app->dict, app->protocol_id), | ||||||
|  |         protocol_dict_get_manufacturer(app->dict, app->protocol_id)); | ||||||
|  | 
 | ||||||
|  |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|  |     uint8_t* data = (uint8_t*)malloc(size); | ||||||
|  |     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||||
|  |     for(uint8_t i = 0; i < size; i++) { | ||||||
|  |         if(i != 0) { | ||||||
|  |             string_cat_printf(string_info, " "); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(i >= 9) { | ||||||
|  |             string_cat_printf(string_info, "..."); | ||||||
|  |             break; | ||||||
|  |         } else { | ||||||
|  |             string_cat_printf(string_info, "%02X", data[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     free(data); | ||||||
|  | 
 | ||||||
|  |     string_t render_data; | ||||||
|  |     string_init(render_data); | ||||||
|  |     protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id); | ||||||
|  |     string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); | ||||||
|  |     string_clear(render_data); | ||||||
| 
 | 
 | ||||||
|     auto container = app->view_controller.get<ContainerVM>(); |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
| 
 | 
 | ||||||
| @ -19,90 +46,11 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ | |||||||
|     button->set_type(ButtonElement::Type::Right, "More"); |     button->set_type(ButtonElement::Type::Right, "More"); | ||||||
|     button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback); |     button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback); | ||||||
| 
 | 
 | ||||||
|     auto icon = container->add<IconElement>(); |  | ||||||
|     icon->set_icon(3, 12, &I_RFIDBigChip_37x36); |  | ||||||
| 
 |  | ||||||
|     auto header = container->add<StringElement>(); |     auto header = container->add<StringElement>(); | ||||||
|     header->set_text(app->worker.key.get_type_text(), 89, 3, 0, AlignCenter); |     header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary); | ||||||
| 
 | 
 | ||||||
|     auto line_1_text = container->add<StringElement>(); |     auto text = container->add<StringElement>(); | ||||||
|     auto line_2l_text = container->add<StringElement>(); |     text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary); | ||||||
|     auto line_2r_text = container->add<StringElement>(); |  | ||||||
|     auto line_3_text = container->add<StringElement>(); |  | ||||||
| 
 |  | ||||||
|     auto line_1_value = container->add<StringElement>(); |  | ||||||
|     auto line_2l_value = container->add<StringElement>(); |  | ||||||
|     auto line_2r_value = container->add<StringElement>(); |  | ||||||
|     auto line_3_value = container->add<StringElement>(); |  | ||||||
| 
 |  | ||||||
|     const uint8_t* data = app->worker.key.get_data(); |  | ||||||
| 
 |  | ||||||
|     switch(app->worker.key.get_type()) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         line_1_text->set_text("HEX:", 65, 23, 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++) { |  | ||||||
|             string_cat_printf(string[0], "%02X", data[i]); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         string_printf(string[1], "Manchester"); |  | ||||||
|         string_printf(string[2], "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); |  | ||||||
| 
 |  | ||||||
|         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_3_value->set_text( |  | ||||||
|             string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary); |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         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_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[1] << 8) | (data[2]))); |  | ||||||
| 
 |  | ||||||
|         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_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<ContainerVM>(); |     app->view_controller.switch_to<ContainerVM>(); | ||||||
| 
 | 
 | ||||||
| @ -129,9 +77,8 @@ bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event | |||||||
| void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) { | void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) { | ||||||
|     notification_message_block(app->notification, &sequence_reset_green); |     notification_message_block(app->notification, &sequence_reset_green); | ||||||
|     app->view_controller.get<ContainerVM>()->clean(); |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|     string_clear(string[0]); |     string_clear(string_info); | ||||||
|     string_clear(string[1]); |     string_clear(string_header); | ||||||
|     string_clear(string[2]); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneReadSuccess::back_callback(void* context) { | void LfRfidAppSceneReadSuccess::back_callback(void* context) { | ||||||
|  | |||||||
| @ -11,5 +11,6 @@ private: | |||||||
|     static void back_callback(void* context); |     static void back_callback(void* context); | ||||||
|     static void more_callback(void* context); |     static void more_callback(void* context); | ||||||
| 
 | 
 | ||||||
|     string_t string[3]; |     string_t string_header; | ||||||
|  |     string_t string_info; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -37,12 +37,13 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|         bool result = false; |         bool result = false; | ||||||
|         if(arg && !emulating) { |         if(arg && !emulating) { | ||||||
|             string_set_str(app->file_path, arg); |             string_set_str(app->file_path, arg); | ||||||
|             if(app->load_key_data(app->file_path, &(app->worker.key), false)) { |             if(app->load_key_data(app->file_path, false)) { | ||||||
|                 app->worker.start_emulate(); |                 lfrfid_worker_start_thread(app->lfworker); | ||||||
|  |                 lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); | ||||||
|                 emulating = true; |                 emulating = true; | ||||||
| 
 | 
 | ||||||
|                 auto popup = app->view_controller.get<PopupVM>(); |                 auto popup = app->view_controller.get<PopupVM>(); | ||||||
|                 app->text_store.set("emulating\n%s", app->worker.key.get_name()); |                 app->text_store.set("emulating\n%s", string_get_cstr(app->file_name)); | ||||||
|                 popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); |                 popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|                 notification_message(app->notification, &sequence_blink_start_magenta); |                 notification_message(app->notification, &sequence_blink_start_magenta); | ||||||
| @ -57,7 +58,8 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { | void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) { | ||||||
|     if(emulating) { |     if(emulating) { | ||||||
|         app->worker.stop_emulate(); |         lfrfid_worker_stop(app->lfworker); | ||||||
|  |         lfrfid_worker_stop_thread(app->lfworker); | ||||||
|         notification_message(app->notification, &sequence_blink_stop); |         notification_message(app->notification, &sequence_blink_stop); | ||||||
|     } |     } | ||||||
|     app->view_controller.get<PopupVM>()->clean(); |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|  | |||||||
| @ -3,31 +3,29 @@ | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { | void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|     auto byte_input = app->view_controller.get<ByteInputVM>(); |     auto byte_input = app->view_controller.get<ByteInputVM>(); | ||||||
|     RfidKey& key = app->worker.key; |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
| 
 |  | ||||||
|     if(need_restore) printf("restored\r\n"); |  | ||||||
| 
 | 
 | ||||||
|     if(need_restore) { |     if(need_restore) { | ||||||
|         key.set_data(old_key_data, key.get_type_data_count()); |         protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size); | ||||||
|     } else { |     } else { | ||||||
|         memcpy(old_key_data, key.get_data(), key.get_type_data_count()); |         protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     memcpy(new_key_data, key.get_data(), key.get_type_data_count()); |     protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size); | ||||||
|  | 
 | ||||||
|     byte_input->set_header_text("Enter the data in hex"); |     byte_input->set_header_text("Enter the data in hex"); | ||||||
| 
 | 
 | ||||||
|     byte_input->set_result_callback( |     byte_input->set_result_callback(save_callback, NULL, app, app->new_key_data, size); | ||||||
|         save_callback, NULL, app, new_key_data, app->worker.key.get_type_data_count()); |  | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<ByteInputVM>(); |     app->view_controller.switch_to<ByteInputVM>(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     RfidKey& key = app->worker.key; |  | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Next) { |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|         key.set_data(new_key_data, key.get_type_data_count()); |         size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|  |         protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size); | ||||||
|         DOLPHIN_DEED(DolphinDeedRfidAdd); |         DOLPHIN_DEED(DolphinDeedRfidAdd); | ||||||
|         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -9,25 +9,4 @@ public: | |||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     static void save_callback(void* context); |     static void save_callback(void* context); | ||||||
|     uint8_t old_key_data[LFRFID_KEY_SIZE] = { |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|         0xAA, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     uint8_t new_key_data[LFRFID_KEY_SIZE] = { |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|         0xBB, |  | ||||||
|     }; |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ | |||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     const char* key_name = app->worker.key.get_name(); |     const char* key_name = string_get_cstr(app->file_name); | ||||||
| 
 | 
 | ||||||
|     bool key_name_empty = !strcmp(key_name, ""); |     bool key_name_empty = (string_size(app->file_name) == 0); | ||||||
|     if(key_name_empty) { |     if(key_name_empty) { | ||||||
|         string_set_str(app->file_path, app->app_folder); |         string_set_str(app->file_path, app->app_folder); | ||||||
|         set_random_name(app->text_store.text, app->text_store.text_size); |         set_random_name(app->text_store.text, app->text_store.text_size); | ||||||
| @ -18,11 +18,7 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) { | |||||||
|     text_input->set_header_text("Name the card"); |     text_input->set_header_text("Name the card"); | ||||||
| 
 | 
 | ||||||
|     text_input->set_result_callback( |     text_input->set_result_callback( | ||||||
|         save_callback, |         save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty); | ||||||
|         app, |  | ||||||
|         app->text_store.text, |  | ||||||
|         app->worker.key.get_name_length(), |  | ||||||
|         key_name_empty); |  | ||||||
| 
 | 
 | ||||||
|     string_t folder_path; |     string_t folder_path; | ||||||
|     string_init(folder_path); |     string_init(folder_path); | ||||||
| @ -42,13 +38,13 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Next) { |     if(event->type == LfRfidApp::EventType::Next) { | ||||||
|         if(strlen(app->worker.key.get_name())) { |         if(string_size(app->file_name) > 0) { | ||||||
|             app->delete_key(&app->worker.key); |             app->delete_key(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         app->worker.key.set_name(app->text_store.text); |         string_set_str(app->file_name, app->text_store.text); | ||||||
| 
 | 
 | ||||||
|         if(app->save_key(&app->worker.key)) { |         if(app->save_key()) { | ||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); | ||||||
|         } else { |         } else { | ||||||
|             app->scene_controller.search_and_switch_to_previous_scene( |             app->scene_controller.search_and_switch_to_previous_scene( | ||||||
|  | |||||||
| @ -3,12 +3,12 @@ | |||||||
| void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { | void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|     auto submenu = app->view_controller.get<SubmenuVM>(); |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
| 
 | 
 | ||||||
|     for(uint8_t i = 0; i <= keys_count; i++) { |     for(uint8_t i = 0; i < keys_count; i++) { | ||||||
|         string_init_printf( |         string_init_printf( | ||||||
|             submenu_name[i], |             submenu_name[i], | ||||||
|             "%s %s", |             "%s %s", | ||||||
|             lfrfid_key_get_manufacturer_string(static_cast<LfrfidKeyType>(i)), |             protocol_dict_get_manufacturer(app->dict, i), | ||||||
|             lfrfid_key_get_type_string(static_cast<LfrfidKeyType>(i))); |             protocol_dict_get_name(app->dict, i)); | ||||||
|         submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); |         submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -19,15 +19,15 @@ void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     app->view_controller.switch_to<SubmenuVM>(); |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
| 
 | 
 | ||||||
|     // clear key name
 |     // clear key name
 | ||||||
|     app->worker.key.set_name(""); |     string_reset(app->file_name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::MenuSelected) { |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|         submenu_item_selected = event->payload.menu_index; |         submenu_item_selected = event->payload.signed_int; | ||||||
|         app->worker.key.set_type(static_cast<LfrfidKeyType>(event->payload.menu_index)); |         app->protocol_id = event->payload.signed_int; | ||||||
|         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData); | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } |     } | ||||||
| @ -37,7 +37,7 @@ bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { | void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) { | ||||||
|     app->view_controller.get<SubmenuVM>()->clean(); |     app->view_controller.get<SubmenuVM>()->clean(); | ||||||
|     for(uint8_t i = 0; i <= keys_count; i++) { |     for(uint8_t i = 0; i < keys_count; i++) { | ||||||
|         string_clear(submenu_name[i]); |         string_clear(submenu_name[i]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -47,7 +47,7 @@ void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) { | |||||||
|     LfRfidApp::Event event; |     LfRfidApp::Event event; | ||||||
| 
 | 
 | ||||||
|     event.type = LfRfidApp::EventType::MenuSelected; |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|     event.payload.menu_index = index; |     event.payload.signed_int = index; | ||||||
| 
 | 
 | ||||||
|     app->view_controller.send_event(&event); |     app->view_controller.send_event(&event); | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,6 @@ public: | |||||||
| private: | private: | ||||||
|     static void submenu_callback(void* context, uint32_t index); |     static void submenu_callback(void* context, uint32_t index); | ||||||
|     uint32_t submenu_item_selected = 0; |     uint32_t submenu_item_selected = 0; | ||||||
|     static const uint8_t keys_count = static_cast<uint8_t>(LfrfidKeyType::KeyIoProxXSF); |     static const uint8_t keys_count = static_cast<uint8_t>(LFRFIDProtocol::LFRFIDProtocolMax); | ||||||
|     string_t submenu_name[keys_count + 1]; |     string_t submenu_name[keys_count]; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -4,65 +4,36 @@ | |||||||
| #include "../view/elements/string_element.h" | #include "../view/elements/string_element.h" | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { | void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     string_init(string_data); |     string_init(string_info); | ||||||
|     string_init(string_decrypted); | 
 | ||||||
|  |     string_printf( | ||||||
|  |         string_info, | ||||||
|  |         "%s [%s]\r\n", | ||||||
|  |         string_get_cstr(app->file_name), | ||||||
|  |         protocol_dict_get_name(app->dict, app->protocol_id)); | ||||||
|  | 
 | ||||||
|  |     size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); | ||||||
|  |     uint8_t* data = (uint8_t*)malloc(size); | ||||||
|  |     protocol_dict_get_data(app->dict, app->protocol_id, data, size); | ||||||
|  |     for(uint8_t i = 0; i < size; i++) { | ||||||
|  |         if(i != 0) { | ||||||
|  |             string_cat_printf(string_info, " "); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         string_cat_printf(string_info, "%02X", data[i]); | ||||||
|  |     } | ||||||
|  |     free(data); | ||||||
|  | 
 | ||||||
|  |     string_t render_data; | ||||||
|  |     string_init(render_data); | ||||||
|  |     protocol_dict_render_data(app->dict, render_data, app->protocol_id); | ||||||
|  |     string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data)); | ||||||
|  |     string_clear(render_data); | ||||||
| 
 | 
 | ||||||
|     auto container = app->view_controller.get<ContainerVM>(); |     auto container = app->view_controller.get<ContainerVM>(); | ||||||
| 
 | 
 | ||||||
|     auto button = container->add<ButtonElement>(); |  | ||||||
|     button->set_type(ButtonElement::Type::Left, "Back"); |  | ||||||
|     button->set_callback(app, LfRfidAppSceneSavedInfo::back_callback); |  | ||||||
| 
 |  | ||||||
|     auto line_1 = container->add<StringElement>(); |     auto line_1 = container->add<StringElement>(); | ||||||
|     auto line_2 = container->add<StringElement>(); |     line_1->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary); | ||||||
|     auto line_3 = container->add<StringElement>(); |  | ||||||
|     auto line_4 = container->add<StringElement>(); |  | ||||||
| 
 |  | ||||||
|     RfidKey& key = app->worker.key; |  | ||||||
|     const uint8_t* data = key.get_data(); |  | ||||||
| 
 |  | ||||||
|     for(uint8_t i = 0; i < key.get_type_data_count(); i++) { |  | ||||||
|         if(i != 0) { |  | ||||||
|             string_cat_printf(string_data, " "); |  | ||||||
|         } |  | ||||||
|         string_cat_printf(string_data, "%02X", data[i]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     line_1->set_text(key.get_name(), 64, 17, 128 - 2, AlignCenter, AlignBottom, FontSecondary); |  | ||||||
|     line_2->set_text( |  | ||||||
|         string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontPrimary); |  | ||||||
| 
 |  | ||||||
|     switch(key.get_type()) { |  | ||||||
|     case LfrfidKeyType::KeyEM4100: |  | ||||||
|         string_printf( |  | ||||||
|             string_decrypted, "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4]))); |  | ||||||
| 
 |  | ||||||
|         break; |  | ||||||
|     case LfrfidKeyType::KeyH10301: |  | ||||||
|     case LfrfidKeyType::KeyI40134: |  | ||||||
|         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); |  | ||||||
| 
 |  | ||||||
|     line_4->set_text( |  | ||||||
|         lfrfid_key_get_type_string(key.get_type()), |  | ||||||
|         64, |  | ||||||
|         49, |  | ||||||
|         0, |  | ||||||
|         AlignCenter, |  | ||||||
|         AlignBottom, |  | ||||||
|         FontSecondary); |  | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<ContainerVM>(); |     app->view_controller.switch_to<ContainerVM>(); | ||||||
| } | } | ||||||
| @ -73,13 +44,5 @@ bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* / | |||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { | void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) { | ||||||
|     app->view_controller.get<ContainerVM>()->clean(); |     app->view_controller.get<ContainerVM>()->clean(); | ||||||
|     string_clear(string_data); |     string_clear(string_info); | ||||||
|     string_clear(string_decrypted); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void LfRfidAppSceneSavedInfo::back_callback(void* context) { |  | ||||||
|     LfRfidApp* app = static_cast<LfRfidApp*>(context); |  | ||||||
|     LfRfidApp::Event event; |  | ||||||
|     event.type = LfRfidApp::EventType::Back; |  | ||||||
|     app->view_controller.send_event(&event); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,8 +8,5 @@ public: | |||||||
|     void on_exit(LfRfidApp* app) final; |     void on_exit(LfRfidApp* app) final; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     static void back_callback(void* context); |     string_t string_info; | ||||||
| 
 |  | ||||||
|     string_t string_data; |  | ||||||
|     string_t string_decrypted; |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -28,8 +28,8 @@ bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* even | |||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::MenuSelected) { |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|         submenu_item_selected = event->payload.menu_index; |         submenu_item_selected = event->payload.signed_int; | ||||||
|         switch(event->payload.menu_index) { |         switch(event->payload.signed_int) { | ||||||
|         case SubmenuEmulate: |         case SubmenuEmulate: | ||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate); | ||||||
|             break; |             break; | ||||||
| @ -61,7 +61,7 @@ void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) | |||||||
|     LfRfidApp::Event event; |     LfRfidApp::Event event; | ||||||
| 
 | 
 | ||||||
|     event.type = LfRfidApp::EventType::MenuSelected; |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|     event.payload.menu_index = index; |     event.payload.signed_int = index; | ||||||
| 
 | 
 | ||||||
|     app->view_controller.send_event(&event); |     app->view_controller.send_event(&event); | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ typedef enum { | |||||||
|     SubmenuRead, |     SubmenuRead, | ||||||
|     SubmenuSaved, |     SubmenuSaved, | ||||||
|     SubmenuAddManually, |     SubmenuAddManually, | ||||||
|  |     SubmenuExtraActions, | ||||||
| } SubmenuIndex; | } SubmenuIndex; | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { | void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
| @ -12,6 +13,7 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     submenu->add_item("Read", SubmenuRead, submenu_callback, app); |     submenu->add_item("Read", SubmenuRead, submenu_callback, app); | ||||||
|     submenu->add_item("Saved", SubmenuSaved, submenu_callback, app); |     submenu->add_item("Saved", SubmenuSaved, submenu_callback, app); | ||||||
|     submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app); |     submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app); | ||||||
|  |     submenu->add_item("Extra Actions", SubmenuExtraActions, submenu_callback, app); | ||||||
| 
 | 
 | ||||||
|     if(need_restore) { |     if(need_restore) { | ||||||
|         submenu->set_selected_item(submenu_item_selected); |         submenu->set_selected_item(submenu_item_selected); | ||||||
| @ -20,15 +22,17 @@ void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) { | |||||||
|     app->view_controller.switch_to<SubmenuVM>(); |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
| 
 | 
 | ||||||
|     // clear key
 |     // clear key
 | ||||||
|     app->worker.key.clear(); |     string_reset(app->file_name); | ||||||
|  |     app->protocol_id = PROTOCOL_NO; | ||||||
|  |     app->read_type = LFRFIDWorkerReadTypeAuto; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::MenuSelected) { |     if(event->type == LfRfidApp::EventType::MenuSelected) { | ||||||
|         submenu_item_selected = event->payload.menu_index; |         submenu_item_selected = event->payload.signed_int; | ||||||
|         switch(event->payload.menu_index) { |         switch(event->payload.signed_int) { | ||||||
|         case SubmenuRead: |         case SubmenuRead: | ||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read); | ||||||
|             break; |             break; | ||||||
| @ -38,6 +42,9 @@ bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|         case SubmenuAddManually: |         case SubmenuAddManually: | ||||||
|             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType); | ||||||
|             break; |             break; | ||||||
|  |         case SubmenuExtraActions: | ||||||
|  |             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ExtraActions); | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } |     } | ||||||
| @ -54,7 +61,7 @@ void LfRfidAppSceneStart::submenu_callback(void* context, uint32_t index) { | |||||||
|     LfRfidApp::Event event; |     LfRfidApp::Event event; | ||||||
| 
 | 
 | ||||||
|     event.type = LfRfidApp::EventType::MenuSelected; |     event.type = LfRfidApp::EventType::MenuSelected; | ||||||
|     event.payload.menu_index = index; |     event.payload.signed_int = index; | ||||||
| 
 | 
 | ||||||
|     app->view_controller.send_event(&event); |     app->view_controller.send_event(&event); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,66 +1,79 @@ | |||||||
| #include "lfrfid_app_scene_write.h" | #include "lfrfid_app_scene_write.h" | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { | static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) { | ||||||
|     card_not_supported = false; |     LfRfidApp* app = static_cast<LfRfidApp*>(ctx); | ||||||
|     string_init(data_string); |     LfRfidApp::Event event; | ||||||
| 
 | 
 | ||||||
|     const uint8_t* data = app->worker.key.get_data(); |     switch(result) { | ||||||
| 
 |     case LFRFIDWorkerWriteOK: | ||||||
|     for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { |         event.type = LfRfidApp::EventType::WriteEventOK; | ||||||
|         string_cat_printf(data_string, "%02X", data[i]); |         break; | ||||||
|  |     case LFRFIDWorkerWriteProtocolCannotBeWritten: | ||||||
|  |         event.type = LfRfidApp::EventType::WriteEventProtocolCannotBeWritten; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerWriteFobCannotBeWritten: | ||||||
|  |         event.type = LfRfidApp::EventType::WriteEventFobCannotBeWritten; | ||||||
|  |         break; | ||||||
|  |     case LFRFIDWorkerWriteTooLongToWrite: | ||||||
|  |         event.type = LfRfidApp::EventType::WriteEventTooLongToWrite; | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) { | ||||||
|     auto popup = app->view_controller.get<PopupVM>(); |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     popup->set_header("Writing", 89, 30, AlignCenter, AlignTop); |     popup->set_header("Writing", 89, 30, AlignCenter, AlignTop); | ||||||
|     if(strlen(app->worker.key.get_name())) { |     if(string_size(app->file_name)) { | ||||||
|         popup->set_text(app->worker.key.get_name(), 89, 43, AlignCenter, AlignTop); |         popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop); | ||||||
|     } else { |     } else { | ||||||
|         popup->set_text(string_get_cstr(data_string), 89, 43, AlignCenter, AlignTop); |         popup->set_text( | ||||||
|  |             protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop); | ||||||
|     } |     } | ||||||
|     popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); |     popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61); | ||||||
| 
 | 
 | ||||||
|     app->view_controller.switch_to<PopupVM>(); |     app->view_controller.switch_to<PopupVM>(); | ||||||
|     app->worker.start_write(); |     lfrfid_worker_start_thread(app->lfworker); | ||||||
|  |     lfrfid_worker_write_start( | ||||||
|  |         app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app); | ||||||
|  |     notification_message(app->notification, &sequence_blink_start_magenta); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | ||||||
|     bool consumed = false; |     bool consumed = true; | ||||||
|  |     auto popup = app->view_controller.get<PopupVM>(); | ||||||
| 
 | 
 | ||||||
|     if(event->type == LfRfidApp::EventType::Tick) { |     switch(event->type) { | ||||||
|         RfidWorker::WriteResult result = app->worker.write(); |     case LfRfidApp::EventType::WriteEventOK: | ||||||
| 
 |  | ||||||
|         switch(result) { |  | ||||||
|         case RfidWorker::WriteResult::Nothing: |  | ||||||
|             notification_message(app->notification, &sequence_blink_magenta_10); |  | ||||||
|             break; |  | ||||||
|         case RfidWorker::WriteResult::Ok: |  | ||||||
|         notification_message(app->notification, &sequence_success); |         notification_message(app->notification, &sequence_success); | ||||||
|         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess); |         app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess); | ||||||
|         break; |         break; | ||||||
|         case RfidWorker::WriteResult::NotWritable: |     case LfRfidApp::EventType::WriteEventProtocolCannotBeWritten: | ||||||
|             if(!card_not_supported) { |         popup->set_icon(72, 17, &I_DolphinCommon_56x48); | ||||||
|                 auto popup = app->view_controller.get<PopupVM>(); |         popup->set_header("Error", 64, 3, AlignCenter, AlignTop); | ||||||
|  |         popup->set_text("This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop); | ||||||
|  |         notification_message(app->notification, &sequence_blink_start_red); | ||||||
|  |         break; | ||||||
|  |     case LfRfidApp::EventType::WriteEventFobCannotBeWritten: | ||||||
|  |     case LfRfidApp::EventType::WriteEventTooLongToWrite: | ||||||
|         popup->set_icon(72, 17, &I_DolphinCommon_56x48); |         popup->set_icon(72, 17, &I_DolphinCommon_56x48); | ||||||
|         popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); |         popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop); | ||||||
|         popup->set_text( |         popup->set_text( | ||||||
|                     "Make sure this\ncard is writable\nand not\nprotected.", |             "Make sure this\ncard is writable\nand not\nprotected.", 3, 17, AlignLeft, AlignTop); | ||||||
|                     3, |         notification_message(app->notification, &sequence_blink_start_yellow); | ||||||
|                     17, |  | ||||||
|                     AlignLeft, |  | ||||||
|                     AlignTop); |  | ||||||
|                 card_not_supported = true; |  | ||||||
|             } |  | ||||||
|             notification_message(app->notification, &sequence_blink_yellow_10); |  | ||||||
|         break; |         break; | ||||||
|         } |     default: | ||||||
|  |         consumed = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) { | void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) { | ||||||
|  |     notification_message(app->notification, &sequence_blink_stop); | ||||||
|     app->view_controller.get<PopupVM>()->clean(); |     app->view_controller.get<PopupVM>()->clean(); | ||||||
|     app->worker.stop_write(); |     lfrfid_worker_stop(app->lfworker); | ||||||
|     string_clear(data_string); |     lfrfid_worker_stop_thread(app->lfworker); | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,8 +6,4 @@ public: | |||||||
|     void on_enter(LfRfidApp* app, bool need_restore) final; |     void on_enter(LfRfidApp* app, bool need_restore) final; | ||||||
|     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; |     bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; | ||||||
|     void on_exit(LfRfidApp* app) final; |     void on_exit(LfRfidApp* app) final; | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     string_t data_string; |  | ||||||
|     bool card_not_supported; |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -136,6 +136,15 @@ bool storage_file_sync(File* file); | |||||||
|  */ |  */ | ||||||
| bool storage_file_eof(File* file); | bool storage_file_eof(File* file); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Check that file exists | ||||||
|  |  *  | ||||||
|  |  * @param storage  | ||||||
|  |  * @param path  | ||||||
|  |  * @return true if file exists | ||||||
|  |  */ | ||||||
|  | bool storage_file_exists(Storage* storage, const char* path); | ||||||
|  | 
 | ||||||
| /******************* Dir Functions *******************/ | /******************* Dir Functions *******************/ | ||||||
| 
 | 
 | ||||||
| /** Opens a directory to get objects from it
 | /** Opens a directory to get objects from it
 | ||||||
|  | |||||||
| @ -240,6 +240,18 @@ bool storage_file_eof(File* file) { | |||||||
|     return S_RETURN_BOOL; |     return S_RETURN_BOOL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool storage_file_exists(Storage* storage, const char* path) { | ||||||
|  |     bool exist = false; | ||||||
|  |     FileInfo fileinfo; | ||||||
|  |     FS_Error error = storage_common_stat(storage, path, &fileinfo); | ||||||
|  | 
 | ||||||
|  |     if(error == FSE_OK && !(fileinfo.flags & FSF_DIRECTORY)) { | ||||||
|  |         exist = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return exist; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /****************** DIR ******************/ | /****************** DIR ******************/ | ||||||
| 
 | 
 | ||||||
| static bool storage_dir_open_internal(File* file, const char* path) { | static bool storage_dir_open_internal(File* file, const char* path) { | ||||||
|  | |||||||
							
								
								
									
										473
									
								
								applications/unit_tests/lfrfid/bit_lib_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								applications/unit_tests/lfrfid/bit_lib_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,473 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | #include <lfrfid/tools/bit_lib.h> | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_increment_index) { | ||||||
|  |     uint32_t index = 0; | ||||||
|  | 
 | ||||||
|  |     // test increment
 | ||||||
|  |     for(uint32_t i = 0; i < 31; ++i) { | ||||||
|  |         bit_lib_increment_index(index, 32); | ||||||
|  |         mu_assert_int_eq(i + 1, index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // test wrap around
 | ||||||
|  |     for(uint32_t i = 0; i < 512; ++i) { | ||||||
|  |         bit_lib_increment_index(index, 32); | ||||||
|  |         mu_assert_int_less_than(32, index); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_is_set) { | ||||||
|  |     uint32_t value = 0x0000FFFF; | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < 16; ++i) { | ||||||
|  |         mu_check(bit_lib_bit_is_set(value, i)); | ||||||
|  |         mu_check(!bit_lib_bit_is_not_set(value, i)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 16; i < 32; ++i) { | ||||||
|  |         mu_check(!bit_lib_bit_is_set(value, i)); | ||||||
|  |         mu_check(bit_lib_bit_is_not_set(value, i)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_push) { | ||||||
|  | #define TEST_BIT_LIB_PUSH_DATA_SIZE 4 | ||||||
|  |     uint8_t data[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0}; | ||||||
|  |     uint8_t expected_data_1[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x0F, 0xFF}; | ||||||
|  |     uint8_t expected_data_2[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0xFF, 0xF0, 0x00}; | ||||||
|  |     uint8_t expected_data_3[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0x00, 0x00, 0xFF}; | ||||||
|  |     uint8_t expected_data_4[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF}; | ||||||
|  |     uint8_t expected_data_5[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x00, 0x00}; | ||||||
|  |     uint8_t expected_data_6[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xCC, 0xCC, 0xCC, 0xCC}; | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < 12; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_1, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < 12; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_2, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < 4; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); | ||||||
|  |     } | ||||||
|  |     for(uint32_t i = 0; i < 8; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_3, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_4, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_5, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 2; ++i) { | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true); | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); | ||||||
|  |         bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false); | ||||||
|  |     } | ||||||
|  |     mu_assert_mem_eq(expected_data_6, data, TEST_BIT_LIB_PUSH_DATA_SIZE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_set_bit) { | ||||||
|  |     uint8_t value[2] = {0x00, 0xFF}; | ||||||
|  |     bit_lib_set_bit(value, 15, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFE}), 2); | ||||||
|  |     bit_lib_set_bit(value, 14, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFC}), 2); | ||||||
|  |     bit_lib_set_bit(value, 13, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF8}), 2); | ||||||
|  |     bit_lib_set_bit(value, 12, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF0}), 2); | ||||||
|  |     bit_lib_set_bit(value, 11, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xE0}), 2); | ||||||
|  |     bit_lib_set_bit(value, 10, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xC0}), 2); | ||||||
|  |     bit_lib_set_bit(value, 9, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x80}), 2); | ||||||
|  |     bit_lib_set_bit(value, 8, false); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x00}), 2); | ||||||
|  | 
 | ||||||
|  |     bit_lib_set_bit(value, 7, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x01, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 6, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x03, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 5, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x07, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 4, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x0F, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 3, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x1F, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 2, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x3F, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 1, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0x7F, 0x00}), 2); | ||||||
|  |     bit_lib_set_bit(value, 0, true); | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0xFF, 0x00}), 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_set_bits) { | ||||||
|  |     uint8_t value[2] = {0b00000000, 0b11111111}; | ||||||
|  |     // set 4 bits to 0b0100 from 12 index
 | ||||||
|  |     bit_lib_set_bits(value, 12, 0b0100, 4); | ||||||
|  |     //                                                    [0100]
 | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11110100}), 2); | ||||||
|  | 
 | ||||||
|  |     // set 2 bits to 0b11 from 11 index
 | ||||||
|  |     bit_lib_set_bits(value, 11, 0b11, 2); | ||||||
|  |     //                                                    [11]
 | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11111100}), 2); | ||||||
|  | 
 | ||||||
|  |     // set 3 bits to 0b111 from 0 index
 | ||||||
|  |     bit_lib_set_bits(value, 0, 0b111, 3); | ||||||
|  |     //                                    [111]
 | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0b11100000, 0b11111100}), 2); | ||||||
|  | 
 | ||||||
|  |     // set 8 bits to 0b11111000 from 3 index
 | ||||||
|  |     bit_lib_set_bits(value, 3, 0b11111000, 8); | ||||||
|  |     //                                       [11111    000]
 | ||||||
|  |     mu_assert_mem_eq(value, ((uint8_t[]){0b11111111, 0b00011100}), 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_get_bit) { | ||||||
|  |     uint8_t value[2] = {0b00000000, 0b11111111}; | ||||||
|  |     for(uint32_t i = 0; i < 8; ++i) { | ||||||
|  |         mu_check(bit_lib_get_bit(value, i) == false); | ||||||
|  |     } | ||||||
|  |     for(uint32_t i = 8; i < 16; ++i) { | ||||||
|  |         mu_check(bit_lib_get_bit(value, i) == true); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_get_bits) { | ||||||
|  |     uint8_t value[2] = {0b00000000, 0b11111111}; | ||||||
|  |     mu_assert_int_eq(0b00000000, bit_lib_get_bits(value, 0, 8)); | ||||||
|  |     mu_assert_int_eq(0b00000001, bit_lib_get_bits(value, 1, 8)); | ||||||
|  |     mu_assert_int_eq(0b00000011, bit_lib_get_bits(value, 2, 8)); | ||||||
|  |     mu_assert_int_eq(0b00000111, bit_lib_get_bits(value, 3, 8)); | ||||||
|  |     mu_assert_int_eq(0b00001111, bit_lib_get_bits(value, 4, 8)); | ||||||
|  |     mu_assert_int_eq(0b00011111, bit_lib_get_bits(value, 5, 8)); | ||||||
|  |     mu_assert_int_eq(0b00111111, bit_lib_get_bits(value, 6, 8)); | ||||||
|  |     mu_assert_int_eq(0b01111111, bit_lib_get_bits(value, 7, 8)); | ||||||
|  |     mu_assert_int_eq(0b11111111, bit_lib_get_bits(value, 8, 8)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_get_bits_16) { | ||||||
|  |     uint8_t value[2] = {0b00001001, 0b10110001}; | ||||||
|  |     mu_assert_int_eq(0b0, bit_lib_get_bits_16(value, 0, 1)); | ||||||
|  |     mu_assert_int_eq(0b00, bit_lib_get_bits_16(value, 0, 2)); | ||||||
|  |     mu_assert_int_eq(0b000, bit_lib_get_bits_16(value, 0, 3)); | ||||||
|  |     mu_assert_int_eq(0b0000, bit_lib_get_bits_16(value, 0, 4)); | ||||||
|  |     mu_assert_int_eq(0b00001, bit_lib_get_bits_16(value, 0, 5)); | ||||||
|  |     mu_assert_int_eq(0b000010, bit_lib_get_bits_16(value, 0, 6)); | ||||||
|  |     mu_assert_int_eq(0b0000100, bit_lib_get_bits_16(value, 0, 7)); | ||||||
|  |     mu_assert_int_eq(0b00001001, bit_lib_get_bits_16(value, 0, 8)); | ||||||
|  |     mu_assert_int_eq(0b000010011, bit_lib_get_bits_16(value, 0, 9)); | ||||||
|  |     mu_assert_int_eq(0b0000100110, bit_lib_get_bits_16(value, 0, 10)); | ||||||
|  |     mu_assert_int_eq(0b00001001101, bit_lib_get_bits_16(value, 0, 11)); | ||||||
|  |     mu_assert_int_eq(0b000010011011, bit_lib_get_bits_16(value, 0, 12)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_16(value, 0, 13)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_16(value, 0, 14)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_16(value, 0, 15)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_16(value, 0, 16)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_get_bits_32) { | ||||||
|  |     uint8_t value[4] = {0b00001001, 0b10110001, 0b10001100, 0b01100010}; | ||||||
|  |     mu_assert_int_eq(0b0, bit_lib_get_bits_32(value, 0, 1)); | ||||||
|  |     mu_assert_int_eq(0b00, bit_lib_get_bits_32(value, 0, 2)); | ||||||
|  |     mu_assert_int_eq(0b000, bit_lib_get_bits_32(value, 0, 3)); | ||||||
|  |     mu_assert_int_eq(0b0000, bit_lib_get_bits_32(value, 0, 4)); | ||||||
|  |     mu_assert_int_eq(0b00001, bit_lib_get_bits_32(value, 0, 5)); | ||||||
|  |     mu_assert_int_eq(0b000010, bit_lib_get_bits_32(value, 0, 6)); | ||||||
|  |     mu_assert_int_eq(0b0000100, bit_lib_get_bits_32(value, 0, 7)); | ||||||
|  |     mu_assert_int_eq(0b00001001, bit_lib_get_bits_32(value, 0, 8)); | ||||||
|  |     mu_assert_int_eq(0b000010011, bit_lib_get_bits_32(value, 0, 9)); | ||||||
|  |     mu_assert_int_eq(0b0000100110, bit_lib_get_bits_32(value, 0, 10)); | ||||||
|  |     mu_assert_int_eq(0b00001001101, bit_lib_get_bits_32(value, 0, 11)); | ||||||
|  |     mu_assert_int_eq(0b000010011011, bit_lib_get_bits_32(value, 0, 12)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_32(value, 0, 13)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_32(value, 0, 14)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_32(value, 0, 15)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_32(value, 0, 16)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011, bit_lib_get_bits_32(value, 0, 17)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000110, bit_lib_get_bits_32(value, 0, 18)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001100, bit_lib_get_bits_32(value, 0, 19)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011000, bit_lib_get_bits_32(value, 0, 20)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000110001, bit_lib_get_bits_32(value, 0, 21)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001100011, bit_lib_get_bits_32(value, 0, 22)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011000110, bit_lib_get_bits_32(value, 0, 23)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000110001100, bit_lib_get_bits_32(value, 0, 24)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001100011000, bit_lib_get_bits_32(value, 0, 25)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011000110001, bit_lib_get_bits_32(value, 0, 26)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000110001100011, bit_lib_get_bits_32(value, 0, 27)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001100011000110, bit_lib_get_bits_32(value, 0, 28)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011000110001100, bit_lib_get_bits_32(value, 0, 29)); | ||||||
|  |     mu_assert_int_eq(0b000010011011000110001100011000, bit_lib_get_bits_32(value, 0, 30)); | ||||||
|  |     mu_assert_int_eq(0b0000100110110001100011000110001, bit_lib_get_bits_32(value, 0, 31)); | ||||||
|  |     mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_32(value, 0, 32)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_test_parity_u32) { | ||||||
|  |     // test even parity
 | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityEven), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityEven), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityEven), 1); | ||||||
|  | 
 | ||||||
|  |     // test odd parity
 | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityOdd), 0); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityOdd), 1); | ||||||
|  |     mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityOdd), 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_test_parity) { | ||||||
|  |     // next data contains valid parity for 1-3 nibble and invalid for 4 nibble
 | ||||||
|  |     uint8_t data_always_0_parity[2] = {0b11101110, 0b11101111}; | ||||||
|  |     uint8_t data_always_1_parity[2] = {0b00010001, 0b00010000}; | ||||||
|  |     uint8_t data_always_odd_parity[2] = {0b00000011, 0b11110111}; | ||||||
|  |     uint8_t data_always_even_parity[2] = {0b00010111, 0b10110011}; | ||||||
|  | 
 | ||||||
|  |     // test alawys 0 parity
 | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_0_parity, 0, 12, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_0_parity, 4, 8, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_0_parity, 8, 4, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways0, 4)); | ||||||
|  | 
 | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_0_parity, 0, 16, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_0_parity, 4, 12, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_0_parity, 8, 8, BitLibParityAlways0, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways0, 4)); | ||||||
|  | 
 | ||||||
|  |     // test alawys 1 parity
 | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_1_parity, 0, 12, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_1_parity, 4, 8, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_1_parity, 8, 4, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways1, 4)); | ||||||
|  | 
 | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_1_parity, 0, 16, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_1_parity, 4, 12, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_1_parity, 8, 8, BitLibParityAlways1, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways1, 4)); | ||||||
|  | 
 | ||||||
|  |     // test odd parity
 | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_odd_parity, 0, 12, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_odd_parity, 4, 8, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_odd_parity, 8, 4, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityOdd, 4)); | ||||||
|  | 
 | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_odd_parity, 0, 16, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_odd_parity, 4, 12, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_odd_parity, 8, 8, BitLibParityOdd, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityOdd, 4)); | ||||||
|  | 
 | ||||||
|  |     // test even parity
 | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_even_parity, 0, 12, BitLibParityEven, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_even_parity, 4, 8, BitLibParityEven, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_even_parity, 8, 4, BitLibParityEven, 4)); | ||||||
|  |     mu_check(bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityEven, 4)); | ||||||
|  | 
 | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_even_parity, 0, 16, BitLibParityEven, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_even_parity, 4, 12, BitLibParityEven, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_even_parity, 8, 8, BitLibParityEven, 4)); | ||||||
|  |     mu_check(!bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityEven, 4)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_remove_bit_every_nth) { | ||||||
|  |     // TODO: more tests
 | ||||||
|  |     uint8_t data_i[1] = {0b00001111}; | ||||||
|  |     uint8_t data_o[1] = {0b00011111}; | ||||||
|  |     size_t length; | ||||||
|  | 
 | ||||||
|  |     length = bit_lib_remove_bit_every_nth(data_i, 0, 8, 3); | ||||||
|  |     mu_assert_int_eq(6, length); | ||||||
|  |     mu_assert_mem_eq(data_o, data_i, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_reverse_bits) { | ||||||
|  |     uint8_t data_1_i[2] = {0b11001010, 0b00011111}; | ||||||
|  |     uint8_t data_1_o[2] = {0b11111000, 0b01010011}; | ||||||
|  | 
 | ||||||
|  |     // reverse bits [0..15]
 | ||||||
|  |     bit_lib_reverse_bits(data_1_i, 0, 16); | ||||||
|  |     mu_assert_mem_eq(data_1_o, data_1_i, 2); | ||||||
|  | 
 | ||||||
|  |     uint8_t data_2_i[2] = {0b11001010, 0b00011111}; | ||||||
|  |     uint8_t data_2_o[2] = {0b11001000, 0b01011111}; | ||||||
|  | 
 | ||||||
|  |     // reverse bits [4..11]
 | ||||||
|  |     bit_lib_reverse_bits(data_2_i, 4, 8); | ||||||
|  |     mu_assert_mem_eq(data_2_o, data_2_i, 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_copy_bits) { | ||||||
|  |     uint8_t data_1_i[2] = {0b11001010, 0b00011111}; | ||||||
|  |     uint8_t data_1_o[2] = {0}; | ||||||
|  | 
 | ||||||
|  |     // data_1_o[0..15] = data_1_i[0..15]
 | ||||||
|  |     bit_lib_copy_bits(data_1_o, 0, 16, data_1_i, 0); | ||||||
|  |     mu_assert_mem_eq(data_1_i, data_1_o, 2); | ||||||
|  | 
 | ||||||
|  |     memset(data_1_o, 0, 2); | ||||||
|  |     // data_1_o[4..11] = data_1_i[0..7]
 | ||||||
|  |     bit_lib_copy_bits(data_1_o, 4, 8, data_1_i, 0); | ||||||
|  |     mu_assert_mem_eq(((uint8_t[]){0b00001100, 0b10100000}), data_1_o, 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_get_bit_count) { | ||||||
|  |     mu_assert_int_eq(0, bit_lib_get_bit_count(0)); | ||||||
|  |     mu_assert_int_eq(1, bit_lib_get_bit_count(0b1)); | ||||||
|  |     mu_assert_int_eq(1, bit_lib_get_bit_count(0b10)); | ||||||
|  |     mu_assert_int_eq(2, bit_lib_get_bit_count(0b11)); | ||||||
|  |     mu_assert_int_eq(4, bit_lib_get_bit_count(0b11000011)); | ||||||
|  |     mu_assert_int_eq(6, bit_lib_get_bit_count(0b11000011000011)); | ||||||
|  |     mu_assert_int_eq(8, bit_lib_get_bit_count(0b11111111)); | ||||||
|  |     mu_assert_int_eq(16, bit_lib_get_bit_count(0b11111110000000000000000111111111)); | ||||||
|  |     mu_assert_int_eq(32, bit_lib_get_bit_count(0b11111111111111111111111111111111)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_reverse_16_fast) { | ||||||
|  |     mu_assert_int_eq(0b0000000000000000, bit_lib_reverse_16_fast(0b0000000000000000)); | ||||||
|  |     mu_assert_int_eq(0b1000000000000000, bit_lib_reverse_16_fast(0b0000000000000001)); | ||||||
|  |     mu_assert_int_eq(0b1100000000000000, bit_lib_reverse_16_fast(0b0000000000000011)); | ||||||
|  |     mu_assert_int_eq(0b0000100000001001, bit_lib_reverse_16_fast(0b1001000000010000)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_bit_lib_crc16) { | ||||||
|  |     uint8_t data[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'}; | ||||||
|  |     uint8_t data_size = 9; | ||||||
|  | 
 | ||||||
|  |     // Algorithm
 | ||||||
|  |     // Check	Poly	Init	RefIn	RefOut	XorOut
 | ||||||
|  |     // CRC-16/CCITT-FALSE
 | ||||||
|  |     // 0x29B1	0x1021	0xFFFF	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x29B1, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0x0000)); | ||||||
|  |     // CRC-16/ARC
 | ||||||
|  |     // 0xBB3D	0x8005	0x0000	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0xBB3D, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0x0000)); | ||||||
|  |     // CRC-16/AUG-CCITT
 | ||||||
|  |     // 0xE5CC	0x1021	0x1D0F	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0xE5CC, bit_lib_crc16(data, data_size, 0x1021, 0x1D0F, false, false, 0x0000)); | ||||||
|  |     // CRC-16/BUYPASS
 | ||||||
|  |     // 0xFEE8	0x8005	0x0000	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0xFEE8, bit_lib_crc16(data, data_size, 0x8005, 0x0000, false, false, 0x0000)); | ||||||
|  |     // CRC-16/CDMA2000
 | ||||||
|  |     // 0x4C06	0xC867	0xFFFF	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x4C06, bit_lib_crc16(data, data_size, 0xC867, 0xFFFF, false, false, 0x0000)); | ||||||
|  |     // CRC-16/DDS-110
 | ||||||
|  |     // 0x9ECF	0x8005	0x800D	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x9ECF, bit_lib_crc16(data, data_size, 0x8005, 0x800D, false, false, 0x0000)); | ||||||
|  |     // CRC-16/DECT-R
 | ||||||
|  |     // 0x007E	0x0589	0x0000	false	false	0x0001
 | ||||||
|  |     mu_assert_int_eq(0x007E, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0001)); | ||||||
|  |     // CRC-16/DECT-X
 | ||||||
|  |     // 0x007F	0x0589	0x0000	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x007F, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0000)); | ||||||
|  |     // CRC-16/DNP
 | ||||||
|  |     // 0xEA82	0x3D65	0x0000	true	true	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0xEA82, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, true, true, 0xFFFF)); | ||||||
|  |     // CRC-16/EN-13757
 | ||||||
|  |     // 0xC2B7	0x3D65	0x0000	false	false	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0xC2B7, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, false, false, 0xFFFF)); | ||||||
|  |     // CRC-16/GENIBUS
 | ||||||
|  |     // 0xD64E	0x1021	0xFFFF	false	false	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0xD64E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0xFFFF)); | ||||||
|  |     // CRC-16/MAXIM
 | ||||||
|  |     // 0x44C2	0x8005	0x0000	true	true	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0x44C2, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0xFFFF)); | ||||||
|  |     // CRC-16/MCRF4XX
 | ||||||
|  |     // 0x6F91	0x1021	0xFFFF	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x6F91, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0x0000)); | ||||||
|  |     // CRC-16/RIELLO
 | ||||||
|  |     // 0x63D0	0x1021	0xB2AA	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x63D0, bit_lib_crc16(data, data_size, 0x1021, 0xB2AA, true, true, 0x0000)); | ||||||
|  |     // CRC-16/T10-DIF
 | ||||||
|  |     // 0xD0DB	0x8BB7	0x0000	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0xD0DB, bit_lib_crc16(data, data_size, 0x8BB7, 0x0000, false, false, 0x0000)); | ||||||
|  |     // CRC-16/TELEDISK
 | ||||||
|  |     // 0x0FB3	0xA097	0x0000	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x0FB3, bit_lib_crc16(data, data_size, 0xA097, 0x0000, false, false, 0x0000)); | ||||||
|  |     // CRC-16/TMS37157
 | ||||||
|  |     // 0x26B1	0x1021	0x89EC	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x26B1, bit_lib_crc16(data, data_size, 0x1021, 0x89EC, true, true, 0x0000)); | ||||||
|  |     // CRC-16/USB
 | ||||||
|  |     // 0xB4C8	0x8005	0xFFFF	true	true	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0xB4C8, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0xFFFF)); | ||||||
|  |     // CRC-A
 | ||||||
|  |     // 0xBF05	0x1021	0xC6C6	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0xBF05, bit_lib_crc16(data, data_size, 0x1021, 0xC6C6, true, true, 0x0000)); | ||||||
|  |     // CRC-16/KERMIT
 | ||||||
|  |     // 0x2189	0x1021	0x0000	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x2189, bit_lib_crc16(data, data_size, 0x1021, 0x0000, true, true, 0x0000)); | ||||||
|  |     // CRC-16/MODBUS
 | ||||||
|  |     // 0x4B37	0x8005	0xFFFF	true	true	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x4B37, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0x0000)); | ||||||
|  |     // CRC-16/X-25
 | ||||||
|  |     // 0x906E	0x1021	0xFFFF	true	true	0xFFFF
 | ||||||
|  |     mu_assert_int_eq(0x906E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0xFFFF)); | ||||||
|  |     // CRC-16/XMODEM
 | ||||||
|  |     // 0x31C3	0x1021	0x0000	false	false	0x0000
 | ||||||
|  |     mu_assert_int_eq(0x31C3, bit_lib_crc16(data, data_size, 0x1021, 0x0000, false, false, 0x0000)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_bit_lib) { | ||||||
|  |     MU_RUN_TEST(test_bit_lib_increment_index); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_is_set); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_push); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_set_bit); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_set_bits); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_get_bit); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_get_bits); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_get_bits_16); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_get_bits_32); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_test_parity_u32); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_test_parity); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_remove_bit_every_nth); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_copy_bits); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_reverse_bits); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_get_bit_count); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_reverse_16_fast); | ||||||
|  |     MU_RUN_TEST(test_bit_lib_crc16); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_bit_lib() { | ||||||
|  |     MU_RUN_SUITE(test_bit_lib); | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
							
								
								
									
										464
									
								
								applications/unit_tests/lfrfid/lfrfid_protocols.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										464
									
								
								applications/unit_tests/lfrfid/lfrfid_protocols.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,464 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | #include <toolbox/protocols/protocol_dict.h> | ||||||
|  | #include <lfrfid/protocols/lfrfid_protocols.h> | ||||||
|  | #include <toolbox/pulse_protocols/pulse_glue.h> | ||||||
|  | 
 | ||||||
|  | #define LF_RFID_READ_TIMING_MULTIPLIER 8 | ||||||
|  | 
 | ||||||
|  | #define EM_TEST_DATA \ | ||||||
|  |     { 0x58, 0x00, 0x85, 0x64, 0x02 } | ||||||
|  | #define EM_TEST_DATA_SIZE 5 | ||||||
|  | #define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2) | ||||||
|  | 
 | ||||||
|  | const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = { | ||||||
|  |     32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, -32, | ||||||
|  |     32,  32,  -32, -32, 32,  32,  -32, -32, 32,  32,  -32, -32, 32,  -32, 32,  -32, 32,  32,  -32, | ||||||
|  |     -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, | ||||||
|  |     32,  32,  -32, -32, 32,  -32, 32,  -32, 32,  32,  -32, -32, 32,  32,  -32, -32, 32,  32,  -32, | ||||||
|  |     -32, 32,  -32, 32,  32,  -32, 32,  -32, -32, 32,  -32, 32,  -32, 32,  32,  -32, -32, 32,  -32, | ||||||
|  |     32,  32,  -32, -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32,  32,  -32, | ||||||
|  |     -32, 32,  32,  -32, -32, 32,  -32, 32,  -32, 32,  -32, 32,  -32, 32, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define HID10301_TEST_DATA \ | ||||||
|  |     { 0x8D, 0x48, 0xA8 } | ||||||
|  | #define HID10301_TEST_DATA_SIZE 3 | ||||||
|  | #define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2) | ||||||
|  | 
 | ||||||
|  | const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = { | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define IOPROX_XSF_TEST_DATA \ | ||||||
|  |     { 0x65, 0x01, 0x05, 0x39 } | ||||||
|  | #define IOPROX_XSF_TEST_DATA_SIZE 4 | ||||||
|  | #define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2) | ||||||
|  | 
 | ||||||
|  | const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] = { | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, | ||||||
|  |     4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  |     5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2) | ||||||
|  | #define INDALA26_TEST_DATA \ | ||||||
|  |     { 0x3B, 0x73, 0x64, 0xA8 } | ||||||
|  | #define INDALA26_TEST_DATA_SIZE 4 | ||||||
|  | 
 | ||||||
|  | const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = { | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, | ||||||
|  |     1,  -1, 1,  -1, 1,  -1, 1,  -1, -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  |     -1, 1,  -1, 1,  -1, 1,  -1, 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_em_read_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100)); | ||||||
|  |     mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100)); | ||||||
|  |     mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_decoders_start(dict); | ||||||
|  | 
 | ||||||
|  |     ProtocolId protocol = PROTOCOL_NO; | ||||||
|  |     PulseGlue* pulse_glue = pulse_glue_alloc(); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { | ||||||
|  |         bool pulse_pop = pulse_glue_push( | ||||||
|  |             pulse_glue, | ||||||
|  |             em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT] >= 0, | ||||||
|  |             abs(em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT]) * | ||||||
|  |                 LF_RFID_READ_TIMING_MULTIPLIER); | ||||||
|  | 
 | ||||||
|  |         if(pulse_pop) { | ||||||
|  |             uint32_t length, period; | ||||||
|  |             pulse_glue_pop(pulse_glue, &length, &period); | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, true, period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, false, length - period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pulse_glue_free(pulse_glue); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(LFRFIDProtocolEM4100, protocol); | ||||||
|  |     uint8_t received_data[EM_TEST_DATA_SIZE] = {0}; | ||||||
|  |     protocol_dict_get_data(dict, protocol, received_data, EM_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     mu_assert_mem_eq(data, received_data, EM_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_em_emulate_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100)); | ||||||
|  |     mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100)); | ||||||
|  |     mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_set_data(dict, LFRFIDProtocolEM4100, data, EM_TEST_DATA_SIZE); | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolEM4100)); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT; i++) { | ||||||
|  |         LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolEM4100); | ||||||
|  | 
 | ||||||
|  |         if(level_duration_get_level(level_duration)) { | ||||||
|  |             mu_assert_int_eq(em_test_timings[i], level_duration_get_duration(level_duration)); | ||||||
|  |         } else { | ||||||
|  |             mu_assert_int_eq(em_test_timings[i], -level_duration_get_duration(level_duration)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_h10301_read_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq( | ||||||
|  |         HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301)); | ||||||
|  |     mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301)); | ||||||
|  |     mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_decoders_start(dict); | ||||||
|  | 
 | ||||||
|  |     ProtocolId protocol = PROTOCOL_NO; | ||||||
|  |     PulseGlue* pulse_glue = pulse_glue_alloc(); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { | ||||||
|  |         bool pulse_pop = pulse_glue_push( | ||||||
|  |             pulse_glue, | ||||||
|  |             hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT] >= 0, | ||||||
|  |             abs(hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT]) * | ||||||
|  |                 LF_RFID_READ_TIMING_MULTIPLIER); | ||||||
|  | 
 | ||||||
|  |         if(pulse_pop) { | ||||||
|  |             uint32_t length, period; | ||||||
|  |             pulse_glue_pop(pulse_glue, &length, &period); | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, true, period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, false, length - period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pulse_glue_free(pulse_glue); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(LFRFIDProtocolH10301, protocol); | ||||||
|  |     uint8_t received_data[HID10301_TEST_DATA_SIZE] = {0}; | ||||||
|  |     protocol_dict_get_data(dict, protocol, received_data, HID10301_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     mu_assert_mem_eq(data, received_data, HID10301_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_h10301_emulate_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq( | ||||||
|  |         HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301)); | ||||||
|  |     mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301)); | ||||||
|  |     mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_set_data(dict, LFRFIDProtocolH10301, data, HID10301_TEST_DATA_SIZE); | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolH10301)); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT; i++) { | ||||||
|  |         LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolH10301); | ||||||
|  | 
 | ||||||
|  |         if(level_duration_get_level(level_duration)) { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 hid10301_test_timings[i], level_duration_get_duration(level_duration)); | ||||||
|  |         } else { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 hid10301_test_timings[i], -level_duration_get_duration(level_duration)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq( | ||||||
|  |         IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  |     mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  |     mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_decoders_start(dict); | ||||||
|  | 
 | ||||||
|  |     ProtocolId protocol = PROTOCOL_NO; | ||||||
|  |     PulseGlue* pulse_glue = pulse_glue_alloc(); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT * 10; i++) { | ||||||
|  |         bool pulse_pop = pulse_glue_push( | ||||||
|  |             pulse_glue, | ||||||
|  |             ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] >= 0, | ||||||
|  |             abs(ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT]) * | ||||||
|  |                 LF_RFID_READ_TIMING_MULTIPLIER); | ||||||
|  | 
 | ||||||
|  |         if(pulse_pop) { | ||||||
|  |             uint32_t length, period; | ||||||
|  |             pulse_glue_pop(pulse_glue, &length, &period); | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, true, period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  | 
 | ||||||
|  |             protocol = protocol_dict_decoders_feed(dict, false, length - period); | ||||||
|  |             if(protocol != PROTOCOL_NO) break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pulse_glue_free(pulse_glue); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(LFRFIDProtocolIOProxXSF, protocol); | ||||||
|  |     uint8_t received_data[IOPROX_XSF_TEST_DATA_SIZE] = {0}; | ||||||
|  |     protocol_dict_get_data(dict, protocol, received_data, IOPROX_XSF_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     mu_assert_mem_eq(data, received_data, IOPROX_XSF_TEST_DATA_SIZE); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq( | ||||||
|  |         IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  |     mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  |     mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_set_data(dict, LFRFIDProtocolIOProxXSF, data, IOPROX_XSF_TEST_DATA_SIZE); | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIOProxXSF)); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT; i++) { | ||||||
|  |         LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIOProxXSF); | ||||||
|  | 
 | ||||||
|  |         if(level_duration_get_level(level_duration)) { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 ioprox_xsf_test_timings[i], level_duration_get_duration(level_duration)); | ||||||
|  |         } else { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 ioprox_xsf_test_timings[i], -level_duration_get_duration(level_duration)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_lfrfid_protocol_inadala26_emulate_simple) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax); | ||||||
|  |     mu_assert_int_eq( | ||||||
|  |         INDALA26_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIndala26)); | ||||||
|  |     mu_assert_string_eq("Indala26", protocol_dict_get_name(dict, LFRFIDProtocolIndala26)); | ||||||
|  |     mu_assert_string_eq("Motorola", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIndala26)); | ||||||
|  | 
 | ||||||
|  |     const uint8_t data[INDALA26_TEST_DATA_SIZE] = INDALA26_TEST_DATA; | ||||||
|  | 
 | ||||||
|  |     protocol_dict_set_data(dict, LFRFIDProtocolIndala26, data, INDALA26_TEST_DATA_SIZE); | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIndala26)); | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < INDALA26_EMULATION_TIMINGS_COUNT; i++) { | ||||||
|  |         LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIndala26); | ||||||
|  | 
 | ||||||
|  |         if(level_duration_get_level(level_duration)) { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 indala26_test_timings[i], level_duration_get_duration(level_duration)); | ||||||
|  |         } else { | ||||||
|  |             mu_assert_int_eq( | ||||||
|  |                 indala26_test_timings[i], -level_duration_get_duration(level_duration)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_lfrfid_protocols_suite) { | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_em_read_simple); | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_em_emulate_simple); | ||||||
|  | 
 | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_h10301_read_simple); | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_h10301_emulate_simple); | ||||||
|  | 
 | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple); | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple); | ||||||
|  | 
 | ||||||
|  |     MU_RUN_TEST(test_lfrfid_protocol_inadala26_emulate_simple); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_lfrfid_protocols() { | ||||||
|  |     MU_RUN_SUITE(test_lfrfid_protocols_suite); | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
| @ -157,7 +157,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                        \ |             snprintf(                        \ | ||||||
|                 minunit_last_message,        \ |                 minunit_last_message,        \ | ||||||
|                 MINUNIT_MESSAGE_LEN,         \ |                 MINUNIT_MESSAGE_LEN,         \ | ||||||
|                 "%s failed:\n\t%s:%d: %s", \ |                 "%s failed:\r\n\t%s:%d: %s", \ | ||||||
|                 __func__,                    \ |                 __func__,                    \ | ||||||
|                 __FILE__,                    \ |                 __FILE__,                    \ | ||||||
|                 __LINE__,                    \ |                 __LINE__,                    \ | ||||||
| @ -170,7 +170,7 @@ void minunit_print_fail(const char* error); | |||||||
|     MU__SAFE_BLOCK(minunit_assert++; snprintf(      \ |     MU__SAFE_BLOCK(minunit_assert++; snprintf(      \ | ||||||
|                        minunit_last_message,        \ |                        minunit_last_message,        \ | ||||||
|                        MINUNIT_MESSAGE_LEN,         \ |                        MINUNIT_MESSAGE_LEN,         \ | ||||||
|                        "%s failed:\n\t%s:%d: %s", \ |                        "%s failed:\r\n\t%s:%d: %s", \ | ||||||
|                        __func__,                    \ |                        __func__,                    \ | ||||||
|                        __FILE__,                    \ |                        __FILE__,                    \ | ||||||
|                        __LINE__,                    \ |                        __LINE__,                    \ | ||||||
| @ -184,7 +184,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                        \ |             snprintf(                        \ | ||||||
|                 minunit_last_message,        \ |                 minunit_last_message,        \ | ||||||
|                 MINUNIT_MESSAGE_LEN,         \ |                 MINUNIT_MESSAGE_LEN,         \ | ||||||
|                 "%s failed:\n\t%s:%d: %s", \ |                 "%s failed:\r\n\t%s:%d: %s", \ | ||||||
|                 __func__,                    \ |                 __func__,                    \ | ||||||
|                 __FILE__,                    \ |                 __FILE__,                    \ | ||||||
|                 __LINE__,                    \ |                 __LINE__,                    \ | ||||||
| @ -201,7 +201,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                       \ |             snprintf(                                                                       \ | ||||||
|                 minunit_last_message,                                                       \ |                 minunit_last_message,                                                       \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                        \ |                 MINUNIT_MESSAGE_LEN,                                                        \ | ||||||
|                 "%s failed:\n\t%s:%d: %d expected but was %d",                              \ |                 "%s failed:\r\n\t%s:%d: %d expected but was %d",                            \ | ||||||
|                 __func__,                                                                   \ |                 __func__,                                                                   \ | ||||||
|                 __FILE__,                                                                   \ |                 __FILE__,                                                                   \ | ||||||
|                 __LINE__,                                                                   \ |                 __LINE__,                                                                   \ | ||||||
| @ -219,7 +219,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                       \ |             snprintf(                                                                       \ | ||||||
|                 minunit_last_message,                                                       \ |                 minunit_last_message,                                                       \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                        \ |                 MINUNIT_MESSAGE_LEN,                                                        \ | ||||||
|                 "%s failed:\n\t%s:%d: expected different results but both were %d",         \ |                 "%s failed:\r\n\t%s:%d: expected different results but both were %d",       \ | ||||||
|                 __func__,                                                                   \ |                 __func__,                                                                   \ | ||||||
|                 __FILE__,                                                                   \ |                 __FILE__,                                                                   \ | ||||||
|                 __LINE__,                                                                   \ |                 __LINE__,                                                                   \ | ||||||
| @ -236,7 +236,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                  \ |             snprintf(                                                                  \ | ||||||
|                 minunit_last_message,                                                  \ |                 minunit_last_message,                                                  \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                   \ |                 MINUNIT_MESSAGE_LEN,                                                   \ | ||||||
|                 "%s failed:\n\t%s:%d: %d <= %d",                                       \ |                 "%s failed:\r\n\t%s:%d: %d <= %d",                                     \ | ||||||
|                 __func__,                                                              \ |                 __func__,                                                              \ | ||||||
|                 __FILE__,                                                              \ |                 __FILE__,                                                              \ | ||||||
|                 __LINE__,                                                              \ |                 __LINE__,                                                              \ | ||||||
| @ -254,7 +254,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                  \ |             snprintf(                                                                  \ | ||||||
|                 minunit_last_message,                                                  \ |                 minunit_last_message,                                                  \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                   \ |                 MINUNIT_MESSAGE_LEN,                                                   \ | ||||||
|                 "%s failed:\n\t%s:%d: %d >= %d",                                       \ |                 "%s failed:\r\n\t%s:%d: %d >= %d",                                     \ | ||||||
|                 __func__,                                                              \ |                 __func__,                                                              \ | ||||||
|                 __FILE__,                                                              \ |                 __FILE__,                                                              \ | ||||||
|                 __LINE__,                                                              \ |                 __LINE__,                                                              \ | ||||||
| @ -274,7 +274,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                              \ |             snprintf(                                                              \ | ||||||
|                 minunit_last_message,                                              \ |                 minunit_last_message,                                              \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                               \ |                 MINUNIT_MESSAGE_LEN,                                               \ | ||||||
|                 "%s failed:\n\t%s:%d: %d was not between (inclusive) %d and %d",   \ |                 "%s failed:\r\n\t%s:%d: %d was not between (inclusive) %d and %d", \ | ||||||
|                 __func__,                                                          \ |                 __func__,                                                          \ | ||||||
|                 __FILE__,                                                          \ |                 __FILE__,                                                          \ | ||||||
|                 __LINE__,                                                          \ |                 __LINE__,                                                          \ | ||||||
| @ -302,7 +302,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                    \ |             snprintf(                                                                    \ | ||||||
|                 minunit_last_message,                                                    \ |                 minunit_last_message,                                                    \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                     \ |                 MINUNIT_MESSAGE_LEN,                                                     \ | ||||||
|                 "%s failed:\n\t%s:%d: expected to be one of %s but was %d",              \ |                 "%s failed:\r\n\t%s:%d: expected to be one of %s but was %d",            \ | ||||||
|                 __func__,                                                                \ |                 __func__,                                                                \ | ||||||
|                 __FILE__,                                                                \ |                 __FILE__,                                                                \ | ||||||
|                 __LINE__,                                                                \ |                 __LINE__,                                                                \ | ||||||
| @ -321,7 +321,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                             \ |             snprintf(                                                                             \ | ||||||
|                 minunit_last_message,                                                             \ |                 minunit_last_message,                                                             \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                              \ |                 MINUNIT_MESSAGE_LEN,                                                              \ | ||||||
|                 "%s failed:\n\t%s:%d: %.*g expected but was %.*g",                                \ |                 "%s failed:\r\n\t%s:%d: %.*g expected but was %.*g",                              \ | ||||||
|                 __func__,                                                                         \ |                 __func__,                                                                         \ | ||||||
|                 __FILE__,                                                                         \ |                 __FILE__,                                                                         \ | ||||||
|                 __LINE__,                                                                         \ |                 __LINE__,                                                                         \ | ||||||
| @ -341,7 +341,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                        \ |             snprintf(                                                                        \ | ||||||
|                 minunit_last_message,                                                        \ |                 minunit_last_message,                                                        \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                         \ |                 MINUNIT_MESSAGE_LEN,                                                         \ | ||||||
|                 "%s failed:\n\t%s:%d: %f <= %f",                                             \ |                 "%s failed:\r\n\t%s:%d: %f <= %f",                                           \ | ||||||
|                 __func__,                                                                    \ |                 __func__,                                                                    \ | ||||||
|                 __FILE__,                                                                    \ |                 __FILE__,                                                                    \ | ||||||
|                 __LINE__,                                                                    \ |                 __LINE__,                                                                    \ | ||||||
| @ -359,7 +359,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                        \ |             snprintf(                                                                        \ | ||||||
|                 minunit_last_message,                                                        \ |                 minunit_last_message,                                                        \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                         \ |                 MINUNIT_MESSAGE_LEN,                                                         \ | ||||||
|                 "%s failed:\n\t%s:%d: %f >= %f",                                             \ |                 "%s failed:\r\n\t%s:%d: %f >= %f",                                           \ | ||||||
|                 __func__,                                                                    \ |                 __func__,                                                                    \ | ||||||
|                 __FILE__,                                                                    \ |                 __FILE__,                                                                    \ | ||||||
|                 __LINE__,                                                                    \ |                 __LINE__,                                                                    \ | ||||||
| @ -379,7 +379,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                       \ |             snprintf(                                                                       \ | ||||||
|                 minunit_last_message,                                                       \ |                 minunit_last_message,                                                       \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                        \ |                 MINUNIT_MESSAGE_LEN,                                                        \ | ||||||
|                 "%s failed:\n\t%s:%d: %f was not between (inclusive) %f and %f",            \ |                 "%s failed:\r\n\t%s:%d: %f was not between (inclusive) %f and %f",          \ | ||||||
|                 __func__,                                                                   \ |                 __func__,                                                                   \ | ||||||
|                 __FILE__,                                                                   \ |                 __FILE__,                                                                   \ | ||||||
|                 __LINE__,                                                                   \ |                 __LINE__,                                                                   \ | ||||||
| @ -400,7 +400,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                 \ |             snprintf(                                                                 \ | ||||||
|                 minunit_last_message,                                                 \ |                 minunit_last_message,                                                 \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                  \ |                 MINUNIT_MESSAGE_LEN,                                                  \ | ||||||
|                 "%s failed:\n\t%s:%d: '%s' expected but was '%s'",                    \ |                 "%s failed:\r\n\t%s:%d: '%s' expected but was '%s'",                  \ | ||||||
|                 __func__,                                                             \ |                 __func__,                                                             \ | ||||||
|                 __FILE__,                                                             \ |                 __FILE__,                                                             \ | ||||||
|                 __LINE__,                                                             \ |                 __LINE__,                                                             \ | ||||||
| @ -410,13 +410,41 @@ void minunit_print_fail(const char* error); | |||||||
|             return;                                                                   \ |             return;                                                                   \ | ||||||
|         } else { minunit_print_progress(); }) |         } else { minunit_print_progress(); }) | ||||||
| 
 | 
 | ||||||
|  | #define mu_assert_mem_eq(expected, result, size)                                   \ | ||||||
|  |     MU__SAFE_BLOCK(                                                                \ | ||||||
|  |         const void* minunit_tmp_e = expected; const void* minunit_tmp_r = result;  \ | ||||||
|  |         minunit_assert++;                                                          \ | ||||||
|  |         if(memcmp(minunit_tmp_e, minunit_tmp_r, size)) {                           \ | ||||||
|  |             snprintf(                                                              \ | ||||||
|  |                 minunit_last_message,                                              \ | ||||||
|  |                 MINUNIT_MESSAGE_LEN,                                               \ | ||||||
|  |                 "%s failed:\r\n\t%s:%d: mem not equal\r\n\tEXP  RES",              \ | ||||||
|  |                 __func__,                                                          \ | ||||||
|  |                 __FILE__,                                                          \ | ||||||
|  |                 __LINE__);                                                         \ | ||||||
|  |             for(size_t __index = 0; __index < size; __index++) {                   \ | ||||||
|  |                 if(strlen(minunit_last_message) > MINUNIT_MESSAGE_LEN - 20) break; \ | ||||||
|  |                 uint8_t __e = ((uint8_t*)minunit_tmp_e)[__index];                  \ | ||||||
|  |                 uint8_t __r = ((uint8_t*)minunit_tmp_r)[__index];                  \ | ||||||
|  |                 snprintf(                                                          \ | ||||||
|  |                     minunit_last_message + strlen(minunit_last_message),           \ | ||||||
|  |                     MINUNIT_MESSAGE_LEN - strlen(minunit_last_message),            \ | ||||||
|  |                     "\r\n\t%02X %s %02X",                                          \ | ||||||
|  |                     __e,                                                           \ | ||||||
|  |                     ((__e == __r) ? ".." : "!="),                                  \ | ||||||
|  |                     __r);                                                          \ | ||||||
|  |             }                                                                      \ | ||||||
|  |             minunit_status = 1;                                                    \ | ||||||
|  |             return;                                                                \ | ||||||
|  |         } else { minunit_print_progress(); }) | ||||||
|  | 
 | ||||||
| #define mu_assert_null(result)                                                    \ | #define mu_assert_null(result)                                                    \ | ||||||
|     MU__SAFE_BLOCK(                                                               \ |     MU__SAFE_BLOCK(                                                               \ | ||||||
|         minunit_assert++; if(result == NULL) { minunit_print_progress(); } else { \ |         minunit_assert++; if(result == NULL) { minunit_print_progress(); } else { \ | ||||||
|             snprintf(                                                             \ |             snprintf(                                                             \ | ||||||
|                 minunit_last_message,                                             \ |                 minunit_last_message,                                             \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                              \ |                 MINUNIT_MESSAGE_LEN,                                              \ | ||||||
|                 "%s failed:\n\t%s:%d: Expected result was not NULL",              \ |                 "%s failed:\r\n\t%s:%d: Expected result was not NULL",            \ | ||||||
|                 __func__,                                                         \ |                 __func__,                                                         \ | ||||||
|                 __FILE__,                                                         \ |                 __FILE__,                                                         \ | ||||||
|                 __LINE__);                                                        \ |                 __LINE__);                                                        \ | ||||||
| @ -430,7 +458,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                             \ |             snprintf(                                                             \ | ||||||
|                 minunit_last_message,                                             \ |                 minunit_last_message,                                             \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                              \ |                 MINUNIT_MESSAGE_LEN,                                              \ | ||||||
|                 "%s failed:\n\t%s:%d: Expected result was not NULL",              \ |                 "%s failed:\r\n\t%s:%d: Expected result was not NULL",            \ | ||||||
|                 __func__,                                                         \ |                 __func__,                                                         \ | ||||||
|                 __FILE__,                                                         \ |                 __FILE__,                                                         \ | ||||||
|                 __LINE__);                                                        \ |                 __LINE__);                                                        \ | ||||||
| @ -444,7 +472,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                                \ |             snprintf(                                                                                \ | ||||||
|                 minunit_last_message,                                                                \ |                 minunit_last_message,                                                                \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                                 \ |                 MINUNIT_MESSAGE_LEN,                                                                 \ | ||||||
|                 "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", \ |                 "%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \ | ||||||
|                 __func__,                                                                            \ |                 __func__,                                                                            \ | ||||||
|                 __FILE__,                                                                            \ |                 __FILE__,                                                                            \ | ||||||
|                 __LINE__);                                                                           \ |                 __LINE__);                                                                           \ | ||||||
| @ -458,7 +486,7 @@ void minunit_print_fail(const char* error); | |||||||
|             snprintf(                                                                                \ |             snprintf(                                                                                \ | ||||||
|                 minunit_last_message,                                                                \ |                 minunit_last_message,                                                                \ | ||||||
|                 MINUNIT_MESSAGE_LEN,                                                                 \ |                 MINUNIT_MESSAGE_LEN,                                                                 \ | ||||||
|                 "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", \ |                 "%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \ | ||||||
|                 __func__,                                                                            \ |                 __func__,                                                                            \ | ||||||
|                 __FILE__,                                                                            \ |                 __FILE__,                                                                            \ | ||||||
|                 __LINE__);                                                                           \ |                 __LINE__);                                                                           \ | ||||||
|  | |||||||
							
								
								
									
										222
									
								
								applications/unit_tests/protocol_dict/protocol_dict_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								applications/unit_tests/protocol_dict/protocol_dict_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,222 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | #include <toolbox/protocols/protocol_dict.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     TestDictProtocol0, | ||||||
|  |     TestDictProtocol1, | ||||||
|  | 
 | ||||||
|  |     TestDictProtocolMax, | ||||||
|  | } TestDictProtocols; | ||||||
|  | 
 | ||||||
|  | /*********************** PROTOCOL 0 START ***********************/ | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t data; | ||||||
|  |     size_t encoder_counter; | ||||||
|  | } Protocol0Data; | ||||||
|  | 
 | ||||||
|  | static const uint32_t protocol_0_decoder_result = 0xDEADBEEF; | ||||||
|  | 
 | ||||||
|  | static void* protocol_0_alloc() { | ||||||
|  |     void* data = malloc(sizeof(Protocol0Data)); | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void protocol_0_free(Protocol0Data* data) { | ||||||
|  |     free(data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint8_t* protocol_0_get_data(Protocol0Data* data) { | ||||||
|  |     return (uint8_t*)&data->data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void protocol_0_decoder_start(Protocol0Data* data) { | ||||||
|  |     data->data = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool protocol_0_decoder_feed(Protocol0Data* data, bool level, uint32_t duration) { | ||||||
|  |     if(level && duration == 666) { | ||||||
|  |         data->data = protocol_0_decoder_result; | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool protocol_0_encoder_start(Protocol0Data* data) { | ||||||
|  |     data->encoder_counter = 0; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static LevelDuration protocol_0_encoder_yield(Protocol0Data* data) { | ||||||
|  |     data->encoder_counter++; | ||||||
|  |     return level_duration_make(data->encoder_counter % 2, data->data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*********************** PROTOCOL 1 START ***********************/ | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint64_t data; | ||||||
|  |     size_t encoder_counter; | ||||||
|  | } Protocol1Data; | ||||||
|  | 
 | ||||||
|  | static const uint64_t protocol_1_decoder_result = 0x1234567890ABCDEF; | ||||||
|  | 
 | ||||||
|  | static void* protocol_1_alloc() { | ||||||
|  |     void* data = malloc(sizeof(Protocol1Data)); | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void protocol_1_free(Protocol1Data* data) { | ||||||
|  |     free(data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint8_t* protocol_1_get_data(Protocol1Data* data) { | ||||||
|  |     return (uint8_t*)&data->data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void protocol_1_decoder_start(Protocol1Data* data) { | ||||||
|  |     data->data = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool protocol_1_decoder_feed(Protocol1Data* data, bool level, uint32_t duration) { | ||||||
|  |     if(level && duration == 543) { | ||||||
|  |         data->data = 0x1234567890ABCDEF; | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool protocol_1_encoder_start(Protocol1Data* data) { | ||||||
|  |     data->encoder_counter = 0; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static LevelDuration protocol_1_encoder_yield(Protocol1Data* data) { | ||||||
|  |     data->encoder_counter++; | ||||||
|  |     return level_duration_make(!(data->encoder_counter % 2), 100); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*********************** PROTOCOLS DESCRIPTION ***********************/ | ||||||
|  | static const ProtocolBase protocol_0 = { | ||||||
|  |     .name = "Protocol 0", | ||||||
|  |     .manufacturer = "Manufacturer 0", | ||||||
|  |     .data_size = 4, | ||||||
|  |     .alloc = (ProtocolAlloc)protocol_0_alloc, | ||||||
|  |     .free = (ProtocolFree)protocol_0_free, | ||||||
|  |     .get_data = (ProtocolGetData)protocol_0_get_data, | ||||||
|  |     .decoder = | ||||||
|  |         { | ||||||
|  |             .start = (ProtocolDecoderStart)protocol_0_decoder_start, | ||||||
|  |             .feed = (ProtocolDecoderFeed)protocol_0_decoder_feed, | ||||||
|  |         }, | ||||||
|  |     .encoder = | ||||||
|  |         { | ||||||
|  |             .start = (ProtocolEncoderStart)protocol_0_encoder_start, | ||||||
|  |             .yield = (ProtocolEncoderYield)protocol_0_encoder_yield, | ||||||
|  |         }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const ProtocolBase protocol_1 = { | ||||||
|  |     .name = "Protocol 1", | ||||||
|  |     .manufacturer = "Manufacturer 1", | ||||||
|  |     .data_size = 8, | ||||||
|  |     .alloc = (ProtocolAlloc)protocol_1_alloc, | ||||||
|  |     .free = (ProtocolFree)protocol_1_free, | ||||||
|  |     .get_data = (ProtocolGetData)protocol_1_get_data, | ||||||
|  |     .decoder = | ||||||
|  |         { | ||||||
|  |             .start = (ProtocolDecoderStart)protocol_1_decoder_start, | ||||||
|  |             .feed = (ProtocolDecoderFeed)protocol_1_decoder_feed, | ||||||
|  |         }, | ||||||
|  |     .encoder = | ||||||
|  |         { | ||||||
|  |             .start = (ProtocolEncoderStart)protocol_1_encoder_start, | ||||||
|  |             .yield = (ProtocolEncoderYield)protocol_1_encoder_yield, | ||||||
|  |         }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const ProtocolBase* test_protocols_base[] = { | ||||||
|  |     [TestDictProtocol0] = &protocol_0, | ||||||
|  |     [TestDictProtocol1] = &protocol_1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_protocol_dict) { | ||||||
|  |     ProtocolDict* dict = protocol_dict_alloc(test_protocols_base, TestDictProtocolMax); | ||||||
|  |     size_t max_data_size = protocol_dict_get_max_data_size(dict); | ||||||
|  |     mu_assert_int_eq(8, max_data_size); | ||||||
|  |     uint8_t* data = malloc(max_data_size); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_decoders_start(dict); | ||||||
|  |     ProtocolId protocol_id = PROTOCOL_NO; | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < 100; i++) { | ||||||
|  |         protocol_id = protocol_dict_decoders_feed(dict, i % 2, 100); | ||||||
|  |         mu_assert_int_eq(PROTOCOL_NO, protocol_id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // trigger protocol 1
 | ||||||
|  |     protocol_id = protocol_dict_decoders_feed(dict, true, 543); | ||||||
|  |     mu_assert_int_eq(TestDictProtocol1, protocol_id); | ||||||
|  | 
 | ||||||
|  |     mu_assert_string_eq("Protocol 1", protocol_dict_get_name(dict, protocol_id)); | ||||||
|  |     mu_assert_string_eq("Manufacturer 1", protocol_dict_get_manufacturer(dict, protocol_id)); | ||||||
|  | 
 | ||||||
|  |     size_t data_size = protocol_dict_get_data_size(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(8, data_size); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_get_data(dict, protocol_id, data, data_size); | ||||||
|  |     mu_assert_mem_eq(&protocol_1_decoder_result, data, data_size); | ||||||
|  | 
 | ||||||
|  |     // trigger protocol 0
 | ||||||
|  |     protocol_id = protocol_dict_decoders_feed(dict, true, 666); | ||||||
|  |     mu_assert_int_eq(TestDictProtocol0, protocol_id); | ||||||
|  | 
 | ||||||
|  |     mu_assert_string_eq("Protocol 0", protocol_dict_get_name(dict, protocol_id)); | ||||||
|  |     mu_assert_string_eq("Manufacturer 0", protocol_dict_get_manufacturer(dict, protocol_id)); | ||||||
|  | 
 | ||||||
|  |     data_size = protocol_dict_get_data_size(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(4, data_size); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_get_data(dict, protocol_id, data, data_size); | ||||||
|  |     mu_assert_mem_eq(&protocol_0_decoder_result, data, data_size); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_decoders_start(dict); | ||||||
|  | 
 | ||||||
|  |     protocol_id = TestDictProtocol0; | ||||||
|  | 
 | ||||||
|  |     const uint8_t protocol_0_test_data[4] = {100, 0, 0, 0}; | ||||||
|  |     protocol_dict_set_data(dict, protocol_id, protocol_0_test_data, 4); | ||||||
|  | 
 | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, protocol_id)); | ||||||
|  | 
 | ||||||
|  |     LevelDuration level; | ||||||
|  |     level = protocol_dict_encoder_yield(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(true, level_duration_get_level(level)); | ||||||
|  |     mu_assert_int_eq(100, level_duration_get_duration(level)); | ||||||
|  |     level = protocol_dict_encoder_yield(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(false, level_duration_get_level(level)); | ||||||
|  |     mu_assert_int_eq(100, level_duration_get_duration(level)); | ||||||
|  |     level = protocol_dict_encoder_yield(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(true, level_duration_get_level(level)); | ||||||
|  |     mu_assert_int_eq(100, level_duration_get_duration(level)); | ||||||
|  | 
 | ||||||
|  |     mu_check(protocol_dict_encoder_start(dict, protocol_id)); | ||||||
|  |     level = protocol_dict_encoder_yield(dict, protocol_id); | ||||||
|  |     mu_assert_int_eq(true, level_duration_get_level(level)); | ||||||
|  |     mu_assert_int_eq(100, level_duration_get_duration(level)); | ||||||
|  | 
 | ||||||
|  |     protocol_dict_free(dict); | ||||||
|  |     free(data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_protocol_dict_suite) { | ||||||
|  |     MU_RUN_TEST(test_protocol_dict); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_protocol_dict() { | ||||||
|  |     MU_RUN_SUITE(test_protocol_dict_suite); | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
| @ -19,7 +19,10 @@ int run_minunit_test_stream(); | |||||||
| int run_minunit_test_storage(); | int run_minunit_test_storage(); | ||||||
| int run_minunit_test_subghz(); | int run_minunit_test_subghz(); | ||||||
| int run_minunit_test_dirwalk(); | int run_minunit_test_dirwalk(); | ||||||
|  | int run_minunit_test_protocol_dict(); | ||||||
|  | int run_minunit_test_lfrfid_protocols(); | ||||||
| int run_minunit_test_nfc(); | int run_minunit_test_nfc(); | ||||||
|  | int run_minunit_test_bit_lib(); | ||||||
| 
 | 
 | ||||||
| typedef int (*UnitTestEntry)(); | typedef int (*UnitTestEntry)(); | ||||||
| 
 | 
 | ||||||
| @ -39,6 +42,9 @@ const UnitTest unit_tests[] = { | |||||||
|     {.name = "subghz", .entry = run_minunit_test_subghz}, |     {.name = "subghz", .entry = run_minunit_test_subghz}, | ||||||
|     {.name = "infrared", .entry = run_minunit_test_infrared}, |     {.name = "infrared", .entry = run_minunit_test_infrared}, | ||||||
|     {.name = "nfc", .entry = run_minunit_test_nfc}, |     {.name = "nfc", .entry = run_minunit_test_nfc}, | ||||||
|  |     {.name = "protocol_dict", .entry = run_minunit_test_protocol_dict}, | ||||||
|  |     {.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols}, | ||||||
|  |     {.name = "bit_lib", .entry = run_minunit_test_bit_lib}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void minunit_print_progress() { | void minunit_print_progress() { | ||||||
|  | |||||||
							
								
								
									
										88
									
								
								applications/unit_tests/varint/varint_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								applications/unit_tests/varint/varint_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | #include "../minunit.h" | ||||||
|  | #include <toolbox/varint.h> | ||||||
|  | #include <toolbox/profiler.h> | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_varint_basic_u) { | ||||||
|  |     mu_assert_int_eq(1, varint_uint32_length(0)); | ||||||
|  |     mu_assert_int_eq(5, varint_uint32_length(UINT32_MAX)); | ||||||
|  | 
 | ||||||
|  |     uint8_t data[8] = {}; | ||||||
|  |     uint32_t out_value; | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(1, varint_uint32_pack(0, data)); | ||||||
|  |     mu_assert_int_eq(1, varint_uint32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(0, out_value); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(5, varint_uint32_pack(UINT32_MAX, data)); | ||||||
|  |     mu_assert_int_eq(5, varint_uint32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(UINT32_MAX, out_value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_varint_basic_i) { | ||||||
|  |     mu_assert_int_eq(5, varint_int32_length(INT32_MIN / 2)); | ||||||
|  |     mu_assert_int_eq(1, varint_int32_length(0)); | ||||||
|  |     mu_assert_int_eq(5, varint_int32_length(INT32_MAX / 2)); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(2, varint_int32_length(127)); | ||||||
|  |     mu_assert_int_eq(2, varint_int32_length(-127)); | ||||||
|  | 
 | ||||||
|  |     uint8_t data[8] = {}; | ||||||
|  |     int32_t out_value; | ||||||
|  |     mu_assert_int_eq(1, varint_int32_pack(0, data)); | ||||||
|  |     mu_assert_int_eq(1, varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(0, out_value); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(2, varint_int32_pack(127, data)); | ||||||
|  |     mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(127, out_value); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(2, varint_int32_pack(-127, data)); | ||||||
|  |     mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(-127, out_value); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(5, varint_int32_pack(INT32_MAX, data)); | ||||||
|  |     mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(INT32_MAX, out_value); | ||||||
|  | 
 | ||||||
|  |     mu_assert_int_eq(5, varint_int32_pack(INT32_MIN / 2 + 1, data)); | ||||||
|  |     mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |     mu_assert_int_eq(INT32_MIN / 2 + 1, out_value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_varint_rand_u) { | ||||||
|  |     uint8_t data[8] = {}; | ||||||
|  |     uint32_t out_value; | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < 200000; i++) { | ||||||
|  |         uint32_t rand_value = rand(); | ||||||
|  |         mu_assert_int_eq( | ||||||
|  |             varint_uint32_pack(rand_value, data), varint_uint32_unpack(&out_value, data, 8)); | ||||||
|  |         mu_assert_int_eq(rand_value, out_value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_varint_rand_i) { | ||||||
|  |     uint8_t data[8] = {}; | ||||||
|  |     int32_t out_value; | ||||||
|  | 
 | ||||||
|  |     for(size_t i = 0; i < 200000; i++) { | ||||||
|  |         int32_t rand_value = rand() + (INT32_MIN / 2 + 1); | ||||||
|  |         mu_assert_int_eq( | ||||||
|  |             varint_int32_pack(rand_value, data), varint_int32_unpack(&out_value, data, 8)); | ||||||
|  |         mu_assert_int_eq(rand_value, out_value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST_SUITE(test_varint_suite) { | ||||||
|  |     MU_RUN_TEST(test_varint_basic_u); | ||||||
|  |     MU_RUN_TEST(test_varint_basic_i); | ||||||
|  |     MU_RUN_TEST(test_varint_rand_u); | ||||||
|  |     MU_RUN_TEST(test_varint_rand_i); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int run_minunit_test_varint() { | ||||||
|  |     MU_RUN_SUITE(test_varint_suite); | ||||||
|  |     return MU_EXIT_CODE; | ||||||
|  | } | ||||||
| @ -170,8 +170,7 @@ static bool update_task_check_file_exists(UpdateTask* update_task, string_t file | |||||||
|     string_t tmp_path; |     string_t tmp_path; | ||||||
|     string_init_set(tmp_path, update_task->update_path); |     string_init_set(tmp_path, update_task->update_path); | ||||||
|     path_append(tmp_path, string_get_cstr(filename)); |     path_append(tmp_path, string_get_cstr(filename)); | ||||||
|     bool exists = |     bool exists = storage_file_exists(update_task->storage, string_get_cstr(tmp_path)); | ||||||
|         (storage_common_stat(update_task->storage, string_get_cstr(tmp_path), NULL) == FSE_OK); |  | ||||||
|     string_clear(tmp_path); |     string_clear(tmp_path); | ||||||
|     return exists; |     return exists; | ||||||
| } | } | ||||||
|  | |||||||
| @ -200,6 +200,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program( | |||||||
|         "misc", |         "misc", | ||||||
|         "mbedtls", |         "mbedtls", | ||||||
|         "loclass", |         "loclass", | ||||||
|  |         "lfrfid", | ||||||
|         # 2nd round |         # 2nd round | ||||||
|         "flipperformat", |         "flipperformat", | ||||||
|         "toolbox", |         "toolbox", | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_tim.h> | #include <stm32wbxx_ll_tim.h> | ||||||
| #include <stm32wbxx_ll_comp.h> | #include <stm32wbxx_ll_comp.h> | ||||||
|  | #include <stm32wbxx_ll_dma.h> | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_RFID_READ_TIMER TIM1 | #define FURI_HAL_RFID_READ_TIMER TIM1 | ||||||
| #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N | #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N | ||||||
| @ -16,8 +17,14 @@ | |||||||
| #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 | #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 | ||||||
| #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 | #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 | ||||||
| 
 | 
 | ||||||
|  | #define RFID_CAPTURE_TIM TIM2 | ||||||
|  | #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 | ||||||
|  | #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     FuriHalRfidEmulateCallback callback; |     FuriHalRfidEmulateCallback callback; | ||||||
|  |     FuriHalRfidDMACallback dma_callback; | ||||||
|  |     FuriHalRfidReadCaptureCallback read_capture_callback; | ||||||
|     void* context; |     void* context; | ||||||
| } FuriHalRfid; | } FuriHalRfid; | ||||||
| 
 | 
 | ||||||
| @ -212,6 +219,185 @@ void furi_hal_rfid_tim_emulate_stop() { | |||||||
|     furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); |     furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void furi_hal_capture_dma_isr(void* context) { | ||||||
|  |     UNUSED(context); | ||||||
|  | 
 | ||||||
|  |     // Channel 3, positive level
 | ||||||
|  |     if(LL_TIM_IsActiveFlag_CC3(RFID_CAPTURE_TIM)) { | ||||||
|  |         LL_TIM_ClearFlag_CC3(RFID_CAPTURE_TIM); | ||||||
|  |         furi_hal_rfid->read_capture_callback( | ||||||
|  |             true, LL_TIM_IC_GetCaptureCH3(RFID_CAPTURE_TIM), furi_hal_rfid->context); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Channel 4, overall level
 | ||||||
|  |     if(LL_TIM_IsActiveFlag_CC4(RFID_CAPTURE_TIM)) { | ||||||
|  |         LL_TIM_ClearFlag_CC4(RFID_CAPTURE_TIM); | ||||||
|  |         LL_TIM_SetCounter(RFID_CAPTURE_TIM, 0); | ||||||
|  |         furi_hal_rfid->read_capture_callback( | ||||||
|  |             false, LL_TIM_IC_GetCaptureCH4(RFID_CAPTURE_TIM), furi_hal_rfid->context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context) { | ||||||
|  |     FURI_CRITICAL_ENTER(); | ||||||
|  |     LL_TIM_DeInit(RFID_CAPTURE_TIM); | ||||||
|  |     FURI_CRITICAL_EXIT(); | ||||||
|  | 
 | ||||||
|  |     furi_assert(furi_hal_rfid); | ||||||
|  | 
 | ||||||
|  |     furi_hal_rfid->read_capture_callback = callback; | ||||||
|  |     furi_hal_rfid->context = context; | ||||||
|  | 
 | ||||||
|  |     // Timer: base
 | ||||||
|  |     LL_TIM_InitTypeDef TIM_InitStruct = {0}; | ||||||
|  |     TIM_InitStruct.Prescaler = 64 - 1; | ||||||
|  |     TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; | ||||||
|  |     TIM_InitStruct.Autoreload = UINT32_MAX; | ||||||
|  |     TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; | ||||||
|  |     LL_TIM_Init(RFID_CAPTURE_TIM, &TIM_InitStruct); | ||||||
|  | 
 | ||||||
|  |     // Timer: advanced
 | ||||||
|  |     LL_TIM_SetClockSource(RFID_CAPTURE_TIM, LL_TIM_CLOCKSOURCE_INTERNAL); | ||||||
|  |     LL_TIM_DisableARRPreload(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_SetTriggerInput(RFID_CAPTURE_TIM, LL_TIM_TS_TI2FP2); | ||||||
|  |     LL_TIM_SetSlaveMode(RFID_CAPTURE_TIM, LL_TIM_SLAVEMODE_DISABLED); | ||||||
|  |     LL_TIM_SetTriggerOutput(RFID_CAPTURE_TIM, LL_TIM_TRGO_RESET); | ||||||
|  |     LL_TIM_EnableMasterSlaveMode(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_DisableDMAReq_TRIG(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_DisableIT_TRIG(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_SetRemap(RFID_CAPTURE_TIM, LL_TIM_TIM2_TI4_RMP_COMP1); | ||||||
|  | 
 | ||||||
|  |     // Timer: channel 3 indirect
 | ||||||
|  |     LL_TIM_IC_SetActiveInput(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_ACTIVEINPUT_INDIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_IC_POLARITY_FALLING); | ||||||
|  |     LL_TIM_IC_SetFilter(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  | 
 | ||||||
|  |     // Timer: channel 4 direct
 | ||||||
|  |     LL_TIM_IC_SetActiveInput(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_ACTIVEINPUT_DIRECTTI); | ||||||
|  |     LL_TIM_IC_SetPrescaler(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_ICPSC_DIV1); | ||||||
|  |     LL_TIM_IC_SetPolarity(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_IC_POLARITY_RISING); | ||||||
|  |     LL_TIM_IC_SetFilter(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH, LL_TIM_IC_FILTER_FDIV1); | ||||||
|  | 
 | ||||||
|  |     furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, furi_hal_capture_dma_isr, NULL); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_EnableIT_CC3(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_EnableIT_CC4(RFID_CAPTURE_TIM); | ||||||
|  |     LL_TIM_CC_EnableChannel(RFID_CAPTURE_TIM, RFID_CAPTURE_IND_CH); | ||||||
|  |     LL_TIM_CC_EnableChannel(RFID_CAPTURE_TIM, RFID_CAPTURE_DIR_CH); | ||||||
|  |     LL_TIM_SetCounter(RFID_CAPTURE_TIM, 0); | ||||||
|  |     LL_TIM_EnableCounter(RFID_CAPTURE_TIM); | ||||||
|  | 
 | ||||||
|  |     furi_hal_rfid_comp_start(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_read_capture_stop() { | ||||||
|  |     furi_hal_rfid_comp_stop(); | ||||||
|  | 
 | ||||||
|  |     furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); | ||||||
|  | 
 | ||||||
|  |     FURI_CRITICAL_ENTER(); | ||||||
|  |     LL_TIM_DeInit(RFID_CAPTURE_TIM); | ||||||
|  |     FURI_CRITICAL_EXIT(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_rfid_dma_isr() { | ||||||
|  |     if(LL_DMA_IsActiveFlag_HT1(DMA1)) { | ||||||
|  |         LL_DMA_ClearFlag_HT1(DMA1); | ||||||
|  |         furi_hal_rfid->dma_callback(true, furi_hal_rfid->context); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(LL_DMA_IsActiveFlag_TC1(DMA1)) { | ||||||
|  |         LL_DMA_ClearFlag_TC1(DMA1); | ||||||
|  |         furi_hal_rfid->dma_callback(false, furi_hal_rfid->context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_emulate_dma_start( | ||||||
|  |     uint32_t* duration, | ||||||
|  |     uint32_t* pulse, | ||||||
|  |     size_t length, | ||||||
|  |     FuriHalRfidDMACallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(furi_hal_rfid); | ||||||
|  | 
 | ||||||
|  |     // setup interrupts
 | ||||||
|  |     furi_hal_rfid->dma_callback = callback; | ||||||
|  |     furi_hal_rfid->context = context; | ||||||
|  | 
 | ||||||
|  |     // setup pins
 | ||||||
|  |     furi_hal_rfid_pins_emulate(); | ||||||
|  | 
 | ||||||
|  |     // configure timer
 | ||||||
|  |     furi_hal_rfid_tim_emulate(125000); | ||||||
|  |     LL_TIM_OC_SetPolarity( | ||||||
|  |         FURI_HAL_RFID_EMULATE_TIMER, FURI_HAL_RFID_EMULATE_TIMER_CHANNEL, LL_TIM_OCPOLARITY_HIGH); | ||||||
|  |     LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  | 
 | ||||||
|  |     // configure DMA "mem -> ARR" channel
 | ||||||
|  |     LL_DMA_InitTypeDef dma_config = {0}; | ||||||
|  |     dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (FURI_HAL_RFID_EMULATE_TIMER->ARR); | ||||||
|  |     dma_config.MemoryOrM2MDstAddress = (uint32_t)duration; | ||||||
|  |     dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; | ||||||
|  |     dma_config.Mode = LL_DMA_MODE_CIRCULAR; | ||||||
|  |     dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; | ||||||
|  |     dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; | ||||||
|  |     dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; | ||||||
|  |     dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; | ||||||
|  |     dma_config.NbData = length; | ||||||
|  |     dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; | ||||||
|  |     dma_config.Priority = LL_DMA_MODE_NORMAL; | ||||||
|  |     LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); | ||||||
|  |     LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  | 
 | ||||||
|  |     // configure DMA "mem -> CCR3" channel
 | ||||||
|  | #if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 | ||||||
|  |     dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (FURI_HAL_RFID_EMULATE_TIMER->CCR3); | ||||||
|  | #else | ||||||
|  | #error Update this code. Would you kindly? | ||||||
|  | #endif | ||||||
|  |     dma_config.MemoryOrM2MDstAddress = (uint32_t)pulse; | ||||||
|  |     dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; | ||||||
|  |     dma_config.Mode = LL_DMA_MODE_CIRCULAR; | ||||||
|  |     dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; | ||||||
|  |     dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; | ||||||
|  |     dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; | ||||||
|  |     dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; | ||||||
|  |     dma_config.NbData = length; | ||||||
|  |     dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; | ||||||
|  |     dma_config.Priority = LL_DMA_MODE_NORMAL; | ||||||
|  |     LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); | ||||||
|  |     LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); | ||||||
|  | 
 | ||||||
|  |     // attach interrupt to one of DMA channels
 | ||||||
|  |     furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, furi_hal_rfid_dma_isr, NULL); | ||||||
|  |     LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  |     LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  | 
 | ||||||
|  |     // start
 | ||||||
|  |     LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  | 
 | ||||||
|  |     LL_TIM_SetCounter(FURI_HAL_RFID_EMULATE_TIMER, 0); | ||||||
|  |     LL_TIM_EnableCounter(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_emulate_dma_stop() { | ||||||
|  |     LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  |     LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  | 
 | ||||||
|  |     furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); | ||||||
|  |     LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  |     LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  | 
 | ||||||
|  |     FURI_CRITICAL_ENTER(); | ||||||
|  | 
 | ||||||
|  |     LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1); | ||||||
|  |     LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_2); | ||||||
|  |     LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); | ||||||
|  | 
 | ||||||
|  |     FURI_CRITICAL_EXIT(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void furi_hal_rfid_tim_reset() { | void furi_hal_rfid_tim_reset() { | ||||||
|     FURI_CRITICAL_ENTER(); |     FURI_CRITICAL_ENTER(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -63,6 +64,23 @@ typedef void (*FuriHalRfidEmulateCallback)(void* context); | |||||||
|  */ |  */ | ||||||
| void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); | void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); | ||||||
| 
 | 
 | ||||||
|  | typedef void (*FuriHalRfidReadCaptureCallback)(bool level, uint32_t duration, void* context); | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context); | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_read_capture_stop(); | ||||||
|  | 
 | ||||||
|  | typedef void (*FuriHalRfidDMACallback)(bool half, void* context); | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_emulate_dma_start( | ||||||
|  |     uint32_t* duration, | ||||||
|  |     uint32_t* pulse, | ||||||
|  |     size_t length, | ||||||
|  |     FuriHalRfidDMACallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | void furi_hal_rfid_tim_emulate_dma_stop(); | ||||||
|  | 
 | ||||||
| /** Stop emulation timer
 | /** Stop emulation timer
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_rfid_tim_emulate_stop(); | void furi_hal_rfid_tim_emulate_stop(); | ||||||
|  | |||||||
| @ -92,6 +92,8 @@ extern "C" { | |||||||
| #define FURI_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) | #define FURI_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #define FURI_SW_MEMBARRIER() asm volatile("" : : : "memory") | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -77,6 +77,7 @@ libs = env.BuildModules( | |||||||
|         "appframe", |         "appframe", | ||||||
|         "misc", |         "misc", | ||||||
|         "loclass", |         "loclass", | ||||||
|  |         "lfrfid", | ||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG