Skip to content

Commit

Permalink
Merge pull request #3 from maybe-hello-world/gpio_motor
Browse files Browse the repository at this point in the history
Add GPIO motor driven view
  • Loading branch information
maybe-hello-world authored Jan 10, 2023
2 parents 646b3ac + f9ca8b9 commit b7c1814
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 4 deletions.
4 changes: 2 additions & 2 deletions device-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
],
"btle": {
"names": [
"Flipper Zero"
"Flipper *"
],
"services": {
"8fe5b3d5-2e7f-4a98-2a48-7acc60fe0000": {
Expand All @@ -41,4 +41,4 @@
}
}
}
}
}
15 changes: 15 additions & 0 deletions src/fbp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

enum FBPSubmenuIndex {
FBPSubmenuIndexInternal,
FBPSubmenuIndexGPIOSimpleMotor,
};

uint32_t fbp_start_view(void* context) {
Expand All @@ -19,6 +20,8 @@ void fbp_submenu_callback(void* context, uint32_t index) {
FBP* app = context;
if(index == FBPSubmenuIndexInternal) {
view_dispatcher_switch_to_view(app->view_dispatcher, FBPAppViewInternal);
} else if (index == FBPSubmenuIndexGPIOSimpleMotor) {
view_dispatcher_switch_to_view(app->view_dispatcher, FBPAppViewGPIOSimpleMotor);
}
}

Expand Down Expand Up @@ -46,6 +49,12 @@ FBP* fbp_alloc() {
view_set_previous_callback(flipper_vibrator_get_view(app->flipper_vibrator), fbp_start_view);
view_dispatcher_add_view(app->view_dispatcher, FBPAppViewInternal, flipper_vibrator_get_view(app->flipper_vibrator));

// add GPIO Simple Motor View
app->gpio_simple_motor = gpio_simple_motor_alloc(app);
submenu_add_item(app->submenu, "Flipper GPIO Simple Motor", FBPSubmenuIndexGPIOSimpleMotor, fbp_submenu_callback, app);
view_set_previous_callback(gpio_simple_motor_get_view(app->gpio_simple_motor), fbp_start_view);
view_dispatcher_add_view(app->view_dispatcher, FBPAppViewGPIOSimpleMotor, gpio_simple_motor_get_view(app->gpio_simple_motor));

view_dispatcher_switch_to_view(app->view_dispatcher, FBPAppViewSubmenu);
return app;
}
Expand All @@ -57,9 +66,15 @@ void fbs_free(FBP* app) {
view_dispatcher_remove_view(app->view_dispatcher, FBPAppViewSubmenu);
submenu_free(app->submenu);

// free Flipper Internal Vibrator
view_dispatcher_remove_view(app->view_dispatcher, FBPAppViewInternal);
flipper_vibrator_free(app->flipper_vibrator);

// free GPIO Simple Motor
view_dispatcher_remove_view(app->view_dispatcher, FBPAppViewGPIOSimpleMotor);
gpio_simple_motor_free(app->gpio_simple_motor);

// Other deallocations
view_dispatcher_free(app->view_dispatcher);


Expand Down
3 changes: 3 additions & 0 deletions src/fbp.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "tcode.h"
#include "views/internal.h"
#include "views/gpio_simple_motor.h"

#define TAG "Flipper BP"

Expand All @@ -27,9 +28,11 @@ struct FBP {
FuriMessageQueue* event_queue;

FlipperVibrator* flipper_vibrator;
GPIOSimpleMotor* gpio_simple_motor;
};

typedef enum {
FBPAppViewSubmenu,
FBPAppViewInternal,
FBPAppViewGPIOSimpleMotor,
} FBPAppView;
1 change: 1 addition & 0 deletions src/tcode.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#pragma once
#include <furi.h>

typedef enum {
Expand Down
149 changes: 149 additions & 0 deletions src/views/gpio_simple_motor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include "gpio_simple_motor.h"
#include "../fbp.h"

static const uint16_t BT_SERIAL_BUFFER_SIZE = 128;
static const uint32_t DEFAULT_FREQ = 1000;
static const FuriHalPwmOutputId DEFAULT_PWM_OUTPUT_ID = FuriHalPwmOutputIdTim1PA7;

struct GPIOSimpleMotor {
View* view;
FBP* fbp;

uint8_t current_pwm_duty;
};

typedef struct {
char* display_text_1;
char* display_text_2;
char* display_text_3;
} GPIOSimpleMotorModel;


static void process_general_command(TCodeCommand command, GPIOSimpleMotor* motor) {
if (command.command_type == Magnitude && command.data.magnitude_command.motion_type == Vibrate && command.data.magnitude_command.channel_id == 0) {
// just enable vibration on X
uint8_t new_duty = (uint8_t) (command.data.magnitude_command.magnitude * 100);
if (new_duty > 100) {
new_duty = 100;
}
FURI_LOG_D(TAG, "Setting vibration power on %u", new_duty);

// using Pulse-Widht Modulation to control a motor via a transistor
// just google for a typical arduino + PWM + motor scheme
if (new_duty == 0) {
furi_hal_pwm_stop(DEFAULT_PWM_OUTPUT_ID);
} else if (motor->current_pwm_duty == 0) {
furi_hal_pwm_start(DEFAULT_PWM_OUTPUT_ID, DEFAULT_FREQ, new_duty);
} else {
furi_hal_pwm_set_params(DEFAULT_PWM_OUTPUT_ID, DEFAULT_FREQ, new_duty);
}
motor->current_pwm_duty = new_duty;
return;
}
}

static uint16_t bt_serial_event_callback(SerialServiceEvent event, void* context) {
furi_assert(context);
GPIOSimpleMotor* motor = context;

if(event.event == SerialServiceEventTypeDataReceived) {
TCodeCommandArray commands = tcode_decode(event.data.buffer, event.data.size);
FURI_LOG_D(TAG, "Decoded commands array size: %u", commands.size);
for (uint16_t i = 0; i < commands.size; i++) {
FURI_LOG_D(TAG, "Command #%u, type: %u\n", i, commands.commands[i].command_type);
}
for (uint16_t i = 0; i < commands.size; i++) {
// looking for first vibro command to execute
TCodeCommand current_command = commands.commands[i];
TCodeCommandType type = current_command.command_type;
if ((type == Magnitude || type == MagnitudeSpeed || type == MagnitudeTimeInterval)) {
process_general_command(current_command, motor);
}
}
}
return 0;
}

static bool input_callback(InputEvent* event, void* ctx) {
furi_assert(ctx);
GPIOSimpleMotor* motor = ctx;
if(event->key == InputKeyBack) {
furi_hal_bt_serial_set_event_callback(0, NULL, NULL);
return false;
}

if (event->key == InputKeyOk) {
if (furi_hal_bt_is_active()) {
FURI_LOG_D(TAG, "BT is working, hijacking the serial connection...");
furi_hal_bt_start_advertising();
furi_hal_bt_serial_set_event_callback(BT_SERIAL_BUFFER_SIZE, bt_serial_event_callback, motor);

with_view_model(
motor->view,
GPIOSimpleMotorModel * model,
{
model->display_text_1 = "";
model->display_text_2 = "Ready ^_^";
model->display_text_3 = "";
},
true);

} else {
FURI_LOG_E(TAG, "Please, enable the Bluetooth and restart the app");

with_view_model(
motor->view,
GPIOSimpleMotorModel * model,
{
model->display_text_1 = "Error:";
model->display_text_2 = "Bluetooth is not enabled";
model->display_text_3 = "";
},
true);
}
}
return true;
}

static void draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
GPIOSimpleMotorModel* app = ctx;
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, (char*)app->display_text_1);
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, (char*)app->display_text_2);
canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, (char*)app->display_text_3);
}

GPIOSimpleMotor* gpio_simple_motor_alloc(FBP* fbp) {
furi_assert(fbp);
GPIOSimpleMotor* motor = malloc(sizeof(GPIOSimpleMotor));
motor->view = view_alloc();
motor->fbp = fbp;
view_set_context(motor->view, motor);
view_allocate_model(motor->view, ViewModelTypeLocking, sizeof(GPIOSimpleMotorModel));
view_set_draw_callback(motor->view, draw_callback);
view_set_input_callback(motor->view, input_callback);

with_view_model(
motor->view,
GPIOSimpleMotorModel * model,
{
model->display_text_1 = "Please, connect the";
model->display_text_2 = "transistor base to pin A7!";
model->display_text_3 = "Press OK to start";
},
true);

return motor;
}

void gpio_simple_motor_free(GPIOSimpleMotor* motor) {
furi_assert(motor);
furi_hal_pwm_stop(DEFAULT_PWM_OUTPUT_ID);
view_free(motor->view);
free(motor);
}

View* gpio_simple_motor_get_view(GPIOSimpleMotor* motor) {
furi_assert(motor);
return motor->view;
}
13 changes: 13 additions & 0 deletions src/views/gpio_simple_motor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once
#include <gui/view.h>
#include <furi_hal_gpio.h>
#include <furi_hal_pwm.h>

typedef struct FBP FBP;
typedef struct GPIOSimpleMotor GPIOSimpleMotor;

GPIOSimpleMotor* gpio_simple_motor_alloc(FBP* fbp);

void gpio_simple_motor_free(GPIOSimpleMotor* motor_app);

View* gpio_simple_motor_get_view(GPIOSimpleMotor* motor_app);
4 changes: 2 additions & 2 deletions src/views/internal.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "internal.h"
#include "../fbp.h"

const uint16_t BT_SERIAL_BUFFER_SIZE = 128;
static const uint16_t BT_SERIAL_BUFFER_SIZE = 128;

struct FlipperVibrator {
View* view;
Expand Down Expand Up @@ -96,7 +96,7 @@ static bool input_callback(InputEvent* event, void* ctx) {
return true;
}

void draw_callback(Canvas* canvas, void* ctx) {
static void draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
FlipperVibratorModel* app = ctx;
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, (char*)app->display_text);
Expand Down

0 comments on commit b7c1814

Please sign in to comment.