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

[FL-3057] Allow use of any suitable pin for 1-Wire devices (#2350)

* Add 1-wire thermometer example app stub
* Working 1-wire thermometer app
* Refactor app to use threads
* Clean up code, add comments
* Add CRC checking
* Increase update period
* Fix error in fbt
* Revert the old update period
* Use settable pin in onewire_host
* Use settable pin for onewire_slave
* Clear EXTI flag after callback, make private methods static in onewire_slave
* Do not hardcode GPIO pin number
* Remove iButton hal from furi_hal_rfid
* Remove most of furi_hal_ibutton
* Add some of furi_hal_ibutton back
* Slightly neater code
* Fix formatting
* Fix PVS-studio warnings
* Update CODEOWNERS
* Add furi_hal_gpio_get_ext_pin_number
* Create README.md
* FuriHal: move furi_hal_gpio_get_ext_pin_number to resources

---------

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Georgii Surkov 2 лет назад
Родитель
Сommit
7a3a1aaf0d

+ 2 - 0
.github/CODEOWNERS

@@ -42,6 +42,8 @@
 
 
 /applications/debug/unit_tests/ @skotopes @DrZlo13 @hedger @nminaylov @gornekich @Astrrra @gsurkov @Skorpionm
 /applications/debug/unit_tests/ @skotopes @DrZlo13 @hedger @nminaylov @gornekich @Astrrra @gsurkov @Skorpionm
 
 
+/applications/examples/example_thermo/ @skotopes @DrZlo13 @hedger @gsurkov
+
 # Assets
 # Assets
 /assets/resources/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
 /assets/resources/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
 
 

+ 44 - 0
applications/examples/example_thermo/README.md

@@ -0,0 +1,44 @@
+# 1-Wire Thermometer
+This example application demonstrates the use of the 1-Wire library with a DS18B20 thermometer. 
+It also covers basic GUI, input handling, threads and localisation.
+
+## Electrical connections
+Before launching the application, connect the sensor to Flipper's external GPIO according to the table below:
+| DS18B20 | Flipper |
+| :-----: | :-----: |
+| VDD | 9 |
+| GND | 18 |
+| DQ  | 17 |
+
+*NOTE 1*: GND is also available on pins 8 and 11.
+
+*NOTE 2*: For any other pin than 17, connect an external 4.7k pull-up resistor to pin 9.
+
+## Launching the application
+In order to launch this demo, follow the steps below:
+1. Make sure your Flipper has an SD card installed.
+2. Connect your Flipper to the computer via a USB cable.
+3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice.
+
+## Changing the data pin
+It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below:
+
+```c
+/* Possible GPIO pin choices:
+ - gpio_ext_pc0
+ - gpio_ext_pc1
+ - gpio_ext_pc3
+ - gpio_ext_pb2
+ - gpio_ext_pb3
+ - gpio_ext_pa4
+ - gpio_ext_pa6
+ - gpio_ext_pa7
+ - ibutton_gpio
+*/
+
+#define THERMO_GPIO_PIN (ibutton_gpio)
+```
+Do not forget about the external pull-up resistor as these pins do not have one built-in.
+
+With the changes been made, recompile and launch the application again. 
+The on-screen text should reflect it by asking to connect the thermometer to another pin.

+ 10 - 0
applications/examples/example_thermo/application.fam

@@ -0,0 +1,10 @@
+App(
+    appid="example_thermo",
+    name="Example: Thermometer",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="example_thermo_main",
+    requires=["gui"],
+    stack_size=1 * 1024,
+    fap_icon="example_thermo_10px.png",
+    fap_category="Examples",
+)

+ 356 - 0
applications/examples/example_thermo/example_thermo.c

@@ -0,0 +1,356 @@
+/*
+ * This file contains an example application that reads and displays
+ * the temperature from a DS18B20 1-wire thermometer.
+ *
+ * It also covers basic GUI, input handling, threads and localisation.
+ *
+ * References:
+ * [1] DS18B20 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf
+ */
+
+#include <gui/gui.h>
+#include <gui/view_port.h>
+
+#include <core/thread.h>
+#include <core/kernel.h>
+
+#include <locale/locale.h>
+
+#include <one_wire/maxim_crc.h>
+#include <one_wire/one_wire_host.h>
+
+#define UPDATE_PERIOD_MS 1000UL
+#define TEXT_STORE_SIZE 64U
+
+#define DS18B20_CMD_CONVERT 0x44U
+#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU
+
+#define DS18B20_CFG_RESOLUTION_POS 5U
+#define DS18B20_CFG_RESOLUTION_MASK 0x03U
+#define DS18B20_DECIMAL_PART_MASK 0x0fU
+
+#define DS18B20_SIGN_MASK 0xf0U
+
+/* Possible GPIO pin choices:
+ - gpio_ext_pc0
+ - gpio_ext_pc1
+ - gpio_ext_pc3
+ - gpio_ext_pb2
+ - gpio_ext_pb3
+ - gpio_ext_pa4
+ - gpio_ext_pa6
+ - gpio_ext_pa7
+ - ibutton_gpio
+*/
+
+#define THERMO_GPIO_PIN (ibutton_gpio)
+
+/* Flags which the reader thread responds to */
+typedef enum {
+    ReaderThreadFlagExit = 1,
+} ReaderThreadFlag;
+
+typedef union {
+    struct {
+        uint8_t temp_lsb; /* Least significant byte of the temperature */
+        uint8_t temp_msb; /* Most significant byte of the temperature */
+        uint8_t user_alarm_high; /* User register 1 (Temp high alarm) */
+        uint8_t user_alarm_low; /* User register 2 (Temp low alarm) */
+        uint8_t config; /* Configuration register */
+        uint8_t reserved[3]; /* Not used */
+        uint8_t crc; /* CRC checksum for error detection */
+    } fields;
+    uint8_t bytes[9];
+} DS18B20Scratchpad;
+
+/* Application context structure */
+typedef struct {
+    Gui* gui;
+    ViewPort* view_port;
+    FuriThread* reader_thread;
+    FuriMessageQueue* event_queue;
+    OneWireHost* onewire;
+    float temp_celsius;
+    bool has_device;
+} ExampleThermoContext;
+
+/*************** 1-Wire Communication and Processing *****************/
+
+/* Commands the thermometer to begin measuring the temperature. */
+static void example_thermo_request_temperature(ExampleThermoContext* context) {
+    OneWireHost* onewire = context->onewire;
+
+    /* All 1-wire transactions must happen in a critical section, i.e
+       not interrupted by other threads. */
+    FURI_CRITICAL_ENTER();
+
+    bool success = false;
+    do {
+        /* Each communication with a 1-wire device starts by a reset.
+           The functon will return true if a device responded with a presence pulse. */
+        if(!onewire_host_reset(onewire)) break;
+        /* After the reset, a ROM operation must follow.
+           If there is only one device connected, the "Skip ROM" command is most appropriate
+           (it can also be used to address all of the connected devices in some cases).*/
+        onewire_host_skip(onewire);
+        /* After the ROM operation, a device-specific command is issued.
+           In this case, it's a request to start measuring the temperature. */
+        onewire_host_write(onewire, DS18B20_CMD_CONVERT);
+
+        success = true;
+    } while(false);
+
+    context->has_device = success;
+
+    FURI_CRITICAL_EXIT();
+}
+
+/* Reads the measured temperature from the thermometer. */
+static void example_thermo_read_temperature(ExampleThermoContext* context) {
+    /* If there was no device detected, don't try to read the temperature */
+    if(!context->has_device) {
+        return;
+    }
+
+    OneWireHost* onewire = context->onewire;
+
+    /* All 1-wire transactions must happen in a critical section, i.e
+       not interrupted by other threads. */
+    FURI_CRITICAL_ENTER();
+
+    bool success = false;
+
+    do {
+        DS18B20Scratchpad buf;
+
+        /* Attempt reading the temperature 10 times before giving up */
+        size_t attempts_left = 10;
+        do {
+            /* Each communication with a 1-wire device starts by a reset.
+            The functon will return true if a device responded with a presence pulse. */
+            if(!onewire_host_reset(onewire)) continue;
+
+            /* After the reset, a ROM operation must follow.
+            If there is only one device connected, the "Skip ROM" command is most appropriate
+            (it can also be used to address all of the connected devices in some cases).*/
+            onewire_host_skip(onewire);
+
+            /* After the ROM operation, a device-specific command is issued.
+            This time, it will be the "Read Scratchpad" command which will
+            prepare the device's internal buffer memory for reading. */
+            onewire_host_write(onewire, DS18B20_CMD_READ_SCRATCHPAD);
+
+            /* The actual reading happens here. A total of 9 bytes is read. */
+            onewire_host_read_bytes(onewire, buf.bytes, sizeof(buf.bytes));
+
+            /* Calculate the checksum and compare it with one provided by the device. */
+            const uint8_t crc = maxim_crc8(buf.bytes, sizeof(buf.bytes) - 1, MAXIM_CRC8_INIT);
+
+            /* Checksums match, exit the loop */
+            if(crc == buf.fields.crc) break;
+
+        } while(--attempts_left);
+
+        if(attempts_left == 0) break;
+
+        /* Get the measurement resolution from the configuration register. (See [1] page 9) */
+        const uint8_t resolution_mode = (buf.fields.config >> DS18B20_CFG_RESOLUTION_POS) &
+                                        DS18B20_CFG_RESOLUTION_MASK;
+
+        /* Generate a mask for undefined bits in the decimal part. (See [1] page 6) */
+        const uint8_t decimal_mask =
+            (DS18B20_DECIMAL_PART_MASK << (DS18B20_CFG_RESOLUTION_MASK - resolution_mode)) &
+            DS18B20_DECIMAL_PART_MASK;
+
+        /* Get the integer and decimal part of the temperature (See [1] page 6) */
+        const uint8_t integer_part = (buf.fields.temp_msb << 4U) | (buf.fields.temp_lsb >> 4U);
+        const uint8_t decimal_part = buf.fields.temp_lsb & decimal_mask;
+
+        /* Calculate the sign of the temperature (See [1] page 6) */
+        const bool is_negative = (buf.fields.temp_msb & DS18B20_SIGN_MASK) != 0;
+
+        /* Combine the integer and decimal part together */
+        const float temp_celsius_abs = integer_part + decimal_part / 16.f;
+
+        /* Set the appropriate sign */
+        context->temp_celsius = is_negative ? -temp_celsius_abs : temp_celsius_abs;
+
+        success = true;
+    } while(false);
+
+    context->has_device = success;
+
+    FURI_CRITICAL_EXIT();
+}
+
+/* Periodically requests measurements and reads temperature. This function runs in a separare thread. */
+static int32_t example_thermo_reader_thread_callback(void* ctx) {
+    ExampleThermoContext* context = ctx;
+
+    for(;;) {
+        /* Tell the termometer to start measuring the temperature. The process may take up to 750ms. */
+        example_thermo_request_temperature(context);
+
+        /* Wait for the measurement to finish. At the same time wait for an exit signal. */
+        const uint32_t flags =
+            furi_thread_flags_wait(ReaderThreadFlagExit, FuriFlagWaitAny, UPDATE_PERIOD_MS);
+
+        /* If an exit signal was received, return from this thread. */
+        if(flags != (unsigned)FuriFlagErrorTimeout) break;
+
+        /* The measurement is now ready, read it from the termometer. */
+        example_thermo_read_temperature(context);
+    }
+
+    return 0;
+}
+
+/*************** GUI, Input and Main Loop *****************/
+
+/* Draw the GUI of the application. The screen is completely redrawn during each call. */
+static void example_thermo_draw_callback(Canvas* canvas, void* ctx) {
+    ExampleThermoContext* context = ctx;
+    char text_store[TEXT_STORE_SIZE];
+    const size_t middle_x = canvas_width(canvas) / 2U;
+
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(canvas, middle_x, 12, AlignCenter, AlignBottom, "Thermometer Demo");
+    canvas_draw_line(canvas, 0, 16, 128, 16);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(
+        canvas, middle_x, 30, AlignCenter, AlignBottom, "Connnect thermometer");
+
+    snprintf(
+        text_store,
+        TEXT_STORE_SIZE,
+        "to GPIO pin %ld",
+        furi_hal_resources_get_ext_pin_number(&THERMO_GPIO_PIN));
+    canvas_draw_str_aligned(canvas, middle_x, 42, AlignCenter, AlignBottom, text_store);
+
+    canvas_set_font(canvas, FontKeyboard);
+
+    if(context->has_device) {
+        float temp;
+        char temp_units;
+
+        /* The applicaton is locale-aware.
+           Change Settings->System->Units to check it out. */
+        switch(locale_get_measurement_unit()) {
+        case LocaleMeasurementUnitsMetric:
+            temp = context->temp_celsius;
+            temp_units = 'C';
+            break;
+        case LocaleMeasurementUnitsImperial:
+            temp = locale_celsius_to_fahrenheit(context->temp_celsius);
+            temp_units = 'F';
+            break;
+        default:
+            furi_crash("Illegal measurement units");
+        }
+        /* If a reading is available, display it */
+        snprintf(text_store, TEXT_STORE_SIZE, "Temperature: %+.1f%c", (double)temp, temp_units);
+    } else {
+        /* Or show a message that no data is available */
+        strncpy(text_store, "-- No data --", TEXT_STORE_SIZE);
+    }
+
+    canvas_draw_str_aligned(canvas, middle_x, 58, AlignCenter, AlignBottom, text_store);
+}
+
+/* This function is called from the GUI thread. All it does is put the event
+   into the application's queue so it can be processed later. */
+static void example_thermo_input_callback(InputEvent* event, void* ctx) {
+    ExampleThermoContext* context = ctx;
+    furi_message_queue_put(context->event_queue, event, FuriWaitForever);
+}
+
+/* Starts the reader thread and handles the input */
+static void example_thermo_run(ExampleThermoContext* context) {
+    /* Configure the hardware in host mode */
+    onewire_host_start(context->onewire);
+
+    /* Start the reader thread. It will talk to the thermometer in the background. */
+    furi_thread_start(context->reader_thread);
+
+    /* An endless loop which handles the input*/
+    for(bool is_running = true; is_running;) {
+        InputEvent event;
+        /* Wait for an input event. Input events come from the GUI thread via a callback. */
+        const FuriStatus status =
+            furi_message_queue_get(context->event_queue, &event, FuriWaitForever);
+
+        /* This application is only interested in short button presses. */
+        if((status != FuriStatusOk) || (event.type != InputTypeShort)) {
+            continue;
+        }
+
+        /* When the user presses the "Back" button, break the loop and exit the application. */
+        if(event.key == InputKeyBack) {
+            is_running = false;
+        }
+    }
+
+    /* Signal the reader thread to cease operation and exit */
+    furi_thread_flags_set(furi_thread_get_id(context->reader_thread), ReaderThreadFlagExit);
+
+    /* Wait for the reader thread to finish */
+    furi_thread_join(context->reader_thread);
+
+    /* Reset the hardware */
+    onewire_host_stop(context->onewire);
+}
+
+/******************** Initialisation & startup *****************************/
+
+/* Allocate the memory and initialise the variables */
+static ExampleThermoContext* example_thermo_context_alloc() {
+    ExampleThermoContext* context = malloc(sizeof(ExampleThermoContext));
+
+    context->view_port = view_port_alloc();
+    view_port_draw_callback_set(context->view_port, example_thermo_draw_callback, context);
+    view_port_input_callback_set(context->view_port, example_thermo_input_callback, context);
+
+    context->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
+
+    context->reader_thread = furi_thread_alloc();
+    furi_thread_set_stack_size(context->reader_thread, 1024U);
+    furi_thread_set_context(context->reader_thread, context);
+    furi_thread_set_callback(context->reader_thread, example_thermo_reader_thread_callback);
+
+    context->gui = furi_record_open(RECORD_GUI);
+    gui_add_view_port(context->gui, context->view_port, GuiLayerFullscreen);
+
+    context->onewire = onewire_host_alloc(&THERMO_GPIO_PIN);
+
+    return context;
+}
+
+/* Release the unused resources and deallocate memory */
+static void example_thermo_context_free(ExampleThermoContext* context) {
+    view_port_enabled_set(context->view_port, false);
+    gui_remove_view_port(context->gui, context->view_port);
+
+    onewire_host_free(context->onewire);
+    furi_thread_free(context->reader_thread);
+    furi_message_queue_free(context->event_queue);
+    view_port_free(context->view_port);
+
+    furi_record_close(RECORD_GUI);
+}
+
+/* The application's entry point. Execution starts from here. */
+int32_t example_thermo_main(void* p) {
+    UNUSED(p);
+
+    /* Allocate all of the necessary structures */
+    ExampleThermoContext* context = example_thermo_context_alloc();
+
+    /* Start the applicaton's main loop. It won't return until the application was requested to exit. */
+    example_thermo_run(context);
+
+    /* Release all unneeded resources */
+    example_thermo_context_free(context);
+
+    return 0;
+}

BIN
applications/examples/example_thermo/example_thermo_10px.png


+ 1 - 1
applications/main/ibutton/ibutton_cli.c

@@ -271,7 +271,7 @@ void onewire_cli_print_usage() {
 
 
 static void onewire_cli_search(Cli* cli) {
 static void onewire_cli_search(Cli* cli) {
     UNUSED(cli);
     UNUSED(cli);
-    OneWireHost* onewire = onewire_host_alloc();
+    OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
     uint8_t address[8];
     uint8_t address[8];
     bool done = false;
     bool done = false;
 
 

+ 2 - 1
firmware/targets/f18/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
 entry,status,name,type,params
-Version,+,12.2,,
+Version,+,13.0,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
@@ -910,6 +910,7 @@ Function,-,furi_hal_flash_write_dword,void,"size_t, uint64_t"
 Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*"
 Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*"
 Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin*
+Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin*
 Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed"
 Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed"
 Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn"
 Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn"
 Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
 Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"

+ 24 - 0
firmware/targets/f18/furi_hal/furi_hal_resources.c

@@ -199,3 +199,27 @@ void furi_hal_resources_init() {
     NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
     NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
     NVIC_EnableIRQ(EXTI15_10_IRQn);
     NVIC_EnableIRQ(EXTI15_10_IRQn);
 }
 }
+
+int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) {
+    // TODO: describe second ROW
+    if(gpio == &gpio_ext_pa7)
+        return 2;
+    else if(gpio == &gpio_ext_pa6)
+        return 3;
+    else if(gpio == &gpio_ext_pa4)
+        return 4;
+    else if(gpio == &gpio_ext_pb3)
+        return 5;
+    else if(gpio == &gpio_ext_pb2)
+        return 6;
+    else if(gpio == &gpio_ext_pc3)
+        return 7;
+    else if(gpio == &gpio_ext_pc1)
+        return 15;
+    else if(gpio == &gpio_ext_pc0)
+        return 16;
+    else if(gpio == &ibutton_gpio)
+        return 17;
+    else
+        return -1;
+}

+ 7 - 0
firmware/targets/f18/furi_hal/furi_hal_resources.h

@@ -111,6 +111,13 @@ void furi_hal_resources_deinit_early();
 
 
 void furi_hal_resources_init();
 void furi_hal_resources_init();
 
 
+/**
+ * Get a corresponding external connector pin number for a gpio
+ * @param gpio GpioPin
+ * @return pin number or -1 if gpio is not on the external connector
+ */
+int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 7 - 13
firmware/targets/f7/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
 entry,status,name,type,params
-Version,+,12.2,,
+Version,+,13.0,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/bt/bt_service/bt.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
 Header,+,applications/services/cli/cli_vcp.h,,
@@ -1094,6 +1094,7 @@ Function,-,furi_hal_flash_write_dword,void,"size_t, uint64_t"
 Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*"
 Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*"
 Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin*
 Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin*
+Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin*
 Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed"
 Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed"
 Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn"
 Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn"
 Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
 Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
@@ -1129,20 +1130,13 @@ Function,+,furi_hal_i2c_tx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uin
 Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t"
 Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t"
 Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t"
 Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t"
 Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t"
 Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t"
-Function,+,furi_hal_ibutton_add_interrupt,void,"GpioExtiCallback, void*"
 Function,+,furi_hal_ibutton_emulate_set_next,void,uint32_t
 Function,+,furi_hal_ibutton_emulate_set_next,void,uint32_t
 Function,+,furi_hal_ibutton_emulate_start,void,"uint32_t, FuriHalIbuttonEmulateCallback, void*"
 Function,+,furi_hal_ibutton_emulate_start,void,"uint32_t, FuriHalIbuttonEmulateCallback, void*"
 Function,+,furi_hal_ibutton_emulate_stop,void,
 Function,+,furi_hal_ibutton_emulate_stop,void,
 Function,-,furi_hal_ibutton_init,void,
 Function,-,furi_hal_ibutton_init,void,
-Function,+,furi_hal_ibutton_pin_get_level,_Bool,
-Function,+,furi_hal_ibutton_pin_high,void,
-Function,+,furi_hal_ibutton_pin_low,void,
-Function,+,furi_hal_ibutton_remove_interrupt,void,
-Function,+,furi_hal_ibutton_start_drive,void,
-Function,+,furi_hal_ibutton_start_drive_in_isr,void,
-Function,+,furi_hal_ibutton_start_interrupt,void,
-Function,+,furi_hal_ibutton_start_interrupt_in_isr,void,
-Function,+,furi_hal_ibutton_stop,void,
+Function,+,furi_hal_ibutton_pin_configure,void,
+Function,+,furi_hal_ibutton_pin_reset,void,
+Function,+,furi_hal_ibutton_pin_write,void,const _Bool
 Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
 Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*"
 Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*"
 Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*"
 Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t
 Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t
@@ -2040,7 +2034,7 @@ Function,+,onewire_device_detach,void,OneWireDevice*
 Function,+,onewire_device_free,void,OneWireDevice*
 Function,+,onewire_device_free,void,OneWireDevice*
 Function,+,onewire_device_get_id_p,uint8_t*,OneWireDevice*
 Function,+,onewire_device_get_id_p,uint8_t*,OneWireDevice*
 Function,+,onewire_device_send_id,void,OneWireDevice*
 Function,+,onewire_device_send_id,void,OneWireDevice*
-Function,+,onewire_host_alloc,OneWireHost*,
+Function,+,onewire_host_alloc,OneWireHost*,const GpioPin*
 Function,+,onewire_host_free,void,OneWireHost*
 Function,+,onewire_host_free,void,OneWireHost*
 Function,+,onewire_host_read,uint8_t,OneWireHost*
 Function,+,onewire_host_read,uint8_t,OneWireHost*
 Function,+,onewire_host_read_bit,_Bool,OneWireHost*
 Function,+,onewire_host_read_bit,_Bool,OneWireHost*
@@ -2054,7 +2048,7 @@ Function,+,onewire_host_stop,void,OneWireHost*
 Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t"
 Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t"
 Function,+,onewire_host_write,void,"OneWireHost*, uint8_t"
 Function,+,onewire_host_write,void,"OneWireHost*, uint8_t"
 Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool"
 Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool"
-Function,+,onewire_slave_alloc,OneWireSlave*,
+Function,+,onewire_slave_alloc,OneWireSlave*,const GpioPin*
 Function,+,onewire_slave_attach,void,"OneWireSlave*, OneWireDevice*"
 Function,+,onewire_slave_attach,void,"OneWireSlave*, OneWireDevice*"
 Function,+,onewire_slave_detach,void,OneWireSlave*
 Function,+,onewire_slave_detach,void,OneWireSlave*
 Function,+,onewire_slave_free,void,OneWireSlave*
 Function,+,onewire_slave_free,void,OneWireSlave*

+ 17 - 16
firmware/targets/f7/furi_hal/furi_hal_gpio.c

@@ -1,6 +1,7 @@
 #include <furi.h>
 #include <furi.h>
 #include <furi_hal_gpio.h>
 #include <furi_hal_gpio.h>
 #include <furi_hal_version.h>
 #include <furi_hal_version.h>
+#include <furi_hal_resources.h>
 #include <stm32wbxx_ll_comp.h>
 #include <stm32wbxx_ll_comp.h>
 
 
 #define GET_SYSCFG_EXTI_PORT(gpio)                \
 #define GET_SYSCFG_EXTI_PORT(gpio)                \
@@ -224,85 +225,85 @@ static void furi_hal_gpio_int_call(uint16_t pin_num) {
 /* Interrupt handlers */
 /* Interrupt handlers */
 void EXTI0_IRQHandler(void) {
 void EXTI0_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
         furi_hal_gpio_int_call(0);
         furi_hal_gpio_int_call(0);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0);
     }
     }
 }
 }
 
 
 void EXTI1_IRQHandler(void) {
 void EXTI1_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1);
         furi_hal_gpio_int_call(1);
         furi_hal_gpio_int_call(1);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1);
     }
     }
 }
 }
 
 
 void EXTI2_IRQHandler(void) {
 void EXTI2_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2);
         furi_hal_gpio_int_call(2);
         furi_hal_gpio_int_call(2);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2);
     }
     }
 }
 }
 
 
 void EXTI3_IRQHandler(void) {
 void EXTI3_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
         furi_hal_gpio_int_call(3);
         furi_hal_gpio_int_call(3);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
     }
     }
 }
 }
 
 
 void EXTI4_IRQHandler(void) {
 void EXTI4_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
         furi_hal_gpio_int_call(4);
         furi_hal_gpio_int_call(4);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
     }
     }
 }
 }
 
 
 void EXTI9_5_IRQHandler(void) {
 void EXTI9_5_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
         furi_hal_gpio_int_call(5);
         furi_hal_gpio_int_call(5);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
         furi_hal_gpio_int_call(6);
         furi_hal_gpio_int_call(6);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7);
         furi_hal_gpio_int_call(7);
         furi_hal_gpio_int_call(7);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
         furi_hal_gpio_int_call(8);
         furi_hal_gpio_int_call(8);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
         furi_hal_gpio_int_call(9);
         furi_hal_gpio_int_call(9);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
     }
     }
 }
 }
 
 
 void EXTI15_10_IRQHandler(void) {
 void EXTI15_10_IRQHandler(void) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10);
         furi_hal_gpio_int_call(10);
         furi_hal_gpio_int_call(10);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11);
         furi_hal_gpio_int_call(11);
         furi_hal_gpio_int_call(11);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
         furi_hal_gpio_int_call(12);
         furi_hal_gpio_int_call(12);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
         furi_hal_gpio_int_call(13);
         furi_hal_gpio_int_call(13);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14);
         furi_hal_gpio_int_call(14);
         furi_hal_gpio_int_call(14);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14);
     }
     }
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) {
     if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) {
-        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15);
         furi_hal_gpio_int_call(15);
         furi_hal_gpio_int_call(15);
+        LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15);
     }
     }
 }
 }

+ 6 - 37
firmware/targets/f7/furi_hal/furi_hal_ibutton.c

@@ -89,47 +89,16 @@ void furi_hal_ibutton_emulate_stop() {
     }
     }
 }
 }
 
 
-void furi_hal_ibutton_start_drive() {
-    furi_hal_ibutton_pin_high();
-    furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
-}
-
-void furi_hal_ibutton_start_drive_in_isr() {
+void furi_hal_ibutton_pin_configure() {
+    furi_hal_gpio_write(&ibutton_gpio, true);
     furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
     furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
-    LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin);
-}
-
-void furi_hal_ibutton_start_interrupt() {
-    furi_hal_ibutton_pin_high();
-    furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
-}
-
-void furi_hal_ibutton_start_interrupt_in_isr() {
-    furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
-    LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin);
-}
-
-void furi_hal_ibutton_stop() {
-    furi_hal_ibutton_pin_high();
-    furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
-void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) {
-    furi_hal_gpio_add_int_callback(&ibutton_gpio, cb, context);
-}
-
-void furi_hal_ibutton_remove_interrupt() {
-    furi_hal_gpio_remove_int_callback(&ibutton_gpio);
-}
-
-void furi_hal_ibutton_pin_low() {
-    furi_hal_gpio_write(&ibutton_gpio, false);
-}
-
-void furi_hal_ibutton_pin_high() {
+void furi_hal_ibutton_pin_reset() {
     furi_hal_gpio_write(&ibutton_gpio, true);
     furi_hal_gpio_write(&ibutton_gpio, true);
+    furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
-bool furi_hal_ibutton_pin_get_level() {
-    return furi_hal_gpio_read(&ibutton_gpio);
+void furi_hal_ibutton_pin_write(const bool state) {
+    furi_hal_gpio_write(&ibutton_gpio, state);
 }
 }

+ 17 - 45
firmware/targets/f7/furi_hal/furi_hal_ibutton.h

@@ -7,7 +7,6 @@
 
 
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
-#include <furi_hal_gpio.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -18,70 +17,43 @@ typedef void (*FuriHalIbuttonEmulateCallback)(void* context);
 /** Initialize */
 /** Initialize */
 void furi_hal_ibutton_init();
 void furi_hal_ibutton_init();
 
 
+/**
+ * Start emulation timer
+ * @param period timer period
+ * @param callback timer callback
+ * @param context callback context
+ */
 void furi_hal_ibutton_emulate_start(
 void furi_hal_ibutton_emulate_start(
     uint32_t period,
     uint32_t period,
     FuriHalIbuttonEmulateCallback callback,
     FuriHalIbuttonEmulateCallback callback,
     void* context);
     void* context);
 
 
-void furi_hal_ibutton_emulate_set_next(uint32_t period);
-
-void furi_hal_ibutton_emulate_stop();
-
 /**
 /**
- * Sets the pin to normal mode (open collector), and sets it to float
+ * Update emulation timer period
+ * @param period new timer period
  */
  */
-void furi_hal_ibutton_start_drive();
-
-/**
- * Sets the pin to normal mode (open collector), and clears pin EXTI interrupt.
- * Used in EXTI interrupt context.
- */
-void furi_hal_ibutton_start_drive_in_isr();
+void furi_hal_ibutton_emulate_set_next(uint32_t period);
 
 
 /**
 /**
- * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and sets it to float
+ * Stop emulation timer
  */
  */
-void furi_hal_ibutton_start_interrupt();
+void furi_hal_ibutton_emulate_stop();
 
 
 /**
 /**
- * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and clears pin EXTI interrupt.
- * Used in EXTI interrupt context.
+ * Set the pin to normal mode (open collector), and sets it to float
  */
  */
-void furi_hal_ibutton_start_interrupt_in_isr();
+void furi_hal_ibutton_pin_configure();
 
 
 /**
 /**
  * Sets the pin to analog mode, and sets it to float
  * Sets the pin to analog mode, and sets it to float
  */
  */
-void furi_hal_ibutton_stop();
-
-/**
- * Attach interrupt callback to iButton pin
- * @param cb callback
- * @param context context
- */
-void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context);
-
-/**
- * Remove interrupt callback from iButton pin
- */
-void furi_hal_ibutton_remove_interrupt();
-
-/**
- * Sets the pin to low
- */
-void furi_hal_ibutton_pin_low();
-
-/**
- * Sets the pin to high (float in iButton pin modes)
- */
-void furi_hal_ibutton_pin_high();
+void furi_hal_ibutton_pin_reset();
 
 
 /**
 /**
- * Get pin level
- * @return true if level is high
- * @return false if level is low
+ * iButton write pin
+ * @param state true / false
  */
  */
-bool furi_hal_ibutton_pin_get_level();
+void furi_hal_ibutton_pin_write(const bool state);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 23 - 0
firmware/targets/f7/furi_hal/furi_hal_resources.c

@@ -191,3 +191,26 @@ void furi_hal_resources_init() {
     NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
     NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
     NVIC_EnableIRQ(EXTI15_10_IRQn);
     NVIC_EnableIRQ(EXTI15_10_IRQn);
 }
 }
+
+int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) {
+    if(gpio == &gpio_ext_pa7)
+        return 2;
+    else if(gpio == &gpio_ext_pa6)
+        return 3;
+    else if(gpio == &gpio_ext_pa4)
+        return 4;
+    else if(gpio == &gpio_ext_pb3)
+        return 5;
+    else if(gpio == &gpio_ext_pb2)
+        return 6;
+    else if(gpio == &gpio_ext_pc3)
+        return 7;
+    else if(gpio == &gpio_ext_pc1)
+        return 15;
+    else if(gpio == &gpio_ext_pc0)
+        return 16;
+    else if(gpio == &ibutton_gpio)
+        return 17;
+    else
+        return -1;
+}

+ 7 - 0
firmware/targets/f7/furi_hal/furi_hal_resources.h

@@ -216,6 +216,13 @@ void furi_hal_resources_deinit_early();
 
 
 void furi_hal_resources_init();
 void furi_hal_resources_init();
 
 
+/**
+ * Get a corresponding external connector pin number for a gpio
+ * @param gpio GpioPin
+ * @return pin number or -1 if gpio is not on the external connector
+ */
+int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 5 - 5
firmware/targets/f7/furi_hal/furi_hal_rfid.c

@@ -77,7 +77,7 @@ void furi_hal_rfid_init() {
 
 
 void furi_hal_rfid_pins_reset() {
 void furi_hal_rfid_pins_reset() {
     // ibutton bus disable
     // ibutton bus disable
-    furi_hal_ibutton_stop();
+    furi_hal_ibutton_pin_reset();
 
 
     // pulldown rfid antenna
     // pulldown rfid antenna
     furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -94,8 +94,8 @@ void furi_hal_rfid_pins_reset() {
 
 
 void furi_hal_rfid_pins_emulate() {
 void furi_hal_rfid_pins_emulate() {
     // ibutton low
     // ibutton low
-    furi_hal_ibutton_start_drive();
-    furi_hal_ibutton_pin_low();
+    furi_hal_ibutton_pin_configure();
+    furi_hal_ibutton_pin_write(false);
 
 
     // pull pin to timer out
     // pull pin to timer out
     furi_hal_gpio_init_ex(
     furi_hal_gpio_init_ex(
@@ -115,8 +115,8 @@ void furi_hal_rfid_pins_emulate() {
 
 
 void furi_hal_rfid_pins_read() {
 void furi_hal_rfid_pins_read() {
     // ibutton low
     // ibutton low
-    furi_hal_ibutton_start_drive();
-    furi_hal_ibutton_pin_low();
+    furi_hal_ibutton_pin_configure();
+    furi_hal_ibutton_pin_write(false);
 
 
     // dont pull rfid antenna
     // dont pull rfid antenna
     furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);

+ 2 - 2
lib/one_wire/ibutton/ibutton_worker.c

@@ -25,8 +25,8 @@ iButtonWorker* ibutton_worker_alloc() {
     iButtonWorker* worker = malloc(sizeof(iButtonWorker));
     iButtonWorker* worker = malloc(sizeof(iButtonWorker));
     worker->key_p = NULL;
     worker->key_p = NULL;
     worker->key_data = malloc(ibutton_key_get_max_size());
     worker->key_data = malloc(ibutton_key_get_max_size());
-    worker->host = onewire_host_alloc();
-    worker->slave = onewire_slave_alloc();
+    worker->host = onewire_host_alloc(&ibutton_gpio);
+    worker->slave = onewire_slave_alloc(&ibutton_gpio);
     worker->writer = ibutton_writer_alloc(worker->host);
     worker->writer = ibutton_writer_alloc(worker->host);
     worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0);
     worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0);
     worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage));
     worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage));

+ 5 - 8
lib/one_wire/ibutton/ibutton_worker_modes.c

@@ -234,16 +234,13 @@ void ibutton_worker_emulate_timer_cb(void* context) {
     furi_assert(context);
     furi_assert(context);
     iButtonWorker* worker = context;
     iButtonWorker* worker = context;
 
 
-    LevelDuration level =
+    const LevelDuration level_duration =
         protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode);
         protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode);
 
 
-    furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level));
+    const bool level = level_duration_get_level(level_duration);
 
 
-    if(level_duration_get_level(level)) {
-        furi_hal_ibutton_pin_high();
-    } else {
-        furi_hal_ibutton_pin_low();
-    }
+    furi_hal_ibutton_emulate_set_next(level);
+    furi_hal_ibutton_pin_write(level);
 }
 }
 
 
 void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
 void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
@@ -266,7 +263,7 @@ void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
     protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size);
     protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size);
     protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode);
     protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode);
 
 
-    furi_hal_ibutton_start_drive();
+    furi_hal_ibutton_pin_configure();
     furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker);
     furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker);
 }
 }
 
 

+ 23 - 25
lib/one_wire/one_wire_host.c

@@ -1,18 +1,19 @@
 #include <furi.h>
 #include <furi.h>
-#include <furi_hal.h>
+
 #include "one_wire_host.h"
 #include "one_wire_host.h"
 #include "one_wire_host_timing.h"
 #include "one_wire_host_timing.h"
 
 
 struct OneWireHost {
 struct OneWireHost {
-    // global search state
-    unsigned char saved_rom[8];
+    const GpioPin* gpio_pin;
+    unsigned char saved_rom[8]; /** < global search state */
     uint8_t last_discrepancy;
     uint8_t last_discrepancy;
     uint8_t last_family_discrepancy;
     uint8_t last_family_discrepancy;
     bool last_device_flag;
     bool last_device_flag;
 };
 };
 
 
-OneWireHost* onewire_host_alloc() {
+OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin) {
     OneWireHost* host = malloc(sizeof(OneWireHost));
     OneWireHost* host = malloc(sizeof(OneWireHost));
+    host->gpio_pin = gpio_pin;
     onewire_host_reset_search(host);
     onewire_host_reset_search(host);
     return host;
     return host;
 }
 }
@@ -23,49 +24,47 @@ void onewire_host_free(OneWireHost* host) {
 }
 }
 
 
 bool onewire_host_reset(OneWireHost* host) {
 bool onewire_host_reset(OneWireHost* host) {
-    UNUSED(host);
     uint8_t r;
     uint8_t r;
     uint8_t retries = 125;
     uint8_t retries = 125;
 
 
     // wait until the gpio is high
     // wait until the gpio is high
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(host->gpio_pin, true);
     do {
     do {
         if(--retries == 0) return 0;
         if(--retries == 0) return 0;
         furi_delay_us(2);
         furi_delay_us(2);
-    } while(!furi_hal_ibutton_pin_get_level());
+    } while(!furi_hal_gpio_read(host->gpio_pin));
 
 
     // pre delay
     // pre delay
     furi_delay_us(OWH_RESET_DELAY_PRE);
     furi_delay_us(OWH_RESET_DELAY_PRE);
 
 
     // drive low
     // drive low
-    furi_hal_ibutton_pin_low();
+    furi_hal_gpio_write(host->gpio_pin, false);
     furi_delay_us(OWH_RESET_DRIVE);
     furi_delay_us(OWH_RESET_DRIVE);
 
 
     // release
     // release
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(host->gpio_pin, true);
     furi_delay_us(OWH_RESET_RELEASE);
     furi_delay_us(OWH_RESET_RELEASE);
 
 
     // read and post delay
     // read and post delay
-    r = !furi_hal_ibutton_pin_get_level();
+    r = !furi_hal_gpio_read(host->gpio_pin);
     furi_delay_us(OWH_RESET_DELAY_POST);
     furi_delay_us(OWH_RESET_DELAY_POST);
 
 
     return r;
     return r;
 }
 }
 
 
 bool onewire_host_read_bit(OneWireHost* host) {
 bool onewire_host_read_bit(OneWireHost* host) {
-    UNUSED(host);
     bool result;
     bool result;
 
 
     // drive low
     // drive low
-    furi_hal_ibutton_pin_low();
+    furi_hal_gpio_write(host->gpio_pin, false);
     furi_delay_us(OWH_READ_DRIVE);
     furi_delay_us(OWH_READ_DRIVE);
 
 
     // release
     // release
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(host->gpio_pin, true);
     furi_delay_us(OWH_READ_RELEASE);
     furi_delay_us(OWH_READ_RELEASE);
 
 
     // read and post delay
     // read and post delay
-    result = furi_hal_ibutton_pin_get_level();
+    result = furi_hal_gpio_read(host->gpio_pin);
     furi_delay_us(OWH_READ_DELAY_POST);
     furi_delay_us(OWH_READ_DELAY_POST);
 
 
     return result;
     return result;
@@ -90,22 +89,21 @@ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count)
 }
 }
 
 
 void onewire_host_write_bit(OneWireHost* host, bool value) {
 void onewire_host_write_bit(OneWireHost* host, bool value) {
-    UNUSED(host);
     if(value) {
     if(value) {
         // drive low
         // drive low
-        furi_hal_ibutton_pin_low();
+        furi_hal_gpio_write(host->gpio_pin, false);
         furi_delay_us(OWH_WRITE_1_DRIVE);
         furi_delay_us(OWH_WRITE_1_DRIVE);
 
 
         // release
         // release
-        furi_hal_ibutton_pin_high();
+        furi_hal_gpio_write(host->gpio_pin, true);
         furi_delay_us(OWH_WRITE_1_RELEASE);
         furi_delay_us(OWH_WRITE_1_RELEASE);
     } else {
     } else {
         // drive low
         // drive low
-        furi_hal_ibutton_pin_low();
+        furi_hal_gpio_write(host->gpio_pin, false);
         furi_delay_us(OWH_WRITE_0_DRIVE);
         furi_delay_us(OWH_WRITE_0_DRIVE);
 
 
         // release
         // release
-        furi_hal_ibutton_pin_high();
+        furi_hal_gpio_write(host->gpio_pin, true);
         furi_delay_us(OWH_WRITE_0_RELEASE);
         furi_delay_us(OWH_WRITE_0_RELEASE);
     }
     }
 }
 }
@@ -123,13 +121,13 @@ void onewire_host_skip(OneWireHost* host) {
 }
 }
 
 
 void onewire_host_start(OneWireHost* host) {
 void onewire_host_start(OneWireHost* host) {
-    UNUSED(host);
-    furi_hal_ibutton_start_drive();
+    furi_hal_gpio_write(host->gpio_pin, true);
+    furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
 void onewire_host_stop(OneWireHost* host) {
 void onewire_host_stop(OneWireHost* host) {
-    UNUSED(host);
-    furi_hal_ibutton_stop();
+    furi_hal_gpio_write(host->gpio_pin, true);
+    furi_hal_gpio_init(host->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
 void onewire_host_reset_search(OneWireHost* host) {
 void onewire_host_reset_search(OneWireHost* host) {
@@ -150,7 +148,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) {
     host->last_device_flag = false;
     host->last_device_flag = false;
 }
 }
 
 
-uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode) {
+uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) {
     uint8_t id_bit_number;
     uint8_t id_bit_number;
     uint8_t last_zero, rom_byte_number, search_result;
     uint8_t last_zero, rom_byte_number, search_result;
     uint8_t id_bit, cmp_id_bit;
     uint8_t id_bit, cmp_id_bit;
@@ -259,7 +257,7 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSear
         host->last_family_discrepancy = 0;
         host->last_family_discrepancy = 0;
         search_result = false;
         search_result = false;
     } else {
     } else {
-        for(int i = 0; i < 8; i++) newAddr[i] = host->saved_rom[i];
+        for(int i = 0; i < 8; i++) new_addr[i] = host->saved_rom[i];
     }
     }
 
 
     return search_result;
     return search_result;

+ 3 - 3
lib/one_wire/one_wire_host.h

@@ -22,10 +22,10 @@ typedef struct OneWireHost OneWireHost;
 
 
 /**
 /**
  * Allocate onewire host bus
  * Allocate onewire host bus
- * @param gpio 
+ * @param pin
  * @return OneWireHost* 
  * @return OneWireHost* 
  */
  */
-OneWireHost* onewire_host_alloc();
+OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin);
 
 
 /**
 /**
  * Deallocate onewire host bus
  * Deallocate onewire host bus
@@ -114,7 +114,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code);
  * @param mode 
  * @param mode 
  * @return uint8_t 
  * @return uint8_t 
  */
  */
-uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode);
+uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 27 - 24
lib/one_wire/one_wire_slave.c

@@ -27,6 +27,7 @@ typedef enum {
 } OneWireSlaveError;
 } OneWireSlaveError;
 
 
 struct OneWireSlave {
 struct OneWireSlave {
+    const GpioPin* gpio_pin;
     OneWireSlaveError error;
     OneWireSlaveError error;
     OneWireDevice* device;
     OneWireDevice* device;
     OneWireSlaveResultCallback result_cb;
     OneWireSlaveResultCallback result_cb;
@@ -35,15 +36,15 @@ struct OneWireSlave {
 
 
 /*********************** PRIVATE ***********************/
 /*********************** PRIVATE ***********************/
 
 
-uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) {
-    UNUSED(bus);
+static uint32_t
+    onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) {
     uint32_t start = DWT->CYCCNT;
     uint32_t start = DWT->CYCCNT;
     uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond();
     uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond();
     uint32_t time_captured;
     uint32_t time_captured;
 
 
     do { //-V1044
     do { //-V1044
         time_captured = DWT->CYCCNT;
         time_captured = DWT->CYCCNT;
-        if(furi_hal_ibutton_pin_get_level() != pin_value) {
+        if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) {
             uint32_t remaining_time = time_ticks - (time_captured - start);
             uint32_t remaining_time = time_ticks - (time_captured - start);
             remaining_time /= furi_hal_cortex_instructions_per_microsecond();
             remaining_time /= furi_hal_cortex_instructions_per_microsecond();
             return remaining_time;
             return remaining_time;
@@ -53,14 +54,14 @@ uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, cons
     return 0;
     return 0;
 }
 }
 
 
-bool onewire_slave_show_presence(OneWireSlave* bus) {
+static bool onewire_slave_show_presence(OneWireSlave* bus) {
     // wait while master delay presence check
     // wait while master delay presence check
     onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true);
     onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true);
 
 
     // show presence
     // show presence
-    furi_hal_ibutton_pin_low();
+    furi_hal_gpio_write(bus->gpio_pin, false);
     furi_delay_us(OWS_PRESENCE_MIN);
     furi_delay_us(OWS_PRESENCE_MIN);
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(bus->gpio_pin, true);
 
 
     // somebody also can show presence
     // somebody also can show presence
     const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN;
     const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN;
@@ -74,7 +75,7 @@ bool onewire_slave_show_presence(OneWireSlave* bus) {
     return true;
     return true;
 }
 }
 
 
-bool onewire_slave_receive_bit(OneWireSlave* bus) {
+static bool onewire_slave_receive_bit(OneWireSlave* bus) {
     // wait while bus is low
     // wait while bus is low
     uint32_t time = OWS_SLOT_MAX;
     uint32_t time = OWS_SLOT_MAX;
     time = onewire_slave_wait_while_gpio_is(bus, time, false);
     time = onewire_slave_wait_while_gpio_is(bus, time, false);
@@ -98,7 +99,7 @@ bool onewire_slave_receive_bit(OneWireSlave* bus) {
     return (time > 0);
     return (time > 0);
 }
 }
 
 
-bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
+static bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
     const bool write_zero = !value;
     const bool write_zero = !value;
 
 
     // wait while bus is low
     // wait while bus is low
@@ -119,7 +120,7 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
 
 
     // choose write time
     // choose write time
     if(write_zero) {
     if(write_zero) {
-        furi_hal_ibutton_pin_low();
+        furi_hal_gpio_write(bus->gpio_pin, false);
         time = OWS_WRITE_ZERO;
         time = OWS_WRITE_ZERO;
     } else {
     } else {
         time = OWS_READ_MAX;
         time = OWS_READ_MAX;
@@ -127,12 +128,12 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) {
 
 
     // hold line for ZERO or ONE time
     // hold line for ZERO or ONE time
     furi_delay_us(time);
     furi_delay_us(time);
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(bus->gpio_pin, true);
 
 
     return true;
     return true;
 }
 }
 
 
-void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
+static void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
     const uint8_t key_bytes = 8;
     const uint8_t key_bytes = 8;
     uint8_t* key = onewire_device_get_id_p(bus->device);
     uint8_t* key = onewire_device_get_id_p(bus->device);
 
 
@@ -151,7 +152,7 @@ void onewire_slave_cmd_search_rom(OneWireSlave* bus) {
     }
     }
 }
 }
 
 
-bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
+static bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
     uint8_t cmd;
     uint8_t cmd;
     onewire_slave_receive(bus, &cmd, 1);
     onewire_slave_receive(bus, &cmd, 1);
 
 
@@ -178,14 +179,14 @@ bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) {
     }
     }
 }
 }
 
 
-bool onewire_slave_bus_start(OneWireSlave* bus) {
+static bool onewire_slave_bus_start(OneWireSlave* bus) {
     bool result = true;
     bool result = true;
 
 
     if(bus->device == NULL) {
     if(bus->device == NULL) {
         result = false;
         result = false;
     } else {
     } else {
         FURI_CRITICAL_ENTER();
         FURI_CRITICAL_ENTER();
-        furi_hal_ibutton_start_drive_in_isr();
+        furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
         bus->error = NO_ERROR;
         bus->error = NO_ERROR;
 
 
         if(onewire_slave_show_presence(bus)) {
         if(onewire_slave_show_presence(bus)) {
@@ -197,7 +198,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) {
             result = false;
             result = false;
         }
         }
 
 
-        furi_hal_ibutton_start_interrupt_in_isr();
+        furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
         FURI_CRITICAL_EXIT();
         FURI_CRITICAL_EXIT();
     }
     }
 
 
@@ -207,7 +208,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) {
 static void exti_cb(void* context) {
 static void exti_cb(void* context) {
     OneWireSlave* bus = context;
     OneWireSlave* bus = context;
 
 
-    volatile bool input_state = furi_hal_ibutton_pin_get_level();
+    volatile bool input_state = furi_hal_gpio_read(bus->gpio_pin);
     static uint32_t pulse_start = 0;
     static uint32_t pulse_start = 0;
 
 
     if(input_state) {
     if(input_state) {
@@ -234,8 +235,9 @@ static void exti_cb(void* context) {
 
 
 /*********************** PUBLIC ***********************/
 /*********************** PUBLIC ***********************/
 
 
-OneWireSlave* onewire_slave_alloc() {
+OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) {
     OneWireSlave* bus = malloc(sizeof(OneWireSlave));
     OneWireSlave* bus = malloc(sizeof(OneWireSlave));
+    bus->gpio_pin = gpio_pin;
     bus->error = NO_ERROR;
     bus->error = NO_ERROR;
     bus->device = NULL;
     bus->device = NULL;
     bus->result_cb = NULL;
     bus->result_cb = NULL;
@@ -249,14 +251,15 @@ void onewire_slave_free(OneWireSlave* bus) {
 }
 }
 
 
 void onewire_slave_start(OneWireSlave* bus) {
 void onewire_slave_start(OneWireSlave* bus) {
-    furi_hal_ibutton_add_interrupt(exti_cb, bus);
-    furi_hal_ibutton_start_interrupt();
+    furi_hal_gpio_add_int_callback(bus->gpio_pin, exti_cb, bus);
+    furi_hal_gpio_write(bus->gpio_pin, true);
+    furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow);
 }
 }
 
 
 void onewire_slave_stop(OneWireSlave* bus) {
 void onewire_slave_stop(OneWireSlave* bus) {
-    UNUSED(bus);
-    furi_hal_ibutton_stop();
-    furi_hal_ibutton_remove_interrupt();
+    furi_hal_gpio_write(bus->gpio_pin, true);
+    furi_hal_gpio_init(bus->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_remove_int_callback(bus->gpio_pin);
 }
 }
 
 
 void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) {
 void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) {
@@ -282,7 +285,7 @@ void onewire_slave_set_result_callback(
 bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) {
 bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) {
     uint8_t bytes_sent = 0;
     uint8_t bytes_sent = 0;
 
 
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(bus->gpio_pin, true);
 
 
     // bytes loop
     // bytes loop
     for(; bytes_sent < data_length; ++bytes_sent) {
     for(; bytes_sent < data_length; ++bytes_sent) {
@@ -304,7 +307,7 @@ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t
 bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) {
 bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) {
     uint8_t bytes_received = 0;
     uint8_t bytes_received = 0;
 
 
-    furi_hal_ibutton_pin_high();
+    furi_hal_gpio_write(bus->gpio_pin, true);
 
 
     for(; bytes_received < data_length; ++bytes_received) {
     for(; bytes_received < data_length; ++bytes_received) {
         uint8_t value = 0;
         uint8_t value = 0;

+ 2 - 2
lib/one_wire/one_wire_slave.h

@@ -19,10 +19,10 @@ typedef void (*OneWireSlaveResultCallback)(void* context);
 
 
 /**
 /**
  * Allocate onewire slave
  * Allocate onewire slave
- * @param pin 
+ * @param gpio_pin
  * @return OneWireSlave* 
  * @return OneWireSlave* 
  */
  */
-OneWireSlave* onewire_slave_alloc();
+OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin);
 
 
 /**
 /**
  * Free onewire slave
  * Free onewire slave