diff --git a/ReadMe.md b/ReadMe.md
index d1555e2bb..b3d79bb38 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -1,9 +1,11 @@
[Join THE Flipper Uncensored Discord](https://discord.gg/gF2bBUzAFe) & [support us if you like what you see](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/SUPPORT.md)! 😄🚀💸
+
+
#### Thank you to all the supporters; this firmware is a fork of [Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware) & the main Flipper Devices FW! I will try to keep active development and updates from both in this build along with any other projects that can be found to be useful to the community. I try to keep this FW build the most cutting edge with updates from both and updates from active community projects. All features and projects pulled are listed in expandable sections below. Please do [support us](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/SUPPORT.md) and/or [xMasterX](https://github.com/Eng1n33r/flipperzero-firmware)! Everyone gives much of their uncompensated free time to ensure the success of the Flipper Zero!
-
+ |  |
Latest Updates:
@@ -14,8 +16,6 @@
TO DO
- GPIO: Feature to read EEPROM of SFP Modules using I2C [(By marcusju)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/198)
-- Settings: Favorite Game by holding UP on Desktop [Thanks to gotnull](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/57)
-- Settings: Hold Down for Games Menu [(Thanks to ESurge)](https://github.com/ESurge/flipperzero-firmware-wPlugins)
- Settings: Rename from SD `dolphin/name.txt` [(Thanks to E_Surge)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/259)
- Settings: Scan names will have timestamp instead of random name assigned for [NFC](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/lib/toolbox/random_name.c) and [SubGHz](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/subghz/scenes/subghz_scene_read_raw.c) (By RogueMaster)
- SubGHz: [Add settings to subghz read functionality to allow setting RSSI threshold (raw only) (By PolymerPrints)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/184)
@@ -26,6 +26,8 @@
- [Keynote BT plugin: long press on OK to switch between Space and Retur… #1729 (By coded-with-claws)](https://github.com/flipperdevices/flipperzero-firmware/pull/1729)
- [SubGhz: fix display information in the file if the frequenc… #1724 (By Skorpionm)](https://github.com/flipperdevices/flipperzero-firmware/pull/1724)
- [Show error popup when NFC chip is not init/disconnected #1722 (By Astrrra)](https://github.com/flipperdevices/flipperzero-firmware/pull/1722)
+- Lost To Faps: Settings: Favorite Game by holding UP on Desktop [Thanks to gotnull](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/57)
+- Lost To Faps: Settings: Hold Down for Games Menu [(Thanks to ESurge)](https://github.com/ESurge/flipperzero-firmware-wPlugins)
@@ -132,7 +134,6 @@ $ ./fbt plugin_dist FIRMWARE_APP_SET=ext_apps
- Settings: Desktop => [Games Only Mode (By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/GAMES_ONLY.md) [(Thanks to Astrrra for Inverted Mode to Mimic)](https://github.com/wetox-team/flipperzero-firmware/commit/ce91582b7417c5d7a9d8416c17a102d3a5868238)
- - [UP UP DOWN DOWN LEFT RIGHT LEFT RIGHT FROM CLOCK](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/GAMES_ONLY.md)<== FULL LIST OF GAMES ONLY CONTROLS
- Settings: "DUMB Mode" is now "Lock W PIN + Off" [(By RogueMaster)]
-- Settings: Favorite Game by holding UP on Desktop [Thanks to gotnull](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/57)
- Settings: Hold Down for Games Menu [(Thanks to ESurge)](https://github.com/ESurge/flipperzero-firmware-wPlugins)
- Settings: LCD Timeout Options Added: 10s+90s+2min+5min+10min [(By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/notification/notification_settings_app.c)
- Settings: Rename from SD `dolphin/name.txt` [(Thanks to E_Surge)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/259)
diff --git a/applications/main/gpio/gpio_app.c b/applications/main/gpio/gpio_app.c
index b8afdc8ea..19e53f453 100644
--- a/applications/main/gpio/gpio_app.c
+++ b/applications/main/gpio/gpio_app.c
@@ -51,6 +51,16 @@ GpioApp* gpio_app_alloc() {
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));
@@ -75,6 +85,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);
@@ -82,6 +94,8 @@ void gpio_app_free(GpioApp* app) {
widget_free(app->widget);
gpio_test_free(app->gpio_test);
gpio_usb_uart_free(app->gpio_usb_uart);
+ 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 fa91e8f79..9637f5345 100644
--- a/applications/main/gpio/gpio_app_i.h
+++ b/applications/main/gpio/gpio_app_i.h
@@ -15,6 +15,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"
struct GpioApp {
Gui* gui;
@@ -27,6 +29,8 @@ struct GpioApp {
GpioTest* gpio_test;
GpioUsbUart* gpio_usb_uart;
UsbUartBridge* usb_uart_bridge;
+ GpioI2CScanner* gpio_i2c_scanner;
+ GpioI2CSfp* gpio_i2c_sfp;
};
typedef enum {
@@ -35,4 +39,6 @@ typedef enum {
GpioAppViewUsbUart,
GpioAppViewUsbUartCfg,
GpioAppViewUsbUartCloseRpc,
+ GpioAppViewI2CScanner,
+ GpioAppViewI2CSfp
} GpioAppView;
diff --git a/applications/main/gpio/gpio_custom_event.h b/applications/main/gpio/gpio_custom_event.h
index 2bf3e5a8b..02e24f753 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 000000000..bf3f1090d
--- /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 000000000..011f8aa36
--- /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 000000000..d14ba1b8e
--- /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 000000000..7a9f4bcbe
--- /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 3406e42d3..faca22d8d 100644
--- a/applications/main/gpio/scenes/gpio_scene_config.h
+++ b/applications/main/gpio/scenes/gpio_scene_config.h
@@ -3,3 +3,5 @@ ADD_SCENE(gpio, test, Test)
ADD_SCENE(gpio, usb_uart, UsbUart)
ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg)
ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc)
+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 000000000..7b310debc
--- /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 000000000..49d0e8dd2
--- /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 41b745233..08b77238f 100644
--- a/applications/main/gpio/scenes/gpio_scene_start.c
+++ b/applications/main/gpio/scenes/gpio_scene_start.c
@@ -6,6 +6,8 @@ enum GpioItem {
GpioItemUsbUart,
GpioItemTest,
GpioItemOtg,
+ GpioItemI2CScanner,
+ GpioItemI2CSfp,
};
enum GpioOtg {
@@ -26,6 +28,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);
}
}
@@ -67,6 +73,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));
@@ -85,6 +94,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()) {
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 000000000..a867ff5da
--- /dev/null
+++ b/applications/main/gpio/views/gpio_i2c_scanner.c
@@ -0,0 +1,136 @@
+#include
+#include "gpio_i2c_scanner.h"
+#include "../gpio_item.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;
+ return 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];
+ }
+
+ return 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 000000000..52ebf3de3
--- /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 000000000..66e88a131
--- /dev/null
+++ b/applications/main/gpio/views/gpio_i2c_sfp.c
@@ -0,0 +1,145 @@
+#include
+#include "gpio_i2c_sfp.h"
+#include "../gpio_item.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;
+ return 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;
+ return 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 000000000..c57c143a4
--- /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);