Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gpio i2c scanner #139

Merged
merged 7 commits into from
Jul 31, 2022
Merged
6 changes: 6 additions & 0 deletions applications/gpio/gpio_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ 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->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, GpioAppViewUsbUartCloseRpc, widget_get_view(app->widget));
Expand All @@ -75,13 +79,15 @@ 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, GpioAppViewUsbUart);
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUartCfg);
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUartCloseRpc);
variable_item_list_free(app->var_item_list);
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);

// View dispatcher
view_dispatcher_free(app->view_dispatcher);
Expand Down
3 changes: 3 additions & 0 deletions applications/gpio/gpio_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <gui/modules/widget.h>
#include "views/gpio_test.h"
#include "views/gpio_usb_uart.h"
#include "views/gpio_i2c_scanner.h"

struct GpioApp {
Gui* gui;
Expand All @@ -27,6 +28,7 @@ struct GpioApp {
GpioTest* gpio_test;
GpioUsbUart* gpio_usb_uart;
UsbUartBridge* usb_uart_bridge;
GpioI2CScanner* gpio_i2c_scanner;
};

typedef enum {
Expand All @@ -35,4 +37,5 @@ typedef enum {
GpioAppViewUsbUart,
GpioAppViewUsbUartCfg,
GpioAppViewUsbUartCloseRpc,
GpioAppViewI2CScanner,
} GpioAppView;
3 changes: 2 additions & 1 deletion applications/gpio/gpio_custom_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ typedef enum {
GpioStartEventOtgOn,
GpioStartEventManualControl,
GpioStartEventUsbUart,

GpioStartEventI2CScanner,

GpioCustomEventErrorBack,

GpioUsbUartEventConfig,
Expand Down
21 changes: 21 additions & 0 deletions applications/gpio/gpio_i2c_scanner_control.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "gpio_i2c_scanner_control.h"
#include <furi_hal_delay.h>


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_hal_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);
}
21 changes: 21 additions & 0 deletions applications/gpio/gpio_i2c_scanner_control.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

#include <furi_hal_i2c.h>

#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);
1 change: 1 addition & 0 deletions applications/gpio/scenes/gpio_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ 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)
36 changes: 36 additions & 0 deletions applications/gpio/scenes/gpio_scene_i2c_scanner.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "../gpio_app_i.h"
#include <furi_hal_gpio.h>

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);
}
8 changes: 8 additions & 0 deletions applications/gpio/scenes/gpio_scene_start.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum GpioItem {
GpioItemUsbUart,
GpioItemTest,
GpioItemOtg,
GpioItemI2CScanner,
};

enum GpioOtg {
Expand All @@ -26,6 +27,8 @@ 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);
}
}

Expand Down Expand Up @@ -66,6 +69,8 @@ void gpio_scene_start_on_enter(void* context) {
variable_item_set_current_value_index(item, GpioOtgOff);
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_set_selected_item(
var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioSceneStart));
Expand All @@ -85,6 +90,9 @@ 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 == GpioStartEventUsbUart) {
scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart);
if(!furi_hal_usb_is_locked()) {
Expand Down
136 changes: 136 additions & 0 deletions applications/gpio/views/gpio_i2c_scanner.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <gui/elements.h>
#include "gpio_i2c_scanner.h"
#include "../gpio_item.h"

#include <string.h>


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


19 changes: 19 additions & 0 deletions applications/gpio/views/gpio_i2c_scanner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <gui/view.h>
#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);