Просмотр исходного кода

[FL-85][FL-446][FL-720] Dallas key blanks and OneWire lib rework (#313)

* sepate one wire class
* TM2004 writer
* app mode write ds1990
* test another blanks protocol
* new ibutton slave
* one wire states
* tim1 capture compare and update interrupts
* interrupt mgr, new timers IRQ
* discard HAL_TIM_PeriodElapsedCallback from main
* add exti_14 line
* add external interrupt callback
* use int mgr in input
* better interrupt managment
* add interrupt callback enable and disable fns
* properly init app
* changed timings
* rename one wire classes
* use new owb classes
* properly remove interrupts
* new blanks writer
* remove unused tests
* new core includes
* extern c guard
* fix api_interrupt_remove usage
* remove debug info, new way to detect blanks writing
* remove copy constructor
* change keys template
* fix app sources recipe
DrZlo13 5 лет назад
Родитель
Сommit
cf1c8fb223
31 измененных файлов с 1099 добавлено и 869 удалено
  1. 1 1
      applications/applications.mk
  2. 319 0
      applications/ibutton/blanks_writer.cpp
  3. 40 0
      applications/ibutton/blanks_writer.h
  4. 8 4
      applications/ibutton/ibutton.cpp
  5. 1 1
      applications/ibutton/ibutton.h
  6. 25 9
      applications/ibutton/ibutton_mode_dallas_emulate.h
  7. 5 18
      applications/ibutton/ibutton_mode_dallas_read.h
  8. 64 0
      applications/ibutton/ibutton_mode_dallas_write.h
  9. 9 2
      applications/input/input.c
  10. 2 1
      applications/lf-rfid/lf-rfid.c
  11. 0 97
      applications/tests/furi_new_test.c
  12. 0 6
      applications/tests/minunit_test.c
  13. 81 26
      core/api-hal/api-interrupt-mgr.c
  14. 6 1
      core/api-hal/api-interrupt-mgr.h
  15. 2 0
      firmware/targets/f4/Inc/stm32wbxx_it.h
  16. 33 1
      firmware/targets/f4/Src/stm32wbxx_it.c
  17. 11 1
      firmware/targets/f4/api-hal/api-hal-timebase.h
  18. 23 0
      firmware/targets/f4/api-hal/api-interrupts.c
  19. 1 1
      lib/cyfral/cyfral_reader_comp.h
  20. 18 5
      lib/onewire/one_wire_device.cpp
  21. 6 14
      lib/onewire/one_wire_device.h
  22. 0 15
      lib/onewire/one_wire_device_ds_1990.cpp
  23. 0 5
      lib/onewire/one_wire_device_ds_1990.h
  24. 15 28
      lib/onewire/one_wire_master.cpp
  25. 21 0
      lib/onewire/one_wire_master.h
  26. 312 0
      lib/onewire/one_wire_slave.cpp
  27. 74 0
      lib/onewire/one_wire_slave.h
  28. 0 517
      lib/onewire/one_wire_slave_gpio.cpp
  29. 0 92
      lib/onewire/one_wire_slave_gpio.h
  30. 8 9
      lib/onewire/one_wire_timings.cpp
  31. 14 15
      lib/onewire/one_wire_timings.h

+ 1 - 1
applications/applications.mk

@@ -286,7 +286,7 @@ endif
 BUILD_IBUTTON ?= 0
 ifeq ($(BUILD_IBUTTON), 1)
 CFLAGS		+= -DBUILD_IBUTTON
-CPP_SOURCES	+= $(APP_DIR)/ibutton/ibutton.cpp
+CPP_SOURCES	+= $(wildcard $(APP_DIR)/ibutton/*.cpp)
 endif
 
 APP_SDNFC ?= 0

+ 319 - 0
applications/ibutton/blanks_writer.cpp

@@ -0,0 +1,319 @@
+#include "blanks_writer.h"
+
+class RW1990_1 {
+public:
+    constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xD1;
+    constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0xB5;
+    constexpr static const uint8_t CMD_WRITE_ROM = 0xD5;
+};
+
+class RW1990_2 {
+public:
+    constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0x1D;
+    constexpr static const uint8_t CMD_READ_RECORD_FLAG = 0x1E;
+    constexpr static const uint8_t CMD_WRITE_ROM = 0xD5;
+};
+
+class TM2004 {
+public:
+    constexpr static const uint8_t CMD_READ_STATUS = 0xAA;
+    constexpr static const uint8_t CMD_READ_MEMORY = 0xF0;
+    constexpr static const uint8_t CMD_WRITE_ROM = 0x3C;
+    constexpr static const uint8_t CMD_FINALIZATION = 0x35;
+
+    constexpr static const uint8_t ANSWER_READ_MEMORY = 0xF5;
+};
+
+class TM01 {
+public:
+    constexpr static const uint8_t CMD_WRITE_RECORD_FLAG = 0xC1;
+    constexpr static const uint8_t CMD_WRITE_ROM = 0xC5;
+    constexpr static const uint8_t CMD_SWITCH_TO_CYFRAL = 0xCA;
+    constexpr static const uint8_t CMD_SWITCH_TO_METAKOM = 0xCB;
+};
+
+class DS1990 {
+public:
+    constexpr static const uint8_t CMD_READ_ROM = 0x33;
+};
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+void BlanksWriter::onewire_release(void) {
+    gpio_write(gpio, true);
+}
+
+void BlanksWriter::onewire_write_one_bit(bool value, uint32_t delay = 10000) {
+    onewire->write_bit(value);
+    delay_us(delay);
+    onewire_release();
+}
+
+BlanksWriter::BlanksWriter(const GpioPin* one_wire_gpio) {
+    gpio = one_wire_gpio;
+    onewire = new OneWireMaster(gpio);
+}
+
+BlanksWriter::~BlanksWriter() {
+    free(onewire);
+}
+
+WriterResult BlanksWriter::write(KeyType type, const uint8_t* key, uint8_t key_length) {
+    uint8_t write_result = -1;
+    WriterResult result = WR_ERROR;
+
+    bool same_key = false;
+
+    osKernelLock();
+    bool presence = onewire->reset();
+    osKernelUnlock();
+
+    if(presence) {
+        switch(type) {
+        case KeyType::KEY_DS1990:
+            same_key = compare_key_ds1990(key, key_length);
+
+            if(!same_key) {
+                // currently we can write:
+                // RW1990, TM08v2, TM08vi-2 by write_1990_1()
+                // RW2004, RW2004 with EEPROM by write_TM2004();
+
+                if(write_result != 1) {
+                    write_result = write_1990_1(key, key_length);
+                }
+                if(write_result != 1) {
+                    write_result = write_1990_2(key, key_length);
+                }
+                if(write_result != 1) {
+                    write_result = write_TM2004(key, key_length);
+                }
+
+                if(write_result == 1) {
+                    result = WR_OK;
+                } else if(write_result == 0) {
+                    result = WR_ERROR;
+                }
+            } else {
+                write_result = 0;
+                result = WR_SAME_KEY;
+            }
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    return result;
+}
+
+bool BlanksWriter::write_TM2004(const uint8_t* key, uint8_t key_length) {
+    uint8_t answer;
+    bool result = true;
+
+    osKernelLock();
+    __disable_irq();
+
+    // write rom, addr is 0x0000
+    onewire->reset();
+    onewire->write(TM2004::CMD_WRITE_ROM);
+    onewire->write(0x00);
+    onewire->write(0x00);
+
+    // write key
+    for(uint8_t i = 0; i < key_length; i++) {
+        // write key byte
+        onewire->write(key[i]);
+        answer = onewire->read();
+        // TODO: check answer CRC
+
+        // pulse indicating that data is correct
+        delay_us(600);
+        onewire_write_one_bit(1, 50000);
+
+        // read writed key byte
+        answer = onewire->read();
+
+        // check that writed and readed are same
+        if(key[i] != answer) {
+            result = false;
+            break;
+        }
+    }
+
+    onewire->reset();
+
+    __enable_irq();
+    osKernelUnlock();
+
+    return result;
+}
+
+bool BlanksWriter::write_1990_1(const uint8_t* key, uint8_t key_length) {
+    bool result = true;
+
+    osKernelLock();
+    __disable_irq();
+
+    // unlock
+    onewire->reset();
+    onewire->write(RW1990_1::CMD_WRITE_RECORD_FLAG);
+    delay_us(10);
+    onewire_write_one_bit(0, 5000);
+
+    // write key
+    onewire->reset();
+    onewire->write(RW1990_1::CMD_WRITE_ROM);
+    for(uint8_t i = 0; i < key_length; i++) {
+        // inverted key for RW1990.1
+        write_byte_ds1990(~key[i]);
+        delay_us(30000);
+    }
+
+    // lock
+    onewire->write(RW1990_1::CMD_WRITE_RECORD_FLAG);
+    onewire_write_one_bit(1);
+
+    __enable_irq();
+    osKernelUnlock();
+
+    if(!compare_key_ds1990(key, key_length)) {
+        result = false;
+    }
+
+    return result;
+}
+
+bool BlanksWriter::write_1990_2(const uint8_t* key, uint8_t key_length) {
+    bool result = true;
+
+    osKernelLock();
+    __disable_irq();
+
+    // unlock
+    onewire->reset();
+    onewire->write(RW1990_2::CMD_WRITE_RECORD_FLAG);
+    delay_us(10);
+    onewire_write_one_bit(1, 5000);
+
+    // write key
+    onewire->reset();
+    onewire->write(RW1990_2::CMD_WRITE_ROM);
+    for(uint8_t i = 0; i < key_length; i++) {
+        write_byte_ds1990(key[i]);
+        delay_us(30000);
+    }
+
+    // lock
+    onewire->write(RW1990_2::CMD_WRITE_RECORD_FLAG);
+    onewire_write_one_bit(0);
+
+    __enable_irq();
+    osKernelUnlock();
+
+    if(!compare_key_ds1990(key, key_length)) {
+        result = false;
+    }
+
+    return result;
+}
+
+// TODO: untested
+bool BlanksWriter::write_TM01(KeyType type, const uint8_t* key, uint8_t key_length) {
+    bool result = true;
+
+    osKernelLock();
+    __disable_irq();
+
+    // unlock
+    onewire->reset();
+    onewire->write(TM01::CMD_WRITE_RECORD_FLAG);
+    onewire_write_one_bit(1, 10000);
+
+    // write key
+    onewire->reset();
+    onewire->write(TM01::CMD_WRITE_ROM);
+
+    // TODO: key types
+    //if(type == KEY_METAKOM || type == KEY_CYFRAL) {
+    //} else {
+    for(uint8_t i = 0; i < key_length; i++) {
+        write_byte_ds1990(key[i]);
+        delay_us(10000);
+    }
+    //}
+
+    // lock
+    onewire->write(TM01::CMD_WRITE_RECORD_FLAG);
+    onewire_write_one_bit(0, 10000);
+
+    __enable_irq();
+    osKernelUnlock();
+
+    if(!compare_key_ds1990(key, key_length)) {
+        result = false;
+    }
+
+    osKernelLock();
+    __disable_irq();
+
+    if(type == KEY_METAKOM || type == KEY_CYFRAL) {
+        onewire->reset();
+        if(type == KEY_CYFRAL)
+            onewire->write(TM01::CMD_SWITCH_TO_CYFRAL);
+        else
+            onewire->write(TM01::CMD_SWITCH_TO_METAKOM);
+        onewire_write_one_bit(1);
+    }
+
+    __enable_irq();
+    osKernelUnlock();
+
+    return result;
+}
+
+void BlanksWriter::write_byte_ds1990(uint8_t data) {
+    for(uint8_t n_bit = 0; n_bit < 8; n_bit++) {
+        onewire->write_bit(data & 1);
+        onewire_release();
+        delay_us(5000);
+        data = data >> 1;
+    }
+}
+
+bool BlanksWriter::compare_key_ds1990(const uint8_t* key, uint8_t key_length) {
+    uint8_t buff[key_length];
+    bool result = false;
+
+    osKernelLock();
+    bool presence = onewire->reset();
+    osKernelUnlock();
+
+    if(presence) {
+        osKernelLock();
+        __disable_irq();
+        onewire->write(DS1990::CMD_READ_ROM);
+        onewire->read_bytes(buff, key_length);
+        __enable_irq();
+        osKernelUnlock();
+
+        result = true;
+        for(uint8_t i = 0; i < 8; i++) {
+            if(key[i] != buff[i]) {
+                result = false;
+                break;
+            }
+        }
+    }
+    return result;
+}
+
+void BlanksWriter::start() {
+    onewire->start();
+}
+
+void BlanksWriter::stop() {
+    onewire->stop();
+}

+ 40 - 0
applications/ibutton/blanks_writer.h

@@ -0,0 +1,40 @@
+#pragma once
+#include "one_wire_master.h"
+#include "maxim_crc.h"
+
+typedef enum {
+    KEY_DS1990, /**< DS1990 */
+    KEY_CYFRAL, /**< CYFRAL*/
+    KEY_METAKOM, /**< METAKOM */
+} KeyType;
+
+typedef enum {
+    WR_OK,
+    WR_SAME_KEY,
+    WR_ERROR,
+} WriterResult;
+
+class BlanksWriter {
+private:
+    const GpioPin* gpio;
+    OneWireMaster* onewire;
+
+    void onewire_release(void);
+    void onewire_write_one_bit(bool value, uint32_t delay);
+
+    bool write_TM2004(const uint8_t* key, uint8_t key_length);
+    bool write_1990_1(const uint8_t* key, uint8_t key_length);
+    bool write_1990_2(const uint8_t* key, uint8_t key_length);
+    bool write_TM01(KeyType type, const uint8_t* key, uint8_t key_length);
+
+    void write_byte_ds1990(uint8_t data);
+    bool compare_key_ds1990(const uint8_t* key, uint8_t key_length);
+
+public:
+    BlanksWriter(const GpioPin* one_wire_gpio);
+    ~BlanksWriter();
+
+    WriterResult write(KeyType type, const uint8_t* key, uint8_t key_length);
+    void start();
+    void stop();
+};

+ 8 - 4
applications/ibutton/ibutton.cpp

@@ -1,6 +1,7 @@
 #include "ibutton.h"
 #include "ibutton_mode_dallas_read.h"
 #include "ibutton_mode_dallas_emulate.h"
+#include "ibutton_mode_dallas_write.h"
 #include "ibutton_mode_cyfral_read.h"
 #include "ibutton_mode_cyfral_emulate.h"
 
@@ -8,8 +9,9 @@
 void AppiButton::run() {
     mode[0] = new AppiButtonModeDallasRead(this);
     mode[1] = new AppiButtonModeDallasEmulate(this);
-    mode[2] = new AppiButtonModeCyfralRead(this);
-    mode[3] = new AppiButtonModeCyfralEmulate(this);
+    mode[2] = new AppiButtonModeDallasWrite(this);
+    mode[3] = new AppiButtonModeCyfralRead(this);
+    mode[4] = new AppiButtonModeCyfralEmulate(this);
 
     switch_to_mode(0);
 
@@ -21,6 +23,7 @@ void AppiButton::run() {
     gpio_init(red_led_record, GpioModeOutputOpenDrain);
     gpio_init(green_led_record, GpioModeOutputOpenDrain);
 
+    api_hal_timebase_insomnia_enter();
     app_ready();
 
     AppiButtonEvent event;
@@ -29,9 +32,10 @@ void AppiButton::run() {
             if(event.type == AppiButtonEvent::EventTypeKey) {
                 // press events
                 if(event.value.input.state && event.value.input.input == InputBack) {
-                    printf("[ibutton] bye!\n");
-                    // TODO remove all widgets create by app
                     widget_enabled_set(widget, false);
+                    gui_remove_widget(gui, widget);
+                    api_hal_timebase_insomnia_exit();
+
                     osThreadExit();
                 }
 

+ 1 - 1
applications/ibutton/ibutton.h

@@ -56,7 +56,7 @@ public:
     const GpioPin* red_led_record;
     const GpioPin* green_led_record;
 
-    static const uint8_t modes_count = 4;
+    static const uint8_t modes_count = 5;
     AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count];
 
     void run();

+ 25 - 9
applications/ibutton/ibutton_mode_dallas_emulate.h

@@ -1,38 +1,50 @@
 #pragma once
 #include "ibutton.h"
-#include "one_wire_slave_gpio.h"
+#include "one_wire_slave.h"
 #include "one_wire_device_ds_1990.h"
+#include "callback-connector.h"
+#include <atomic>
 
 class AppiButtonModeDallasEmulate : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+private:
+    void result_callback(bool success, void* ctx);
+
 public:
     const char* name = "dallas emulate";
     AppiButton* app;
-    OneWireGpioSlave* onewire_slave;
     DS1990 key;
+    OneWireSlave* onewire_slave;
 
     void event(AppiButtonEvent* event, AppiButtonState* state);
     void render(Canvas* canvas, AppiButtonState* state);
     void acquire();
     void release();
 
+    std::atomic<bool> emulated_result{false};
+
     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);
+        onewire_slave = new OneWireSlave(one_wire_pin_record);
+        onewire_slave->attach(&key);
+
+        auto cb = cbc::obtain_connector(this, &AppiButtonModeDallasEmulate::result_callback);
+        onewire_slave->set_result_callback(cb, this);
     };
 };
 
+void AppiButtonModeDallasEmulate::result_callback(bool success, void* ctx) {
+    AppiButtonModeDallasEmulate* _this = static_cast<AppiButtonModeDallasEmulate*>(ctx);
+    _this->emulated_result = success;
+}
+
 void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* state) {
     if(event->type == AppiButtonEvent::EventTypeTick) {
-        onewire_slave->detach(key);
-        memcpy(key.id_storage, state->dallas_address[state->dallas_address_index], 8);
-        onewire_slave->attach(key);
-
-        if(onewire_slave->emulate()) {
+        if(emulated_result) {
+            emulated_result = false;
             app->blink_green();
         }
     } else if(event->type == AppiButtonEvent::EventTypeKey) {
@@ -44,6 +56,10 @@ void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState*
             app->increase_dallas_address();
         }
     }
+
+    onewire_slave->deattach();
+    memcpy(key.id_storage, state->dallas_address[state->dallas_address_index], 8);
+    onewire_slave->attach(&key);
 }
 
 void AppiButtonModeDallasEmulate::render(Canvas* canvas, AppiButtonState* state) {

+ 5 - 18
applications/ibutton/ibutton_mode_dallas_read.h

@@ -1,13 +1,13 @@
 #pragma once
 #include "ibutton.h"
-#include "one_wire_gpio.h"
+#include "one_wire_master.h"
 #include "maxim_crc.h"
 
 class AppiButtonModeDallasRead : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
 public:
     const char* name = "dallas read";
     AppiButton* app;
-    OneWireGpio* onewire;
+    OneWireMaster* onewire;
 
     void event(AppiButtonEvent* event, AppiButtonState* state);
     void render(Canvas* canvas, AppiButtonState* state);
@@ -19,7 +19,7 @@ public:
 
         // TODO open record
         const GpioPin* one_wire_pin_record = &ibutton_gpio;
-        onewire = new OneWireGpio(one_wire_pin_record);
+        onewire = new OneWireMaster(one_wire_pin_record);
     };
 };
 
@@ -33,30 +33,17 @@ void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* st
         osKernelUnlock();
 
         if(result) {
-            printf("device on line\n");
-
-            delay(50);
             osKernelLock();
+            __disable_irq();
             onewire->write(0x33);
             onewire->read_bytes(address, 8);
+            __enable_irq();
             osKernelUnlock();
 
-            printf("address: %x", address[0]);
-            for(uint8_t i = 1; i < 8; i++) {
-                printf(":%x", address[i]);
-            }
-            printf("\n");
-
-            printf("crc8: %x\n", maxim_crc8(address, 7));
-
             if(maxim_crc8(address, 8) == 0) {
-                printf("CRC valid\n");
                 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) {

+ 64 - 0
applications/ibutton/ibutton_mode_dallas_write.h

@@ -0,0 +1,64 @@
+#pragma once
+#include "ibutton.h"
+#include "blanks_writer.h"
+#include "maxim_crc.h"
+
+class AppiButtonModeDallasWrite : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+public:
+    const char* name = "dallas read";
+    AppiButton* app;
+    BlanksWriter* writer;
+
+    void event(AppiButtonEvent* event, AppiButtonState* state);
+    void render(Canvas* canvas, AppiButtonState* state);
+    void acquire();
+    void release();
+
+    const GpioPin* one_wire_pin_record;
+
+    AppiButtonModeDallasWrite(AppiButton* parent_app) {
+        app = parent_app;
+
+        // TODO open record
+        one_wire_pin_record = &ibutton_gpio;
+        writer = new BlanksWriter(one_wire_pin_record);
+    };
+};
+
+void AppiButtonModeDallasWrite::event(AppiButtonEvent* event, AppiButtonState* state) {
+    if(event->type == AppiButtonEvent::EventTypeTick) {
+        WriterResult result =
+            writer->write(KEY_DS1990, state->dallas_address[state->dallas_address_index], 8);
+
+        if(result == WR_SAME_KEY) {
+            app->blink_green();
+        }
+
+        if(result == WR_OK) {
+            app->blink_red();
+        }
+
+    } 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 AppiButtonModeDallasWrite::render(Canvas* canvas, AppiButtonState* state) {
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str(canvas, 2, 25, "< Dallas write >");
+    app->render_dallas_list(canvas, state);
+}
+
+void AppiButtonModeDallasWrite::acquire() {
+    writer->start();
+}
+
+void AppiButtonModeDallasWrite::release() {
+    writer->stop();
+}

+ 9 - 2
applications/input/input.c

@@ -18,6 +18,8 @@ static InputState input_state = {
     false,
 };
 
+static void exti_input_callback(void* _pin, void* _ctx);
+
 void input_task(void* p) {
     uint32_t state_bits = 0;
     uint8_t debounce_counters[INPUT_COUNT];
@@ -38,6 +40,8 @@ void input_task(void* p) {
     furi_record_create("input_state", &input_state_record);
     furi_record_create("input_events", &input_events_record);
 
+    api_interrupt_add(exti_input_callback, InterruptTypeExternalInterrupt, NULL);
+
     // we ready to work
     initialized = true;
 
@@ -103,7 +107,10 @@ void input_task(void* p) {
     }
 }
 
-void HAL_GPIO_EXTI_Callback(uint16_t pin) {
+static void exti_input_callback(void* _pin, void* _ctx) {
+    // interrupt manager get us pin constant, so...
+    uint32_t pin = (uint32_t)_pin;
+
 #ifdef APP_NFC
     if(pin == NFC_IRQ_Pin) {
         nfc_isr();
@@ -121,4 +128,4 @@ void HAL_GPIO_EXTI_Callback(uint16_t pin) {
     if(!initialized) return;
 
     signal_event(&event);
-}
+}

+ 2 - 1
applications/lf-rfid/lf-rfid.c

@@ -330,7 +330,8 @@ void lf_rfid_workaround(void* p) {
                     api_interrupt_add(
                         comparator_trigger_callback, InterruptTypeComparatorTrigger, comp_ctx);
                 } else {
-                    api_interrupt_remove(comparator_trigger_callback);
+                    api_interrupt_remove(
+                        comparator_trigger_callback, InterruptTypeComparatorTrigger);
                 }
 
                 hal_pwmn_set(

+ 0 - 97
applications/tests/furi_new_test.c

@@ -1,97 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <furi.h>
-#include "minunit.h"
-#include "furi-new.h"
-
-const int int_value_init = 0x1234;
-const int int_value_changed = 0x5678;
-osMessageQueueId_t test_messages;
-
-typedef struct {
-    char text[256];
-    bool result;
-} test_message;
-
-#define SEND_MESSAGE(value, data)                                            \
-    {                                                                        \
-        message.result = value;                                              \
-        snprintf(message.text, 256, "Error at line %d, %s", __LINE__, data); \
-        osMessageQueuePut(test_messages, &message, 0U, 0U);                  \
-    }
-
-void _furi_new_wait() {
-    osThreadFlagsWait(0x0001U, osFlagsWaitAny, osWaitForever);
-}
-
-void _furi_new_continue(FuriAppId thread_id) {
-    osThreadFlagsSet(thread_id, 0x0001U);
-}
-
-void _furi_new_main_app(void* p) {
-    test_message message;
-
-    _furi_new_wait();
-
-    int another_test_value = int_value_init;
-    furi_record_create("test/another_app_record", &another_test_value);
-
-    SEND_MESSAGE(false, "dummy text");
-
-    new_flapp_app_exit();
-}
-
-void test_furi_new() {
-    test_message message;
-    test_messages = osMessageQueueNew(1, sizeof(test_message), NULL);
-
-    // init core
-    new_furi_init();
-
-    // launch test thread
-    FuriAppId main_app = new_flapp_app_start(_furi_new_main_app, "main_app", 512, NULL);
-    _furi_new_continue(main_app);
-
-    while(1) {
-        if(osMessageQueueGet(test_messages, &message, NULL, osWaitForever) == osOK) {
-            if(message.result == true) {
-                break;
-            } else {
-                mu_assert(false, message.text);
-            }
-        }
-    };
-
-    /*
-    // test that "create" wont affect pointer value
-    furi_record_create("test/record", &test_value);
-    mu_assert_int_eq(test_value, int_value_init);
-
-    // test that we get correct pointer
-    int* test_value_pointer = furi_record_open("test/record");
-    mu_assert_pointers_not_eq(test_value_pointer, NULL);
-    mu_assert_pointers_eq(test_value_pointer, &test_value);
-
-    *test_value_pointer = int_value_changed;
-    mu_assert_int_eq(test_value, int_value_changed);
-
-    // start another app
-    new_record_available = osSemaphoreNew(1, 1, NULL);
-    osSemaphoreAcquire(new_record_available, osWaitForever);
-
-    osThreadAttr_t another_app_attr = {.name = "another_app", .stack_size = 512};
-    osThreadId_t player = osThreadNew(another_app, NULL, &another_app_attr);
-
-    // wait until app create record
-    osSemaphoreAcquire(new_record_available, osWaitForever);
-
-    // open record, test that record pointed to int_value_init
-    test_value_pointer = furi_record_open("test/another_app_record");
-    mu_assert_pointers_not_eq(test_value_pointer, NULL);
-    mu_assert_int_eq(*test_value_pointer, int_value_init);
-
-    // test that we can close, (unsubscribe) from record
-    bool close_result = new_furi_close("test/another_app_record");
-    mu_assert(close_result, "cannot close record");
-    */
-}

+ 0 - 6
applications/tests/minunit_test.c

@@ -16,7 +16,6 @@ void test_furi_value_manager();
 void test_furi_event();
 
 void test_furi_memmgr();
-void test_furi_new();
 
 static int foo = 0;
 
@@ -63,10 +62,6 @@ MU_TEST(mu_test_furi_memmgr) {
     test_furi_memmgr();
 }
 
-MU_TEST(mu_test_furi_new) {
-    test_furi_new();
-}
-
 MU_TEST(mu_test_furi_value_expanders) {
     test_furi_value_composer();
     test_furi_value_manager();
@@ -92,7 +87,6 @@ MU_TEST_SUITE(test_suite) {
     MU_RUN_TEST(mu_test_furi_event);
 
     MU_RUN_TEST(mu_test_furi_memmgr);
-    MU_RUN_TEST(mu_test_furi_new);
 }
 
 int run_minunit() {

+ 81 - 26
core/api-hal/api-interrupt-mgr.c

@@ -1,23 +1,36 @@
 #include "api-interrupt-mgr.h"
+#include "mlib/m-dict.h"
 
 #include <m-list.h>
 #include <cmsis_os2.h>
 
 LIST_DEF(list_interrupt, InterruptCallbackItem, M_POD_OPLIST);
-list_interrupt_t interrupts;
-osMutexId_t interrupt_list_mutex;
+DICT_DEF2(dict_interrupt, uint32_t, M_DEFAULT_OPLIST, list_interrupt_t, M_A1_OPLIST);
+
+dict_interrupt_t interrupts_dict;
+osMutexId_t interrupt_mutex;
 
 bool api_interrupt_init() {
-    interrupt_list_mutex = osMutexNew(NULL);
-    return (interrupt_list_mutex != NULL);
+    dict_interrupt_init(interrupts_dict);
+    interrupt_mutex = osMutexNew(NULL);
+    return (interrupt_mutex != NULL);
 }
 
 void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context) {
-    if(osMutexAcquire(interrupt_list_mutex, osWaitForever) == osOK) {
+    if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) {
+        list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
+
+        if(list == NULL) {
+            list_interrupt_t new_list;
+            list_interrupt_init(new_list);
+            dict_interrupt_set_at(interrupts_dict, (uint32_t)type, new_list);
+            list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
+        }
+
         // put uninitialized item to the list
         // M_POD_OPLIST provide memset(&(a), 0, sizeof (a)) constructor
         // so item will not be ready until we set ready flag
-        InterruptCallbackItem* item = list_interrupt_push_new(interrupts);
+        InterruptCallbackItem* item = list_interrupt_push_new(*list);
 
         // initialize item
         item->callback = callback;
@@ -28,26 +41,66 @@ void api_interrupt_add(InterruptCallback callback, InterruptType type, void* con
         // TODO remove on app exit
         //flapp_on_exit(api_interrupt_remove, callback);
 
-        osMutexRelease(interrupt_list_mutex);
+        osMutexRelease(interrupt_mutex);
     }
 }
 
-void api_interrupt_remove(InterruptCallback callback) {
-    if(osMutexAcquire(interrupt_list_mutex, osWaitForever) == osOK) {
-        // iterate over items
-        list_interrupt_it_t it;
-        for(list_interrupt_it(it, interrupts); !list_interrupt_end_p(it);
-            list_interrupt_next(it)) {
-            const InterruptCallbackItem* item = list_interrupt_cref(it);
+void api_interrupt_remove(InterruptCallback callback, InterruptType type) {
+    if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) {
+        list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
 
-            // if the iterator is equal to our element
-            if(item->callback == callback) {
-                list_interrupt_remove(interrupts, it);
-                break;
+        if(list != NULL) {
+            // iterate over items
+            list_interrupt_it_t it;
+            list_interrupt_it(it, *list);
+            while(!list_interrupt_end_p(it)) {
+                if(it->current->data.callback == callback) {
+                    list_interrupt_remove(*list, it);
+                } else {
+                    list_interrupt_next(it);
+                }
             }
         }
 
-        osMutexRelease(interrupt_list_mutex);
+        osMutexRelease(interrupt_mutex);
+    }
+}
+
+void api_interrupt_enable(InterruptCallback callback, InterruptType type) {
+    if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) {
+        list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
+
+        if(list != NULL) {
+            // iterate over items
+            list_interrupt_it_t it;
+            for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) {
+                // if the iterator is equal to our element
+                if(it->current->data.callback == callback) {
+                    it->current->data.ready = true;
+                }
+            }
+        }
+
+        osMutexRelease(interrupt_mutex);
+    }
+}
+
+void api_interrupt_disable(InterruptCallback callback, InterruptType type) {
+    if(osMutexAcquire(interrupt_mutex, osWaitForever) == osOK) {
+        list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
+
+        if(list != NULL) {
+            // iterate over items
+            list_interrupt_it_t it;
+            for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) {
+                // if the iterator is equal to our element
+                if(it->current->data.callback == callback) {
+                    it->current->data.ready = false;
+                }
+            }
+        }
+
+        osMutexRelease(interrupt_mutex);
     }
 }
 
@@ -55,14 +108,16 @@ void api_interrupt_call(InterruptType type, void* hw) {
     // that executed in interrupt ctx so mutex don't needed
     // but we need to check ready flag
 
-    // iterate over items
-    list_interrupt_it_t it;
-    for(list_interrupt_it(it, interrupts); !list_interrupt_end_p(it); list_interrupt_next(it)) {
-        const InterruptCallbackItem* item = list_interrupt_cref(it);
+    list_interrupt_t* list = dict_interrupt_get(interrupts_dict, (uint32_t)type);
 
-        // if the iterator is equal to our element
-        if(item->type == type && item->ready) {
-            item->callback(hw, item->context);
+    if(list != NULL) {
+        // iterate over items
+        list_interrupt_it_t it;
+        for(list_interrupt_it(it, *list); !list_interrupt_end_p(it); list_interrupt_next(it)) {
+            // if the iterator is equal to our element
+            if(it->current->data.ready) {
+                it->current->data.callback(hw, it->current->data.context);
+            }
         }
     }
 }

+ 6 - 1
core/api-hal/api-interrupt-mgr.h

@@ -11,6 +11,9 @@ typedef void (*InterruptCallback)(void*, void*);
 typedef enum {
     InterruptTypeComparatorTrigger,
     InterruptTypeTimerCapture,
+    InterruptTypeTimerOutputCompare,
+    InterruptTypeTimerUpdate,
+    InterruptTypeExternalInterrupt,
 } InterruptType;
 
 typedef struct {
@@ -22,7 +25,9 @@ typedef struct {
 
 bool api_interrupt_init();
 void api_interrupt_add(InterruptCallback callback, InterruptType type, void* context);
-void api_interrupt_remove(InterruptCallback callback);
+void api_interrupt_remove(InterruptCallback callback, InterruptType type);
+void api_interrupt_enable(InterruptCallback callback, InterruptType type);
+void api_interrupt_disable(InterruptCallback callback, InterruptType type);
 void api_interrupt_call(InterruptType type, void* hw);
 
 #ifdef __cplusplus

+ 2 - 0
firmware/targets/f4/Inc/stm32wbxx_it.h

@@ -62,7 +62,9 @@ void ADC1_IRQHandler(void);
 void USB_LP_IRQHandler(void);
 void COMP_IRQHandler(void);
 void EXTI9_5_IRQHandler(void);
+void TIM1_UP_TIM16_IRQHandler(void);
 void TIM1_TRG_COM_TIM17_IRQHandler(void);
+void TIM1_CC_IRQHandler(void);
 void TIM2_IRQHandler(void);
 void EXTI15_10_IRQHandler(void);
 void HSEM_IRQHandler(void);

+ 33 - 1
firmware/targets/f4/Src/stm32wbxx_it.c

@@ -64,6 +64,9 @@ extern COMP_HandleTypeDef hcomp1;
 extern RTC_HandleTypeDef hrtc;
 extern TIM_HandleTypeDef htim1;
 extern TIM_HandleTypeDef htim2;
+extern TIM_HandleTypeDef htim16;
+extern TIM_HandleTypeDef htim17;
+
 /* USER CODE BEGIN EV */
 
 /* USER CODE END EV */
@@ -292,6 +295,21 @@ void EXTI9_5_IRQHandler(void)
   /* USER CODE END EXTI9_5_IRQn 1 */
 }
 
+/**
+  * @brief This function handles TIM1 update interrupt and TIM16 global interrupt.
+  */
+void TIM1_UP_TIM16_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */
+
+  /* USER CODE END TIM1_UP_TIM16_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim1);
+  HAL_TIM_IRQHandler(&htim16);
+  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */
+
+  /* USER CODE END TIM1_UP_TIM16_IRQn 1 */
+}
+
 /**
   * @brief This function handles TIM1 trigger and commutation interrupts and TIM17 global interrupt.
   */
@@ -306,6 +324,20 @@ void TIM1_TRG_COM_TIM17_IRQHandler(void)
   /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */
 }
 
+/**
+  * @brief This function handles TIM1 capture compare interrupt.
+  */
+void TIM1_CC_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM1_CC_IRQn 0 */
+
+  /* USER CODE END TIM1_CC_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim1);
+  /* USER CODE BEGIN TIM1_CC_IRQn 1 */
+
+  /* USER CODE END TIM1_CC_IRQn 1 */
+}
+
 /**
   * @brief This function handles TIM2 global interrupt.
   */
@@ -333,7 +365,7 @@ void EXTI15_10_IRQHandler(void)
   HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
   HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
   /* USER CODE BEGIN EXTI15_10_IRQn 1 */
-
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
   /* USER CODE END EXTI15_10_IRQn 1 */
 }
 

+ 11 - 1
firmware/targets/f4/api-hal/api-hal-timebase.h

@@ -2,6 +2,11 @@
 
 #include <stdint.h>
 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Initialize timebase
  * Configure and start tick timer
  */
@@ -24,4 +29,9 @@ void api_hal_timebase_insomnia_enter();
  * @warning Internally decreases insomnia level.
  * Must be paired with api_hal_timebase_insomnia_enter
  */
-void api_hal_timebase_insomnia_exit();
+void api_hal_timebase_insomnia_exit();
+
+
+#ifdef __cplusplus
+}
+#endif

+ 23 - 0
firmware/targets/f4/api-hal/api-interrupts.c

@@ -4,10 +4,33 @@
 extern void api_interrupt_call(InterruptType type, void* hw);
 
 /* interrupts */
+
+/* Comparator trigger event */
 void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp) {
     api_interrupt_call(InterruptTypeComparatorTrigger, hcomp);
 }
 
+/* Timer input capture event */
 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim) {
     api_interrupt_call(InterruptTypeTimerCapture, htim);
+}
+
+/* Output compare event */
+void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) {
+    api_interrupt_call(InterruptTypeTimerOutputCompare, htim);
+}
+
+/* Timer update event */
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) {
+    api_interrupt_call(InterruptTypeTimerUpdate, htim);
+
+    // handle HAL ticks
+    if(htim->Instance == TIM17) {
+        HAL_IncTick();
+    }
+}
+
+/* External interrupt event */
+void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
+    api_interrupt_call(InterruptTypeExternalInterrupt, GPIO_Pin);
 }

+ 1 - 1
lib/cyfral/cyfral_reader_comp.h

@@ -256,7 +256,7 @@ void CyfralReaderComp::stop(void) {
 
     // disconnect comparator callback
     auto cmp_cb = cbc::obtain_connector(this, &CyfralReaderComp::comparator_trigger_callback);
-    api_interrupt_remove(cmp_cb);
+    api_interrupt_remove(cmp_cb, InterruptTypeComparatorTrigger);
     osMessageQueueDelete(comp_event_queue);
 }
 

+ 18 - 5
lib/onewire/one_wire_device.cpp

@@ -1,8 +1,5 @@
 #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,
@@ -21,6 +18,22 @@ OneWireDevice::OneWireDevice(
     id_storage[7] = maxim_crc8(id_storage, 7);
 }
 
-void OneWireDevice::send_id(OneWireGpioSlave* owner) const {
-    owner->send(id_storage, 8);
+OneWireDevice::~OneWireDevice() {
+    if(bus != nullptr) {
+        bus->deattach();
+    }
+}
+
+void OneWireDevice::send_id() const {
+    if(bus != nullptr) {
+        bus->send(id_storage, 8);
+    }
+}
+
+void OneWireDevice::attach(OneWireSlave* _bus) {
+    bus = _bus;
+}
+
+void OneWireDevice::deattach(void) {
+    bus = nullptr;
 }

+ 6 - 14
lib/onewire/one_wire_device.h

@@ -1,10 +1,7 @@
 #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
+#include "one_wire_slave.h"
 
 class OneWireDevice {
 public:
@@ -17,18 +14,13 @@ public:
         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;
+    ~OneWireDevice();
 
     uint8_t id_storage[8];
 
-    void send_id(OneWireGpioSlave* owner) const;
+    void send_id() const;
 
-    virtual void do_work(OneWireGpioSlave* owner) = 0;
+    OneWireSlave* bus = nullptr;
+    void attach(OneWireSlave* _bus);
+    void deattach(void);
 };

+ 0 - 15
lib/onewire/one_wire_device_ds_1990.cpp

@@ -1,8 +1,5 @@
 #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,
@@ -12,16 +9,4 @@ DS1990::DS1990(
     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);
-    }
 }

+ 0 - 5
lib/onewire/one_wire_device_ds_1990.h

@@ -1,9 +1,6 @@
 #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};
@@ -16,6 +13,4 @@ public:
         uint8_t ID5,
         uint8_t ID6,
         uint8_t ID7);
-
-    void do_work(OneWireGpioSlave* owner) final;
 };

+ 15 - 28
lib/onewire/one_wire_gpio.h → lib/onewire/one_wire_master.cpp

@@ -1,41 +1,24 @@
 #pragma once
-#include <furi.h>
+#include "one_wire_master.h"
 #include "one_wire_timings.h"
 
-class OneWireGpio {
-private:
-    const GpioPin* gpio;
-
-public:
-    OneWireGpio(const GpioPin* one_wire_gpio);
-    ~OneWireGpio();
-    bool reset(void);
-    bool read_bit(void);
-    uint8_t read(void);
-    void read_bytes(uint8_t* buf, uint16_t count);
-    void write_bit(bool value);
-    void write(uint8_t value);
-    void start(void);
-    void stop(void);
-};
-
-OneWireGpio::OneWireGpio(const GpioPin* one_wire_gpio) {
+OneWireMaster::OneWireMaster(const GpioPin* one_wire_gpio) {
     gpio = one_wire_gpio;
 }
 
-OneWireGpio::~OneWireGpio() {
+OneWireMaster::~OneWireMaster() {
     stop();
 }
 
-void OneWireGpio::start(void) {
+void OneWireMaster::start(void) {
     gpio_init(gpio, GpioModeOutputOpenDrain);
 }
 
-void OneWireGpio::stop(void) {
+void OneWireMaster::stop(void) {
     gpio_init(gpio, GpioModeAnalog);
 }
 
-bool OneWireGpio::reset(void) {
+bool OneWireMaster::reset(void) {
     uint8_t r;
     uint8_t retries = 125;
 
@@ -64,7 +47,7 @@ bool OneWireGpio::reset(void) {
     return r;
 }
 
-bool OneWireGpio::read_bit(void) {
+bool OneWireMaster::read_bit(void) {
     bool result;
 
     // drive low
@@ -82,7 +65,7 @@ bool OneWireGpio::read_bit(void) {
     return result;
 }
 
-void OneWireGpio::write_bit(bool value) {
+void OneWireMaster::write_bit(bool value) {
     if(value) {
         // drive low
         gpio_write(gpio, false);
@@ -102,7 +85,7 @@ void OneWireGpio::write_bit(bool value) {
     }
 }
 
-uint8_t OneWireGpio::read(void) {
+uint8_t OneWireMaster::read(void) {
     uint8_t result = 0;
 
     for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
@@ -114,16 +97,20 @@ uint8_t OneWireGpio::read(void) {
     return result;
 }
 
-void OneWireGpio::read_bytes(uint8_t* buffer, uint16_t count) {
+void OneWireMaster::read_bytes(uint8_t* buffer, uint16_t count) {
     for(uint16_t i = 0; i < count; i++) {
         buffer[i] = read();
     }
 }
 
-void OneWireGpio::write(uint8_t value) {
+void OneWireMaster::write(uint8_t value) {
     uint8_t bitMask;
 
     for(bitMask = 0x01; bitMask; bitMask <<= 1) {
         write_bit((bitMask & value) ? 1 : 0);
     }
 }
+
+void OneWireMaster::skip(void) {
+    write(0xCC);
+}

+ 21 - 0
lib/onewire/one_wire_master.h

@@ -0,0 +1,21 @@
+#pragma once
+#include <furi.h>
+#include "one_wire_timings.h"
+
+class OneWireMaster {
+private:
+    const GpioPin* gpio;
+
+public:
+    OneWireMaster(const GpioPin* one_wire_gpio);
+    ~OneWireMaster();
+    bool reset(void);
+    bool read_bit(void);
+    uint8_t read(void);
+    void read_bytes(uint8_t* buf, uint16_t count);
+    void write_bit(bool value);
+    void write(uint8_t value);
+    void skip(void);
+    void start(void);
+    void stop(void);
+};

+ 312 - 0
lib/onewire/one_wire_slave.cpp

@@ -0,0 +1,312 @@
+#include "one_wire_slave.h"
+#include "callback-connector.h"
+#include "main.h"
+#include "one_wire_device.h"
+
+#define OWET OneWireEmulateTiming
+
+void OneWireSlave::start(void) {
+    // add exti interrupt
+    api_interrupt_add(exti_cb, InterruptTypeExternalInterrupt, this);
+
+    // init gpio
+    gpio_init(one_wire_pin_record, GpioModeInterruptRiseFall);
+    pin_set_float();
+
+    // init instructions per us count
+    __instructions_per_us = (SystemCoreClock / 1000000.0f);
+}
+
+void OneWireSlave::stop(void) {
+    // deinit gpio
+    gpio_init_ex(one_wire_pin_record, GpioModeInput, GpioPullNo, GpioSpeedLow);
+
+    // remove exti interrupt
+    api_interrupt_remove(exti_cb, InterruptTypeExternalInterrupt);
+
+    // deattach devices
+    deattach();
+}
+
+OneWireSlave::OneWireSlave(const GpioPin* pin) {
+    one_wire_pin_record = pin;
+    exti_cb = cbc::obtain_connector(this, &OneWireSlave::exti_callback);
+}
+
+OneWireSlave::~OneWireSlave() {
+    stop();
+}
+
+void OneWireSlave::attach(OneWireDevice* attached_device) {
+    device = attached_device;
+    device->attach(this);
+}
+
+void OneWireSlave::deattach(void) {
+    device = nullptr;
+    device->deattach();
+}
+
+void OneWireSlave::set_result_callback(OneWireSlaveResultCallback result_cb, void* ctx) {
+    this->result_cb = result_cb;
+    this->result_cb_ctx = ctx;
+}
+
+void OneWireSlave::pin_set_float() {
+    gpio_write(one_wire_pin_record, true);
+}
+
+void OneWireSlave::pin_set_low() {
+    gpio_write(one_wire_pin_record, false);
+}
+
+void OneWireSlave::pin_init_interrupt_in_isr_ctx(void) {
+    hal_gpio_init(one_wire_pin_record, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
+    __HAL_GPIO_EXTI_CLEAR_IT(one_wire_pin_record->pin);
+}
+
+void OneWireSlave::pin_init_opendrain_in_isr_ctx(void) {
+    hal_gpio_init(one_wire_pin_record, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
+    __HAL_GPIO_EXTI_CLEAR_IT(one_wire_pin_record->pin);
+}
+
+OneWiteTimeType OneWireSlave::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(one_wire_pin_record) != 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;
+}
+
+bool OneWireSlave::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);
+    pin_set_float();
+
+    // somebody also can show presence
+    const OneWiteTimeType wait_low_time = OWET::PRESENCE_MAX - OWET::PRESENCE_MIN;
+
+    // so we will wait
+    if(wait_while_gpio_is(wait_low_time, false) == 0) {
+        error = OneWireSlaveError::PRESENCE_LOW_ON_LINE;
+        return false;
+    }
+
+    return true;
+}
+
+bool OneWireSlave::receive_bit(void) {
+    // wait while bus is low
+    OneWiteTimeType time = OWET::SLOT_MAX;
+    time = wait_while_gpio_is(time, false);
+    if(time == 0) {
+        error = OneWireSlaveError::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 = OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH;
+        return false;
+    }
+
+    // wait a time of zero
+    time = OWET::READ_MIN;
+    time = wait_while_gpio_is(time, false);
+
+    return (time > 0);
+}
+
+bool OneWireSlave::send_bit(bool value) {
+    const bool write_zero = !value;
+
+    // wait while bus is low
+    OneWiteTimeType time = OWET::SLOT_MAX;
+    time = wait_while_gpio_is(time, false);
+    if(time == 0) {
+        error = OneWireSlaveError::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 = OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH;
+        return false;
+    }
+
+    // choose write time
+    if(write_zero) {
+        pin_set_low();
+        time = OWET::WRITE_ZERO;
+    } else {
+        time = OWET::READ_MAX;
+    }
+
+    // hold line for ZERO or ONE time
+    delay_us(time);
+    pin_set_float();
+
+    return true;
+}
+
+bool OneWireSlave::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 == OneWireSlaveError::AWAIT_TIMESLOT_TIMEOUT_HIGH))
+                    error = OneWireSlaveError::FIRST_BIT_OF_BYTE_TIMEOUT;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool OneWireSlave::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);
+}
+
+void OneWireSlave::cmd_search_rom(void) {
+    const uint8_t key_bytes = 8;
+    uint8_t* key = device->id_storage;
+
+    for(uint8_t i = 0; i < key_bytes; i++) {
+        uint8_t key_byte = key[i];
+
+        for(uint8_t j = 0; j < 8; j++) {
+            bool bit = (key_byte >> j) & 0x01;
+
+            if(!send_bit(bit)) return;
+            if(!send_bit(!bit)) return;
+
+            const bool bit_recv = receive_bit();
+            if(error != OneWireSlaveError::NO_ERROR) return;
+        }
+    }
+}
+
+bool OneWireSlave::receive_and_process_cmd(void) {
+    uint8_t cmd;
+    receive(&cmd, 1);
+
+    if(error == OneWireSlaveError::RESET_IN_PROGRESS) return true;
+    if(error != OneWireSlaveError::NO_ERROR) return false;
+
+    switch(cmd) {
+    case 0xF0:
+        // SEARCH ROM
+        cmd_search_rom();
+        return true;
+
+    case 0x33:
+        // READ ROM
+        device->send_id();
+        return false;
+
+    default: // Unknown command
+        error = OneWireSlaveError::INCORRECT_ONEWIRE_CMD;
+    }
+
+    if(error == OneWireSlaveError::RESET_IN_PROGRESS) return true;
+    return (error == OneWireSlaveError::NO_ERROR);
+}
+
+bool OneWireSlave::bus_start(void) {
+    bool result = true;
+
+    if(device == nullptr) {
+        result = false;
+    } else {
+        pin_init_opendrain_in_isr_ctx();
+        error = OneWireSlaveError::NO_ERROR;
+
+        if(show_presence()) {
+            __disable_irq();
+
+            // TODO think about multiple command cycles
+            bool return_to_reset = receive_and_process_cmd();
+            result =
+                (error == OneWireSlaveError::NO_ERROR ||
+                 error == OneWireSlaveError::INCORRECT_ONEWIRE_CMD);
+
+            __enable_irq();
+        } else {
+            result = false;
+        }
+
+        pin_init_interrupt_in_isr_ctx();
+    }
+
+    return result;
+}
+
+void OneWireSlave::exti_callback(void* _pin, void* _ctx) {
+    // interrupt manager get us pin constant, so...
+    uint32_t pin = (uint32_t)_pin;
+    OneWireSlave* _this = static_cast<OneWireSlave*>(_ctx);
+
+    if(pin == _this->one_wire_pin_record->pin) {
+        volatile bool input_state = gpio_read(_this->one_wire_pin_record);
+        static uint32_t pulse_start = 0;
+
+        if(input_state) {
+            uint32_t pulse_length = (DWT->CYCCNT - pulse_start) / __instructions_per_us;
+            if(pulse_length >= OWET::RESET_MIN) {
+                if(pulse_length <= OWET::RESET_MAX) {
+                    // reset cycle ok
+                    bool result = _this->bus_start();
+
+                    if(_this->result_cb != nullptr) {
+                        _this->result_cb(result, _this->result_cb_ctx);
+                    }
+                } else {
+                    error = OneWireSlaveError::VERY_LONG_RESET;
+                }
+            } else {
+                error = OneWireSlaveError::VERY_SHORT_RESET;
+            }
+        } else {
+            //FALL event
+            pulse_start = DWT->CYCCNT;
+        }
+    }
+}

+ 74 - 0
lib/onewire/one_wire_slave.h

@@ -0,0 +1,74 @@
+#pragma once
+#include <furi.h>
+#include "one_wire_timings.h"
+
+class OneWireDevice;
+typedef void (*OneWireSlaveResultCallback)(bool success, void* ctx);
+
+class OneWireSlave {
+private:
+    enum class OneWireSlaveError : uint8_t {
+        NO_ERROR = 0,
+        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
+    };
+
+    const GpioPin* one_wire_pin_record;
+
+    // exti callback and its pointer
+    void exti_callback(void* _pin, void* _ctx);
+    void (*exti_cb)(void* _pin, void* _ctx);
+
+    uint32_t __instructions_per_us;
+
+    OneWireSlaveError error;
+    OneWireDevice* device = nullptr;
+
+    bool bus_start(void);
+
+    void pin_set_float(void);
+    void pin_set_low(void);
+    void pin_init_interrupt_in_isr_ctx(void);
+    void pin_init_opendrain_in_isr_ctx(void);
+
+    OneWiteTimeType wait_while_gpio_is(OneWiteTimeType time, const bool pin_value);
+
+    bool show_presence(void);
+    bool receive_and_process_cmd(void);
+
+    bool receive_bit(void);
+    bool send_bit(bool value);
+
+    void cmd_search_rom(void);
+
+    OneWireSlaveResultCallback result_cb = nullptr;
+    void* result_cb_ctx = nullptr;
+
+public:
+    void start(void);
+    void stop(void);
+
+    bool send(const uint8_t* address, const uint8_t data_length);
+    bool receive(uint8_t* data, const uint8_t data_length = 1);
+
+    OneWireSlave(const GpioPin* pin);
+    ~OneWireSlave();
+
+    void attach(OneWireDevice* device);
+    void deattach(void);
+
+    void set_result_callback(OneWireSlaveResultCallback result_cb, void* ctx);
+};

+ 0 - 517
lib/onewire/one_wire_slave_gpio.cpp

@@ -1,517 +0,0 @@
-#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() {
-    bool anything_emulated = false;
-    error = OneWireGpioSlaveError::NO_ERROR;
-
-    while(1) {
-        if(devices_count == 0) return false;
-
-        if(!check_reset()) {
-            return anything_emulated;
-        } else {
-        }
-
-        // OK, we receive reset
-        osKernelLock();
-
-        if(!show_presence()) {
-            return anything_emulated;
-        } else {
-            anything_emulated = true;
-        }
-
-        // and we succefully show our presence on bus
-        __disable_irq();
-
-        // TODO think about return condition
-        if(!receive_and_process_cmd()) {
-            __enable_irq();
-            osKernelUnlock();
-        } else {
-            __enable_irq();
-            osKernelUnlock();
-        }
-    }
-}
-
-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
-    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;
-    }
-
-    // get real reset time
-    time_remaining = OWET::RESET_MAX[0] - time_remaining;
-
-    // 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);
-}

+ 0 - 92
lib/onewire/one_wire_slave_gpio.h

@@ -1,92 +0,0 @@
-#pragma once
-#include <furi.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);
-};

+ 8 - 9
lib/onewire/one_wire_timings.cpp

@@ -1,17 +1,16 @@
 #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::RESET_MIN;
+constexpr const OneWiteTimeType OneWireEmulateTiming::RESET_MAX;
 
 constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_TIMEOUT;
-constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MIN[2];
-constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MAX[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MIN;
+constexpr const OneWiteTimeType OneWireEmulateTiming::PRESENCE_MAX;
 
 constexpr const OneWiteTimeType OneWireEmulateTiming::MSG_HIGH_TIMEOUT;
-constexpr const OneWiteTimeType OneWireEmulateTiming::SLOT_MAX[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::SLOT_MAX;
 
-constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MIN[2];
-constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MAX[2];
-constexpr const OneWiteTimeType OneWireEmulateTiming::WRITE_ZERO[2];
+constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MIN;
+constexpr const OneWiteTimeType OneWireEmulateTiming::READ_MAX;
+constexpr const OneWiteTimeType OneWireEmulateTiming::WRITE_ZERO;

+ 14 - 15
lib/onewire/one_wire_timings.h

@@ -3,10 +3,10 @@
 
 class __OneWireTiming {
 public:
-    constexpr static const uint16_t TIMING_A = 6;
+    constexpr static const uint16_t TIMING_A = 9;
     constexpr static const uint16_t TIMING_B = 64;
-    constexpr static const uint16_t TIMING_C = 60;
-    constexpr static const uint16_t TIMING_D = 10;
+    constexpr static const uint16_t TIMING_C = 64;
+    constexpr static const uint16_t TIMING_D = 14;
     constexpr static const uint16_t TIMING_E = 9;
     constexpr static const uint16_t TIMING_F = 55;
     constexpr static const uint16_t TIMING_G = 0;
@@ -23,7 +23,7 @@ public:
     constexpr static const uint16_t WRITE_0_DRIVE = __OneWireTiming::TIMING_C;
     constexpr static const uint16_t WRITE_0_RELEASE = __OneWireTiming::TIMING_D;
 
-    constexpr static const uint16_t READ_DRIVE = __OneWireTiming::TIMING_A;
+    constexpr static const uint16_t READ_DRIVE = 3;
     constexpr static const uint16_t READ_RELEASE = __OneWireTiming::TIMING_E;
     constexpr static const uint16_t READ_DELAY_POST = __OneWireTiming::TIMING_F;
 
@@ -37,18 +37,17 @@ typedef uint32_t OneWiteTimeType;
 
 class OneWireEmulateTiming {
 public:
-    constexpr static const OneWiteTimeType RESET_TIMEOUT = {5000};
-    constexpr static const OneWiteTimeType RESET_MIN[2] = {430, 48};
-    constexpr static const OneWiteTimeType RESET_MAX[2] = {960, 80};
+    constexpr static const OneWiteTimeType RESET_MIN = 430;
+    constexpr static const OneWiteTimeType RESET_MAX = 960;
 
-    constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = {20};
-    constexpr static const OneWiteTimeType PRESENCE_MIN[2] = {160, 8};
-    constexpr static const OneWiteTimeType PRESENCE_MAX[2] = {480, 32};
+    constexpr static const OneWiteTimeType PRESENCE_TIMEOUT = 20;
+    constexpr static const OneWiteTimeType PRESENCE_MIN = 160;
+    constexpr static const OneWiteTimeType PRESENCE_MAX = 480;
 
-    constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = {15000};
-    constexpr static const OneWiteTimeType SLOT_MAX[2] = {135, 30};
+    constexpr static const OneWiteTimeType MSG_HIGH_TIMEOUT = 15000;
+    constexpr static const OneWiteTimeType SLOT_MAX = 135;
 
-    constexpr static const OneWiteTimeType READ_MIN[2] = {20, 4};
-    constexpr static const OneWiteTimeType READ_MAX[2] = {60, 10};
-    constexpr static const OneWiteTimeType WRITE_ZERO[2] = {30, 8};
+    constexpr static const OneWiteTimeType READ_MIN = 20;
+    constexpr static const OneWiteTimeType READ_MAX = 60;
+    constexpr static const OneWiteTimeType WRITE_ZERO = 30;
 };