[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>
This commit is contained in:
Georgii Surkov 2023-02-08 08:40:44 +03:00 committed by GitHub
parent e3d473bf42
commit 7a3a1aaf0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 592 additions and 184 deletions

2
.github/CODEOWNERS vendored
View File

@ -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

View File

@ -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.

View File

@ -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",
)

View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -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;

View File

@ -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"

1 entry status name type params
2 Version + 12.2 13.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
910 Function + furi_hal_gpio_add_int_callback void const GpioPin*, GpioExtiCallback, void*
911 Function + furi_hal_gpio_disable_int_callback void const GpioPin*
912 Function + furi_hal_gpio_enable_int_callback void const GpioPin*
913 Function + furi_hal_resources_get_ext_pin_number int32_t const GpioPin*
914 Function + furi_hal_gpio_init void const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed
915 Function + furi_hal_gpio_init_ex void const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn
916 Function + furi_hal_gpio_init_simple void const GpioPin*, const GpioMode

View File

@ -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;
}

View File

@ -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

View File

@ -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_configure,void,
Function,+,furi_hal_ibutton_pin_high,void, Function,+,furi_hal_ibutton_pin_reset,void,
Function,+,furi_hal_ibutton_pin_low,void, Function,+,furi_hal_ibutton_pin_write,void,const _Bool
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_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*

1 entry status name type params
2 Version + 12.2 13.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1094 Function + furi_hal_gpio_add_int_callback void const GpioPin*, GpioExtiCallback, void*
1095 Function + furi_hal_gpio_disable_int_callback void const GpioPin*
1096 Function + furi_hal_gpio_enable_int_callback void const GpioPin*
1097 Function + furi_hal_resources_get_ext_pin_number int32_t const GpioPin*
1098 Function + furi_hal_gpio_init void const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed
1099 Function + furi_hal_gpio_init_ex void const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn
1100 Function + furi_hal_gpio_init_simple void const GpioPin*, const GpioMode
1130 Function + furi_hal_i2c_write_mem _Bool FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t
1131 Function + furi_hal_i2c_write_reg_16 _Bool FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t
1132 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*
1133 Function + furi_hal_ibutton_emulate_set_next void uint32_t
1134 Function + furi_hal_ibutton_emulate_start void uint32_t, FuriHalIbuttonEmulateCallback, void*
1135 Function + furi_hal_ibutton_emulate_stop void
1136 Function - furi_hal_ibutton_init void
1137 Function + furi_hal_ibutton_pin_get_level furi_hal_ibutton_pin_configure _Bool void
1138 Function + furi_hal_ibutton_pin_high furi_hal_ibutton_pin_reset void
1139 Function + furi_hal_ibutton_pin_low furi_hal_ibutton_pin_write void const _Bool
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
1140 Function + furi_hal_info_get void PropertyValueCallback, char, void*
1141 Function + furi_hal_infrared_async_rx_set_capture_isr_callback void FuriHalInfraredRxCaptureCallback, void*
1142 Function + furi_hal_infrared_async_rx_set_timeout void uint32_t
2034 Function + onewire_device_free void OneWireDevice*
2035 Function + onewire_device_get_id_p uint8_t* OneWireDevice*
2036 Function + onewire_device_send_id void OneWireDevice*
2037 Function + onewire_host_alloc OneWireHost* const GpioPin*
2038 Function + onewire_host_free void OneWireHost*
2039 Function + onewire_host_read uint8_t OneWireHost*
2040 Function + onewire_host_read_bit _Bool OneWireHost*
2048 Function + onewire_host_target_search void OneWireHost*, uint8_t
2049 Function + onewire_host_write void OneWireHost*, uint8_t
2050 Function + onewire_host_write_bit void OneWireHost*, _Bool
2051 Function + onewire_slave_alloc OneWireSlave* const GpioPin*
2052 Function + onewire_slave_attach void OneWireSlave*, OneWireDevice*
2053 Function + onewire_slave_detach void OneWireSlave*
2054 Function + onewire_slave_free void OneWireSlave*

View File

@ -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);
} }
} }

View File

@ -89,47 +89,16 @@ void furi_hal_ibutton_emulate_stop() {
} }
} }
void furi_hal_ibutton_start_drive() { void furi_hal_ibutton_pin_configure() {
furi_hal_ibutton_pin_high(); 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);
} }
void furi_hal_ibutton_start_drive_in_isr() { void furi_hal_ibutton_pin_reset() {
furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&ibutton_gpio, true);
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); furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
} }
void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) { void furi_hal_ibutton_pin_write(const bool state) {
furi_hal_gpio_add_int_callback(&ibutton_gpio, cb, context); furi_hal_gpio_write(&ibutton_gpio, state);
}
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() {
furi_hal_gpio_write(&ibutton_gpio, true);
}
bool furi_hal_ibutton_pin_get_level() {
return furi_hal_gpio_read(&ibutton_gpio);
} }

View File

@ -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);
/**
* Update emulation timer period
* @param period new timer period
*/
void furi_hal_ibutton_emulate_set_next(uint32_t period); void furi_hal_ibutton_emulate_set_next(uint32_t period);
/**
* Stop emulation timer
*/
void furi_hal_ibutton_emulate_stop(); void furi_hal_ibutton_emulate_stop();
/** /**
* Sets the pin to normal mode (open collector), and sets it to float * Set the pin to normal mode (open collector), and sets it to float
*/ */
void furi_hal_ibutton_start_drive(); void furi_hal_ibutton_pin_configure();
/**
* 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();
/**
* Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and sets it to float
*/
void furi_hal_ibutton_start_interrupt();
/**
* Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and clears pin EXTI interrupt.
* Used in EXTI interrupt context.
*/
void furi_hal_ibutton_start_interrupt_in_isr();
/** /**
* 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(); void furi_hal_ibutton_pin_reset();
/** /**
* Attach interrupt callback to iButton pin * iButton write pin
* @param cb callback * @param state true / false
* @param context context
*/ */
void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context); void furi_hal_ibutton_pin_write(const bool state);
/**
* 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();
/**
* Get pin level
* @return true if level is high
* @return false if level is low
*/
bool furi_hal_ibutton_pin_get_level();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -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;
}

View File

@ -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

View File

@ -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_configure();
furi_hal_ibutton_pin_low(); 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_configure();
furi_hal_ibutton_pin_low(); 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);

View File

@ -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->host = onewire_host_alloc(&ibutton_gpio);
worker->slave = onewire_slave_alloc(); 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));

View File

@ -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_emulate_set_next(level);
furi_hal_ibutton_pin_high(); furi_hal_ibutton_pin_write(level);
} else {
furi_hal_ibutton_pin_low();
}
} }
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);
} }

View File

@ -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 const GpioPin* gpio_pin;
unsigned char saved_rom[8]; 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_gpio_write(host->gpio_pin, true);
furi_hal_ibutton_start_drive(); 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_gpio_write(host->gpio_pin, true);
furi_hal_ibutton_stop(); 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;

View File

@ -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
} }

View File

@ -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) { static uint32_t
UNUSED(bus); 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_gpio_add_int_callback(bus->gpio_pin, exti_cb, bus);
furi_hal_ibutton_start_interrupt(); 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_gpio_write(bus->gpio_pin, true);
furi_hal_ibutton_stop(); furi_hal_gpio_init(bus->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_ibutton_remove_interrupt(); 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;

View File

@ -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