Skip to content

Commit

Permalink
Merge pull request #139 from GitChris3004/gpio_i2c_scanner
Browse files Browse the repository at this point in the history
Gpio i2c scanner
  • Loading branch information
RogueMaster authored Jul 31, 2022
2 parents 368d1a0 + c50b547 commit 66a8aa7
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 1 deletion.
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);

0 comments on commit 66a8aa7

Please sign in to comment.