DrZlo13 5 лет назад
Родитель
Сommit
4eeac6579f

+ 9 - 0
applications/applications.h

@@ -35,6 +35,7 @@ void power_task(void* p);
 void sd_card_test(void* p);
 void sd_card_test(void* p);
 void application_vibro(void* p);
 void application_vibro(void* p);
 void app_gpio_test(void* p);
 void app_gpio_test(void* p);
+void app_ibutton(void* p);
 
 
 const FlipperStartupApp FLIPPER_STARTUP[] = {
 const FlipperStartupApp FLIPPER_STARTUP[] = {
 #ifdef APP_DISPLAY
 #ifdef APP_DISPLAY
@@ -122,6 +123,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = {
         .name = "gpio test",
         .name = "gpio test",
         .libs = {1, FURI_LIB{"gui_task"}},
         .libs = {1, FURI_LIB{"gui_task"}},
 #endif
 #endif
+
+#ifdef APP_IBUTTON
+    {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}},
+#endif
     };
     };
 
 
 const FlipperStartupApp FLIPPER_APPS[] = {
 const FlipperStartupApp FLIPPER_APPS[] = {
@@ -164,4 +169,8 @@ const FlipperStartupApp FLIPPER_APPS[] = {
 #ifdef BUILD_GPIO_DEMO
 #ifdef BUILD_GPIO_DEMO
     {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}},
     {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}},
 #endif
 #endif
+
+#ifdef BUILD_IBUTTON
+    {.app = app_ibutton, .name = "ibutton", .libs = {1, FURI_LIB{"gui_task"}}},
+#endif
 };
 };

+ 101 - 0
applications/ibutton/ibutton.cpp

@@ -0,0 +1,101 @@
+#include "ibutton.h"
+#include "ibutton_mode_dallas_read.h"
+#include "ibutton_mode_dallas_emulate.h"
+
+// start app
+void AppiButton::run() {
+    mode[0] = new AppiButtonModeDallasRead(this);
+    mode[1] = new AppiButtonModeDallasEmulate(this);
+
+    // create pin
+    GpioPin red_led = led_gpio[0];
+    GpioPin green_led = led_gpio[1];
+
+    // TODO open record
+    red_led_record = &red_led;
+    green_led_record = &green_led;
+
+    // configure pin
+    gpio_init(red_led_record, GpioModeOutputOpenDrain);
+    gpio_init(green_led_record, GpioModeOutputOpenDrain);
+
+    AppiButtonEvent event;
+    while(1) {
+        osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
+
+        if(event_status == osOK) {
+            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);
+                    furiac_exit(NULL);
+                }
+
+                if(event.value.input.state && event.value.input.input == InputLeft) {
+                    decrease_mode();
+                }
+
+                if(event.value.input.state && event.value.input.input == InputRight) {
+                    increase_mode();
+                }
+            }
+        } else {
+            event.type = AppiButtonEvent::EventTypeTick;
+        }
+
+        acquire_state();
+        mode[state.mode_index]->event(&event, &state);
+        release_state();
+
+        widget_update(widget);
+    };
+}
+
+// render app
+void AppiButton::render(CanvasApi* canvas) {
+    canvas->set_color(canvas, ColorBlack);
+    canvas->set_font(canvas, FontPrimary);
+    canvas->draw_str(canvas, 2, 12, "iButton");
+
+    mode[state.mode_index]->render(canvas, &state);
+}
+
+void AppiButton::blink_red() {
+    gpio_write(red_led_record, 0);
+    delay(10);
+    gpio_write(red_led_record, 1);
+}
+
+void AppiButton::blink_green() {
+    gpio_write(green_led_record, 0);
+    delay(10);
+    gpio_write(green_led_record, 1);
+}
+
+void AppiButton::increase_mode() {
+    acquire_state();
+    if(state.mode_index < (modes_count - 1)) {
+        mode[state.mode_index]->release();
+        state.mode_index++;
+        mode[state.mode_index]->acquire();
+    }
+    release_state();
+}
+
+void AppiButton::decrease_mode() {
+    acquire_state();
+    if(state.mode_index > 0) {
+        mode[state.mode_index]->release();
+        state.mode_index--;
+        mode[state.mode_index]->acquire();
+    }
+    release_state();
+}
+
+// app enter function
+extern "C" void app_ibutton(void* p) {
+    AppiButton* app = new AppiButton();
+    app->run();
+}

+ 54 - 0
applications/ibutton/ibutton.h

@@ -0,0 +1,54 @@
+#pragma once
+#include "app-template.h"
+#include "ibutton_mode_template.h"
+
+// event enumeration type
+typedef uint8_t event_t;
+
+class AppiButtonState {
+public:
+    // state data
+    uint8_t dallas_address[8] = {0x01, 0xFD, 0x0E, 0x84, 0x01, 0x00, 0x00, 0xDB};
+    uint8_t mode_index;
+
+    // state initializer
+    AppiButtonState() {
+        mode_index = 0;
+    }
+};
+
+// events class
+class AppiButtonEvent {
+public:
+    // events enum
+    static const event_t EventTypeTick = 0;
+    static const event_t EventTypeKey = 1;
+
+    // payload
+    union {
+        InputEvent input;
+    } value;
+
+    // event type
+    event_t type;
+};
+
+// our app derived from base AppTemplate class
+// with template variables <state, events>
+class AppiButton : public AppTemplate<AppiButtonState, AppiButtonEvent> {
+public:
+    GpioPin* red_led_record;
+    GpioPin* green_led_record;
+
+    static const uint8_t modes_count = 2;
+    AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count];
+
+    void run();
+    void render(CanvasApi* canvas);
+
+    void blink_red();
+    void blink_green();
+
+    void increase_mode();
+    void decrease_mode();
+};

+ 64 - 0
applications/ibutton/ibutton_mode_dallas_emulate.h

@@ -0,0 +1,64 @@
+#pragma once
+#include "ibutton.h"
+#include "one_wire_slave_gpio.h"
+
+class AppiButtonModeDallasEmulate : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+public:
+    const char* name = "dallas emulate";
+    AppiButton* app;
+    OneWireGpioSlave* onewire_slave;
+
+    void event(AppiButtonEvent* event, AppiButtonState* state);
+    void render(CanvasApi* canvas, AppiButtonState* state);
+    void acquire();
+    void release();
+
+    AppiButtonModeDallasEmulate(AppiButton* parent_app) {
+        app = parent_app;
+
+        // TODO open record
+        GpioPin one_wire_pin = {iBTN_GPIO_Port, iBTN_Pin};
+        GpioPin* one_wire_pin_record = &one_wire_pin;
+        onewire_slave = new OneWireGpioSlave(one_wire_pin_record);
+    };
+};
+
+void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState* state) {
+    if(event->type == AppiButtonEvent::EventTypeTick) {
+        acquire();
+        if(onewire_slave->emulate(state->dallas_address, 8)) {
+            app->blink_green();
+        } else {
+            
+        }
+    }
+}
+
+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, "give me domophone");
+    {
+        char buf[24];
+        sprintf(
+            buf,
+            "%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);
+    }
+}
+
+void AppiButtonModeDallasEmulate::acquire() {
+    onewire_slave->start();
+}
+
+void AppiButtonModeDallasEmulate::release() {
+    onewire_slave->stop();
+}

+ 119 - 0
applications/ibutton/ibutton_mode_dallas_read.h

@@ -0,0 +1,119 @@
+#pragma once
+#include "ibutton.h"
+#include "one_wire_gpio.h"
+
+class AppiButtonModeDallasRead : public AppTemplateMode<AppiButtonState, AppiButtonEvent> {
+public:
+    const char* name = "dallas read";
+    AppiButton* app;
+    OneWireGpio* onewire;
+
+    void event(AppiButtonEvent* event, AppiButtonState* state);
+    void render(CanvasApi* canvas, AppiButtonState* state);
+    void acquire();
+    void release();
+
+    AppiButtonModeDallasRead(AppiButton* parent_app) {
+        app = parent_app;
+
+        // TODO open record
+        GpioPin one_wire_pin = {iBTN_GPIO_Port, iBTN_Pin};
+        GpioPin* one_wire_pin_record = &one_wire_pin;
+        onewire = new OneWireGpio(one_wire_pin_record);
+    };
+
+    uint8_t crc_8(uint8_t* buffer, uint8_t count);
+};
+
+void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* state) {
+    if(event->type == AppiButtonEvent::EventTypeTick) {
+        bool result = 0;
+        uint8_t address[8];
+
+        osKernelLock();
+        result = onewire->reset();
+        osKernelUnlock();
+
+        if(result) {
+            printf("device on line\n");
+
+            delay(50);
+            osKernelLock();
+            onewire->write(0x33);
+            onewire->read_bytes(address, 8);
+            osKernelUnlock();
+
+            printf("address: %x", address[0]);
+            for(uint8_t i = 1; i < 8; i++) {
+                printf(":%x", address[i]);
+            }
+            printf("\n");
+
+            printf("crc8: %x\n", crc_8(address, 7));
+
+            if(crc_8(address, 8) == 0) {
+                printf("CRC valid\n");
+                memcpy(app->state.dallas_address, address, 8);
+                app->blink_green();
+            } else {
+                printf("CRC invalid\n");
+            }
+        } else {
+        }
+    }
+}
+
+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");
+    {
+        char buf[24];
+        sprintf(
+            buf,
+            "%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;
+}
+
+void AppiButtonModeDallasRead::acquire() {
+    onewire->start();
+}
+
+void AppiButtonModeDallasRead::release() {
+    onewire->stop();
+}

+ 11 - 0
applications/ibutton/ibutton_mode_template.h

@@ -0,0 +1,11 @@
+#pragma once
+
+// template for modes
+template <class TState, class TEvents> class AppTemplateMode {
+public:
+    const char* name;
+    virtual void event(TEvents* event, TState* state) = 0;
+    virtual void render(CanvasApi* canvas, TState* state) = 0;
+    virtual void acquire() = 0;
+    virtual void release() = 0;
+};

+ 130 - 0
applications/ibutton/one_wire_gpio.h

@@ -0,0 +1,130 @@
+#pragma once
+#include "flipper.h"
+#include "flipper_v2.h"
+#include "one_wire_timings.h"
+
+class OneWireGpio {
+private:
+    GpioPin* gpio;
+
+public:
+    OneWireGpio(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(GpioPin* one_wire_gpio) {
+    gpio = one_wire_gpio;
+}
+
+OneWireGpio::~OneWireGpio() {
+    stop();
+}
+
+void OneWireGpio::start(void) {
+    gpio_init(gpio, GpioModeOutputOpenDrain);
+}
+
+void OneWireGpio::stop(void) {
+    gpio_init(gpio, GpioModeAnalog);
+}
+
+bool OneWireGpio::reset(void) {
+    uint8_t r;
+    uint8_t retries = 125;
+
+    // wait until the gpio is high
+    gpio_write(gpio, true);
+    do {
+        if(--retries == 0) return 0;
+        delay_us(2);
+    } while(!gpio_read(gpio));
+
+    // pre delay
+    delay_us(OneWireTiming::RESET_DELAY_PRE);
+
+    // drive low
+    gpio_write(gpio, false);
+    delay_us(OneWireTiming::RESET_DRIVE);
+
+    // release
+    gpio_write(gpio, true);
+    delay_us(OneWireTiming::RESET_RELEASE);
+
+    // read and post delay
+    r = !gpio_read(gpio);
+    delay_us(OneWireTiming::RESET_DELAY_POST);
+
+    return r;
+}
+
+bool OneWireGpio::read_bit(void) {
+    bool result;
+
+    // drive low
+    gpio_write(gpio, false);
+    delay_us(OneWireTiming::READ_DRIVE);
+
+    // release
+    gpio_write(gpio, true);
+    delay_us(OneWireTiming::READ_RELEASE);
+
+    // read and post delay
+    result = gpio_read(gpio);
+    delay_us(OneWireTiming::READ_DELAY_POST);
+
+    return result;
+}
+
+void OneWireGpio::write_bit(bool value) {
+    if(value) {
+        // drive low
+        gpio_write(gpio, false);
+        delay_us(OneWireTiming::WRITE_1_DRIVE);
+
+        // release
+        gpio_write(gpio, true);
+        delay_us(OneWireTiming::WRITE_1_RELEASE);
+    } else {
+        // drive low
+        gpio_write(gpio, false);
+        delay_us(OneWireTiming::WRITE_0_DRIVE);
+
+        // release
+        gpio_write(gpio, true);
+        delay_us(OneWireTiming::WRITE_0_RELEASE);
+    }
+}
+
+uint8_t OneWireGpio::read(void) {
+    uint8_t result = 0;
+
+    for(uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
+        if(read_bit()) {
+            result |= bitMask;
+        }
+    }
+
+    return result;
+}
+
+void OneWireGpio::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) {
+    uint8_t bitMask;
+
+    for(bitMask = 0x01; bitMask; bitMask <<= 1) {
+        write_bit((bitMask & value) ? 1 : 0);
+    }
+}

+ 179 - 0
applications/ibutton/one_wire_slave_gpio.h

@@ -0,0 +1,179 @@
+#pragma once
+#include "flipper.h"
+#include "flipper_v2.h"
+#include "one_wire_timings.h"
+
+class OneWireGpioSlave {
+private:
+    GpioPin* gpio;
+
+public:
+    OneWireGpioSlave(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(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);
+}

+ 54 - 0
applications/ibutton/one_wire_timings.h

@@ -0,0 +1,54 @@
+#pragma once
+#include <stdint.h>
+
+class __OneWireTiming {
+public:
+    constexpr static const uint16_t TIMING_A = 6;
+    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_E = 9;
+    constexpr static const uint16_t TIMING_F = 55;
+    constexpr static const uint16_t TIMING_G = 0;
+    constexpr static const uint16_t TIMING_H = 480;
+    constexpr static const uint16_t TIMING_I = 70;
+    constexpr static const uint16_t TIMING_J = 410;
+};
+
+class OneWireTiming {
+public:
+    constexpr static const uint16_t WRITE_1_DRIVE = __OneWireTiming::TIMING_A;
+    constexpr static const uint16_t WRITE_1_RELEASE = __OneWireTiming::TIMING_B;
+
+    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_RELEASE = __OneWireTiming::TIMING_E;
+    constexpr static const uint16_t READ_DELAY_POST = __OneWireTiming::TIMING_F;
+
+    constexpr static const uint16_t RESET_DELAY_PRE = __OneWireTiming::TIMING_G;
+    constexpr static const uint16_t RESET_DRIVE = __OneWireTiming::TIMING_H;
+    constexpr static const uint16_t RESET_RELEASE = __OneWireTiming::TIMING_I;
+    constexpr static const uint16_t RESET_DELAY_POST = __OneWireTiming::TIMING_J;
+};
+
+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 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 MSG_HIGH_TIMEOUT = {15000};
+    constexpr static const OneWiteTimeType SLOT_MAX[2] = {135, 30};
+
+    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};
+};