diff --git a/applications/applications.c b/applications/applications.c index 00916956..1f3435f8 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -45,6 +45,7 @@ void irda_cli_init(); void nfc_cli_init(); void subghz_cli_init(); void bt_cli_init(); +void lfrfid_cli_init(); const FlipperApplication FLIPPER_SERVICES[] = { #ifdef SRV_CLI @@ -211,6 +212,9 @@ const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = { #ifdef APP_SUBGHZ subghz_cli_init, #endif +#ifdef APP_LF_RFID + lfrfid_cli_init, +#endif #ifdef SRV_BT bt_cli_init, #endif diff --git a/applications/lf-rfid/helpers/key-info.cpp b/applications/lf-rfid/helpers/key-info.cpp new file mode 100644 index 00000000..c6feac81 --- /dev/null +++ b/applications/lf-rfid/helpers/key-info.cpp @@ -0,0 +1,33 @@ +#include "key-info.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; + } + + return "Unknown"; +} + +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; + } + + return 0; +} \ No newline at end of file diff --git a/applications/lf-rfid/helpers/key-info.h b/applications/lf-rfid/helpers/key-info.h index 093bc93c..a29eb602 100644 --- a/applications/lf-rfid/helpers/key-info.h +++ b/applications/lf-rfid/helpers/key-info.h @@ -4,7 +4,10 @@ static const uint8_t LFRFID_KEY_SIZE = 8; enum class LfrfidKeyType : uint8_t { - KeyEmarine, - KeyHID, - KeyIndala, -}; \ No newline at end of file + KeyEM4100, + KeyH10301, + KeyI40134, +}; + +const char* lfrfid_key_get_type_string(LfrfidKeyType type); +uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type); \ No newline at end of file diff --git a/applications/lf-rfid/helpers/rfid-reader.cpp b/applications/lf-rfid/helpers/rfid-reader.cpp index 73df7892..12b37acf 100644 --- a/applications/lf-rfid/helpers/rfid-reader.cpp +++ b/applications/lf-rfid/helpers/rfid-reader.cpp @@ -71,12 +71,12 @@ bool RfidReader::read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size) { bool result = false; if(decoder_em.read(data, data_size)) { - *type = LfrfidKeyType::KeyEmarine; + *type = LfrfidKeyType::KeyEM4100; result = true; } if(decoder_hid26.read(data, data_size)) { - *type = LfrfidKeyType::KeyHID; + *type = LfrfidKeyType::KeyH10301; result = true; } diff --git a/applications/lf-rfid/helpers/rfid-timer-emulator.cpp b/applications/lf-rfid/helpers/rfid-timer-emulator.cpp index 4fcd556f..07ad6ef5 100644 --- a/applications/lf-rfid/helpers/rfid-timer-emulator.cpp +++ b/applications/lf-rfid/helpers/rfid-timer-emulator.cpp @@ -6,7 +6,7 @@ RfidTimerEmulator::RfidTimerEmulator() { } RfidTimerEmulator::~RfidTimerEmulator() { - std::map::iterator it; + std::map::iterator it; for(it = encoders.begin(); it != encoders.end(); ++it) { delete it->second; @@ -14,38 +14,28 @@ RfidTimerEmulator::~RfidTimerEmulator() { } } -void RfidTimerEmulator::start(Type type) { +void RfidTimerEmulator::start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size) { if(encoders.count(type)) { current_encoder = encoders.find(type)->second; - uint8_t em_data[5] = {0x53, 0x00, 0x5F, 0xB3, 0xC2}; - uint8_t hid_data[3] = {0xED, 0x87, 0x70}; - uint8_t indala_data[3] = {0x1F, 0x2E, 0x3D}; - switch(type) { - case Type::EM: - current_encoder->init(em_data, 5); - break; - case Type::HID_H10301: - current_encoder->init(hid_data, 3); - break; - case Type::Indala_40134: - current_encoder->init(indala_data, 3); - break; + if(lfrfid_key_get_type_data_count(type) == data_size) { + current_encoder->init(data, data_size); + + api_hal_rfid_tim_emulate(125000); + api_hal_rfid_pins_emulate(); + + api_interrupt_add(timer_update_callback, InterruptTypeTimerUpdate, this); + + // TODO make api for interrupts priority + for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) { + HAL_NVIC_SetPriority(static_cast(i), 15, 0); + } + + HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); + + api_hal_rfid_tim_emulate_start(); } - - api_hal_rfid_tim_emulate(125000); - api_hal_rfid_pins_emulate(); - - api_interrupt_add(timer_update_callback, InterruptTypeTimerUpdate, this); - - for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) { - HAL_NVIC_SetPriority(static_cast(i), 15, 0); - } - - HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); - - api_hal_rfid_tim_emulate_start(); } else { // not found } diff --git a/applications/lf-rfid/helpers/rfid-timer-emulator.h b/applications/lf-rfid/helpers/rfid-timer-emulator.h index 2fc93894..2a4365b5 100644 --- a/applications/lf-rfid/helpers/rfid-timer-emulator.h +++ b/applications/lf-rfid/helpers/rfid-timer-emulator.h @@ -10,24 +10,18 @@ class RfidTimerEmulator { public: - enum class Type : uint8_t { - EM, - HID_H10301, - Indala_40134, - }; - RfidTimerEmulator(); ~RfidTimerEmulator(); - void start(Type type); + void start(LfrfidKeyType type, const uint8_t* data, uint8_t data_size); void stop(); private: EncoderGeneric* current_encoder = nullptr; - std::map encoders = { - {Type::EM, new EncoderEM()}, - {Type::HID_H10301, new EncoderHID_H10301()}, - {Type::Indala_40134, new EncoderIndala_40134()}, + std::map encoders = { + {LfrfidKeyType::KeyEM4100, new EncoderEM()}, + {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()}, + {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()}, }; PulseJoiner pulse_joiner; diff --git a/applications/lf-rfid/lf-rfid-cli.cpp b/applications/lf-rfid/lf-rfid-cli.cpp new file mode 100644 index 00000000..e7374308 --- /dev/null +++ b/applications/lf-rfid/lf-rfid-cli.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "helpers/rfid-reader.h" +#include "helpers/rfid-timer-emulator.h" + +void lfrfid_cli(Cli* cli, string_t args, void* context); + +// app cli function +extern "C" void lfrfid_cli_init() { + Cli* cli = static_cast(furi_record_open("cli")); + cli_add_command(cli, "rfid", lfrfid_cli, NULL); + furi_record_close("cli"); +} + +void lfrfid_cli_print_usage() { + printf("Usage:\r\n"); + printf("rfid read\r\n"); + printf("rfid \r\n"); + printf("\t 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("\t are hex-formatted\r\n"); +}; + +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; + } + + return result; +} + +void lfrfid_cli_read(Cli* cli) { + RfidReader reader; + reader.start(RfidReader::Type::Normal); + + static const uint8_t data_size = LFRFID_KEY_SIZE; + uint8_t data[data_size] = {0}; + LfrfidKeyType 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)) { + printf(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; + } + delay(100); + } + + printf("Reading stopped\r\n"); + reader.stop(); +} + +void lfrfid_cli_write(Cli* cli, string_t args) { + // TODO implement rfid write + printf("Not implemented :(\r\n"); +} + +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)) { + delay(100); + } + printf("Emulation stopped\r\n"); + emulator.stop(); + + string_clear(data); +} + +void lfrfid_cli(Cli* cli, string_t args, void* 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); + } 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); +} diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.cpp b/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.cpp index 50d96e7f..5f187d8e 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.cpp @@ -14,7 +14,7 @@ void LfrfidSceneEmulateEMMarine::on_enter(LfrfidApp* app) { popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop); view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup); - app->get_emulator()->start(RfidTimerEmulator::Type::EM); + app->get_emulator()->start(LfrfidKeyType::KeyEM4100, data, 5); } bool LfrfidSceneEmulateEMMarine::on_event(LfrfidApp* app, LfrfidEvent* event) { diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h b/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h index f4c0c4a7..8e4464f4 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h @@ -9,4 +9,5 @@ public: void on_exit(LfrfidApp* app) final; private: + const uint8_t data[5] = {0x53, 0x00, 0x5F, 0xB3, 0xC2}; }; \ No newline at end of file diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp b/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp index df62ce77..154a7e98 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp @@ -14,7 +14,7 @@ void LfrfidSceneEmulateHID::on_enter(LfrfidApp* app) { popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop); view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup); - app->get_emulator()->start(RfidTimerEmulator::Type::HID_H10301); + app->get_emulator()->start(LfrfidKeyType::KeyH10301, data, 3); } bool LfrfidSceneEmulateHID::on_event(LfrfidApp* app, LfrfidEvent* event) { diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h b/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h index 08c9da60..27476cb8 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h @@ -9,4 +9,5 @@ public: void on_exit(LfrfidApp* app) final; private: + const uint8_t data[3] = {0xED, 0x87, 0x70}; }; \ No newline at end of file diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp b/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp index 24288cf7..a750a3a7 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp @@ -14,7 +14,7 @@ void LfrfidSceneEmulateIndala::on_enter(LfrfidApp* app) { popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop); view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup); - app->get_emulator()->start(RfidTimerEmulator::Type::Indala_40134); + app->get_emulator()->start(LfrfidKeyType::KeyI40134, data, 3); } bool LfrfidSceneEmulateIndala::on_event(LfrfidApp* app, LfrfidEvent* event) { diff --git a/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h b/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h index 7506c017..7c804ccf 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h +++ b/applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h @@ -9,4 +9,5 @@ public: void on_exit(LfrfidApp* app) final; private: + const uint8_t data[3] = {0x1F, 0x2E, 0x3D}; }; \ No newline at end of file diff --git a/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp b/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp index f1c9f020..afe50e7c 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp @@ -35,7 +35,7 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) { } switch(type) { - case LfrfidKeyType::KeyEmarine: + case LfrfidKeyType::KeyEM4100: app->set_text_store( "[EM] %02X %02X %02X %02X %02X\n" "count: %u", @@ -46,7 +46,7 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) { data[4], success_reads); break; - case LfrfidKeyType::KeyHID: + case LfrfidKeyType::KeyH10301: app->set_text_store( "[HID26] %02X %02X %02X\n" "count: %u", @@ -55,7 +55,7 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) { data[2], success_reads); break; - case LfrfidKeyType::KeyIndala: + case LfrfidKeyType::KeyI40134: app->set_text_store( "[IND] %02X %02X %02X\n" "count: %u", diff --git a/applications/lf-rfid/scene/lf-rfid-scene-write.cpp b/applications/lf-rfid/scene/lf-rfid-scene-write.cpp index 9692d589..4e948d67 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-write.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-write.cpp @@ -38,7 +38,7 @@ bool LfrfidSceneWrite::on_event(LfrfidApp* app, LfrfidEvent* event) { LfrfidKeyType type; app->get_reader()->read(&type, data, LFRFID_KEY_SIZE); - if(type == LfrfidKeyType::KeyEmarine) { + if(type == LfrfidKeyType::KeyEM4100) { if(memcmp(em_data, data, 5) == 0) { readed = true; } diff --git a/lib/args/args.c b/lib/args/args.c new file mode 100644 index 00000000..e8953a86 --- /dev/null +++ b/lib/args/args.c @@ -0,0 +1,76 @@ +#include "args.h" + +size_t args_get_first_word_length(string_t args) { + size_t ws = string_search_char(args, ' '); + if(ws == STRING_FAILURE) { + ws = strlen(string_get_cstr(args)); + } + + return ws; +} + +size_t args_length(string_t args) { + return strlen(string_get_cstr(args)); +} + +bool args_read_string_and_trim(string_t args, string_t word) { + size_t cmd_length = args_get_first_word_length(args); + + if(cmd_length == 0) { + return false; + } + + string_set_n(word, args, 0, cmd_length); + string_right(args, cmd_length); + string_strim(args); + + return true; +} + +bool args_char_to_hex_nibble(char c, uint8_t* nibble) { + if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { + if((c >= '0' && c <= '9')) { + *nibble = c - '0'; + } else if((c >= 'A' && c <= 'F')) { + *nibble = c - 'A' + 10; + } else { + *nibble = c - 'a' + 10; + } + return true; + } else { + return false; + } +} + +bool args_char_to_hex(char hi_nibble, char low_nibble, uint8_t* byte) { + uint8_t hi_nibble_value = 0; + uint8_t low_nibble_value = 0; + bool result = false; + + if(args_char_to_hex_nibble(hi_nibble, &hi_nibble_value)) { + if(args_char_to_hex_nibble(low_nibble, &low_nibble_value)) { + result = true; + *byte = (hi_nibble_value << 4) | low_nibble_value; + } + } + + return result; +} + +bool args_read_hex_bytes(string_t args, uint8_t* bytes, uint8_t bytes_count) { + bool result = true; + const char* str_pointer = string_get_cstr(args); + + if(args_get_first_word_length(args) == (bytes_count * 2)) { + for(uint8_t i = 0; i < bytes_count; i++) { + if(!args_char_to_hex(str_pointer[i * 2], str_pointer[i * 2 + 1], &(bytes[i]))) { + result = false; + break; + } + } + } else { + result = false; + } + + return result; +} \ No newline at end of file diff --git a/lib/args/args.h b/lib/args/args.h new file mode 100644 index 00000000..699e2faa --- /dev/null +++ b/lib/args/args.h @@ -0,0 +1,70 @@ +#pragma once +#include "m-string.h" +#include "stdint.h" +#include "stdbool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Extract first word from arguments string and trim arguments string + * + * @param args arguments string + * @param word first word, output + * @return true - success + * @return false - arguments string does not contain anything + */ +bool args_read_string_and_trim(string_t args, string_t word); + +/** + * @brief Convert hex ASCII values to byte array + * + * @param args arguments string + * @param bytes byte array pointer, output + * @param bytes_count needed bytes count + * @return true - success + * @return false - arguments string does not contain enough values, or contain non-hex ASCII values + */ +bool args_read_hex_bytes(string_t args, uint8_t* bytes, uint8_t bytes_count); + +/************************************ HELPERS ***************************************/ + +/** + * @brief Get length of first word from arguments string + * + * @param args arguments string + * @return size_t length of first word + */ +size_t args_get_first_word_length(string_t args); + +/** + * @brief Get length of arguments string + * + * @param args arguments string + * @return size_t length of arguments string + */ +size_t args_length(string_t args); + +/** + * @brief Convert ASCII hex value to nibble + * + * @param c ASCII character + * @param nibble nibble pointer, output + * @return bool conversion status + */ +bool args_char_to_hex_nibble(char c, uint8_t* nibble); + +/** + * @brief Convert ASCII hex values to byte + * + * @param hi_nibble ASCII hi nibble character + * @param low_nibble ASCII low nibble character + * @param byte byte pointer, output + * @return bool conversion status + */ +bool args_char_to_hex(char hi_nibble, char low_nibble, uint8_t* byte); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/lib.mk b/lib/lib.mk index 119a6ebd..4276b24c 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -66,15 +66,6 @@ CFLAGS += -I$(LIB_DIR)/app-template CFLAGS += -I$(LIB_DIR)/fnv1a-hash C_SOURCES += $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c -# build onewire/cyfral library only if -# we build iButton application -ifeq ($(APP_IBUTTON), 1) -# onewire library -APP_ONEWIRE = 1 -endif - -APP_ONEWIRE ?= 0 -ifeq ($(APP_ONEWIRE), 1) # onewire library ONEWIRE_DIR = $(LIB_DIR)/onewire CFLAGS += -I$(ONEWIRE_DIR) @@ -84,7 +75,6 @@ CPP_SOURCES += $(wildcard $(ONEWIRE_DIR)/*.cpp) CYFRAL_DIR = $(LIB_DIR)/cyfral CFLAGS += -I$(CYFRAL_DIR) CPP_SOURCES += $(wildcard $(CYFRAL_DIR)/*.cpp) -endif # common apps api CFLAGS += -I$(LIB_DIR)/common-api @@ -101,3 +91,7 @@ C_SOURCES += $(LIB_DIR)/version/version.c CFLAGS += -I$(LIB_DIR)/irda C_SOURCES += $(wildcard $(LIB_DIR)/irda/*.c) C_SOURCES += $(wildcard $(LIB_DIR)/irda/*/*.c) + +#args lib +CFLAGS += -I$(LIB_DIR)/args +C_SOURCES += $(wildcard $(LIB_DIR)/args/*.c) \ No newline at end of file