diff --git a/applications/gpio/gpio_app.c b/applications/gpio/gpio_app.c index 7806fee35b6..841d674cb9c 100644 --- a/applications/gpio/gpio_app.c +++ b/applications/gpio/gpio_app.c @@ -57,6 +57,12 @@ GpioApp* gpio_app_alloc() { 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)); @@ -82,6 +88,7 @@ void gpio_app_free(GpioApp* app) { 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); @@ -90,6 +97,7 @@ void gpio_app_free(GpioApp* app) { 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/gpio/gpio_app_i.h b/applications/gpio/gpio_app_i.h index 1174d3b3f99..9637f534537 100644 --- a/applications/gpio/gpio_app_i.h +++ b/applications/gpio/gpio_app_i.h @@ -16,6 +16,7 @@ #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; @@ -29,6 +30,7 @@ struct GpioApp { GpioUsbUart* gpio_usb_uart; UsbUartBridge* usb_uart_bridge; GpioI2CScanner* gpio_i2c_scanner; + GpioI2CSfp* gpio_i2c_sfp; }; typedef enum { @@ -38,4 +40,5 @@ typedef enum { GpioAppViewUsbUartCfg, GpioAppViewUsbUartCloseRpc, GpioAppViewI2CScanner, + GpioAppViewI2CSfp } GpioAppView; diff --git a/applications/gpio/gpio_custom_event.h b/applications/gpio/gpio_custom_event.h index 5c873d19399..02e24f753bc 100644 --- a/applications/gpio/gpio_custom_event.h +++ b/applications/gpio/gpio_custom_event.h @@ -6,6 +6,7 @@ typedef enum { GpioStartEventManualControl, GpioStartEventUsbUart, GpioStartEventI2CScanner, + GpioStartEventI2CSfp, GpioCustomEventErrorBack, diff --git a/applications/gpio/gpio_i2c_sfp_control.c b/applications/gpio/gpio_i2c_sfp_control.c new file mode 100644 index 00000000000..6e7a8fdb00a --- /dev/null +++ b/applications/gpio/gpio_i2c_sfp_control.c @@ -0,0 +1,338 @@ +#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; 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/gpio/gpio_i2c_sfp_control.h b/applications/gpio/gpio_i2c_sfp_control.h new file mode 100644 index 00000000000..7a9f4bcbef5 --- /dev/null +++ b/applications/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/gpio/scenes/gpio_scene_config.h b/applications/gpio/scenes/gpio_scene_config.h index 07937522b54..faca22d8d5f 100644 --- a/applications/gpio/scenes/gpio_scene_config.h +++ b/applications/gpio/scenes/gpio_scene_config.h @@ -4,3 +4,4 @@ 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/gpio/scenes/gpio_scene_i2c_sfp.c b/applications/gpio/scenes/gpio_scene_i2c_sfp.c new file mode 100644 index 00000000000..83511aae7b2 --- /dev/null +++ b/applications/gpio/scenes/gpio_scene_i2c_sfp.c @@ -0,0 +1,37 @@ +#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/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c index dddd5485ffa..08b77238fef 100644 --- a/applications/gpio/scenes/gpio_scene_start.c +++ b/applications/gpio/scenes/gpio_scene_start.c @@ -7,6 +7,7 @@ enum GpioItem { GpioItemTest, GpioItemOtg, GpioItemI2CScanner, + GpioItemI2CSfp, }; enum GpioOtg { @@ -29,6 +30,8 @@ static void gpio_scene_start_var_list_enter_callback(void* context, uint32_t ind 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); } } @@ -71,6 +74,7 @@ void gpio_scene_start_on_enter(void* context) { } 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)); @@ -93,6 +97,9 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { } 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/gpio/views/gpio_i2c_sfp.c b/applications/gpio/views/gpio_i2c_sfp.c new file mode 100644 index 00000000000..79799a1efbf --- /dev/null +++ b/applications/gpio/views/gpio_i2c_sfp.c @@ -0,0 +1,146 @@ +#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/gpio/views/gpio_i2c_sfp.h b/applications/gpio/views/gpio_i2c_sfp.h new file mode 100644 index 00000000000..c57c143a4eb --- /dev/null +++ b/applications/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);