diff --git a/applications/main/gpio/gpio_app.c b/applications/main/gpio/gpio_app.c index 217423ecc31..1d201a73082 100644 --- a/applications/main/gpio/gpio_app.c +++ b/applications/main/gpio/gpio_app.c @@ -60,6 +60,16 @@ GpioApp* gpio_app_alloc(void) { view_dispatcher_add_view( app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test)); + app->gpio_i2c_scanner = gpio_i2c_scanner_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + GpioAppViewI2CScanner, + gpio_i2c_scanner_get_view(app->gpio_i2c_scanner)); + + app->gpio_i2c_sfp = gpio_i2c_sfp_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, GpioAppViewI2CSfp, gpio_i2c_sfp_get_view(app->gpio_i2c_sfp)); + app->widget = widget_alloc(); view_dispatcher_add_view( app->view_dispatcher, GpioAppViewUsbUartCloseRpc, widget_get_view(app->widget)); @@ -84,6 +94,8 @@ void gpio_app_free(GpioApp* app) { // Views view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewVarItemList); view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewGpioTest); + view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewI2CScanner); + view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewI2CSfp); view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUart); view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUartCfg); view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUartCloseRpc); @@ -93,6 +105,8 @@ void gpio_app_free(GpioApp* app) { gpio_test_free(app->gpio_test); gpio_usb_uart_free(app->gpio_usb_uart); dialog_ex_free(app->dialog); + gpio_i2c_scanner_free(app->gpio_i2c_scanner); + gpio_i2c_sfp_free(app->gpio_i2c_sfp); // View dispatcher view_dispatcher_free(app->view_dispatcher); diff --git a/applications/main/gpio/gpio_app_i.h b/applications/main/gpio/gpio_app_i.h index e3a3cadb020..0ba1e8745dd 100644 --- a/applications/main/gpio/gpio_app_i.h +++ b/applications/main/gpio/gpio_app_i.h @@ -16,6 +16,8 @@ #include #include "views/gpio_test.h" #include "views/gpio_usb_uart.h" +#include "views/gpio_i2c_scanner.h" +#include "views/gpio_i2c_sfp.h" #include "gpio_icons.h" #include @@ -34,6 +36,8 @@ struct GpioApp { GpioUsbUart* gpio_usb_uart; GPIOItems* gpio_items; UsbUartBridge* usb_uart_bridge; + GpioI2CScanner* gpio_i2c_scanner; + GpioI2CSfp* gpio_i2c_sfp; UsbUartConfig* usb_uart_cfg; }; @@ -44,4 +48,6 @@ typedef enum { GpioAppViewUsbUartCfg, GpioAppViewUsbUartCloseRpc, GpioAppViewExitConfirm, + GpioAppViewI2CScanner, + GpioAppViewI2CSfp } GpioAppView; diff --git a/applications/main/gpio/gpio_custom_event.h b/applications/main/gpio/gpio_custom_event.h index 72b8feccd00..f203e1b9524 100644 --- a/applications/main/gpio/gpio_custom_event.h +++ b/applications/main/gpio/gpio_custom_event.h @@ -5,6 +5,8 @@ typedef enum { GpioStartEventOtgOn, GpioStartEventManualControl, GpioStartEventUsbUart, + GpioStartEventI2CScanner, + GpioStartEventI2CSfp, GpioCustomEventErrorBack, diff --git a/applications/main/gpio/gpio_i2c_scanner_control.c b/applications/main/gpio/gpio_i2c_scanner_control.c new file mode 100644 index 00000000000..bf3f1090d6e --- /dev/null +++ b/applications/main/gpio/gpio_i2c_scanner_control.c @@ -0,0 +1,23 @@ +#include "gpio_i2c_scanner_control.h" +#include + +void gpio_i2c_scanner_run_once(I2CScannerState* i2c_scanner_state) { + //Reset the number of items for rewriting the array + i2c_scanner_state->items = 0; + furi_hal_i2c_acquire(&furi_hal_i2c_handle_external); + + uint32_t response_timeout_ticks = furi_ms_to_ticks(5.f); + + //Addresses 0 to 7 are reserved and won't be scanned + for(int i = FIRST_NON_RESERVED_I2C_ADDRESS; i <= HIGHEST_I2C_ADDRESS; i++) { + if(furi_hal_i2c_is_device_ready( + &furi_hal_i2c_handle_external, + i << 1, + response_timeout_ticks)) { //Bitshift of 1 bit to convert 7-Bit Address into 8-Bit Address + i2c_scanner_state->responding_address[i2c_scanner_state->items] = i; + i2c_scanner_state->items++; + } + } + + furi_hal_i2c_release(&furi_hal_i2c_handle_external); +} diff --git a/applications/main/gpio/gpio_i2c_scanner_control.h b/applications/main/gpio/gpio_i2c_scanner_control.h new file mode 100644 index 00000000000..011f8aa3618 --- /dev/null +++ b/applications/main/gpio/gpio_i2c_scanner_control.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +#include + +#define FIRST_NON_RESERVED_I2C_ADDRESS 8 +#define HIGHEST_I2C_ADDRESS 127 +#define AVAILABLE_NONRESVERED_I2C_ADDRESSES 120 + +typedef struct { + uint8_t items; + uint8_t responding_address[AVAILABLE_NONRESVERED_I2C_ADDRESSES]; +} I2CScannerState; + +/** Scans the I2C-Bus (SDA: Pin 15, SCL: Pin 16) for available 7-Bit slave addresses. Saves the number of detected slaves and their addresses. + * + * @param i2c_scanner_state State including the detected addresses and the number of addresses saved. + */ +void gpio_i2c_scanner_run_once(I2CScannerState* st); diff --git a/applications/main/gpio/gpio_i2c_sfp_control.c b/applications/main/gpio/gpio_i2c_sfp_control.c new file mode 100644 index 00000000000..d14ba1b8e63 --- /dev/null +++ b/applications/main/gpio/gpio_i2c_sfp_control.c @@ -0,0 +1,334 @@ +#include "gpio_i2c_sfp_control.h" +#include +#include + +// This is map mapping the connector type to the appropriate name. (see SFF-8024 Rev. 4.9, Table 4-3) +const char* sfp_connector_map[256] = { + "Unknown or unspecified", + "SC", + "Fibre Channel Style 1", + "Fibre Channel Style 2", + "BNC/TNC", + "Fibre Channel Coax", + "Fiber Jack", + "LC", + "MT-RJ", + "MU", + "SG", + "Optical Pigtail", + "MP0 1x12", + "MP 2x16", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "HSSDC II", + "Copper pigtail", + "RJ45", + "No seperable connector", + "MXC 2x16", + "CS optical connector", + "SN (prev. Mini CS)", + "MPO 2x12", + "MPO 1x16", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved"}; + +void str_part(uint8_t* data, char* buffer, int start, int len) { + int i; + for(i = start; i < start + len; i++) { + buffer[i - start] = data[i]; + } + buffer[i - start] = '\0'; +} + +/* +void print_part(uint8_t *data, char *ptype, char *prefix, int start, int len){ + printf("%s: ", prefix); + for (int i=start; ivendor, 20, 16); + str_part(sfp_data, i2c_sfp_state->rev, 56, 4); + str_part(sfp_data, i2c_sfp_state->pn, 40, 16); + str_part(sfp_data, i2c_sfp_state->sn, 68, 16); + str_part(sfp_data, i2c_sfp_state->dc, 84, 6); + + //Look up connector in table and copy to struct. + strcpy(i2c_sfp_state->connector, sfp_connector_map[sfp_data[2]]); + i2c_sfp_state->bitrate = sfp_data[12] * 100; + i2c_sfp_state->wavelength = sfp_data[60] * 256 + sfp_data[61]; + i2c_sfp_state->sm_reach = sfp_data[14]; + i2c_sfp_state->mm_reach_om3 = sfp_data[19] * 10; + } + furi_hal_i2c_release(&furi_hal_i2c_handle_external); +} diff --git a/applications/main/gpio/gpio_i2c_sfp_control.h b/applications/main/gpio/gpio_i2c_sfp_control.h new file mode 100644 index 00000000000..7a9f4bcbef5 --- /dev/null +++ b/applications/main/gpio/gpio_i2c_sfp_control.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include + +#define FIRST_NON_RESERVED_I2C_ADDRESS 8 +#define HIGHEST_I2C_ADDRESS 127 +#define AVAILABLE_NONRESVERED_I2C_ADDRESSES 120 +#define SFP_I2C_ADDRESS 0x50 + +typedef struct { + char vendor[32]; + char oui[32]; + char rev[32]; + char pn[32]; + char sn[32]; + char dc[32]; + uint8_t type; + char connector[32]; + int wavelength; + int sm_reach; + int mm_reach_om3; + int bitrate; +} I2CSfpState; + +/** Reads data from a connected SFP on I2C-Bus (SDA: Pin 15, SCL: Pin 16). Saves data from SFP. + * + * @param i2c_sfp_state Data collected from SFP. + */ +void gpio_i2c_sfp_run_once(I2CSfpState* st); diff --git a/applications/main/gpio/scenes/gpio_scene_config.h b/applications/main/gpio/scenes/gpio_scene_config.h index d6fd24d19d3..d2a98a847f6 100644 --- a/applications/main/gpio/scenes/gpio_scene_config.h +++ b/applications/main/gpio/scenes/gpio_scene_config.h @@ -4,3 +4,5 @@ ADD_SCENE(gpio, usb_uart, UsbUart) ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg) ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc) ADD_SCENE(gpio, exit_confirm, ExitConfirm) +ADD_SCENE(gpio, i2c_scanner, I2CScanner) +ADD_SCENE(gpio, i2c_sfp, I2CSfp) diff --git a/applications/main/gpio/scenes/gpio_scene_i2c_scanner.c b/applications/main/gpio/scenes/gpio_scene_i2c_scanner.c new file mode 100644 index 00000000000..7b310debcac --- /dev/null +++ b/applications/main/gpio/scenes/gpio_scene_i2c_scanner.c @@ -0,0 +1,36 @@ +#include "../gpio_app_i.h" +#include + +static I2CScannerState* i2c_scanner_state; + +void gpio_scene_i2c_scanner_ok_callback(InputType type, void* context) { + furi_assert(context); + GpioApp* app = context; + + if(type == InputTypeRelease) { + notification_message(app->notifications, &sequence_set_green_255); + gpio_i2c_scanner_run_once(i2c_scanner_state); + notification_message(app->notifications, &sequence_reset_green); + gpio_i2c_scanner_update_state(app->gpio_i2c_scanner, i2c_scanner_state); + } +} + +void gpio_scene_i2c_scanner_on_enter(void* context) { + GpioApp* app = context; + i2c_scanner_state = malloc(sizeof(I2CScannerState)); + + gpio_i2c_scanner_set_ok_callback( + app->gpio_i2c_scanner, gpio_scene_i2c_scanner_ok_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewI2CScanner); +} + +bool gpio_scene_i2c_scanner_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void gpio_scene_i2c_scanner_on_exit(void* context) { + UNUSED(context); + free(i2c_scanner_state); +} diff --git a/applications/main/gpio/scenes/gpio_scene_i2c_sfp.c b/applications/main/gpio/scenes/gpio_scene_i2c_sfp.c new file mode 100644 index 00000000000..49d0e8dd23b --- /dev/null +++ b/applications/main/gpio/scenes/gpio_scene_i2c_sfp.c @@ -0,0 +1,35 @@ +#include "../gpio_app_i.h" +#include + +static I2CSfpState* i2c_sfp_state; + +void gpio_scene_i2c_sfp_ok_callback(InputType type, void* context) { + furi_assert(context); + GpioApp* app = context; + + if(type == InputTypeRelease) { + notification_message(app->notifications, &sequence_set_green_255); + gpio_i2c_sfp_run_once(i2c_sfp_state); + notification_message(app->notifications, &sequence_reset_green); + gpio_i2c_sfp_update_state(app->gpio_i2c_sfp, i2c_sfp_state); + } +} + +void gpio_scene_i2c_sfp_on_enter(void* context) { + GpioApp* app = context; + i2c_sfp_state = malloc(sizeof(I2CSfpState)); + + gpio_i2c_sfp_set_ok_callback(app->gpio_i2c_sfp, gpio_scene_i2c_sfp_ok_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewI2CSfp); +} + +bool gpio_scene_i2c_sfp_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void gpio_scene_i2c_sfp_on_exit(void* context) { + UNUSED(context); + free(i2c_sfp_state); +} diff --git a/applications/main/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c index 42193648800..3c35b865215 100644 --- a/applications/main/gpio/scenes/gpio_scene_start.c +++ b/applications/main/gpio/scenes/gpio_scene_start.c @@ -1,3 +1,6 @@ +#ifndef __GPIO_SCENE_START_H__ +#define __GPIO_SCENE_START_H__ + #include "../gpio_app_i.h" #include #include @@ -7,6 +10,8 @@ enum GpioItem { GpioItemUsbUart, GpioItemTest, GpioItemOtg, + GpioItemI2CScanner, + GpioItemI2CSfp, }; enum GpioOtg { @@ -27,6 +32,10 @@ static void gpio_scene_start_var_list_enter_callback(void* context, uint32_t ind view_dispatcher_send_custom_event(app->view_dispatcher, GpioStartEventManualControl); } else if(index == GpioItemUsbUart) { view_dispatcher_send_custom_event(app->view_dispatcher, GpioStartEventUsbUart); + } else if(index == GpioItemI2CScanner) { + view_dispatcher_send_custom_event(app->view_dispatcher, GpioStartEventI2CScanner); + } else if(index == GpioItemI2CSfp) { + view_dispatcher_send_custom_event(app->view_dispatcher, GpioStartEventI2CSfp); } } @@ -60,7 +69,9 @@ void gpio_scene_start_on_enter(void* context) { GpioOtgSettingsNum, gpio_scene_start_var_list_change_callback, app); - if(furi_hal_power_is_otg_enabled()) { + if(furi_hal_power_is_charging()) { + variable_item_set_locked(item, true, "Unplug USB!"); + } else if(furi_hal_power_is_otg_enabled()) { variable_item_set_current_value_index(item, GpioOtgOn); variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOn]); } else { @@ -68,6 +79,9 @@ void gpio_scene_start_on_enter(void* context) { variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOff]); } + variable_item_list_add(var_item_list, "I2C-Scanner", 0, NULL, NULL); + variable_item_list_add(var_item_list, "I2C-SFP", 0, NULL, NULL); + variable_item_list_set_selected_item( var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioSceneStart)); @@ -86,6 +100,12 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == GpioStartEventManualControl) { scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemTest); scene_manager_next_scene(app->scene_manager, GpioSceneTest); + } else if(event.event == GpioStartEventI2CScanner) { + scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemI2CScanner); + scene_manager_next_scene(app->scene_manager, GpioSceneI2CScanner); + } else if(event.event == GpioStartEventI2CSfp) { + scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemI2CSfp); + scene_manager_next_scene(app->scene_manager, GpioSceneI2CSfp); } else if(event.event == GpioStartEventUsbUart) { scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); if(!furi_hal_usb_is_locked()) { @@ -104,3 +124,5 @@ void gpio_scene_start_on_exit(void* context) { GpioApp* app = context; variable_item_list_reset(app->var_item_list); } + +#endif // __GPIO_SCENE_START_H__ \ No newline at end of file diff --git a/applications/main/gpio/views/gpio_i2c_scanner.c b/applications/main/gpio/views/gpio_i2c_scanner.c new file mode 100644 index 00000000000..fc9ed78a784 --- /dev/null +++ b/applications/main/gpio/views/gpio_i2c_scanner.c @@ -0,0 +1,139 @@ +#include +#include "gpio_i2c_scanner.h" +#include "../gpio_items.h" + +#include + +struct GpioI2CScanner { + View* view; + GpioI2CScannerOkCallback callback; + void* context; +}; + +typedef struct { + uint8_t items; + uint8_t responding_address[AVAILABLE_NONRESVERED_I2C_ADDRESSES]; +} GpioI2CScannerModel; + +static bool gpio_i2c_scanner_process_ok(GpioI2CScanner* gpio_i2c_scanner, InputEvent* event); + +static void gpio_i2c_scanner_draw_callback(Canvas* canvas, void* _model) { + GpioI2CScannerModel* model = _model; + + char temp_str[25]; + elements_button_center(canvas, "Start scan"); + canvas_draw_line(canvas, 2, 10, 125, 10); + canvas_draw_line(canvas, 2, 52, 125, 52); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 9, "I2C-Scanner"); + canvas_draw_str(canvas, 3, 25, "SDA:"); + canvas_draw_str(canvas, 3, 42, "SCL:"); + + canvas_set_font(canvas, FontSecondary); + snprintf(temp_str, 25, "Slaves: %u", model->items); + canvas_draw_str_aligned(canvas, 126, 8, AlignRight, AlignBottom, temp_str); + + canvas_draw_str(canvas, 29, 25, "Pin 15"); + canvas_draw_str(canvas, 29, 42, "Pin 16"); + + canvas_set_font(canvas, FontSecondary); + + char temp_str2[6]; + if(model->items > 0) { + snprintf(temp_str, 25, "Addr: "); + for(int i = 0; i < model->items; i++) { + snprintf(temp_str2, 6, "0x%x ", model->responding_address[i]); + strcat(temp_str, temp_str2); + + if(i == 1 || model->items == 1) { //Draw a maximum of two addresses in the first line + canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, temp_str); + temp_str[0] = '\0'; + } else if( + i == 4 || (model->items - 1 == i && + i < 6)) { //Draw a maximum of three addresses in the second line + canvas_draw_str_aligned(canvas, 127, 36, AlignRight, AlignBottom, temp_str); + temp_str[0] = '\0'; + } else if(i == 7 || model->items - 1 == i) { //Draw a maximum of three addresses in the third line + canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, temp_str); + break; + } + } + } +} + +static bool gpio_i2c_scanner_input_callback(InputEvent* event, void* context) { + furi_assert(context); + GpioI2CScanner* gpio_i2c_scanner = context; + bool consumed = false; + + if(event->key == InputKeyOk) { + consumed = gpio_i2c_scanner_process_ok(gpio_i2c_scanner, event); + } + + return consumed; +} + +static bool gpio_i2c_scanner_process_ok(GpioI2CScanner* gpio_i2c_scanner, InputEvent* event) { + bool consumed = false; + gpio_i2c_scanner->callback(event->type, gpio_i2c_scanner->context); + + return consumed; +} + +GpioI2CScanner* gpio_i2c_scanner_alloc() { + GpioI2CScanner* gpio_i2c_scanner = malloc(sizeof(GpioI2CScanner)); + + gpio_i2c_scanner->view = view_alloc(); + view_allocate_model(gpio_i2c_scanner->view, ViewModelTypeLocking, sizeof(GpioI2CScannerModel)); + view_set_context(gpio_i2c_scanner->view, gpio_i2c_scanner); + view_set_draw_callback(gpio_i2c_scanner->view, gpio_i2c_scanner_draw_callback); + view_set_input_callback(gpio_i2c_scanner->view, gpio_i2c_scanner_input_callback); + + return gpio_i2c_scanner; +} + +void gpio_i2c_scanner_free(GpioI2CScanner* gpio_i2c_scanner) { + furi_assert(gpio_i2c_scanner); + view_free(gpio_i2c_scanner->view); + free(gpio_i2c_scanner); +} + +View* gpio_i2c_scanner_get_view(GpioI2CScanner* gpio_i2c_scanner) { + furi_assert(gpio_i2c_scanner); + return gpio_i2c_scanner->view; +} + +void gpio_i2c_scanner_set_ok_callback( + GpioI2CScanner* gpio_i2c_scanner, + GpioI2CScannerOkCallback callback, + void* context) { + furi_assert(gpio_i2c_scanner); + furi_assert(callback); + with_view_model( + gpio_i2c_scanner->view, + GpioI2CScannerModel * model, + { + UNUSED(model); + gpio_i2c_scanner->callback = callback; + gpio_i2c_scanner->context = context; + }, + false); +} + +void gpio_i2c_scanner_update_state(GpioI2CScanner* instance, I2CScannerState* st) { + furi_assert(instance); + furi_assert(st); + + with_view_model( + instance->view, + GpioI2CScannerModel * model, + { + model->items = st->items; + + for(int i = 0; i < model->items; i++) { + model->responding_address[i] = st->responding_address[i]; + } + }, + true); +} diff --git a/applications/main/gpio/views/gpio_i2c_scanner.h b/applications/main/gpio/views/gpio_i2c_scanner.h new file mode 100644 index 00000000000..52ebf3de3f4 --- /dev/null +++ b/applications/main/gpio/views/gpio_i2c_scanner.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "../gpio_i2c_scanner_control.h" + +typedef struct GpioI2CScanner GpioI2CScanner; +typedef void (*GpioI2CScannerOkCallback)(InputType type, void* context); + +GpioI2CScanner* gpio_i2c_scanner_alloc(); + +void gpio_i2c_scanner_free(GpioI2CScanner* gpio_i2c_scanner); + +View* gpio_i2c_scanner_get_view(GpioI2CScanner* gpio_i2c_scanner); + +void gpio_i2c_scanner_set_ok_callback( + GpioI2CScanner* gpio_i2c_scanner, + GpioI2CScannerOkCallback callback, + void* context); + +void gpio_i2c_scanner_update_state(GpioI2CScanner* instance, I2CScannerState* st); diff --git a/applications/main/gpio/views/gpio_i2c_sfp.c b/applications/main/gpio/views/gpio_i2c_sfp.c new file mode 100644 index 00000000000..c8e14ce7a86 --- /dev/null +++ b/applications/main/gpio/views/gpio_i2c_sfp.c @@ -0,0 +1,149 @@ +#include +#include "gpio_i2c_sfp.h" +#include "../gpio_items.h" + +#include + +struct GpioI2CSfp { + View* view; + GpioI2CSfpOkCallback callback; + void* context; +}; + +typedef struct { + char vendor[32]; + char oui[32]; + char rev[32]; + char pn[32]; + char sn[32]; + char dc[32]; + uint8_t type; + char connector[32]; + int wavelength; + int sm_reach; + int mm_reach_om3; + int bitrate; +} GpioI2CSfpModel; + +static bool gpio_i2c_sfp_process_ok(GpioI2CSfp* gpio_i2c_sfp, InputEvent* event); + +static void gpio_i2c_sfp_draw_callback(Canvas* canvas, void* _model) { + GpioI2CSfpModel* model = _model; + + // Temp String for formatting output + char temp_str[280]; + + canvas_set_font(canvas, FontSecondary); + elements_button_center(canvas, "Read"); + canvas_draw_str(canvas, 2, 63, "P15 SCL"); + canvas_draw_str(canvas, 92, 63, "P16 SDA"); + + snprintf(temp_str, 280, "Vendor: %s", model->vendor); + canvas_draw_str(canvas, 2, 9, temp_str); + + snprintf(temp_str, 280, "PN: %s", model->pn); + canvas_draw_str(canvas, 2, 19, temp_str); + + snprintf(temp_str, 280, "SN: %s", model->sn); + canvas_draw_str(canvas, 2, 29, temp_str); + + snprintf(temp_str, 280, "REV: %s", model->rev); + canvas_draw_str(canvas, 2, 39, temp_str); + + snprintf(temp_str, 280, "CON: %s", model->connector); + canvas_draw_str(canvas, 50, 39, temp_str); + + //Print Wavelength of Module + snprintf(temp_str, 280, "%u nm", model->wavelength); + canvas_draw_str(canvas, 2, 49, temp_str); + + // These values will be zero if not applicable.. + if(model->sm_reach != 0) { + snprintf(temp_str, 280, "%u km (SM)", model->sm_reach); + canvas_draw_str(canvas, 50, 49, temp_str); + } + if(model->mm_reach_om3 != 0) { + snprintf(temp_str, 280, "%u m (MM OM3)", model->mm_reach_om3); + canvas_draw_str(canvas, 50, 49, temp_str); + } +} + +static bool gpio_i2c_sfp_input_callback(InputEvent* event, void* context) { + furi_assert(context); + GpioI2CSfp* gpio_i2c_sfp = context; + bool consumed = false; + + if(event->key == InputKeyOk) { + consumed = gpio_i2c_sfp_process_ok(gpio_i2c_sfp, event); + } + + return consumed; +} + +static bool gpio_i2c_sfp_process_ok(GpioI2CSfp* gpio_i2c_sfp, InputEvent* event) { + bool consumed = false; + gpio_i2c_sfp->callback(event->type, gpio_i2c_sfp->context); + + return consumed; +} + +GpioI2CSfp* gpio_i2c_sfp_alloc() { + GpioI2CSfp* gpio_i2c_sfp = malloc(sizeof(GpioI2CSfp)); + + gpio_i2c_sfp->view = view_alloc(); + view_allocate_model(gpio_i2c_sfp->view, ViewModelTypeLocking, sizeof(GpioI2CSfpModel)); + view_set_context(gpio_i2c_sfp->view, gpio_i2c_sfp); + view_set_draw_callback(gpio_i2c_sfp->view, gpio_i2c_sfp_draw_callback); + view_set_input_callback(gpio_i2c_sfp->view, gpio_i2c_sfp_input_callback); + + return gpio_i2c_sfp; +} + +void gpio_i2c_sfp_free(GpioI2CSfp* gpio_i2c_sfp) { + furi_assert(gpio_i2c_sfp); + view_free(gpio_i2c_sfp->view); + free(gpio_i2c_sfp); +} + +View* gpio_i2c_sfp_get_view(GpioI2CSfp* gpio_i2c_sfp) { + furi_assert(gpio_i2c_sfp); + return gpio_i2c_sfp->view; +} + +void gpio_i2c_sfp_set_ok_callback( + GpioI2CSfp* gpio_i2c_sfp, + GpioI2CSfpOkCallback callback, + void* context) { + furi_assert(gpio_i2c_sfp); + furi_assert(callback); + with_view_model( + gpio_i2c_sfp->view, + GpioI2CSfpModel * model, + { + UNUSED(model); + gpio_i2c_sfp->callback = callback; + gpio_i2c_sfp->context = context; + }, + false); +} + +void gpio_i2c_sfp_update_state(GpioI2CSfp* instance, I2CSfpState* st) { + furi_assert(instance); + furi_assert(st); + + with_view_model( + instance->view, + GpioI2CSfpModel * model, + { + // Insert values into model... + strcpy(model->vendor, st->vendor); + strcpy(model->pn, st->pn); + strcpy(model->sn, st->sn); + strcpy(model->rev, st->rev); + strcpy(model->connector, st->connector); + model->wavelength = st->wavelength; + model->sm_reach = st->sm_reach; + model->mm_reach_om3 = st->mm_reach_om3; + }, + true); +} diff --git a/applications/main/gpio/views/gpio_i2c_sfp.h b/applications/main/gpio/views/gpio_i2c_sfp.h new file mode 100644 index 00000000000..c57c143a4eb --- /dev/null +++ b/applications/main/gpio/views/gpio_i2c_sfp.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "../gpio_i2c_sfp_control.h" + +typedef struct GpioI2CSfp GpioI2CSfp; +typedef void (*GpioI2CSfpOkCallback)(InputType type, void* context); + +GpioI2CSfp* gpio_i2c_sfp_alloc(); + +void gpio_i2c_sfp_free(GpioI2CSfp* gpio_i2c_sfp); + +View* gpio_i2c_sfp_get_view(GpioI2CSfp* gpio_i2c_sfp); + +void gpio_i2c_sfp_set_ok_callback( + GpioI2CSfp* gpio_i2c_sfp, + GpioI2CSfpOkCallback callback, + void* context); + +void gpio_i2c_sfp_update_state(GpioI2CSfp* instance, I2CSfpState* st); diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index 9aed726dca5..2831590186e 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -32,7 +32,7 @@ #define IBUTTON_APP_FILENAME_PREFIX "iBtn" #define IBUTTON_APP_FILENAME_EXTENSION ".ibtn" -#define IBUTTON_KEY_NAME_SIZE 22 +#define IBUTTON_KEY_NAME_SIZE 25 typedef enum { iButtonWriteModeInvalid, diff --git a/applications/main/ibutton/ibutton_start.c b/applications/main/ibutton/ibutton_start.c index ca07becf524..0200a7ef080 100644 --- a/applications/main/ibutton/ibutton_start.c +++ b/applications/main/ibutton/ibutton_start.c @@ -4,7 +4,7 @@ static void ibutton_cli_wrapper(Cli* cli, FuriString* args, void* context) { cli_plugin_wrapper("ibutton_cli", 1, cli, args, context); } -void ibutton_on_system_start() { +void ibutton_on_system_start(void) { Cli* cli = furi_record_open(RECORD_CLI); cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli_wrapper, cli); furi_record_close(RECORD_CLI); diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_type.c b/applications/main/ibutton/scenes/ibutton_scene_add_type.c index 968bbac1cf7..55e05f20d77 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_type.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_type.c @@ -8,11 +8,20 @@ void ibutton_scene_add_type_on_enter(void* context) { for(uint32_t protocol_id = 0; protocol_id < ibutton_protocols_get_protocol_count(); ++protocol_id) { - furi_string_printf( - tmp, - "%s %s", - ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), - ibutton_protocols_get_name(ibutton->protocols, protocol_id)); + if((strcmp( + ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), + ibutton_protocols_get_name(ibutton->protocols, protocol_id)) != 0) && + (strcmp(ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), "N/A") != + 0)) { + furi_string_printf( + tmp, + "%s %s", + ibutton_protocols_get_manufacturer(ibutton->protocols, protocol_id), + ibutton_protocols_get_name(ibutton->protocols, protocol_id)); + } else { + furi_string_printf( + tmp, "%s", ibutton_protocols_get_name(ibutton->protocols, protocol_id)); + } submenu_add_item( submenu, furi_string_get_cstr(tmp), protocol_id, ibutton_submenu_callback, context); diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_name.c b/applications/main/ibutton/scenes/ibutton_scene_save_name.c index f48ae60d399..7735e284f2d 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_name.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_name.c @@ -17,8 +17,11 @@ void ibutton_scene_save_name_on_enter(void* context) { const bool is_new_file = furi_string_empty(ibutton->file_path); if(is_new_file) { - name_generator_make_auto_basic( - ibutton->key_name, IBUTTON_KEY_NAME_SIZE, IBUTTON_APP_FILENAME_PREFIX); + name_generator_make_auto( + ibutton->key_name, + IBUTTON_KEY_NAME_SIZE, + ibutton_protocols_get_name( + ibutton->protocols, ibutton_key_get_protocol_id(ibutton->key))); } text_input_set_header_text(text_input, "Name the key"); diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index 144d09e16f9..63b4ff5e24f 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -196,9 +196,8 @@ static void lfrfid_free(LfRfid* lfrfid) { free(lfrfid); } -int32_t lfrfid_app(void* p) { +int32_t lfrfid_app(char* args) { LfRfid* app = lfrfid_alloc(); - char* args = p; lfrfid_make_app_folder(app); diff --git a/applications/main/lfrfid/lfrfid_cli.c b/applications/main/lfrfid/lfrfid_cli.c index 7490885afa3..b259e7616f1 100644 --- a/applications/main/lfrfid/lfrfid_cli.c +++ b/applications/main/lfrfid/lfrfid_cli.c @@ -577,6 +577,6 @@ static const FlipperAppPluginDescriptor plugin_descriptor = { .entry_point = &lfrfid_cli, }; -const FlipperAppPluginDescriptor* lfrfid_cli_plugin_ep() { +const FlipperAppPluginDescriptor* lfrfid_cli_plugin_ep(void) { return &plugin_descriptor; } diff --git a/applications/main/lfrfid/lfrfid_start.c b/applications/main/lfrfid/lfrfid_start.c index 1ed88d2f06f..126542b188b 100644 --- a/applications/main/lfrfid/lfrfid_start.c +++ b/applications/main/lfrfid/lfrfid_start.c @@ -4,7 +4,7 @@ static void lfrfid_cli_wrapper(Cli* cli, FuriString* args, void* context) { cli_plugin_wrapper("lfrfid_cli", 1, cli, args, context); } -void lfrfid_on_system_start() { +void lfrfid_on_system_start(void) { Cli* cli = furi_record_open(RECORD_CLI); cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli_wrapper, NULL); furi_record_close(RECORD_CLI); diff --git a/applications/main/onewire/onewire_cli.c b/applications/main/onewire/onewire_cli.c index 49acfef19eb..f6da5b19955 100644 --- a/applications/main/onewire/onewire_cli.c +++ b/applications/main/onewire/onewire_cli.c @@ -69,4 +69,4 @@ static const FlipperAppPluginDescriptor plugin_descriptor = { const FlipperAppPluginDescriptor* onewire_cli_plugin_ep(void) { return &plugin_descriptor; -} \ No newline at end of file +} diff --git a/applications/main/onewire/onewire_start.c b/applications/main/onewire/onewire_start.c index 6249204aba1..a1b201c44fd 100644 --- a/applications/main/onewire/onewire_start.c +++ b/applications/main/onewire/onewire_start.c @@ -4,7 +4,7 @@ static void onewire_cli_wrapper(Cli* cli, FuriString* args, void* context) { cli_plugin_wrapper("onewire_cli", 1, cli, args, context); } -void onewire_on_system_start() { +void onewire_on_system_start(void) { Cli* cli = furi_record_open(RECORD_CLI); cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli_wrapper, cli); furi_record_close(RECORD_CLI); diff --git a/applications/main/u2f/u2f_app.c b/applications/main/u2f/u2f_app.c index 708e9fba03b..5ca5c03dc36 100644 --- a/applications/main/u2f/u2f_app.c +++ b/applications/main/u2f/u2f_app.c @@ -49,16 +49,12 @@ U2fApp* u2f_app_alloc(void) { view_dispatcher_add_view( app->view_dispatcher, U2fAppViewMain, u2f_view_get_view(app->u2f_view)); - if(furi_hal_usb_is_locked()) { - app->error = U2fAppErrorCloseRpc; - scene_manager_next_scene(app->scene_manager, U2fSceneError); + furi_hal_usb_unlock(); + if(u2f_data_check(true)) { + scene_manager_next_scene(app->scene_manager, U2fSceneMain); } else { - if(u2f_data_check(true)) { - scene_manager_next_scene(app->scene_manager, U2fSceneMain); - } else { - app->error = U2fAppErrorNoFiles; - scene_manager_next_scene(app->scene_manager, U2fSceneError); - } + app->error = U2fAppErrorNoFiles; + scene_manager_next_scene(app->scene_manager, U2fSceneError); } return app; diff --git a/applications/main/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c index b78376cc223..ab5712a0dcc 100644 --- a/applications/main/u2f/views/u2f_view.c +++ b/applications/main/u2f/views/u2f_view.c @@ -20,8 +20,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { if(model->display_msg == U2fMsgNotConnected) { canvas_draw_icon(canvas, 22, 15, &I_Connect_me_62x31); - canvas_draw_str_aligned( - canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connect me to computer"); + canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connect to a device"); } else if(model->display_msg == U2fMsgIdle) { canvas_draw_icon(canvas, 22, 15, &I_Connected_62x31); canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connected!");