[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:
		
							parent
							
								
									e3d473bf42
								
							
						
					
					
						commit
						7a3a1aaf0d
					
				
							
								
								
									
										2
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							| @ -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
									
								
								applications/examples/example_thermo/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								applications/examples/example_thermo/README.md
									
									
									
									
									
										Normal 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. | ||||||
							
								
								
									
										10
									
								
								applications/examples/example_thermo/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/examples/example_thermo/application.fam
									
									
									
									
									
										Normal 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", | ||||||
|  | ) | ||||||
							
								
								
									
										356
									
								
								applications/examples/example_thermo/example_thermo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								applications/examples/example_thermo/example_thermo.c
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								applications/examples/example_thermo/example_thermo_10px.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								applications/examples/example_thermo/example_thermo_10px.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.1 KiB | 
| @ -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; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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" | ||||||
|  | |||||||
| 
 | 
| @ -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; | ||||||
|  | } | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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,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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; | ||||||
|  | } | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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)); | ||||||
|  | |||||||
| @ -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); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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,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; | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Georgii Surkov
						Georgii Surkov