Bläddra i källkod

[FL-1063} LF-RFID Cli (#515)

* App lfrfid: update emulator to process external data.
* App lfrfid: cleanup emulator
* App lfrfid: cli interface
* Lib: arguments parser lib

Co-authored-by: あく <alleteam@gmail.com>
SG 4 år sedan
förälder
incheckning
4ad5245969

+ 4 - 0
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

+ 33 - 0
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;
+}

+ 7 - 4
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,
-};
+    KeyEM4100,
+    KeyH10301,
+    KeyI40134,
+};
+
+const char* lfrfid_key_get_type_string(LfrfidKeyType type);
+uint8_t lfrfid_key_get_type_data_count(LfrfidKeyType type);

+ 2 - 2
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;
     }
 

+ 16 - 26
applications/lf-rfid/helpers/rfid-timer-emulator.cpp

@@ -6,7 +6,7 @@ RfidTimerEmulator::RfidTimerEmulator() {
 }
 
 RfidTimerEmulator::~RfidTimerEmulator() {
-    std::map<Type, EncoderGeneric*>::iterator it;
+    std::map<LfrfidKeyType, EncoderGeneric*>::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;
-        }
 
-        api_hal_rfid_tim_emulate(125000);
-        api_hal_rfid_pins_emulate();
+        if(lfrfid_key_get_type_data_count(type) == data_size) {
+            current_encoder->init(data, data_size);
 
-        api_interrupt_add(timer_update_callback, InterruptTypeTimerUpdate, this);
+            api_hal_rfid_tim_emulate(125000);
+            api_hal_rfid_pins_emulate();
 
-        for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) {
-            HAL_NVIC_SetPriority(static_cast<IRQn_Type>(i), 15, 0);
-        }
+            api_interrupt_add(timer_update_callback, InterruptTypeTimerUpdate, this);
 
-        HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0);
-        HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
+            // TODO make api for interrupts priority
+            for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) {
+                HAL_NVIC_SetPriority(static_cast<IRQn_Type>(i), 15, 0);
+            }
 
-        api_hal_rfid_tim_emulate_start();
+            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
     }

+ 5 - 11
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<Type, EncoderGeneric*> encoders = {
-        {Type::EM, new EncoderEM()},
-        {Type::HID_H10301, new EncoderHID_H10301()},
-        {Type::Indala_40134, new EncoderIndala_40134()},
+    std::map<LfrfidKeyType, EncoderGeneric*> encoders = {
+        {LfrfidKeyType::KeyEM4100, new EncoderEM()},
+        {LfrfidKeyType::KeyH10301, new EncoderHID_H10301()},
+        {LfrfidKeyType::KeyI40134, new EncoderIndala_40134()},
     };
 
     PulseJoiner pulse_joiner;

+ 142 - 0
applications/lf-rfid/lf-rfid-cli.cpp

@@ -0,0 +1,142 @@
+#include <furi.h>
+#include <api-hal.h>
+#include <stdarg.h>
+#include <cli/cli.h>
+#include <args.h>
+
+#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<Cli*>(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 <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("\t<key_data> 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);
+}

+ 1 - 1
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) {

+ 1 - 0
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};
 };

+ 1 - 1
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) {

+ 1 - 0
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};
 };

+ 1 - 1
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) {

+ 1 - 0
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};
 };

+ 3 - 3
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",

+ 1 - 1
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;
             }

+ 76 - 0
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;
+}

+ 70 - 0
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

+ 4 - 10
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)