Prechádzať zdrojové kódy

[FL-84] iButton app, dallas emulate + cyfral read, cyfral emulate (#253)

* maxim crc function
* one wire template device and ds1990 classes
* 3 fields for addr
* cyfral emulator lib
* add cyfral read mode, refract rendering and events
* add ADC1_IN14, add adc interrupt
* cyfral read mode
* rename and move api-hal includes folder
* build onewire libs only if we build app
* start in mode 0
DrZlo13 5 rokov pred
rodič
commit
1f761d7fbb
37 zmenil súbory, kde vykonal 1966 pridanie a 791 odobranie
  1. 69 3
      applications/ibutton/ibutton.cpp
  2. 24 3
      applications/ibutton/ibutton.h
  3. 55 0
      applications/ibutton/ibutton_mode_cyfral_emulate.h
  4. 53 0
      applications/ibutton/ibutton_mode_cyfral_read.h
  5. 22 25
      applications/ibutton/ibutton_mode_dallas_emulate.h
  6. 14 50
      applications/ibutton/ibutton_mode_dallas_read.h
  7. 0 177
      applications/ibutton/one_wire_slave_gpio.h
  8. 1 1
      firmware/Makefile
  9. 0 0
      firmware/targets/api-hal-include/api-hal-boot.h
  10. 0 0
      firmware/targets/api-hal-include/api-hal-delay.h
  11. 0 0
      firmware/targets/api-hal-include/api-hal-power.h
  12. 0 0
      firmware/targets/api-hal-include/api-hal-uid.h
  13. 0 0
      firmware/targets/api-hal-include/api-hal-vcp.h
  14. 0 0
      firmware/targets/api-hal-include/api-hal.h
  15. 1 0
      firmware/targets/f3/Inc/stm32wbxx_it.h
  16. 1 1
      firmware/targets/f3/Makefile
  17. 23 1
      firmware/targets/f3/Src/adc.c
  18. 15 0
      firmware/targets/f3/Src/stm32wbxx_it.c
  19. 1 1
      firmware/targets/f3/Src/tim.c
  20. 0 6
      firmware/targets/f3/api-hal/api-hal-delay.h
  21. 521 516
      firmware/targets/f3/f3.ioc
  22. 0 0
      firmware/targets/local/Inc/heap.h
  23. 0 6
      firmware/targets/local/api-hal/api-hal-delay.h
  24. 95 0
      lib/cyfral/cyfral_emulator.h
  25. 273 0
      lib/cyfral/cyfral_reader.h
  26. 15 1
      lib/lib.mk
  27. 48 0
      lib/onewire/maxim_crc.cpp
  28. 6 0
      lib/onewire/maxim_crc.h
  29. 26 0
      lib/onewire/one_wire_device.cpp
  30. 34 0
      lib/onewire/one_wire_device.h
  31. 27 0
      lib/onewire/one_wire_device_ds_1990.cpp
  32. 21 0
      lib/onewire/one_wire_device_ds_1990.h
  33. 0 0
      lib/onewire/one_wire_gpio.h
  34. 511 0
      lib/onewire/one_wire_slave_gpio.cpp
  35. 93 0
      lib/onewire/one_wire_slave_gpio.h
  36. 17 0
      lib/onewire/one_wire_timings.cpp
  37. 0 0
      lib/onewire/one_wire_timings.h

+ 69 - 3
applications/ibutton/ibutton.cpp

@@ -1,11 +1,15 @@
 #include "ibutton.h"
 #include "ibutton_mode_dallas_read.h"
 #include "ibutton_mode_dallas_emulate.h"
+#include "ibutton_mode_cyfral_read.h"
+#include "ibutton_mode_cyfral_emulate.h"
 
 // start app
 void AppiButton::run() {
     mode[0] = new AppiButtonModeDallasRead(this);
     mode[1] = new AppiButtonModeDallasEmulate(this);
+    mode[2] = new AppiButtonModeCyfralRead(this);
+    mode[3] = new AppiButtonModeCyfralEmulate(this);
 
     switch_to_mode(0);
 
@@ -21,7 +25,7 @@ void AppiButton::run() {
 
     AppiButtonEvent event;
     while(1) {
-        if(get_event(&event, 100)) {
+        if(get_event(&event, 20)) {
             if(event.type == AppiButtonEvent::EventTypeKey) {
                 // press events
                 if(event.value.input.state && event.value.input.input == InputBack) {
@@ -60,6 +64,46 @@ void AppiButton::render(CanvasApi* canvas) {
     mode[state.mode_index]->render(canvas, &state);
 }
 
+void AppiButton::render_dallas_list(CanvasApi* canvas, AppiButtonState* state) {
+    const uint8_t buffer_size = 50;
+    char buf[buffer_size];
+    for(uint8_t i = 0; i < state->dallas_address_count; i++) {
+        snprintf(
+            buf,
+            buffer_size,
+            "%s[%u] %x:%x:%x:%x:%x:%x:%x:%x",
+            (i == state->dallas_address_index) ? "> " : "",
+            i + 1,
+            state->dallas_address[i][0],
+            state->dallas_address[i][1],
+            state->dallas_address[i][2],
+            state->dallas_address[i][3],
+            state->dallas_address[i][4],
+            state->dallas_address[i][5],
+            state->dallas_address[i][6],
+            state->dallas_address[i][7]);
+        canvas->draw_str(canvas, 2, 37 + i * 12, buf);
+    }
+}
+
+void AppiButton::render_cyfral_list(CanvasApi* canvas, AppiButtonState* state) {
+    const uint8_t buffer_size = 50;
+    char buf[buffer_size];
+    for(uint8_t i = 0; i < state->cyfral_address_count; i++) {
+        snprintf(
+            buf,
+            buffer_size,
+            "%s[%u] %x:%x:%x:%x",
+            (i == state->cyfral_address_index) ? "> " : "",
+            i + 1,
+            state->cyfral_address[i][0],
+            state->cyfral_address[i][1],
+            state->cyfral_address[i][2],
+            state->cyfral_address[i][3]);
+        canvas->draw_str(canvas, 2, 37 + i * 12, buf);
+    }
+}
+
 void AppiButton::blink_red() {
     gpio_write(red_led_record, 0);
     delay(10);
@@ -92,12 +136,34 @@ void AppiButton::decrease_mode() {
     release_state();
 }
 
+void AppiButton::increase_dallas_address() {
+    if(state.dallas_address_index < (state.dallas_address_count - 1)) {
+        state.dallas_address_index++;
+    }
+}
+
+void AppiButton::decrease_dallas_address() {
+    if(state.dallas_address_index > 0) {
+        state.dallas_address_index--;
+    }
+}
+
+void AppiButton::increase_cyfral_address() {
+    if(state.cyfral_address_index < (state.cyfral_address_count - 1)) {
+        state.cyfral_address_index++;
+    }
+}
+
+void AppiButton::decrease_cyfral_address() {
+    if(state.cyfral_address_index > 0) {
+        state.cyfral_address_index--;
+    }
+}
+
 void AppiButton::switch_to_mode(uint8_t mode_index) {
-    acquire_state();
     mode[state.mode_index]->release();
     state.mode_index = mode_index;
     mode[state.mode_index]->acquire();
-    release_state();
 }
 
 // app enter function

+ 24 - 3
applications/ibutton/ibutton.h

@@ -8,13 +8,28 @@ typedef uint8_t event_t;
 class AppiButtonState {
 public:
     // state data
-    // test key = {0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB};
-    uint8_t dallas_address[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    static const uint8_t dallas_address_count = 3;
+    uint8_t dallas_address[dallas_address_count][8] = {
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+        {0x01, 0x41, 0xCE, 0x67, 0x0F, 0x00, 0x00, 0xB6},
+        {0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB}};
+
+    uint8_t dallas_address_index;
+
+    static const uint8_t cyfral_address_count = 3;
+    uint8_t cyfral_address[cyfral_address_count][4] = {
+        {0x00, 0x00, 0x00, 0x00},
+        {0xBB, 0xBB, 0x7B, 0xBD},
+        {0x7B, 0xDE, 0x7B, 0xDE}};
+    uint8_t cyfral_address_index;
+
     uint8_t mode_index;
 
     // state initializer
     AppiButtonState() {
         mode_index = 0;
+        dallas_address_index = 0;
+        cyfral_address_index = 0;
     }
 };
 
@@ -41,16 +56,22 @@ public:
     const GpioPin* red_led_record;
     const GpioPin* green_led_record;
 
-    static const uint8_t modes_count = 2;
+    static const uint8_t modes_count = 4;
     AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count];
 
     void run();
     void render(CanvasApi* canvas);
+    void render_dallas_list(CanvasApi* canvas, AppiButtonState* state);
+    void render_cyfral_list(CanvasApi* canvas, AppiButtonState* state);
 
     void blink_red();
     void blink_green();
 
     void increase_mode();
     void decrease_mode();
+    void increase_dallas_address();
+    void decrease_dallas_address();
+    void increase_cyfral_address();
+    void decrease_cyfral_address();
     void switch_to_mode(uint8_t mode_index);
 };

+ 55 - 0
applications/ibutton/ibutton_mode_cyfral_emulate.h

@@ -0,0 +1,55 @@
+#pragma once
+#include "ibutton.h"
+#include "cyfral_emulator.h"
+
+class AppiButtonModeCyfralEmulate : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+public:
+    const char* name = "cyfral emulate";
+    AppiButton* app;
+    CyfralEmulator* cyfral_emulator;
+
+    void event(AppiButtonEvent* event, AppiButtonState* state);
+    void render(CanvasApi* canvas, AppiButtonState* state);
+    void acquire();
+    void release();
+
+    AppiButtonModeCyfralEmulate(AppiButton* parent_app) {
+        app = parent_app;
+
+        // TODO open record
+        const GpioPin* one_wire_pin_record = &ibutton_gpio;
+        cyfral_emulator = new CyfralEmulator(one_wire_pin_record);
+    };
+};
+
+void AppiButtonModeCyfralEmulate::event(AppiButtonEvent* event, AppiButtonState* state) {
+    if(event->type == AppiButtonEvent::EventTypeTick) {
+        // repeat key sending 8 times
+        cyfral_emulator->send(state->cyfral_address[state->cyfral_address_index], 4, 8);
+        app->blink_green();
+
+    } else if(event->type == AppiButtonEvent::EventTypeKey) {
+        if(event->value.input.state && event->value.input.input == InputUp) {
+            app->decrease_cyfral_address();
+        }
+
+        if(event->value.input.state && event->value.input.input == InputDown) {
+            app->increase_cyfral_address();
+        }
+    }
+}
+
+void AppiButtonModeCyfralEmulate::render(CanvasApi* canvas, AppiButtonState* state) {
+    canvas->set_font(canvas, FontSecondary);
+    canvas->draw_str(canvas, 2, 25, "< Cyfral emulate");
+
+    app->render_cyfral_list(canvas, state);
+}
+
+void AppiButtonModeCyfralEmulate::acquire() {
+    cyfral_emulator->start();
+}
+
+void AppiButtonModeCyfralEmulate::release() {
+    cyfral_emulator->stop();
+}

+ 53 - 0
applications/ibutton/ibutton_mode_cyfral_read.h

@@ -0,0 +1,53 @@
+#pragma once
+#include "ibutton.h"
+#include "cyfral_reader.h"
+
+class AppiButtonModeCyfralRead : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+public:
+    const char* name = "cyfral read";
+    AppiButton* app;
+    CyfralReader* reader;
+
+    void event(AppiButtonEvent* event, AppiButtonState* state);
+    void render(CanvasApi* canvas, AppiButtonState* state);
+    void acquire();
+    void release();
+
+    AppiButtonModeCyfralRead(AppiButton* parent_app) {
+        app = parent_app;
+        reader = new CyfralReader(ADC1, ADC_CHANNEL_14);
+    };
+};
+
+void AppiButtonModeCyfralRead::event(AppiButtonEvent* event, AppiButtonState* state) {
+    if(event->type == AppiButtonEvent::EventTypeTick) {
+        uint8_t data[8];
+        if(reader->read(data, 4)) {
+            memcpy(app->state.cyfral_address[app->state.cyfral_address_index], data, 4);
+            app->blink_green();
+        }
+    } else if(event->type == AppiButtonEvent::EventTypeKey) {
+        if(event->value.input.state && event->value.input.input == InputUp) {
+            app->decrease_cyfral_address();
+        }
+
+        if(event->value.input.state && event->value.input.input == InputDown) {
+            app->increase_cyfral_address();
+        }
+    }
+}
+
+void AppiButtonModeCyfralRead::render(CanvasApi* canvas, AppiButtonState* state) {
+    canvas->set_font(canvas, FontSecondary);
+    canvas->draw_str(canvas, 2, 25, "< Cyfral read >");
+
+    app->render_cyfral_list(canvas, state);
+}
+
+void AppiButtonModeCyfralRead::acquire() {
+    reader->start();
+}
+
+void AppiButtonModeCyfralRead::release() {
+    reader->stop();
+}

+ 22 - 25
applications/ibutton/ibutton_mode_dallas_emulate.h

@@ -1,59 +1,56 @@
 #pragma once
 #include "ibutton.h"
 #include "one_wire_slave_gpio.h"
+#include "one_wire_device_ds_1990.h"
 
 class AppiButtonModeDallasEmulate : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
 public:
     const char* name = "dallas emulate";
     AppiButton* app;
     OneWireGpioSlave* onewire_slave;
+    DS1990 key;
 
     void event(AppiButtonEvent* event, AppiButtonState* state);
     void render(CanvasApi* canvas, AppiButtonState* state);
     void acquire();
     void release();
 
-    AppiButtonModeDallasEmulate(AppiButton* parent_app) {
+    AppiButtonModeDallasEmulate(AppiButton* parent_app)
+        : key(1, 2, 3, 4, 5, 6, 7) {
         app = parent_app;
 
         // TODO open record
         const GpioPin* one_wire_pin_record = &ibutton_gpio;
         onewire_slave = new OneWireGpioSlave(one_wire_pin_record);
+        onewire_slave->attach(key);
     };
 };
 
 void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* state) {
     if(event->type == AppiButtonEvent::EventTypeTick) {
-        app->blink_red();
-        /*if(onewire_slave->emulate(state->dallas_address, 8)) {
+        onewire_slave->detach(key);
+        memcpy(key.id_storage, state->dallas_address[state->dallas_address_index], 8);
+        onewire_slave->attach(key);
+
+        if(onewire_slave->emulate()) {
             app->blink_green();
-        } else {
-            
-        }*/
+        }
+    } else if(event->type == AppiButtonEvent::EventTypeKey) {
+        if(event->value.input.state && event->value.input.input == InputUp) {
+            app->decrease_dallas_address();
+        }
+
+        if(event->value.input.state && event->value.input.input == InputDown) {
+            app->increase_dallas_address();
+        }
     }
 }
 
 void AppiButtonModeDallasEmulate::render(CanvasApi* canvas, AppiButtonState* state) {
     canvas->set_font(canvas, FontSecondary);
-    canvas->draw_str(canvas, 2, 25, "< dallas emulate");
-    canvas->draw_str(canvas, 2, 37, "unimplemented");
-    {
-        const uint8_t buffer_size = 32;
-        char buf[buffer_size];
-        snprintf(
-            buf,
-            buffer_size,
-            "%x:%x:%x:%x:%x:%x:%x:%x",
-            state->dallas_address[0],
-            state->dallas_address[1],
-            state->dallas_address[2],
-            state->dallas_address[3],
-            state->dallas_address[4],
-            state->dallas_address[5],
-            state->dallas_address[6],
-            state->dallas_address[7]);
-        canvas->draw_str(canvas, 2, 50, buf);
-    }
+    canvas->draw_str(canvas, 2, 25, "< Dallas emulate >");
+
+    app->render_dallas_list(canvas, state);
 }
 
 void AppiButtonModeDallasEmulate::acquire() {

+ 14 - 50
applications/ibutton/ibutton_mode_dallas_read.h

@@ -1,6 +1,7 @@
 #pragma once
 #include "ibutton.h"
 #include "one_wire_gpio.h"
+#include "maxim_crc.h"
 
 class AppiButtonModeDallasRead : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
 public:
@@ -20,8 +21,6 @@ public:
         const GpioPin* one_wire_pin_record = &ibutton_gpio;
         onewire = new OneWireGpio(one_wire_pin_record);
     };
-
-    uint8_t crc_8(uint8_t* buffer, uint8_t count);
 };
 
 void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* state) {
@@ -48,67 +47,32 @@ void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* st
             }
             printf("\n");
 
-            printf("crc8: %x\n", crc_8(address, 7));
+            printf("crc8: %x\n", maxim_crc8(address, 7));
 
-            if(crc_8(address, 8) == 0) {
+            if(maxim_crc8(address, 8) == 0) {
                 printf("CRC valid\n");
-                memcpy(app->state.dallas_address, address, 8);
+                memcpy(app->state.dallas_address[app->state.dallas_address_index], address, 8);
                 app->blink_green();
             } else {
                 printf("CRC invalid\n");
             }
         } else {
         }
+    } else if(event->type == AppiButtonEvent::EventTypeKey) {
+        if(event->value.input.state && event->value.input.input == InputUp) {
+            app->decrease_dallas_address();
+        }
+
+        if(event->value.input.state && event->value.input.input == InputDown) {
+            app->increase_dallas_address();
+        }
     }
 }
 
 void AppiButtonModeDallasRead::render(CanvasApi* canvas, AppiButtonState* state) {
     canvas->set_font(canvas, FontSecondary);
-    canvas->draw_str(canvas, 2, 25, "dallas read >");
-    canvas->draw_str(canvas, 2, 37, "touch me, iButton");
-    {
-        const uint8_t buffer_size = 32;
-        char buf[buffer_size];
-        snprintf(
-            buf,
-            buffer_size,
-            "%x:%x:%x:%x:%x:%x:%x:%x",
-            state->dallas_address[0],
-            state->dallas_address[1],
-            state->dallas_address[2],
-            state->dallas_address[3],
-            state->dallas_address[4],
-            state->dallas_address[5],
-            state->dallas_address[6],
-            state->dallas_address[7]);
-        canvas->draw_str(canvas, 2, 50, buf);
-    }
-}
-
-uint8_t AppiButtonModeDallasRead::crc_8(uint8_t* buffer, uint8_t count) {
-    const uint8_t maxim_crc8_table[256] = {
-        0,   94,  188, 226, 97,  63,  221, 131, 194, 156, 126, 32,  163, 253, 31,  65,  157, 195,
-        33,  127, 252, 162, 64,  30,  95,  1,   227, 189, 62,  96,  130, 220, 35,  125, 159, 193,
-        66,  28,  254, 160, 225, 191, 93,  3,   128, 222, 60,  98,  190, 224, 2,   92,  223, 129,
-        99,  61,  124, 34,  192, 158, 29,  67,  161, 255, 70,  24,  250, 164, 39,  121, 155, 197,
-        132, 218, 56,  102, 229, 187, 89,  7,   219, 133, 103, 57,  186, 228, 6,   88,  25,  71,
-        165, 251, 120, 38,  196, 154, 101, 59,  217, 135, 4,   90,  184, 230, 167, 249, 27,  69,
-        198, 152, 122, 36,  248, 166, 68,  26,  153, 199, 37,  123, 58,  100, 134, 216, 91,  5,
-        231, 185, 140, 210, 48,  110, 237, 179, 81,  15,  78,  16,  242, 172, 47,  113, 147, 205,
-        17,  79,  173, 243, 112, 46,  204, 146, 211, 141, 111, 49,  178, 236, 14,  80,  175, 241,
-        19,  77,  206, 144, 114, 44,  109, 51,  209, 143, 12,  82,  176, 238, 50,  108, 142, 208,
-        83,  13,  239, 177, 240, 174, 76,  18,  145, 207, 45,  115, 202, 148, 118, 40,  171, 245,
-        23,  73,  8,   86,  180, 234, 105, 55,  213, 139, 87,  9,   235, 181, 54,  104, 138, 212,
-        149, 203, 41,  119, 244, 170, 72,  22,  233, 183, 85,  11,  136, 214, 52,  106, 43,  117,
-        151, 201, 74,  20,  246, 168, 116, 42,  200, 150, 21,  75,  169, 247, 182, 232, 10,  84,
-        215, 137, 107, 53};
-
-    uint8_t crc = 0;
-
-    while(count--) {
-        crc = maxim_crc8_table[(crc ^ *buffer++)];
-    }
-    return crc;
+    canvas->draw_str(canvas, 2, 25, "Dallas read >");
+    app->render_dallas_list(canvas, state);
 }
 
 void AppiButtonModeDallasRead::acquire() {

+ 0 - 177
applications/ibutton/one_wire_slave_gpio.h

@@ -1,177 +0,0 @@
-#pragma once
-#include "flipper.h"
-#include "flipper_v2.h"
-#include "one_wire_timings.h"
-
-class OneWireGpioSlave {
-private:
-    const GpioPin* gpio;
-
-public:
-    OneWireGpioSlave(const GpioPin* one_wire_gpio);
-    ~OneWireGpioSlave();
-    void start(void);
-    void stop(void);
-    bool emulate(uint8_t* buffer, uint8_t length);
-
-    bool check_reset(void);
-    bool show_presence(void);
-    bool receive_and_process_cmd(void);
-    bool receive(uint8_t* data, const uint8_t data_length);
-    bool receiveBit(void);
-
-    bool overdrive_mode = false;
-
-    OneWiteTimeType wait_while_gpio(volatile OneWiteTimeType retries, const bool pin_value);
-};
-
-OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) {
-    gpio = one_wire_gpio;
-}
-
-OneWireGpioSlave::~OneWireGpioSlave() {
-    stop();
-}
-
-void OneWireGpioSlave::start(void) {
-    gpio_init(gpio, GpioModeOutputOpenDrain);
-}
-
-void OneWireGpioSlave::stop(void) {
-    gpio_init(gpio, GpioModeAnalog);
-}
-
-bool OneWireGpioSlave::emulate(uint8_t* buffer, uint8_t length) {
-    if(!check_reset()) {
-        printf("reset error\n");
-        return false;
-    }
-
-    if(!show_presence()) {
-        printf("presence error\n");
-        return false;
-    }
-
-    if(!receive_and_process_cmd()) {
-        printf("receive_and_process_cmd error\n");
-        return false;
-    }
-
-    printf("ok\n");
-    return true;
-}
-
-OneWiteTimeType OneWireGpioSlave::wait_while_gpio(OneWiteTimeType time, const bool pin_value) {
-    uint32_t start = DWT->CYCCNT;
-    uint32_t time_ticks = time * (SystemCoreClock / 1000000.0f);
-
-    while(((DWT->CYCCNT - start) < time_ticks)) {
-        if(gpio_read(gpio) != pin_value) {
-            uint32_t time = (DWT->CYCCNT - start);
-            time /= (SystemCoreClock / 1000000.0f);
-            return time;
-        }
-    }
-
-    return 0;
-}
-
-bool OneWireGpioSlave::check_reset(void) {
-    while(gpio_read(gpio) == true) {
-    }
-
-    /*if(wait_while_gpio(OneWireEmulateTiming::RESET_TIMEOUT * 20, true) == 0) {
-        printf("RESET_TIMEOUT\n");
-        return false;
-    }*/
-
-    const OneWiteTimeType time_remaining =
-        wait_while_gpio(OneWireEmulateTiming::RESET_MAX[0], false);
-
-    if(time_remaining == 0) {
-        return false;
-    }
-
-    if(overdrive_mode && ((OneWireEmulateTiming::RESET_MAX[0] -
-                           OneWireEmulateTiming::RESET_MIN[0]) <= time_remaining)) {
-        // normal reset detected
-        overdrive_mode = false;
-    };
-
-    bool result = (time_remaining <= OneWireEmulateTiming::RESET_MAX[0]) &&
-                  time_remaining >= OneWireEmulateTiming::RESET_MIN[overdrive_mode];
-
-    return result;
-}
-
-bool OneWireGpioSlave::show_presence(void) {
-    wait_while_gpio(OneWireEmulateTiming::PRESENCE_TIMEOUT, true);
-    gpio_write(gpio, false);
-    delay_us(OneWireEmulateTiming::PRESENCE_MIN[overdrive_mode]);
-    gpio_write(gpio, true);
-    /*OneWiteTimeType wait_time = OneWireEmulateTiming::PRESENCE_MAX[overdrive_mode] -
-                                OneWireEmulateTiming::PRESENCE_MIN[overdrive_mode];
-    if(wait_while_gpio(wait_time, false) == 0) {
-        return false;
-    }*/
-
-    return true;
-}
-
-bool OneWireGpioSlave::receive_and_process_cmd(void) {
-    uint8_t cmd;
-    receive(&cmd, 1);
-    printf("cmd %x\n", cmd);
-    return false;
-}
-
-bool OneWireGpioSlave::receiveBit(void) {
-    // wait while bus is HIGH
-    OneWiteTimeType time = OneWireEmulateTiming::SLOT_MAX[overdrive_mode];
-    time = wait_while_gpio(time, true);
-    if(time == 0) {
-        printf("RESET_IN_PROGRESS\n");
-        return false;
-    }
-    /*while ((DIRECT_READ(pin_baseReg, pin_bitMask) == 0) && (--retries != 0));
-    if (retries == 0)
-    {
-        _error = Error::RESET_IN_PROGRESS;
-        return false;
-    }*/
-
-    // wait while bus is LOW
-    time = OneWireEmulateTiming::MSG_HIGH_TIMEOUT;
-    time = wait_while_gpio(time, false);
-    if(time == 0) {
-        printf("TIMEOUT_HIGH\n");
-        return false;
-    }
-    /*while ((DIRECT_READ(pin_baseReg, pin_bitMask) != 0) && (--retries != 0));
-    if (retries == 0)
-    {
-        _error = Error::AWAIT_TIMESLOT_TIMEOUT_HIGH;
-        return false;
-    }*/
-
-    // wait a specific time to do a read (data is valid by then), // first difference to inner-loop of write()
-    time = OneWireEmulateTiming::READ_MIN[overdrive_mode];
-    time = wait_while_gpio(time, true);
-    //while ((DIRECT_READ(pin_baseReg, pin_bitMask) == 0) && (--retries != 0));
-
-    return (time > 0);
-}
-
-bool OneWireGpioSlave::receive(uint8_t* data, const uint8_t data_length) {
-    uint8_t bytes_received = 0;
-    for(; bytes_received < data_length; ++bytes_received) {
-        uint8_t value = 0;
-
-        for(uint8_t bitMask = 0x01; bitMask != 0; bitMask <<= 1) {
-            if(receiveBit()) value |= bitMask;
-        }
-
-        data[bytes_received] = value;
-    }
-    return (bytes_received != data_length);
-}

+ 1 - 1
firmware/Makefile

@@ -14,7 +14,7 @@ include			$(PROJECT_ROOT)/lib/lib.mk
 TARGET			?= f2
 TARGET_DIR		= targets/$(TARGET)
 include			$(TARGET_DIR)/target.mk
-CFLAGS			+= -Itargets/Inc
+CFLAGS			+= -Itargets/api-hal-include
 
 include			$(PROJECT_ROOT)/make/git.mk
 include			$(PROJECT_ROOT)/make/toolchain.mk

+ 0 - 0
firmware/targets/Inc/api-hal-boot.h → firmware/targets/api-hal-include/api-hal-boot.h


+ 0 - 0
firmware/targets/f2/api-hal/api-hal-delay.h → firmware/targets/api-hal-include/api-hal-delay.h


+ 0 - 0
firmware/targets/Inc/api-hal-power.h → firmware/targets/api-hal-include/api-hal-power.h


+ 0 - 0
firmware/targets/Inc/api-hal-uid.h → firmware/targets/api-hal-include/api-hal-uid.h


+ 0 - 0
firmware/targets/Inc/api-hal-vcp.h → firmware/targets/api-hal-include/api-hal-vcp.h


+ 0 - 0
firmware/targets/Inc/api-hal.h → firmware/targets/api-hal-include/api-hal.h


+ 1 - 0
firmware/targets/f3/Inc/stm32wbxx_it.h

@@ -55,6 +55,7 @@ void UsageFault_Handler(void);
 void DebugMon_Handler(void);
 void EXTI1_IRQHandler(void);
 void EXTI2_IRQHandler(void);
+void ADC1_IRQHandler(void);
 void USB_LP_IRQHandler(void);
 void COMP_IRQHandler(void);
 void EXTI9_5_IRQHandler(void);

+ 1 - 1
firmware/targets/f3/Makefile

@@ -1,5 +1,5 @@
 ##########################################################################################################################
-# File automatically-generated by tool: [projectgenerator] version: [3.10.0-B14] date: [Thu Nov 05 17:53:24 MSK 2020] 
+# File automatically-generated by tool: [projectgenerator] version: [3.10.0-B14] date: [Mon Nov 23 12:04:48 VLAT 2020] 
 ##########################################################################################################################
 
 # ------------------------------------------------

+ 23 - 1
firmware/targets/f3/Src/adc.c

@@ -54,7 +54,7 @@ void MX_ADC1_Init(void)
   }
   /** Configure Regular Channel
   */
-  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
+  sConfig.Channel = ADC_CHANNEL_14;
   sConfig.Rank = ADC_REGULAR_RANK_1;
   sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
   sConfig.SingleDiff = ADC_SINGLE_ENDED;
@@ -70,6 +70,7 @@ void MX_ADC1_Init(void)
 void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
 {
 
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
   if(adcHandle->Instance==ADC1)
   {
   /* USER CODE BEGIN ADC1_MspInit 0 */
@@ -77,6 +78,19 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
   /* USER CODE END ADC1_MspInit 0 */
     /* ADC1 clock enable */
     __HAL_RCC_ADC_CLK_ENABLE();
+
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    /**ADC1 GPIO Configuration
+    PC5     ------> ADC1_IN14
+    */
+    GPIO_InitStruct.Pin = RFID_RF_IN_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct);
+
+    /* ADC1 interrupt Init */
+    HAL_NVIC_SetPriority(ADC1_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(ADC1_IRQn);
   /* USER CODE BEGIN ADC1_MspInit 1 */
 
   /* USER CODE END ADC1_MspInit 1 */
@@ -93,6 +107,14 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
   /* USER CODE END ADC1_MspDeInit 0 */
     /* Peripheral clock disable */
     __HAL_RCC_ADC_CLK_DISABLE();
+
+    /**ADC1 GPIO Configuration
+    PC5     ------> ADC1_IN14
+    */
+    HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin);
+
+    /* ADC1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(ADC1_IRQn);
   /* USER CODE BEGIN ADC1_MspDeInit 1 */
 
   /* USER CODE END ADC1_MspDeInit 1 */

+ 15 - 0
firmware/targets/f3/Src/stm32wbxx_it.c

@@ -57,6 +57,7 @@
 
 /* External variables --------------------------------------------------------*/
 extern PCD_HandleTypeDef hpcd_USB_FS;
+extern ADC_HandleTypeDef hadc1;
 extern COMP_HandleTypeDef hcomp1;
 extern TIM_HandleTypeDef htim1;
 extern TIM_HandleTypeDef htim2;
@@ -193,6 +194,20 @@ void EXTI2_IRQHandler(void)
   /* USER CODE END EXTI2_IRQn 1 */
 }
 
+/**
+  * @brief This function handles ADC1 global interrupt.
+  */
+void ADC1_IRQHandler(void)
+{
+  /* USER CODE BEGIN ADC1_IRQn 0 */
+
+  /* USER CODE END ADC1_IRQn 0 */
+  HAL_ADC_IRQHandler(&hadc1);
+  /* USER CODE BEGIN ADC1_IRQn 1 */
+
+  /* USER CODE END ADC1_IRQn 1 */
+}
+
 /**
   * @brief This function handles USB low priority interrupt, USB wake-up interrupt through EXTI line 28.
   */

+ 1 - 1
firmware/targets/f3/Src/tim.c

@@ -238,7 +238,7 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
     HAL_GPIO_Init(IR_RX_GPIO_Port, &GPIO_InitStruct);
 
     /* TIM2 interrupt Init */
-    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
+    HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
     HAL_NVIC_EnableIRQ(TIM2_IRQn);
   /* USER CODE BEGIN TIM2_MspInit 1 */
 

+ 0 - 6
firmware/targets/f3/api-hal/api-hal-delay.h

@@ -1,6 +0,0 @@
-#pragma once
-#include "main.h"
-
-void delay(float milliseconds);
-void delay_us(float microseconds);
-void delay_us_init_DWT(void);

+ 521 - 516
firmware/targets/f3/f3.ioc

@@ -1,560 +1,565 @@
 #MicroXplorer Configuration settings - do not modify
-PA11.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-PB13.GPIOParameters=GPIO_Label
-RCC.USART1Freq_Value=64000000
-RF1.Locked=true
-SPI1.VirtualType=VM_MASTER
-PB10.GPIO_PuPd=GPIO_PULLUP
-RF1.Signal=RF_RF1
-SPI2.VirtualType=VM_MASTER
-VP_ADC1_TempSens_Input.Mode=IN-TempSens
-PC12.Locked=true
-TIM1.IPParameters=Channel-Output Compare1 CH1N,Channel-PWM Generation3 CH3N
-PC12.Signal=GPIO_Output
-PB14.GPIO_Label=iBTN
-PC6.GPIO_Label=DISPLAY_DI
-VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
-RCC.RTCFreq_Value=32768
-PA3.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
-PA6.GPIO_Label=PA6
+ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_14
+ADC1.ContinuousConvMode=DISABLE
+ADC1.EnableAnalogWatchDog1=false
+ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master,EnableAnalogWatchDog1,ContinuousConvMode
+ADC1.NbrOfConversionFlag=1
+ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
+ADC1.Rank-0\#ChannelRegularConversion=1
+ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_2CYCLES_5
+ADC1.master=1
 COMP1.Hysteresis=COMP_HYSTERESIS_HIGH
-PD0.Locked=true
-PC5.Mode=INP
-VP_COMP1_VS_VREFINT14.Signal=COMP1_VS_VREFINT14
-USART1.IPParameters=VirtualMode-Asynchronous
-PA3.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PB13.Signal=TIM1_CH1N
-PA2.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
-PC15-OSC32_OUT.GPIO_Label=QUARTZ_32MHZ_OUT
-PinOutPanel.RotationAngle=0
-RCC.MCO1PinFreq_Value=64000000
-RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
-SH.GPXTI13.0=GPIO_EXTI13
-RCC.LPTIM1Freq_Value=64000000
-NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
-FREERTOS.configENABLE_FPU=1
-NVIC.EXTI1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
-SH.S_TIM16_CH1.ConfNb=1
-SPI1.Direction=SPI_DIRECTION_2LINES
-TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICPolarity_CH1,AutoReloadPreload,Prescaler,Channel-Input_Capture2_from_TI1
-RCC.APB2TimFreq_Value=64000000
-PCC.Ble.PowerLevel=Min
+COMP1.IPParameters=TriggerMode,Hysteresis,Mode
 COMP1.Mode=COMP_POWERMODE_MEDIUMSPEED
-PB6.Signal=USART1_TX
-PB6.Mode=Asynchronous
-SPI1.CalculateBaudRate=4.0 MBits/s
-PC3.Signal=GPIO_Analog
-PD0.Signal=GPIO_Output
-VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
-RCC.PREFETCH_ENABLE=1
-PB13.Locked=true
-NVIC.EXTI15_10_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
-ProjectManager.ProjectBuild=false
-NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
-PB2.Signal=GPIO_Analog
-PB3.Mode=Full_Duplex_Master
-PH3-BOOT0.Locked=true
-PA8.Locked=true
-PD1.GPIOParameters=GPIO_Label
-RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
-SH.GPXTI12.0=GPIO_EXTI12
-PD1.GPIO_Label=SPI_D_SCK
-PB12.GPIO_Label=BUTTON_RIGHT
-ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.9.0
-VP_ADC1_Vref_Input.Mode=IN-Vrefint
-MxDb.Version=DB.6.0.0
-PB0.GPIOParameters=GPIO_Label
-PA1.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
-ProjectManager.BackupPrevious=false
-VP_SYS_VS_tim17.Signal=SYS_VS_tim17
-PC4.GPIO_Label=CC1101_G0
-FREERTOS.HEAP_NUMBER=4
-PB1.GPIO_Label=BUTTON_DOWN
-NVIC.TIM2_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
-SPI1.DataSize=SPI_DATASIZE_8BIT
-PE4.GPIO_Label=NFC_CS
-SPI2.CalculateBaudRate=4.0 MBits/s
-PA8.Signal=GPXTI8
-RCC.PLLRCLKFreq_Value=64000000
-SH.GPXTI11.ConfNb=1
-PB6.Locked=true
-NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
-ProjectManager.HalAssertFull=false
-ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_2CYCLES_5
-VP_TIM1_VS_ClockSourceINT.Mode=Internal
-TIM16.Pulse=145
-PA0.Signal=S_TIM2_CH1
-PH3-BOOT0.Signal=GPIO_Analog
-NVIC.HSEM_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true
-PB9.Signal=TIM1_CH3N
-Mcu.Package=VFQFPN68
-TIM2.Prescaler=64-1
-PB1.Signal=GPXTI1
-NVIC.TimeBase=TIM1_TRG_COM_TIM17_IRQn
-SPI2.Mode=SPI_MODE_MASTER
-PA2.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
-SH.GPXTI11.0=GPIO_EXTI11
-SH.GPXTI8.0=GPIO_EXTI8
-PA14.Locked=true
-SH.GPXTI8.ConfNb=1
-NVIC.TimeBaseIP=TIM17
-RCC.LSCOPinFreq_Value=32000
-PA10.Signal=I2C1_SDA
-VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar
+COMP1.TriggerMode=COMP_TRIGGERMODE_IT_RISING_FALLING
 FREERTOS.FootprintOK=true
-PA1.PinState=GPIO_PIN_SET
-PA5.GPIOParameters=GPIO_Label
-NVIC.USB_LP_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true
-PB14.GPIOParameters=GPIO_Label
-VP_HSEM_VS_HSEM.Mode=HSEM_Activate
-NVIC.EXTI2_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
-RCC.PLLPoutputFreq_Value=64000000
-RCC.APB1TimFreq_Value=64000000
-FREERTOS.configGENERATE_RUN_TIME_STATS=1
-NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
-RCC.LPUART1Freq_Value=64000000
-PB10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-PB13.Mode=Output Compare1 CH1N
-TIM16.Prescaler=500 - 1
-PC15-OSC32_OUT.GPIOParameters=GPIO_Label
-I2C1.CustomTiming=Disabled
-PA4.GPIO_Label=PA4
-ProjectManager.CustomerFirmwarePackage=
-PC4.GPIOParameters=GPIO_Label
-RCC.HSI48_VALUE=48000000
-PC2.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-PA6.GPIOParameters=GPIO_Label
-SH.GPXTI10.0=GPIO_EXTI10
-PCC.Ble.Mode=NOT_SELECTED
-RCC.PLLQoutputFreq_Value=64000000
-ProjectManager.ProjectFileName=f3.ioc
-RCC.SMPSFreq_Value=8000000
-PA3.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
+FREERTOS.HEAP_NUMBER=4
+FREERTOS.IPParameters=Tasks01,configTOTAL_HEAP_SIZE,HEAP_NUMBER,configUSE_TIMERS,configUSE_IDLE_HOOK,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,configRECORD_STACK_HIGH_ADDRESS,configGENERATE_RUN_TIME_STATS,configENABLE_FPU
 FREERTOS.Tasks01=defaultTask,24,1024,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;app_main,8,1024,app,As external,NULL,Dynamic,NULL,NULL
-ADC1.Rank-0\#ChannelRegularConversion=1
-PA15.GPIOParameters=GPIO_PuPd,GPIO_Label
-Mcu.PinsNb=64
-PC11.Locked=true
-VP_SYS_VS_tim17.Mode=TIM17
-ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,NbrOfConversionFlag,master
-PC13.Locked=true
-ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
-RCC.HCLK3Freq_Value=64000000
-PA9.GPIO_Label=I2C_SCL
-PC13.Signal=GPXTI13
 FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1
-PC2.Signal=GPXTI2
-PC6.Signal=GPIO_Output
-PB11.GPIO_Label=BUTTON_LEFT
-PD1.Signal=SPI2_SCK
-SH.S_TIM16_CH1.0=TIM16_CH1,PWM Generation1 CH1
-VP_TIM16_VS_ClockSourceINT.Mode=Enable_Timer
-SPI1.CLKPhase=SPI_PHASE_2EDGE
-OSC_IN.Locked=true
-RCC.HCLK2Freq_Value=32000000
-PC0.Signal=GPIO_Analog
-PC14-OSC32_IN.Signal=RCC_OSC32_IN
-PC11.GPIOParameters=PinState,GPIO_Label
-Mcu.Pin62=VP_TIM16_VS_ClockSourceINT
-Mcu.Pin63=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
-Mcu.Pin60=VP_TIM1_VS_ClockSourceINT
-Mcu.Pin61=VP_TIM2_VS_ClockSourceINT
-PD0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-PC3.GPIOParameters=GPIO_Label
-PB8.GPIO_Label=SPEAKER
-PA11.Locked=true
-PA15.Locked=true
-PA8.GPIO_Label=RFID_PULL
-PC15-OSC32_OUT.Locked=true
-Mcu.Pin59=VP_SYS_VS_tim17
-SH.GPXTI2.ConfNb=1
-Mcu.Pin57=VP_RTC_VS_RTC_Activate
-Mcu.Pin58=VP_RTC_VS_RTC_Calendar
-PC12.PinState=GPIO_PIN_SET
-USB_DEVICE.PRODUCT_STRING_CDC_FS=Flipper Control Virtual ComPort
-Mcu.Pin51=PB7
-Mcu.Pin52=VP_ADC1_TempSens_Input
-Mcu.Pin50=PB6
-Mcu.Pin55=VP_FREERTOS_VS_CMSIS_V2
-Mcu.Pin56=VP_HSEM_VS_HSEM
-Mcu.Pin53=VP_ADC1_Vref_Input
-Mcu.Pin54=VP_COMP1_VS_VREFINT14
-PC6.Locked=true
-PA9.Signal=I2C1_SCL
-VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
+FREERTOS.configENABLE_FPU=1
+FREERTOS.configGENERATE_RUN_TIME_STATS=1
+FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1
+FREERTOS.configTOTAL_HEAP_SIZE=40960
+FREERTOS.configUSE_IDLE_HOOK=1
+FREERTOS.configUSE_TIMERS=1
+File.Version=6
+GPIO.groupedBy=Show All
+I2C1.CustomTiming=Disabled
+I2C1.IPParameters=Timing,CustomTiming
 I2C1.Timing=0x10707DBC
-PB11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-PB9.Locked=true
-PB5.Locked=true
-OSC_IN.Signal=RCC_OSC_IN
-Mcu.Pin48=PB4
-Mcu.Pin49=PB5
-RCC.PLLSAI1PoutputFreq_Value=48000000
-Mcu.Pin46=PD1
-Mcu.Pin47=PB3
-PB10.Signal=GPXTI10
-PB14.Signal=GPIO_Analog
-PA5.Signal=GPIO_Analog
+KeepUserPlacement=false
+Mcu.Family=STM32WB
+Mcu.IP0=ADC1
+Mcu.IP1=COMP1
+Mcu.IP10=SPI2
+Mcu.IP11=SYS
+Mcu.IP12=TIM1
+Mcu.IP13=TIM2
+Mcu.IP14=TIM16
+Mcu.IP15=USART1
+Mcu.IP16=USB
+Mcu.IP17=USB_DEVICE
+Mcu.IP2=FREERTOS
+Mcu.IP3=HSEM
+Mcu.IP4=I2C1
+Mcu.IP5=NVIC
+Mcu.IP6=RCC
+Mcu.IP7=RF
+Mcu.IP8=RTC
+Mcu.IP9=SPI1
+Mcu.IPNb=18
+Mcu.Name=STM32WB55RGVx
+Mcu.Package=VFQFPN68
+Mcu.Pin0=PC13
+Mcu.Pin1=PC14-OSC32_IN
+Mcu.Pin10=PA0
+Mcu.Pin11=PA1
+Mcu.Pin12=PA2
+Mcu.Pin13=PA3
+Mcu.Pin14=PA4
+Mcu.Pin15=PA5
+Mcu.Pin16=PA6
+Mcu.Pin17=PA7
+Mcu.Pin18=PA8
+Mcu.Pin19=PA9
+Mcu.Pin2=PC15-OSC32_OUT
+Mcu.Pin20=PC4
+Mcu.Pin21=PC5
+Mcu.Pin22=PB2
+Mcu.Pin23=PB10
+Mcu.Pin24=PB11
+Mcu.Pin25=RF1
+Mcu.Pin26=OSC_OUT
+Mcu.Pin27=OSC_IN
+Mcu.Pin28=PB0
+Mcu.Pin29=PB1
+Mcu.Pin3=PH3-BOOT0
+Mcu.Pin30=PE4
+Mcu.Pin31=PB12
+Mcu.Pin32=PB13
+Mcu.Pin33=PB14
+Mcu.Pin34=PB15
+Mcu.Pin35=PC6
+Mcu.Pin36=PA10
+Mcu.Pin37=PA11
+Mcu.Pin38=PA12
+Mcu.Pin39=PA13
+Mcu.Pin4=PB8
 Mcu.Pin40=PA14
 Mcu.Pin41=PA15
-Mcu.Pin44=PC12
-Mcu.Pin45=PD0
 Mcu.Pin42=PC10
 Mcu.Pin43=PC11
-RCC.Cortex2Freq_Value=32000000
-ProjectManager.LastFirmware=true
-PD1.Mode=TX_Only_Simplex_Unidirect_Master
-Mcu.Pin37=PA11
-PB4.GPIO_Label=SPI_R_MISO
-PCC.Ble.DataLength=6
-Mcu.Pin38=PA12
-Mcu.Pin35=PC6
-PB15.GPIO_Label=SPI_D_MOSI
-RCC.I2C1Freq_Value=64000000
-Mcu.Pin36=PA10
-SPI1.Mode=SPI_MODE_MASTER
-Mcu.Pin39=PA13
-RCC.LCDFreq_Value=32768
-RCC.RNGFreq_Value=32000
-PC2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input
-Mcu.Pin30=PE4
+Mcu.Pin44=PC12
+Mcu.Pin45=PD0
+Mcu.Pin46=PD1
+Mcu.Pin47=PB3
+Mcu.Pin48=PB4
+Mcu.Pin49=PB5
+Mcu.Pin5=PB9
+Mcu.Pin50=PB6
+Mcu.Pin51=PB7
+Mcu.Pin52=VP_ADC1_TempSens_Input
+Mcu.Pin53=VP_ADC1_Vref_Input
+Mcu.Pin54=VP_COMP1_VS_VREFINT14
+Mcu.Pin55=VP_FREERTOS_VS_CMSIS_V2
+Mcu.Pin56=VP_HSEM_VS_HSEM
+Mcu.Pin57=VP_RTC_VS_RTC_Activate
+Mcu.Pin58=VP_RTC_VS_RTC_Calendar
+Mcu.Pin59=VP_SYS_VS_tim17
+Mcu.Pin6=PC0
+Mcu.Pin60=VP_TIM1_VS_ClockSourceINT
+Mcu.Pin61=VP_TIM2_VS_ClockSourceINT
+Mcu.Pin62=VP_TIM16_VS_ClockSourceINT
+Mcu.Pin63=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
+Mcu.Pin7=PC1
+Mcu.Pin8=PC2
+Mcu.Pin9=PC3
+Mcu.PinsNb=64
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32WB55RGVx
+MxCube.Version=6.0.1
+MxDb.Version=DB.6.0.0
+NVIC.ADC1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
 NVIC.COMP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true
-PA1.GPIO_Label=LED_RED
-Mcu.Pin33=PB14
-Mcu.Pin34=PB15
-Mcu.Pin31=PB12
-Mcu.Pin32=PB13
-PA9.Locked=true
-VP_TIM16_VS_ClockSourceINT.Signal=TIM16_VS_ClockSourceINT
-NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
-PC10.GPIOParameters=GPIO_Label
-PA13.Mode=Serial_Wire
-ProjectManager.FreePins=false
-PB10.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-RCC.LPTIM2Freq_Value=64000000
-Mcu.Pin26=OSC_OUT
-Mcu.Pin27=OSC_IN
-Mcu.Pin24=PB11
-ProjectManager.UnderRoot=false
-Mcu.Pin25=RF1
-Mcu.Pin28=PB0
-Mcu.Pin29=PB1
-PB4.Locked=true
-PA4.Signal=GPIO_Analog
-Mcu.Pin22=PB2
-PB5.Signal=SPI1_MOSI
-Mcu.Pin23=PB10
-Mcu.Pin20=PC4
-ADC1.master=1
-PA3.Locked=true
-Mcu.Pin21=PC5
-PA5.GPIO_Label=PA5
-PA10.Locked=true
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
+NVIC.EXTI15_10_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+NVIC.EXTI1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+NVIC.EXTI2_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
 NVIC.ForceEnableDMAVector=true
-OSC_IN.Mode=HSE-External-Oscillator
-NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
-PC12.GPIO_Label=SD_CS
-ProjectManager.CompilerOptimize=6
-PA11.Signal=USB_DM
-ProjectManager.HeapSize=0x200
-PA0.GPIOParameters=GPIO_Label
-Mcu.Pin15=PA5
+NVIC.HSEM_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true
 NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
-Mcu.Pin16=PA6
-Mcu.Pin13=PA3
-Mcu.Pin14=PA4
-Mcu.Pin19=PA9
-ProjectManager.ComputerToolchain=false
-Mcu.Pin17=PA7
-Mcu.Pin18=PA8
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
 NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
-Mcu.Pin11=PA1
-Mcu.Pin12=PA2
-PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
-Mcu.Pin10=PA0
-SH.GPXTI10.ConfNb=1
-USB_DEVICE.APP_RX_DATA_SIZE=512
-TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
-PC3.GPIO_Label=PC3
-PA3.PinState=GPIO_PIN_SET
-PE4.PinState=GPIO_PIN_SET
-RCC.PWRFreq_Value=64000000
-SPI2.DataSize=SPI_DATASIZE_8BIT
-SH.GPXTI1.ConfNb=1
-PB12.GPIO_PuPd=GPIO_PULLUP
-PD1.Locked=true
-PB0.Signal=GPIO_Output
-PA7.GPIOParameters=GPIO_Label
-PC1.Signal=GPIO_Analog
-PB12.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-Mcu.Family=STM32WB
-SH.GPXTI1.0=GPIO_EXTI1
-ProjectManager.MainLocation=Src
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.SavedPendsvIrqHandlerGenerated=false
+NVIC.SavedSvcallIrqHandlerGenerated=false
+NVIC.SavedSystickIrqHandlerGenerated=true
+NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.TIM1_TRG_COM_TIM17_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
+NVIC.TIM2_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+NVIC.TimeBase=TIM1_TRG_COM_TIM17_IRQn
+NVIC.TimeBaseIP=TIM17
+NVIC.USB_LP_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
+OSC_IN.GPIOParameters=GPIO_Label
+OSC_IN.GPIO_Label=QUARTZ_32KHZ_IN
+OSC_IN.Locked=true
+OSC_IN.Mode=HSE-External-Oscillator
+OSC_IN.Signal=RCC_OSC_IN
+OSC_OUT.GPIOParameters=GPIO_Label
 OSC_OUT.GPIO_Label=QUARTZ_32KHZ_OUT
-USB_DEVICE.CLASS_NAME_FS=CDC
-RCC.SAI1Freq_Value=48000000
-RCC.CortexFreq_Value=64000000
-TIM2.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1
-ProjectManager.KeepUserCode=true
-Mcu.UserName=STM32WB55RGVx
-RCC.RFWKPFreq_Value=976.5625
-PC10.Signal=GPIO_Analog
-RCC.PLLSAI1RoutputFreq_Value=48000000
-PC5.Locked=true
+OSC_OUT.Locked=true
+OSC_OUT.Mode=HSE-External-Oscillator
+OSC_OUT.Signal=RCC_OSC_OUT
+PA0.GPIOParameters=GPIO_Label
 PA0.GPIO_Label=IR_RX
-PA12.GPIOParameters=GPIO_Speed
-ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_I2C1_Init-I2C1-false-HAL-true,5-MX_RTC_Init-RTC-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_SPI2_Init-SPI2-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_USB_Device_Init-USB_DEVICE-false-HAL-false,10-MX_TIM1_Init-TIM1-false-HAL-true,11-MX_TIM2_Init-TIM2-false-HAL-true,12-MX_TIM16_Init-TIM16-false-HAL-true,13-MX_COMP1_Init-COMP1-false-HAL-true,14-MX_RF_Init-RF-false-HAL-true,0-MX_HSEM_Init-HSEM-false-HAL-true
-PC0.GPIOParameters=GPIO_Label
-PA9.GPIOParameters=GPIO_Speed,GPIO_Label
-PA2.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-PH3-BOOT0.GPIO_Label=BOOT0
+PA0.Signal=S_TIM2_CH1
+PA1.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
+PA1.GPIO_Label=LED_RED
+PA1.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
+PA1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA1.Locked=true
+PA1.PinState=GPIO_PIN_SET
+PA1.Signal=GPIO_Output
+PA10.GPIOParameters=GPIO_Speed,GPIO_Label
+PA10.GPIO_Label=I2C_SDA
+PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA10.Locked=true
+PA10.Mode=I2C
+PA10.Signal=I2C1_SDA
 PA11.GPIOParameters=GPIO_Speed
-PD0.GPIO_Label=CC1101_CS
-PC0.GPIO_Label=PC0
+PA11.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA11.Locked=true
 PA11.Mode=Device
+PA11.Signal=USB_DM
+PA12.GPIOParameters=GPIO_Speed
+PA12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA12.Locked=true
+PA12.Mode=Device
+PA12.Signal=USB_DP
+PA13.Locked=true
+PA13.Mode=Serial_Wire
+PA13.Signal=SYS_JTMS-SWDIO
+PA14.Locked=true
+PA14.Mode=Serial_Wire
+PA14.Signal=SYS_JTCK-SWCLK
+PA15.GPIOParameters=GPIO_PuPd,GPIO_Label
+PA15.GPIO_Label=DISPLAY_BACKLIGHT
+PA15.GPIO_PuPd=GPIO_PULLDOWN
+PA15.Locked=true
+PA15.Signal=GPIO_Output
+PA2.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
+PA2.GPIO_Label=LED_GREEN
+PA2.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
+PA2.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA2.Locked=true
+PA2.PinState=GPIO_PIN_SET
+PA2.Signal=GPIO_Output
+PA3.GPIOParameters=GPIO_Speed,PinState,GPIO_Label,GPIO_ModeDefaultOutputPP
+PA3.GPIO_Label=LED_BLUE
+PA3.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
+PA3.GPIO_Speed=GPIO_SPEED_FREQ_LOW
+PA3.Locked=true
+PA3.PinState=GPIO_PIN_SET
+PA3.Signal=GPIO_Output
+PA4.GPIOParameters=GPIO_Label
+PA4.GPIO_Label=PA4
+PA4.Signal=GPIO_Analog
+PA5.GPIOParameters=GPIO_Label
+PA5.GPIO_Label=PA5
+PA5.Signal=GPIO_Analog
+PA6.GPIOParameters=GPIO_Label
+PA6.GPIO_Label=PA6
+PA6.Signal=GPIO_Analog
+PA7.GPIOParameters=GPIO_Label
+PA7.GPIO_Label=PA7
+PA7.Signal=GPIO_Analog
+PA8.GPIOParameters=GPIO_Label
+PA8.GPIO_Label=RFID_PULL
+PA8.Locked=true
+PA8.Signal=GPXTI8
+PA9.GPIOParameters=GPIO_Speed,GPIO_Label
+PA9.GPIO_Label=I2C_SCL
+PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PA9.Locked=true
+PA9.Mode=I2C
+PA9.Signal=I2C1_SCL
+PB0.GPIOParameters=GPIO_Label
 PB0.GPIO_Label=DISPLAY_RST
-VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar
+PB0.Locked=true
+PB0.Signal=GPIO_Output
+PB1.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PB1.GPIO_Label=BUTTON_DOWN
+PB1.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
+PB1.GPIO_PuPd=GPIO_PULLUP
+PB1.Locked=true
+PB1.Signal=GPXTI1
+PB10.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PB10.GPIO_Label=BUTTON_UP
+PB10.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
+PB10.GPIO_PuPd=GPIO_PULLUP
+PB10.Locked=true
+PB10.Signal=GPXTI10
+PB11.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PB11.GPIO_Label=BUTTON_LEFT
+PB11.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
 PB11.GPIO_PuPd=GPIO_PULLUP
-PC13.GPIO_Label=BUTTON_BACK
-PB13.GPIO_Label=RFID_OUT
+PB11.Locked=true
 PB11.Signal=GPXTI11
+PB12.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PB12.GPIO_Label=BUTTON_RIGHT
+PB12.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
+PB12.GPIO_PuPd=GPIO_PULLUP
+PB12.Locked=true
+PB12.Signal=GPXTI12
+PB13.GPIOParameters=GPIO_Label
+PB13.GPIO_Label=RFID_OUT
+PB13.Locked=true
+PB13.Mode=Output Compare1 CH1N
+PB13.Signal=TIM1_CH1N
+PB14.GPIOParameters=GPIO_Label
+PB14.GPIO_Label=iBTN
+PB14.Signal=GPIO_Analog
+PB15.GPIOParameters=GPIO_Label
+PB15.GPIO_Label=SPI_D_MOSI
+PB15.Locked=true
+PB15.Mode=TX_Only_Simplex_Unidirect_Master
 PB15.Signal=SPI2_MOSI
-OSC_OUT.GPIOParameters=GPIO_Label
-ProjectManager.StackSize=0x400
-PB5.GPIOParameters=GPIO_Label
-VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
-SH.GPXTI2.0=GPIO_EXTI2
-RCC.I2C3Freq_Value=64000000
-Mcu.IP4=I2C1
-Mcu.IP5=NVIC
-RCC.FCLKCortexFreq_Value=64000000
-USB_DEVICE.MANUFACTURER_STRING=Flipper
-Mcu.IP2=FREERTOS
-I2C1.IPParameters=Timing,CustomTiming
-Mcu.IP3=HSEM
-Mcu.IP0=ADC1
+PB2.GPIOParameters=GPIO_Label
+PB2.GPIO_Label=PB2
+PB2.Signal=GPIO_Analog
+PB3.GPIOParameters=GPIO_Label
+PB3.GPIO_Label=SPI_R_SCK
+PB3.Locked=true
+PB3.Mode=Full_Duplex_Master
+PB3.Signal=SPI1_SCK
 PB4.GPIOParameters=GPIO_Label
-PA15.GPIO_Label=DISPLAY_BACKLIGHT
-PA12.Locked=true
-Mcu.IP1=COMP1
-PA12.Signal=USB_DP
-PE4.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
-Mcu.UserConstants=
-RCC.VCOSAI1OutputFreq_Value=96000000
-TIM2.ICPolarity_CH1=TIM_INPUTCHANNELPOLARITY_FALLING
-PC1.GPIOParameters=GPIO_Label
-SH.GPXTI13.ConfNb=1
-Mcu.ThirdPartyNb=0
-PB1.GPIO_PuPd=GPIO_PULLUP
-RCC.HCLKFreq_Value=64000000
-Mcu.IPNb=18
-ProjectManager.PreviousToolchain=
-PB1.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-PA8.GPIOParameters=GPIO_Label
-Mcu.Pin6=PC0
-Mcu.Pin7=PC1
-Mcu.Pin8=PC2
-Mcu.Pin9=PC3
-OSC_OUT.Mode=HSE-External-Oscillator
-FREERTOS.IPParameters=Tasks01,configTOTAL_HEAP_SIZE,HEAP_NUMBER,configUSE_TIMERS,configUSE_IDLE_HOOK,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,configRECORD_STACK_HIGH_ADDRESS,configGENERATE_RUN_TIME_STATS,configENABLE_FPU
-OSC_OUT.Signal=RCC_OSC_OUT
-RCC.AHBFreq_Value=64000000
-SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
-Mcu.Pin0=PC13
-Mcu.Pin1=PC14-OSC32_IN
-GPIO.groupedBy=Show All
-Mcu.Pin2=PC15-OSC32_OUT
-Mcu.Pin3=PH3-BOOT0
-Mcu.Pin4=PB8
-Mcu.Pin5=PB9
-ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_TEMPSENSOR
-RCC.HSE_VALUE=32000000
-RCC.FCLK2Freq_Value=32000000
-FREERTOS.configUSE_TIMERS=1
-NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
-PH3-BOOT0.GPIOParameters=GPIO_Label
-Mcu.IP10=SPI2
-NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
-Mcu.IP12=TIM1
-Mcu.IP11=SYS
-Mcu.IP17=USB_DEVICE
-NVIC.TIM1_TRG_COM_TIM17_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
-PA2.PinState=GPIO_PIN_SET
-Mcu.IP14=TIM16
+PB4.GPIO_Label=SPI_R_MISO
+PB4.Locked=true
 PB4.Mode=Full_Duplex_Master
-Mcu.IP13=TIM2
-Mcu.IP16=USB
-Mcu.IP15=USART1
-PC14-OSC32_IN.Mode=LSE-External-Oscillator
-RCC.VCOInputFreq_Value=16000000
-PD0.PinState=GPIO_PIN_SET
-PA14.Mode=Serial_Wire
-PE4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-PC11.GPIO_Label=DISPLAY_CS
+PB4.Signal=SPI1_MISO
+PB5.GPIOParameters=GPIO_Label
+PB5.GPIO_Label=SPI_R_MOSI
+PB5.Locked=true
 PB5.Mode=Full_Duplex_Master
-File.Version=6
-PA10.GPIO_Label=I2C_SDA
-PC13.GPIO_PuPd=GPIO_PULLUP
-PB3.GPIOParameters=GPIO_Label
-SH.S_TIM2_CH1.ConfNb=2
+PB5.Signal=SPI1_MOSI
+PB6.Locked=true
+PB6.Mode=Asynchronous
+PB6.Signal=USART1_TX
+PB7.Locked=true
+PB7.Mode=Asynchronous
 PB7.Signal=USART1_RX
+PB8.GPIOParameters=GPIO_Label
+PB8.GPIO_Label=SPEAKER
 PB8.Locked=true
-PE4.Signal=GPIO_Output
-PB0.Locked=true
-FREERTOS.configTOTAL_HEAP_SIZE=40960
+PB8.Signal=S_TIM16_CH1
+PB9.GPIOParameters=GPIO_Label
+PB9.GPIO_Label=IR_TX
+PB9.Locked=true
+PB9.Mode=PWM Generation3 CH3N
+PB9.Signal=TIM1_CH3N
+PC0.GPIOParameters=GPIO_Label
+PC0.GPIO_Label=PC0
+PC0.Signal=GPIO_Analog
+PC1.GPIOParameters=GPIO_Label
+PC1.GPIO_Label=PC1
+PC1.Signal=GPIO_Analog
+PC10.GPIOParameters=GPIO_Label
+PC10.GPIO_Label=PC10
+PC10.Signal=GPIO_Analog
+PC11.GPIOParameters=PinState,GPIO_Label
+PC11.GPIO_Label=DISPLAY_CS
+PC11.Locked=true
+PC11.PinState=GPIO_PIN_SET
+PC11.Signal=GPIO_Output
+PC12.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
+PC12.GPIO_Label=SD_CS
+PC12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PC12.Locked=true
+PC12.PinState=GPIO_PIN_SET
+PC12.Signal=GPIO_Output
+PC13.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PC13.GPIO_Label=BUTTON_BACK
+PC13.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
+PC13.GPIO_PuPd=GPIO_PULLUP
+PC13.Locked=true
+PC13.Signal=GPXTI13
 PC14-OSC32_IN.GPIOParameters=GPIO_Label
-ProjectManager.ProjectName=f3
-RCC.APB3Freq_Value=16000000
-PA6.Signal=GPIO_Analog
-TIM2.Channel-Input_Capture2_from_TI1=TIM_CHANNEL_2
-RCC.EnbaleCSS=true
-ProjectManager.ToolChainLocation=
-PA2.GPIO_Label=LED_GREEN
-RCC.LSI_VALUE=32000
-PB11.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-PA15.Signal=GPIO_Output
-VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS
-RCC.MSIOscState=DISABLED
-SPI2.CLKPhase=SPI_PHASE_1EDGE
-PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-PB5.GPIO_Label=SPI_R_MOSI
-PC4.Locked=true
 PC14-OSC32_IN.GPIO_Label=QUARTZ_32MHZ_IN
-SPI2.Direction=SPI_DIRECTION_2LINES
-PC5.Signal=COMP1_INP
-SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
-OSC_IN.GPIO_Label=QUARTZ_32KHZ_IN
-PC2.GPIO_Label=BUTTON_OK
 PC14-OSC32_IN.Locked=true
-PA12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-COMP1.TriggerMode=COMP_TRIGGERMODE_IT_RISING_FALLING
-PB15.Locked=true
-PB3.Locked=true
-PB4.Signal=SPI1_MISO
-RCC.PLLSAI1N=6
-PA3.Signal=GPIO_Output
-PA2.Locked=true
-PB3.GPIO_Label=SPI_R_SCK
-VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
-RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
+PC14-OSC32_IN.Mode=LSE-External-Oscillator
+PC14-OSC32_IN.Signal=RCC_OSC32_IN
+PC15-OSC32_OUT.GPIOParameters=GPIO_Label
+PC15-OSC32_OUT.GPIO_Label=QUARTZ_32MHZ_OUT
+PC15-OSC32_OUT.Locked=true
 PC15-OSC32_OUT.Mode=LSE-External-Oscillator
-SH.S_TIM2_CH1.1=TIM2_CH1,Input_Capture2_from_TI1
-SH.S_TIM2_CH1.0=TIM2_CH1,Input_Capture1_from_TI1
-PB8.GPIOParameters=GPIO_Label
-PB9.GPIO_Label=IR_TX
-PC10.GPIO_Label=PC10
-PA10.Mode=I2C
-ProjectManager.NoMain=false
-SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,DataSize,CLKPhase
-USB_DEVICE.VirtualModeFS=Cdc_FS
-NVIC.SavedSvcallIrqHandlerGenerated=false
-PC11.Signal=GPIO_Output
+PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
+PC2.GPIO_Label=BUTTON_OK
+PC2.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
+PC2.GPIO_PuPd=GPIO_PULLUP
+PC2.Locked=true
+PC2.Signal=GPXTI2
+PC3.GPIOParameters=GPIO_Label
+PC3.GPIO_Label=PC3
+PC3.Signal=GPIO_Analog
+PC4.GPIOParameters=GPIO_Label
+PC4.GPIO_Label=CC1101_G0
+PC4.Locked=true
 PC4.Signal=GPIO_Input
+PC5.GPIOParameters=GPIO_Label
+PC5.GPIO_Label=RFID_RF_IN
+PC5.Locked=true
+PC5.Signal=SharedAnalog_PC5
+PC6.GPIOParameters=GPIO_Label
+PC6.GPIO_Label=DISPLAY_DI
+PC6.Locked=true
+PC6.Signal=GPIO_Output
+PCC.Ble.ConnectionInterval=1000.0
+PCC.Ble.DataLength=6
+PCC.Ble.Mode=NOT_SELECTED
+PCC.Ble.PowerLevel=Min
+PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
+PD0.GPIO_Label=CC1101_CS
+PD0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PD0.Locked=true
+PD0.PinState=GPIO_PIN_SET
+PD0.Signal=GPIO_Output
+PD1.GPIOParameters=GPIO_Label
+PD1.GPIO_Label=SPI_D_SCK
+PD1.Locked=true
+PD1.Mode=TX_Only_Simplex_Unidirect_Master
+PD1.Signal=SPI2_SCK
+PE4.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
+PE4.GPIO_Label=NFC_CS
+PE4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+PE4.Locked=true
+PE4.PinState=GPIO_PIN_SET
+PE4.Signal=GPIO_Output
+PH3-BOOT0.GPIOParameters=GPIO_Label
+PH3-BOOT0.GPIO_Label=BOOT0
+PH3-BOOT0.Locked=true
+PH3-BOOT0.Signal=GPIO_Analog
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerOptimize=6
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=true
+ProjectManager.CustomerFirmwarePackage=
 ProjectManager.DefaultFWLocation=true
-VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
-OSC_IN.GPIOParameters=GPIO_Label
-PB12.Locked=true
 ProjectManager.DeletePrevious=true
-PB10.Locked=true
-USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS,APP_RX_DATA_SIZE,APP_TX_DATA_SIZE
-TIM16.Channel=TIM_CHANNEL_1
+ProjectManager.DeviceId=STM32WB55RGVx
+ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.9.0
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=2
+ProjectManager.MainLocation=Src
+ProjectManager.NoMain=false
+ProjectManager.PreviousToolchain=
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=f3.ioc
+ProjectManager.ProjectName=f3
+ProjectManager.RegisterCallBack=
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=Makefile
+ProjectManager.ToolChainLocation=
+ProjectManager.UnderRoot=false
+ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_I2C1_Init-I2C1-false-HAL-true,5-MX_RTC_Init-RTC-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_SPI2_Init-SPI2-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_USB_Device_Init-USB_DEVICE-false-HAL-false,10-MX_TIM1_Init-TIM1-false-HAL-true,11-MX_TIM2_Init-TIM2-false-HAL-true,12-MX_TIM16_Init-TIM16-false-HAL-true,13-MX_COMP1_Init-COMP1-false-HAL-true,14-MX_RF_Init-RF-false-HAL-true,0-MX_HSEM_Init-HSEM-false-HAL-true
+RCC.ADCFreq_Value=48000000
 RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2
+RCC.AHBFreq_Value=64000000
+RCC.APB1Freq_Value=64000000
+RCC.APB1TimFreq_Value=64000000
+RCC.APB2Freq_Value=64000000
+RCC.APB2TimFreq_Value=64000000
+RCC.APB3Freq_Value=16000000
+RCC.Cortex2Freq_Value=32000000
+RCC.CortexFreq_Value=64000000
+RCC.EnbaleCSS=true
+RCC.FCLK2Freq_Value=32000000
+RCC.FCLKCortexFreq_Value=64000000
 RCC.FamilyName=M
-PB9.GPIOParameters=GPIO_Label
-PC12.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
-USART1.VirtualMode-Asynchronous=VM_ASYNC
-PA13.Signal=SYS_JTMS-SWDIO
-FREERTOS.configUSE_IDLE_HOOK=1
-VP_COMP1_VS_VREFINT14.Mode=VREFINT_14
-PA9.Mode=I2C
-TIM1.Channel-Output\ Compare1\ CH1N=TIM_CHANNEL_1
-FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1
-ProjectManager.TargetToolchain=Makefile
-PB10.GPIO_Label=BUTTON_UP
-VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
+RCC.HCLK2Freq_Value=32000000
+RCC.HCLK3Freq_Value=64000000
+RCC.HCLKFreq_Value=64000000
 RCC.HCLKRFFreq_Value=16000000
-PC5.GPIOParameters=GPIO_Label
-PB9.Mode=PWM Generation3 CH3N
-PB2.GPIOParameters=GPIO_Label
+RCC.HSE_VALUE=32000000
+RCC.HSI48_VALUE=48000000
+RCC.HSI_VALUE=16000000
+RCC.I2C1Freq_Value=64000000
+RCC.I2C3Freq_Value=64000000
+RCC.IPParameters=ADCFreq_Value,AHB2CLKDivider,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,Cortex2Freq_Value,CortexFreq_Value,EnbaleCSS,FCLK2Freq_Value,FCLKCortexFreq_Value,FamilyName,HCLK2Freq_Value,HCLK3Freq_Value,HCLKFreq_Value,HCLKRFFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C3Freq_Value,LCDFreq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSI_VALUE,MCO1PinFreq_Value,MSIOscState,PLLM,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLSAI1N,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PLLSourceVirtual,PREFETCH_ENABLE,PWRFreq_Value,RFWKPFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SMPS1Freq_Value,SMPSCLockSelectionVirtual,SMPSFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,USART1Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value
+RCC.LCDFreq_Value=32768
+RCC.LPTIM1Freq_Value=64000000
+RCC.LPTIM2Freq_Value=64000000
+RCC.LPUART1Freq_Value=64000000
+RCC.LSCOPinFreq_Value=32000
+RCC.LSI_VALUE=32000
+RCC.MCO1PinFreq_Value=64000000
+RCC.MSIOscState=DISABLED
+RCC.PLLM=RCC_PLLM_DIV2
+RCC.PLLPoutputFreq_Value=64000000
+RCC.PLLQoutputFreq_Value=64000000
+RCC.PLLRCLKFreq_Value=64000000
+RCC.PLLSAI1N=6
+RCC.PLLSAI1PoutputFreq_Value=48000000
+RCC.PLLSAI1QoutputFreq_Value=48000000
+RCC.PLLSAI1RoutputFreq_Value=48000000
+RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
+RCC.PREFETCH_ENABLE=1
+RCC.PWRFreq_Value=64000000
+RCC.RFWKPFreq_Value=976.5625
+RCC.RNGFreq_Value=32000
+RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
+RCC.RTCFreq_Value=32768
+RCC.SAI1Freq_Value=48000000
+RCC.SMPS1Freq_Value=16000000
+RCC.SMPSCLockSelectionVirtual=RCC_SMPSCLKSOURCE_HSE
+RCC.SMPSFreq_Value=8000000
+RCC.SYSCLKFreq_VALUE=64000000
+RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
+RCC.USART1Freq_Value=64000000
+RCC.USBFreq_Value=48000000
+RCC.VCOInputFreq_Value=16000000
+RCC.VCOOutputFreq_Value=128000000
+RCC.VCOSAI1OutputFreq_Value=96000000
+RF1.Locked=true
+RF1.Mode=RF1_Activate
+RF1.Signal=RF_RF1
+SH.GPXTI1.0=GPIO_EXTI1
+SH.GPXTI1.ConfNb=1
+SH.GPXTI10.0=GPIO_EXTI10
+SH.GPXTI10.ConfNb=1
+SH.GPXTI11.0=GPIO_EXTI11
+SH.GPXTI11.ConfNb=1
+SH.GPXTI12.0=GPIO_EXTI12
 SH.GPXTI12.ConfNb=1
-PE4.Locked=true
+SH.GPXTI13.0=GPIO_EXTI13
+SH.GPXTI13.ConfNb=1
+SH.GPXTI2.0=GPIO_EXTI2
+SH.GPXTI2.ConfNb=1
+SH.GPXTI8.0=GPIO_EXTI8
+SH.GPXTI8.ConfNb=1
+SH.S_TIM16_CH1.0=TIM16_CH1,PWM Generation1 CH1
+SH.S_TIM16_CH1.ConfNb=1
+SH.S_TIM2_CH1.0=TIM2_CH1,Input_Capture1_from_TI1
+SH.S_TIM2_CH1.1=TIM2_CH1,Input_Capture2_from_TI1
+SH.S_TIM2_CH1.ConfNb=2
+SH.SharedAnalog_PC5.0=COMP1_INP,INP
+SH.SharedAnalog_PC5.1=ADC1_IN14,IN14-Single-Ended
+SH.SharedAnalog_PC5.ConfNb=2
+SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
+SPI1.CLKPhase=SPI_PHASE_2EDGE
+SPI1.CalculateBaudRate=4.0 MBits/s
+SPI1.DataSize=SPI_DATASIZE_8BIT
+SPI1.Direction=SPI_DIRECTION_2LINES
+SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,DataSize,CLKPhase
+SPI1.Mode=SPI_MODE_MASTER
+SPI1.VirtualType=VM_MASTER
+SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
+SPI2.CLKPhase=SPI_PHASE_1EDGE
+SPI2.CalculateBaudRate=4.0 MBits/s
+SPI2.DataSize=SPI_DATASIZE_8BIT
+SPI2.Direction=SPI_DIRECTION_2LINES
 SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPhase
-PC2.Locked=true
-ProjectManager.RegisterCallBack=
-RCC.USBFreq_Value=48000000
+SPI2.Mode=SPI_MODE_MASTER
+SPI2.VirtualType=VM_MASTER
+TIM1.Channel-Output\ Compare1\ CH1N=TIM_CHANNEL_1
 TIM1.Channel-PWM\ Generation3\ CH3N=TIM_CHANNEL_3
-PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
-PA1.Signal=GPIO_Output
-PB1.Locked=true
-RCC.SMPSCLockSelectionVirtual=RCC_SMPSCLKSOURCE_HSE
-board=custom
-RCC.VCOOutputFreq_Value=128000000
-RCC.SMPS1Freq_Value=16000000
-PB15.Mode=TX_Only_Simplex_Unidirect_Master
+TIM1.IPParameters=Channel-Output Compare1 CH1N,Channel-PWM Generation3 CH3N
+TIM16.Channel=TIM_CHANNEL_1
+TIM16.IPParameters=Channel,Pulse,Prescaler,Period
 TIM16.Period=291
-NVIC.SavedSystickIrqHandlerGenerated=true
-RCC.APB2Freq_Value=64000000
-PC11.PinState=GPIO_PIN_SET
-COMP1.IPParameters=TriggerMode,Hysteresis,Mode
-MxCube.Version=6.0.1
-VP_TIM2_VS_ClockSourceINT.Mode=Internal
-PC13.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-PA1.GPIO_Speed=GPIO_SPEED_FREQ_LOW
-RCC.PLLSAI1QoutputFreq_Value=48000000
-RCC.ADCFreq_Value=48000000
-PC1.GPIO_Label=PC1
-PA10.GPIOParameters=GPIO_Speed,GPIO_Label
-VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input
-OSC_OUT.Locked=true
-PA4.GPIOParameters=GPIO_Label
-PC2.GPIO_PuPd=GPIO_PULLUP
-PB15.GPIOParameters=GPIO_Label
-RCC.IPParameters=ADCFreq_Value,AHB2CLKDivider,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,Cortex2Freq_Value,CortexFreq_Value,EnbaleCSS,FCLK2Freq_Value,FCLKCortexFreq_Value,FamilyName,HCLK2Freq_Value,HCLK3Freq_Value,HCLKFreq_Value,HCLKRFFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C3Freq_Value,LCDFreq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSI_VALUE,MCO1PinFreq_Value,MSIOscState,PLLM,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLSAI1N,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PLLSourceVirtual,PREFETCH_ENABLE,PWRFreq_Value,RFWKPFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SMPS1Freq_Value,SMPSCLockSelectionVirtual,SMPSFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,USART1Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value
-ProjectManager.AskForMigrate=true
-Mcu.Name=STM32WB55RGVx
-NVIC.SavedPendsvIrqHandlerGenerated=false
-PA2.Signal=GPIO_Output
-Mcu.IP8=RTC
-VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
-Mcu.IP9=SPI1
-Mcu.IP6=RCC
-Mcu.IP7=RF
-ProjectManager.CoupleFile=true
-PB3.Signal=SPI1_SCK
-RCC.SYSCLKFreq_VALUE=64000000
-PA7.GPIO_Label=PA7
-PA1.Locked=true
-PA12.Mode=Device
-PCC.Ble.ConnectionInterval=1000.0
-KeepUserPlacement=false
-PC13.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-PC5.GPIO_Label=RFID_RF_IN
-PA13.Locked=true
-RF1.Mode=RF1_Activate
-PB7.Mode=Asynchronous
-NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
+TIM16.Prescaler=500 - 1
+TIM16.Pulse=145
+TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
+TIM2.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1
+TIM2.Channel-Input_Capture2_from_TI1=TIM_CHANNEL_2
+TIM2.ICPolarity_CH1=TIM_INPUTCHANNELPOLARITY_FALLING
+TIM2.IPParameters=Channel-Input_Capture1_from_TI1,ICPolarity_CH1,AutoReloadPreload,Prescaler,Channel-Input_Capture2_from_TI1
+TIM2.Prescaler=64-1
+USART1.IPParameters=VirtualMode-Asynchronous
+USART1.VirtualMode-Asynchronous=VM_ASYNC
+USB_DEVICE.APP_RX_DATA_SIZE=512
 USB_DEVICE.APP_TX_DATA_SIZE=512
-PA14.Signal=SYS_JTCK-SWCLK
-PB2.GPIO_Label=PB2
-PC6.GPIOParameters=GPIO_Label
-PB12.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
-RCC.HSI_VALUE=16000000
-ADC1.NbrOfConversionFlag=1
-RCC.PLLM=RCC_PLLM_DIV2
-PA15.GPIO_PuPd=GPIO_PULLDOWN
-PB7.Locked=true
-PB8.Signal=S_TIM16_CH1
-PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
-TIM16.IPParameters=Channel,Pulse,Prescaler,Period
-RCC.APB1Freq_Value=64000000
-PC12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
+USB_DEVICE.CLASS_NAME_FS=CDC
+USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS,APP_RX_DATA_SIZE,APP_TX_DATA_SIZE
+USB_DEVICE.MANUFACTURER_STRING=Flipper
+USB_DEVICE.PRODUCT_STRING_CDC_FS=Flipper Control Virtual ComPort
 USB_DEVICE.VirtualMode=Cdc
-PB11.Locked=true
-ProjectManager.DeviceId=STM32WB55RGVx
-PB12.Signal=GPXTI12
-ProjectManager.LibraryCopy=2
-PA3.GPIO_Label=LED_BLUE
-PB1.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
-PA7.Signal=GPIO_Analog
-PA1.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_OD
+USB_DEVICE.VirtualModeFS=Cdc_FS
+VP_ADC1_TempSens_Input.Mode=IN-TempSens
+VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input
+VP_ADC1_Vref_Input.Mode=IN-Vrefint
+VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input
+VP_COMP1_VS_VREFINT14.Mode=VREFINT_14
+VP_COMP1_VS_VREFINT14.Signal=COMP1_VS_VREFINT14
+VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
+VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
+VP_HSEM_VS_HSEM.Mode=HSEM_Activate
+VP_HSEM_VS_HSEM.Signal=HSEM_VS_HSEM
+VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
+VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
+VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar
+VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar
+VP_SYS_VS_tim17.Mode=TIM17
+VP_SYS_VS_tim17.Signal=SYS_VS_tim17
+VP_TIM16_VS_ClockSourceINT.Mode=Enable_Timer
+VP_TIM16_VS_ClockSourceINT.Signal=TIM16_VS_ClockSourceINT
+VP_TIM1_VS_ClockSourceINT.Mode=Internal
+VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
+VP_TIM2_VS_ClockSourceINT.Mode=Internal
+VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
+VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
+VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS
+board=custom

+ 0 - 0
firmware/targets/local/fatfs/heap.h → firmware/targets/local/Inc/heap.h


+ 0 - 6
firmware/targets/local/api-hal/api-hal-delay.h

@@ -1,6 +0,0 @@
-#pragma once
-#include "main.h"
-
-void delay_us(float microseconds);
-
-void delay(float milliseconds);

+ 95 - 0
lib/cyfral/cyfral_emulator.h

@@ -0,0 +1,95 @@
+#pragma once
+#include "flipper.h"
+#include "flipper_v2.h"
+
+class CyfralTiming {
+public:
+    constexpr static const uint8_t ZERO_HIGH = 50;
+    constexpr static const uint8_t ZERO_LOW = 70;
+    constexpr static const uint8_t ONE_HIGH = 100;
+    constexpr static const uint8_t ONE_LOW = 70;
+};
+
+class CyfralEmulator {
+private:
+    void send_nibble(uint8_t nibble);
+    void send_byte(uint8_t data);
+    inline void send_bit(bool bit);
+    const GpioPin* emulate_pin_record;
+
+public:
+    CyfralEmulator(const GpioPin* emulate_pin);
+    ~CyfralEmulator();
+    void send(uint8_t* data, uint8_t count = 1, uint8_t repeat = 1);
+    void start(void);
+    void stop(void);
+};
+
+// 7 = 0 1 1 1
+// B = 1 0 1 1
+// D = 1 1 0 1
+// E = 1 1 1 0
+
+void CyfralEmulator::send_nibble(uint8_t nibble) {
+    for(uint8_t i = 0; i < 4; i++) {
+        bool bit = nibble & (0b1000 >> i);
+        send_bit(bit);
+    }
+}
+
+void CyfralEmulator::send_byte(uint8_t data) {
+    for(uint8_t i = 0; i < 8; i++) {
+        bool bit = data & (0b10000000 >> i);
+        send_bit(bit);
+    }
+}
+
+void CyfralEmulator::send_bit(bool bit) {
+    if(!bit) {
+        gpio_write(&ibutton_gpio, false);
+        delay_us(CyfralTiming::ZERO_LOW);
+        gpio_write(&ibutton_gpio, true);
+        delay_us(CyfralTiming::ZERO_HIGH);
+        gpio_write(&ibutton_gpio, false);
+        delay_us(CyfralTiming::ZERO_LOW);
+    } else {
+        gpio_write(&ibutton_gpio, true);
+        delay_us(CyfralTiming::ONE_HIGH);
+        gpio_write(&ibutton_gpio, false);
+        delay_us(CyfralTiming::ONE_LOW);
+    }
+}
+
+CyfralEmulator::CyfralEmulator(const GpioPin* emulate_pin) {
+    emulate_pin_record = emulate_pin;
+}
+
+CyfralEmulator::~CyfralEmulator() {
+}
+
+void CyfralEmulator::send(uint8_t* data, uint8_t count, uint8_t repeat) {
+    osKernelLock();
+    __disable_irq();
+
+    for(uint8_t i = 0; i < repeat; i++) {
+        // start sequence
+        send_nibble(0x01);
+
+        // send data
+        for(uint8_t i = 0; i < count; i++) {
+            send_byte(data[i]);
+        }
+    }
+
+    __enable_irq();
+    osKernelUnlock();
+}
+
+void CyfralEmulator::start(void) {
+    gpio_init(emulate_pin_record, GpioModeOutputOpenDrain);
+    gpio_write(emulate_pin_record, false);
+}
+
+void CyfralEmulator::stop(void) {
+    gpio_init(emulate_pin_record, GpioModeAnalog);
+}

+ 273 - 0
lib/cyfral/cyfral_reader.h

@@ -0,0 +1,273 @@
+#pragma once
+#include "flipper.h"
+#include "flipper_v2.h"
+
+enum class CyfralReaderError : uint8_t {
+    NO_ERROR = 0,
+    UNABLE_TO_DETECT = 1,
+    RAW_DATA_SIZE_ERROR = 2,
+    UNKNOWN_NIBBLE_VALUE = 3,
+    NO_START_NIBBLE = 4,
+};
+
+class CyfralReader {
+private:
+    ADC_HandleTypeDef adc_config;
+    ADC_TypeDef* adc_instance;
+    uint32_t adc_channel;
+
+    void get_line_minmax(uint16_t times, uint32_t* min_level, uint32_t* max_level);
+    void capture_data(bool* data, uint16_t capture_size, uint32_t line_min, uint32_t line_max);
+    bool parse_data(bool* raw_data, uint16_t capture_size, uint8_t* data, uint8_t count);
+    uint32_t search_array_in_array(
+        const bool* haystack,
+        const uint32_t haystack_size,
+        const bool* needle,
+        const uint32_t needle_size);
+
+    // key is 9 nibbles
+    static const uint16_t bits_in_nibble = 4;
+    static const uint16_t key_length = 9;
+    static const uint32_t capture_size = key_length * bits_in_nibble * 2;
+    CyfralReaderError error;
+
+public:
+    CyfralReader(ADC_TypeDef* adc, uint32_t Channel);
+    ~CyfralReader();
+    void start(void);
+    void stop(void);
+    bool read(uint8_t* data, uint8_t count);
+};
+
+void CyfralReader::get_line_minmax(uint16_t times, uint32_t* min_level, uint32_t* max_level) {
+    uint32_t in = 0;
+    uint32_t min = UINT_MAX;
+    uint32_t max = 0;
+
+    for(uint32_t i = 0; i < 256; i++) {
+        HAL_ADC_Start(&adc_config);
+        HAL_ADC_PollForConversion(&adc_config, 100);
+        in = HAL_ADC_GetValue(&adc_config);
+        if(in < min) min = in;
+        if(in > max) max = in;
+    }
+
+    *min_level = min;
+    *max_level = max;
+}
+
+void CyfralReader::capture_data(
+    bool* data,
+    uint16_t capture_size,
+    uint32_t line_min,
+    uint32_t line_max) {
+    uint32_t input_value = 0;
+    bool last_input_value = 0;
+
+    uint32_t diff = line_max - line_min;
+    uint32_t mid = line_min + diff / 2;
+
+    uint32_t low_threshold = mid - (diff / 4);
+    uint32_t high_threshold = mid - (diff / 4);
+
+    uint16_t capture_position = 0;
+    uint32_t instructions_per_us = (SystemCoreClock / 1000000.0f);
+    uint32_t time_threshold = 75 * instructions_per_us;
+    uint32_t capture_max_time = 140 * (capture_size * 2) * instructions_per_us;
+
+    uint32_t start = DWT->CYCCNT;
+    uint32_t end = DWT->CYCCNT;
+
+    memset(data, 0, capture_size);
+
+    osKernelLock();
+
+    uint32_t capture_start = DWT->CYCCNT;
+    while((capture_position < capture_size) &&
+          ((DWT->CYCCNT - capture_start) < capture_max_time)) {
+        // read adc
+        HAL_ADC_Start(&adc_config);
+        HAL_ADC_PollForConversion(&adc_config, 100);
+        input_value = HAL_ADC_GetValue(&adc_config);
+
+        // low to high transition
+        if((input_value > high_threshold) && last_input_value == 0) {
+            last_input_value = 1;
+            start = DWT->CYCCNT;
+        }
+
+        // high to low transition
+        if((input_value < low_threshold) && last_input_value == 1) {
+            last_input_value = 0;
+            end = DWT->CYCCNT;
+
+            // check transition time
+            if(end - start < time_threshold) {
+                data[capture_position] = 1;
+                capture_position++;
+            } else {
+                data[capture_position] = 0;
+                capture_position++;
+            }
+        }
+    }
+
+    osKernelUnlock();
+}
+
+uint32_t CyfralReader::search_array_in_array(
+    const bool* haystack,
+    const uint32_t haystack_size,
+    const bool* needle,
+    const uint32_t needle_size) {
+    uint32_t haystack_index = 0, needle_index = 0;
+
+    while(haystack_index < haystack_size && needle_index < needle_size) {
+        if(haystack[haystack_index] == needle[needle_index]) {
+            haystack_index++;
+            needle_index++;
+            if(needle_index == needle_size) {
+                return (haystack_index - needle_size);
+            };
+        } else {
+            haystack_index = haystack_index - needle_index + 1;
+            needle_index = 0;
+        }
+    }
+
+    return haystack_index;
+}
+
+bool CyfralReader::parse_data(bool* raw_data, uint16_t capture_size, uint8_t* data, uint8_t count) {
+    const bool start_nibble[bits_in_nibble] = {1, 1, 1, 0};
+    uint32_t start_position =
+        search_array_in_array(raw_data, capture_size, start_nibble, bits_in_nibble);
+    uint32_t end_position = 0;
+
+    memset(data, 0, count);
+
+    if(start_position < capture_size) {
+        start_position = start_position + bits_in_nibble;
+        end_position = start_position + count * 2 * bits_in_nibble;
+
+        if(end_position >= capture_size) {
+            error = CyfralReaderError::RAW_DATA_SIZE_ERROR;
+            return false;
+        }
+
+        bool first_nibble = true;
+        uint8_t data_position = 0;
+        uint8_t nibble_value = 0;
+
+        while(data_position < count) {
+            nibble_value = !raw_data[start_position] << 3 | !raw_data[start_position + 1] << 2 |
+                           !raw_data[start_position + 2] << 1 | !raw_data[start_position + 3];
+
+            switch(nibble_value) {
+            case(0x7):
+            case(0xB):
+            case(0xD):
+            case(0xE):
+                break;
+            default:
+                error = CyfralReaderError::UNKNOWN_NIBBLE_VALUE;
+                return false;
+                break;
+            }
+
+            if(first_nibble) {
+                data[data_position] |= nibble_value << 4;
+            } else {
+                data[data_position] |= nibble_value;
+            }
+
+            first_nibble = !first_nibble;
+
+            if(first_nibble) {
+                data_position++;
+            }
+
+            start_position = start_position + bits_in_nibble;
+        }
+
+        error = CyfralReaderError::NO_ERROR;
+        return true;
+    }
+
+    error = CyfralReaderError::NO_START_NIBBLE;
+    return false;
+}
+
+CyfralReader::CyfralReader(ADC_TypeDef* adc, uint32_t channel) {
+    adc_instance = adc;
+    adc_channel = channel;
+}
+
+CyfralReader::~CyfralReader() {
+}
+
+void CyfralReader::start(void) {
+    ADC_ChannelConfTypeDef sConfig = {0};
+
+    // init ADC
+    adc_config.Instance = adc_instance;
+    adc_config.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
+    adc_config.Init.Resolution = ADC_RESOLUTION_12B;
+    adc_config.Init.DataAlign = ADC_DATAALIGN_RIGHT;
+    adc_config.Init.ScanConvMode = ADC_SCAN_DISABLE;
+    adc_config.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+    adc_config.Init.LowPowerAutoWait = DISABLE;
+    adc_config.Init.ContinuousConvMode = DISABLE;
+    adc_config.Init.NbrOfConversion = 1;
+    adc_config.Init.DiscontinuousConvMode = DISABLE;
+    adc_config.Init.ExternalTrigConv = ADC_SOFTWARE_START;
+    adc_config.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
+    adc_config.Init.DMAContinuousRequests = DISABLE;
+    adc_config.Init.Overrun = ADC_OVR_DATA_PRESERVED;
+    adc_config.Init.OversamplingMode = DISABLE;
+    if(HAL_ADC_Init(&adc_config) != HAL_OK) {
+        Error_Handler();
+    }
+
+    // init channel
+    sConfig.Channel = adc_channel;
+    sConfig.Rank = ADC_REGULAR_RANK_1;
+    sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
+    sConfig.SingleDiff = ADC_SINGLE_ENDED;
+    sConfig.OffsetNumber = ADC_OFFSET_NONE;
+    sConfig.Offset = 0;
+    if(HAL_ADC_ConfigChannel(&adc_config, &sConfig) != HAL_OK) {
+        Error_Handler();
+    }
+}
+
+void CyfralReader::stop(void) {
+    HAL_ADC_DeInit(&adc_config);
+}
+
+bool CyfralReader::read(uint8_t* data, uint8_t count) {
+    uint32_t line_level_min, line_level_max;
+    bool raw_data[capture_size];
+    bool result = false;
+    error = CyfralReaderError::NO_ERROR;
+
+    // calibrate
+    get_line_minmax(256, &line_level_min, &line_level_max);
+
+    // TODO think about other detection method
+    // key not on line
+    if(line_level_max > 2000) {
+        error = CyfralReaderError::UNABLE_TO_DETECT;
+        return false;
+    }
+
+    // capturing raw data consisting of bits
+    capture_data(raw_data, capture_size, line_level_min, line_level_max);
+
+    // parse captured data
+    if(parse_data(raw_data, capture_size, data, count)) {
+        result = true;
+    }
+
+    return result;
+}

+ 15 - 1
lib/lib.mk

@@ -54,4 +54,18 @@ CFLAGS			+= -I$(LIB_DIR)/app-template
 
 # fnv1a hash library
 CFLAGS			+= -I$(LIB_DIR)/fnv1a-hash
-C_SOURCES		+= $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c
+C_SOURCES		+= $(LIB_DIR)/fnv1a-hash/fnv1a-hash.c
+
+# build onewire/cyfral library only if
+# we build iButton application
+ifeq ($(BUILD_IBUTTON), 1)
+# onewire library
+ONEWIRE_DIR		= $(LIB_DIR)/onewire
+CFLAGS			+= -I$(ONEWIRE_DIR)
+CPP_SOURCES		+= $(wildcard $(ONEWIRE_DIR)/*.cpp)
+
+# cyfral library
+CYFRAL_DIR		= $(LIB_DIR)/cyfral
+CFLAGS			+= -I$(CYFRAL_DIR)
+CPP_SOURCES		+= $(wildcard $(CYFRAL_DIR)/*.cpp)
+endif

+ 48 - 0
lib/onewire/maxim_crc.cpp

@@ -0,0 +1,48 @@
+#include "maxim_crc.h"
+
+uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init) {
+    uint8_t crc = crc_init;
+
+    for(uint8_t index = 0; index < data_size; ++index) {
+        uint8_t input_byte = data[index];
+        for(uint8_t bit_position = 0; bit_position < 8; ++bit_position) {
+            const uint8_t mix = (crc ^ input_byte) & static_cast<uint8_t>(0x01);
+            crc >>= 1;
+            if(mix != 0) crc ^= 0x8C;
+            input_byte >>= 1;
+        }
+    }
+    return crc;
+}
+
+uint16_t maxim_crc16(const uint8_t* address, const uint8_t length, const uint16_t init) {
+    uint16_t crc = init;
+
+    static const uint8_t odd_parity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};
+
+    for(uint8_t i = 0; i < length; ++i) {
+        uint16_t cdata = address[i];
+        cdata = (cdata ^ crc) & static_cast<uint16_t>(0xff);
+        crc >>= 8;
+
+        if((odd_parity[cdata & 0x0F] ^ odd_parity[cdata >> 4]) != 0) crc ^= 0xC001;
+
+        cdata <<= 6;
+        crc ^= cdata;
+        cdata <<= 1;
+        crc ^= cdata;
+    }
+
+    return crc;
+}
+
+uint16_t maxim_crc16(uint8_t value, uint16_t crc) {
+    static const uint8_t odd_parity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};
+    value = (value ^ static_cast<uint8_t>(crc));
+    crc >>= 8;
+    if((odd_parity[value & 0x0F] ^ odd_parity[value >> 4]) != 0) crc ^= 0xC001;
+    uint16_t cdata = (static_cast<uint16_t>(value) << 6);
+    crc ^= cdata;
+    crc ^= (static_cast<uint16_t>(cdata) << 1);
+    return crc;
+}

+ 6 - 0
lib/onewire/maxim_crc.h

@@ -0,0 +1,6 @@
+#pragma once
+#include <stdint.h>
+
+uint8_t maxim_crc8(const uint8_t* data, const uint8_t data_size, const uint8_t crc_init = 0);
+uint16_t maxim_crc16(const uint8_t* address, const uint8_t length, const uint16_t init = 0);
+uint16_t maxim_crc16(uint8_t value, uint16_t crc);

+ 26 - 0
lib/onewire/one_wire_device.cpp

@@ -0,0 +1,26 @@
+#include "one_wire_device.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+OneWireDevice::OneWireDevice(
+    uint8_t id_1,
+    uint8_t id_2,
+    uint8_t id_3,
+    uint8_t id_4,
+    uint8_t id_5,
+    uint8_t id_6,
+    uint8_t id_7) {
+    id_storage[0] = id_1;
+    id_storage[1] = id_2;
+    id_storage[2] = id_3;
+    id_storage[3] = id_4;
+    id_storage[4] = id_5;
+    id_storage[5] = id_6;
+    id_storage[6] = id_7;
+    id_storage[7] = maxim_crc8(id_storage, 7);
+}
+
+void OneWireDevice::send_id(OneWireGpioSlave* owner) const {
+    owner->send(id_storage, 8);
+}

+ 34 - 0
lib/onewire/one_wire_device.h

@@ -0,0 +1,34 @@
+#pragma once
+#include <stdint.h>
+#include "maxim_crc.h"
+#include "one_wire_slave_gpio.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+class OneWireDevice {
+public:
+    OneWireDevice(
+        uint8_t id_1,
+        uint8_t id_2,
+        uint8_t id_3,
+        uint8_t id_4,
+        uint8_t id_5,
+        uint8_t id_6,
+        uint8_t id_7);
+
+    ~OneWireDevice() = default; // TODO: detach if deleted before hub
+
+    // allow only move constructor
+    OneWireDevice(OneWireDevice&& one_wire_device) = default;
+    OneWireDevice(const OneWireDevice& one_wire_device) = delete;
+    OneWireDevice& operator=(OneWireDevice& one_wire_device) = delete;
+    OneWireDevice& operator=(const OneWireDevice& one_wire_device) = delete;
+    OneWireDevice& operator=(OneWireDevice&& one_wire_device) = delete;
+
+    uint8_t id_storage[8];
+
+    void send_id(OneWireGpioSlave* owner) const;
+
+    virtual void do_work(OneWireGpioSlave* owner) = 0;
+};

+ 27 - 0
lib/onewire/one_wire_device_ds_1990.cpp

@@ -0,0 +1,27 @@
+#include "one_wire_device_ds_1990.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+DS1990::DS1990(
+    uint8_t ID1,
+    uint8_t ID2,
+    uint8_t ID3,
+    uint8_t ID4,
+    uint8_t ID5,
+    uint8_t ID6,
+    uint8_t ID7)
+    : OneWireDevice(ID1, ID2, ID3, ID4, ID5, ID6, ID7) {
+}
+
+void DS1990::do_work(OneWireGpioSlave* owner) {
+    uint8_t cmd;
+
+    if(owner->receive(&cmd)) return;
+
+    switch(cmd) {
+    default:
+        return;
+        //owner->raiseSlaveError(cmd);
+    }
+}

+ 21 - 0
lib/onewire/one_wire_device_ds_1990.h

@@ -0,0 +1,21 @@
+#pragma once
+#include "one_wire_device.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+class DS1990 : public OneWireDevice {
+public:
+    static constexpr uint8_t family_code{0x01};
+
+    DS1990(
+        uint8_t ID1,
+        uint8_t ID2,
+        uint8_t ID3,
+        uint8_t ID4,
+        uint8_t ID5,
+        uint8_t ID6,
+        uint8_t ID7);
+
+    void do_work(OneWireGpioSlave* owner) final;
+};

+ 0 - 0
applications/ibutton/one_wire_gpio.h → lib/onewire/one_wire_gpio.h


+ 511 - 0
lib/onewire/one_wire_slave_gpio.cpp

@@ -0,0 +1,511 @@
+#include "one_wire_slave_gpio.h"
+#include "one_wire_device.h"
+#include "one_wire_device_ds_1990.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+static uint32_t __instructions_per_us = 0;
+
+OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) {
+    gpio = one_wire_gpio;
+    error = OneWireGpioSlaveError::NO_ERROR;
+    devices_count = 0;
+    device_selected = nullptr;
+
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        devices[i] = nullptr;
+    }
+
+    __instructions_per_us = (SystemCoreClock / 1000000.0f);
+}
+
+OneWireGpioSlave::~OneWireGpioSlave() {
+    stop();
+}
+
+void OneWireGpioSlave::start(void) {
+    gpio_init(gpio, GpioModeOutputOpenDrain);
+}
+
+void OneWireGpioSlave::stop(void) {
+    gpio_init(gpio, GpioModeAnalog);
+}
+
+bool OneWireGpioSlave::emulate() {
+    error = OneWireGpioSlaveError::NO_ERROR;
+
+    while(1) {
+        if(devices_count == 0) return false;
+
+        if(!check_reset()) {
+            return false;
+        } else {
+        }
+
+        // OK, we receive reset
+        osKernelLock();
+
+        if(!show_presence()) {
+            return false;
+        } else {
+        }
+
+        // and we succefully show our presence on bus
+        __disable_irq();
+
+        if(!receive_and_process_cmd()) {
+            __enable_irq();
+            osKernelUnlock();
+            return false;
+        } else {
+            __enable_irq();
+            osKernelUnlock();
+            return (error == OneWireGpioSlaveError::NO_ERROR);
+        }
+    }
+}
+
+OneWiteTimeType OneWireGpioSlave::wait_while_gpio_is(OneWiteTimeType time, const bool pin_value) {
+    uint32_t start = DWT->CYCCNT;
+    uint32_t time_ticks = time * __instructions_per_us;
+    uint32_t time_captured;
+
+    do {
+        time_captured = DWT->CYCCNT;
+        if(gpio_read(gpio) != pin_value) {
+            OneWiteTimeType remaining_time = time_ticks - (time_captured - start);
+            remaining_time /= __instructions_per_us;
+            return remaining_time;
+        }
+    } while((time_captured - start) < time_ticks);
+
+    return 0;
+}
+
+void OneWireGpioSlave::pin_set_float() {
+    gpio_write(gpio, true);
+}
+
+void OneWireGpioSlave::pin_set_low() {
+    gpio_write(gpio, false);
+}
+
+const char* OneWireGpioSlave::decode_error() {
+    const char* error_text[16] = {
+        "NO_ERROR",
+        "READ_TIMESLOT_TIMEOUT",
+        "WRITE_TIMESLOT_TIMEOUT",
+        "WAIT_RESET_TIMEOUT",
+        "VERY_LONG_RESET",
+        "VERY_SHORT_RESET",
+        "PRESENCE_LOW_ON_LINE",
+        "READ_TIMESLOT_TIMEOUT_LOW",
+        "AWAIT_TIMESLOT_TIMEOUT_HIGH",
+        "PRESENCE_HIGH_ON_LINE",
+        "INCORRECT_ONEWIRE_CMD",
+        "INCORRECT_SLAVE_USAGE",
+        "TRIED_INCORRECT_WRITE",
+        "FIRST_TIMESLOT_TIMEOUT",
+        "FIRST_BIT_OF_BYTE_TIMEOUT",
+        "RESET_IN_PROGRESS"};
+
+    return error_text[static_cast<uint8_t>(error)];
+}
+
+uint8_t OneWireGpioSlave::attach(OneWireDevice& device) {
+    if(devices_count >= ONE_WIRE_MAX_DEVICES) return 255; // hub is full
+
+    uint8_t position = 255;
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if(devices[i] == &device) {
+            return i;
+        }
+        if((position > ONE_WIRE_MAX_DEVICES) && (devices[i] == nullptr)) {
+            position = i;
+        }
+    }
+
+    if(position == 255) return 255;
+
+    devices[position] = &device;
+    devices_count++;
+    build_id_tree();
+    return position;
+}
+
+bool OneWireGpioSlave::detach(const OneWireDevice& device) {
+    uint8_t position = 255;
+
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if(devices[i] == &device) {
+            position = i;
+            break;
+        }
+    }
+
+    if(position != 255) return detach(position);
+
+    return false;
+}
+
+bool OneWireGpioSlave::detach(uint8_t device_number) {
+    if(devices[device_number] == nullptr) return false;
+    if(devices_count == 0) return false;
+    if(device_number >= ONE_WIRE_MAX_DEVICES) return false;
+
+    devices[device_number] = nullptr;
+    devices_count--;
+    build_id_tree();
+
+    return true;
+}
+
+uint8_t OneWireGpioSlave::get_next_device_index(const uint8_t index_start) const {
+    for(uint8_t i = index_start; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if(devices[i] != nullptr) return i;
+    }
+    return 0;
+}
+
+uint8_t OneWireGpioSlave::build_id_tree(void) {
+    uint32_t device_mask = 0;
+    uint32_t bit_mask = 0x01;
+
+    // build mask
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if(devices[i] != nullptr) device_mask |= bit_mask;
+        bit_mask <<= 1;
+    }
+
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        id_tree[i].id_position = 255;
+    }
+
+    // begin with root-element
+    build_id_tree(0, device_mask); // goto branch
+
+    return 0;
+}
+
+uint8_t OneWireGpioSlave::build_id_tree(uint8_t id_bit_position, uint32_t device_mask) {
+    if(device_mask == 0) return (255);
+
+    while(id_bit_position < 64) {
+        uint32_t mask_pos{0};
+        uint32_t mask_neg{0};
+        const uint8_t pos_byte{static_cast<uint8_t>(id_bit_position >> 3)};
+        const uint8_t mask_bit{static_cast<uint8_t>(1 << (id_bit_position & 7))};
+        uint32_t mask_id{1};
+
+        // searchid_tree through all active slaves
+        for(uint8_t id = 0; id < ONE_WIRE_MAX_DEVICES; ++id) {
+            if((device_mask & mask_id) != 0) {
+                // if slave is in mask differentiate the bitValue
+                if((devices[id]->id_storage[pos_byte] & mask_bit) != 0)
+                    mask_pos |= mask_id;
+                else
+                    mask_neg |= mask_id;
+            }
+            mask_id <<= 1;
+        }
+
+        if((mask_neg != 0) && (mask_pos != 0)) {
+            // there was found a junction
+            const uint8_t active_element = get_first_id_tree_el_position();
+
+            id_tree[active_element].id_position = id_bit_position;
+            id_tree[active_element].device_selected = get_first_bit_set_position(device_mask);
+            id_bit_position++;
+            id_tree[active_element].got_one = build_id_tree(id_bit_position, mask_pos);
+            id_tree[active_element].got_zero = build_id_tree(id_bit_position, mask_neg);
+            return active_element;
+        }
+
+        id_bit_position++;
+    }
+
+    // gone through the address, store this result
+    uint8_t active_element = get_first_id_tree_el_position();
+
+    id_tree[active_element].id_position = 128;
+    id_tree[active_element].device_selected = get_first_bit_set_position(device_mask);
+    id_tree[active_element].got_one = 255;
+    id_tree[active_element].got_zero = 255;
+
+    return active_element;
+}
+
+uint8_t OneWireGpioSlave::get_first_bit_set_position(uint32_t mask) const {
+    uint32_t _mask = mask;
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if((_mask & 1) != 0) return i;
+        _mask >>= 1;
+    }
+    return 0;
+}
+
+uint8_t OneWireGpioSlave::get_first_id_tree_el_position(void) const {
+    for(uint8_t i = 0; i < ONE_WIRE_MAX_DEVICES; ++i) {
+        if(id_tree[i].id_position == 255) return i;
+    }
+    return 0;
+}
+
+void OneWireGpioSlave::cmd_search_rom(void) {
+    uint8_t id_bit_position = 0;
+    uint8_t trigger_position = 0;
+    uint8_t active_slave = id_tree[trigger_position].device_selected;
+    uint8_t trigger_bit = id_tree[trigger_position].id_position;
+
+    while(id_bit_position < 64) {
+        // if junction is reached, act different
+        if(id_bit_position == trigger_bit) {
+            if(!send_bit(false)) return;
+            if(!send_bit(false)) return;
+
+            const bool bit_recv = receive_bit();
+            if(error != OneWireGpioSlaveError::NO_ERROR) return;
+
+            // switch to next junction
+            trigger_position = bit_recv ? id_tree[trigger_position].got_one :
+                                          id_tree[trigger_position].got_zero;
+
+            active_slave = id_tree[trigger_position].device_selected;
+
+            trigger_bit = (trigger_position == 255) ? uint8_t(255) :
+                                                      id_tree[trigger_position].id_position;
+        } else {
+            const uint8_t pos_byte = (id_bit_position >> 3);
+            const uint8_t mask_bit = (static_cast<uint8_t>(1) << (id_bit_position & (7)));
+            bool bit_send;
+
+            if((devices[active_slave]->id_storage[pos_byte] & mask_bit) != 0) {
+                bit_send = true;
+                if(!send_bit(true)) return;
+                if(!send_bit(false)) return;
+            } else {
+                bit_send = false;
+                if(!send_bit(false)) return;
+                if(!send_bit(true)) return;
+            }
+
+            const bool bit_recv = receive_bit();
+            if(error != OneWireGpioSlaveError::NO_ERROR) return;
+
+            if(bit_send != bit_recv) return;
+        }
+        id_bit_position++;
+    }
+
+    device_selected = devices[active_slave];
+}
+
+bool OneWireGpioSlave::check_reset(void) {
+    pin_set_float();
+
+    if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) {
+        error = OneWireGpioSlaveError::NO_ERROR;
+
+        if(wait_while_gpio_is(
+               OWET::RESET_MIN[overdrive_mode] - OWET::SLOT_MAX[overdrive_mode] -
+                   OWET::READ_MAX[overdrive_mode],
+               false) == 0) {
+            // we want to show_presence on high, so wait for it
+            const OneWiteTimeType time_remaining = wait_while_gpio_is(OWET::RESET_MAX[0], false);
+
+            if(overdrive_mode &&
+               ((OWET::RESET_MAX[0] - OWET::RESET_MIN[overdrive_mode]) > time_remaining)) {
+                overdrive_mode = false;
+            };
+
+            return true;
+        }
+    }
+
+    // if line is low, then just leave
+    if(gpio_read(gpio) == 0) return false;
+
+    // wait while gpio is high
+    if(wait_while_gpio_is(OWET::RESET_TIMEOUT, true) == 0) {
+        return false;
+    }
+
+    // store low time
+    const OneWiteTimeType time_remaining = wait_while_gpio_is(OWET::RESET_MAX[0], false);
+
+    // low time more than RESET_MAX time
+    if(time_remaining == 0) {
+        error = OneWireGpioSlaveError::VERY_LONG_RESET;
+        return false;
+    }
+
+    // if time, while bus was low, fit in standart reset timings
+    if(overdrive_mode && ((OWET::RESET_MAX[0] - OWET::RESET_MIN[0]) <= time_remaining)) {
+        // normal reset detected
+        overdrive_mode = false;
+    };
+
+    bool result = (time_remaining <= OWET::RESET_MAX[0]) &&
+                  time_remaining >= OWET::RESET_MIN[overdrive_mode];
+
+    return result;
+}
+
+bool OneWireGpioSlave::show_presence(void) {
+    // wait while master delay presence check
+    wait_while_gpio_is(OWET::PRESENCE_TIMEOUT, true);
+
+    // show presence
+    pin_set_low();
+    delay_us(OWET::PRESENCE_MIN[overdrive_mode]);
+    pin_set_float();
+
+    // somebody also can show presence
+    const OneWiteTimeType wait_low_time =
+        OWET::PRESENCE_MAX[overdrive_mode] - OWET::PRESENCE_MIN[overdrive_mode];
+
+    // so we will wait
+    if(wait_while_gpio_is(wait_low_time, false) == 0) {
+        error = OneWireGpioSlaveError::PRESENCE_LOW_ON_LINE;
+        return false;
+    }
+
+    return true;
+}
+
+bool OneWireGpioSlave::receive_and_process_cmd(void) {
+    receive(&cmd);
+
+    if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) return true;
+    if(error != OneWireGpioSlaveError::NO_ERROR) return false;
+
+    switch(cmd) {
+    case 0xF0:
+        // SEARCH ROM
+        device_selected = nullptr;
+        cmd_search_rom();
+
+        // trigger reinit
+        return true;
+
+    case 0x33: 
+        // READ ROM
+
+        // work only when one slave on the bus
+        if((device_selected == nullptr) && (devices_count == 1)) {
+            device_selected = devices[get_next_device_index()];
+        }
+        if(device_selected != nullptr) {
+            device_selected->send_id(this);
+        }
+        return false;
+
+    default: // Unknown command
+        error = OneWireGpioSlaveError::INCORRECT_ONEWIRE_CMD;
+        //error_cmd = cmd;
+    }
+
+    if(error == OneWireGpioSlaveError::RESET_IN_PROGRESS) return true;
+    return (error == OneWireGpioSlaveError::NO_ERROR);
+}
+
+bool OneWireGpioSlave::receive_bit(void) {
+    // wait while bus is low
+    OneWiteTimeType time = OWET::SLOT_MAX[overdrive_mode];
+    time = wait_while_gpio_is(time, false);
+    if(time == 0) {
+        error = OneWireGpioSlaveError::RESET_IN_PROGRESS;
+        return false;
+    }
+
+    // wait while bus is high
+    time = OWET::MSG_HIGH_TIMEOUT;
+    time = wait_while_gpio_is(time, true);
+    if(time == 0) {
+        error = OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH;
+        error_place = 1;
+        return false;
+    }
+
+    // wait a time of zero
+    time = OWET::READ_MIN[overdrive_mode];
+    time = wait_while_gpio_is(time, false);
+
+    return (time > 0);
+}
+
+bool OneWireGpioSlave::send_bit(bool value) {
+    const bool write_zero = !value;
+
+    // wait while bus is low
+    OneWiteTimeType time = OWET::SLOT_MAX[overdrive_mode];
+    time = wait_while_gpio_is(time, false);
+    if(time == 0) {
+        error = OneWireGpioSlaveError::RESET_IN_PROGRESS;
+        return false;
+    }
+
+    // wait while bus is high
+    time = OWET::MSG_HIGH_TIMEOUT;
+    time = wait_while_gpio_is(time, true);
+    if(time == 0) {
+        error = OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH;
+        error_place = 2;
+        return false;
+    }
+
+    // choose write time
+    if(write_zero) {
+        pin_set_low();
+        time = OWET::WRITE_ZERO[overdrive_mode];
+    } else {
+        time = OWET::READ_MAX[overdrive_mode];
+    }
+
+    // hold line for ZERO or ONE time
+    delay_us(time);
+    pin_set_float();
+
+    return true;
+}
+
+bool OneWireGpioSlave::send(const uint8_t* address, const uint8_t data_length) {
+    uint8_t bytes_sent = 0;
+
+    pin_set_float();
+
+    // bytes loop
+    for(; bytes_sent < data_length; ++bytes_sent) {
+        const uint8_t data_byte = address[bytes_sent];
+
+        // bit loop
+        for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) {
+            if(!send_bit(static_cast<bool>(bit_mask & data_byte))) {
+                // if we cannot send first bit
+                if((bit_mask == 0x01) &&
+                   (error == OneWireGpioSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH))
+                    error = OneWireGpioSlaveError::FIRST_BIT_OF_BYTE_TIMEOUT;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool OneWireGpioSlave::receive(uint8_t* data, const uint8_t data_length) {
+    uint8_t bytes_received = 0;
+
+    pin_set_float();
+
+    for(; bytes_received < data_length; ++bytes_received) {
+        uint8_t value = 0;
+
+        for(uint8_t bit_mask = 0x01; bit_mask != 0; bit_mask <<= 1) {
+            if(receive_bit()) value |= bit_mask;
+        }
+
+        data[bytes_received] = value;
+    }
+    return (bytes_received != data_length);
+}

+ 93 - 0
lib/onewire/one_wire_slave_gpio.h

@@ -0,0 +1,93 @@
+#pragma once
+#include "flipper.h"
+#include "flipper_v2.h"
+#include "one_wire_timings.h"
+
+// TODO fix GPL compability
+// currently we use rework of OneWireHub
+
+#define ONE_WIRE_MAX_DEVICES 1
+#define ONE_WIRE_TREE_SIZE ((2 * ONE_WIRE_MAX_DEVICES) - 1)
+
+#define OWET OneWireEmulateTiming
+
+class OneWireDevice;
+
+enum class OneWireGpioSlaveError : uint8_t {
+    NO_ERROR = 0,
+    READ_TIMESLOT_TIMEOUT = 1,
+    WRITE_TIMESLOT_TIMEOUT = 2,
+    WAIT_RESET_TIMEOUT = 3,
+    VERY_LONG_RESET = 4,
+    VERY_SHORT_RESET = 5,
+    PRESENCE_LOW_ON_LINE = 6,
+    READ_TIMESLOT_TIMEOUT_LOW = 7,
+    AWAIT_TIMESLOT_TIMEOUT_HIGH = 8,
+    PRESENCE_HIGH_ON_LINE = 9,
+    INCORRECT_ONEWIRE_CMD = 10,
+    INCORRECT_SLAVE_USAGE = 11,
+    TRIED_INCORRECT_WRITE = 12,
+    FIRST_TIMESLOT_TIMEOUT = 13,
+    FIRST_BIT_OF_BYTE_TIMEOUT = 14,
+    RESET_IN_PROGRESS = 15
+};
+
+class OneWireGpioSlave {
+private:
+    const GpioPin* gpio;
+    bool overdrive_mode = false;
+    uint8_t cmd;
+    OneWireGpioSlaveError error;
+    uint8_t error_place;
+
+    uint8_t devices_count;
+    OneWireDevice* devices[ONE_WIRE_MAX_DEVICES];
+    OneWireDevice* device_selected;
+
+    struct IDTree {
+        uint8_t device_selected; // for which slave is this jump-command relevant
+        uint8_t id_position; // where does the algorithm has to look for a junction
+        uint8_t got_zero; // if 0 switch to which tree branch
+        uint8_t got_one; // if 1 switch to which tree branch
+    } id_tree[ONE_WIRE_TREE_SIZE];
+
+public:
+    OneWireGpioSlave(const GpioPin* one_wire_gpio);
+    ~OneWireGpioSlave();
+
+    void start(void);
+    void stop(void);
+    bool emulate();
+    bool check_reset(void);
+    bool show_presence(void);
+    bool receive_and_process_cmd(void);
+    bool receive(uint8_t* data, const uint8_t data_length = 1);
+    bool receive_bit(void);
+    bool send_bit(bool value);
+    bool send(const uint8_t* address, const uint8_t data_length = 1);
+
+    OneWiteTimeType wait_while_gpio_is(volatile OneWiteTimeType retries, const bool pin_value);
+
+    // set pin state
+    inline void pin_set_float();
+    inline void pin_set_low();
+
+    // get error text
+    const char* decode_error();
+
+    // devices managment
+    uint8_t attach(OneWireDevice& device);
+    bool detach(const OneWireDevice& device);
+    bool detach(uint8_t device_number);
+    uint8_t get_next_device_index(const uint8_t index_start = 0) const;
+
+    // id tree managment
+    uint8_t build_id_tree(void);
+    uint8_t build_id_tree(uint8_t id_bit_position, uint32_t device_mask);
+
+    uint8_t get_first_bit_set_position(uint32_t mask) const;
+    uint8_t get_first_id_tree_el_position(void) const;
+
+    // commands
+    void cmd_search_rom(void);
+};

+ 17 - 0
lib/onewire/one_wire_timings.cpp

@@ -0,0 +1,17 @@
+#include "one_wire_timings.h"
+
+// fix pre C++17 "undefined reference" errors
+constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_TIMEOUT;
+constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MIN[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MAX[2];
+
+constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_TIMEOUT;
+constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MIN[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MAX[2];
+
+constexpr const OneWiteTimeType OneWireEmulateTiming::MSG_HIGH_TIMEOUT;
+constexpr const OneWiteTimeType OneWireEmulateTiming::SLOT_MAX[2];
+
+constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MIN[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MAX[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::WRITE_ZERO[2];

+ 0 - 0
applications/ibutton/one_wire_timings.h → lib/onewire/one_wire_timings.h