From 8a04b4ac328bbb63b79b0b8400ab8e137f75ea29 Mon Sep 17 00:00:00 2001 From: maybe-hello-world Date: Mon, 9 Jan 2023 21:58:14 -0800 Subject: [PATCH 1/3] WIP: using simple external motor --- src/fbp.c | 15 +++ src/fbp.h | 3 + src/tcode.h | 1 + src/views/gpio_simple_motor.c | 174 ++++++++++++++++++++++++++++++++++ src/views/gpio_simple_motor.h | 13 +++ src/views/internal.c | 4 +- 6 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 src/views/gpio_simple_motor.c create mode 100644 src/views/gpio_simple_motor.h diff --git a/src/fbp.c b/src/fbp.c index 1478f614b7a..60083a4a69e 100644 --- a/src/fbp.c +++ b/src/fbp.c @@ -2,6 +2,7 @@ enum FBPSubmenuIndex { FBPSubmenuIndexInternal, + FBPSubmenuIndexGPIOSimpleMotor, }; uint32_t fbp_start_view(void* context) { @@ -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); } } @@ -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; } @@ -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); diff --git a/src/fbp.h b/src/fbp.h index 08d2d10611e..bd669ad0332 100644 --- a/src/fbp.h +++ b/src/fbp.h @@ -10,6 +10,7 @@ #include "tcode.h" #include "views/internal.h" +#include "views/gpio_simple_motor.h" #define TAG "Flipper BP" @@ -27,9 +28,11 @@ struct FBP { FuriMessageQueue* event_queue; FlipperVibrator* flipper_vibrator; + GPIOSimpleMotor* gpio_simple_motor; }; typedef enum { FBPAppViewSubmenu, FBPAppViewInternal, + FBPAppViewGPIOSimpleMotor, } FBPAppView; \ No newline at end of file diff --git a/src/tcode.h b/src/tcode.h index e5fc04d510e..7174965fe0c 100644 --- a/src/tcode.h +++ b/src/tcode.h @@ -1,3 +1,4 @@ +#pragma once #include typedef enum { diff --git a/src/views/gpio_simple_motor.c b/src/views/gpio_simple_motor.c new file mode 100644 index 00000000000..338d1883508 --- /dev/null +++ b/src/views/gpio_simple_motor.c @@ -0,0 +1,174 @@ +#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; + } + + if (command.command_type == MagnitudeSpeed && command.data.magnitude_speed_command.motion_type == Vibrate && command.data.magnitude_speed_command.channel_id == 0) { + // furi_hal_vibro_on(command.data.magnitude_speed_command.magnitude > 0.1f); + return; + } + + if (command.command_type == MagnitudeTimeInterval && command.data.magnitude_time_interval_command.motion_type == Vibrate && command.data.magnitude_time_interval_command.channel_id == 0) { + // furi_hal_vibro_on(command.data.magnitude_time_interval_command.magnitude > 0.1f); + 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); + + + // init gpio?? + // furi_hal_clock_mco_enable(app->mco_src, app->mco_div); + // furi_hal_gpio_init_ex(&gpio_usart_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn0MCO); + + return motor; +} + +void gpio_simple_motor_free(GPIOSimpleMotor* motor) { + furi_assert(motor); + furi_hal_pwm_stop(DEFAULT_PWM_OUTPUT_ID); + + // disable gpio?? + // furi_hal_gpio_init_ex( + // &gpio_usart_tx, + // GpioModeAltFunctionPushPull, + // GpioPullUp, + // GpioSpeedVeryHigh, + // GpioAltFn7USART1); + // furi_hal_clock_mco_disable(); + + view_free(motor->view); + free(motor); +} + +View* gpio_simple_motor_get_view(GPIOSimpleMotor* motor) { + furi_assert(motor); + return motor->view; +} \ No newline at end of file diff --git a/src/views/gpio_simple_motor.h b/src/views/gpio_simple_motor.h new file mode 100644 index 00000000000..e2668a45df9 --- /dev/null +++ b/src/views/gpio_simple_motor.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include + +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); diff --git a/src/views/internal.c b/src/views/internal.c index def09764d37..8d458d92094 100644 --- a/src/views/internal.c +++ b/src/views/internal.c @@ -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; @@ -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); From 237f5d4ef3d11f1c4d0e459056f4ff4f8cac19e8 Mon Sep 17 00:00:00 2001 From: maybe-hello-world Date: Mon, 9 Jan 2023 23:54:18 -0800 Subject: [PATCH 2/3] fix device config --- device-config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device-config.json b/device-config.json index eef6036bcf3..898e84ea87a 100644 --- a/device-config.json +++ b/device-config.json @@ -16,7 +16,7 @@ ], "btle": { "names": [ - "Flipper Zero" + "Flipper *" ], "services": { "8fe5b3d5-2e7f-4a98-2a48-7acc60fe0000": { @@ -41,4 +41,4 @@ } } } -} \ No newline at end of file +} From f9ca8b9f53b16198a6788a18bc4a2bf61f35b23d Mon Sep 17 00:00:00 2001 From: maybe-hello-world Date: Mon, 9 Jan 2023 23:56:53 -0800 Subject: [PATCH 3/3] cleanup --- src/views/gpio_simple_motor.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/views/gpio_simple_motor.c b/src/views/gpio_simple_motor.c index 338d1883508..5fef098dc9a 100644 --- a/src/views/gpio_simple_motor.c +++ b/src/views/gpio_simple_motor.c @@ -40,16 +40,6 @@ static void process_general_command(TCodeCommand command, GPIOSimpleMotor* motor motor->current_pwm_duty = new_duty; return; } - - if (command.command_type == MagnitudeSpeed && command.data.magnitude_speed_command.motion_type == Vibrate && command.data.magnitude_speed_command.channel_id == 0) { - // furi_hal_vibro_on(command.data.magnitude_speed_command.magnitude > 0.1f); - return; - } - - if (command.command_type == MagnitudeTimeInterval && command.data.magnitude_time_interval_command.motion_type == Vibrate && command.data.magnitude_time_interval_command.channel_id == 0) { - // furi_hal_vibro_on(command.data.magnitude_time_interval_command.magnitude > 0.1f); - return; - } } static uint16_t bt_serial_event_callback(SerialServiceEvent event, void* context) { @@ -142,11 +132,6 @@ GPIOSimpleMotor* gpio_simple_motor_alloc(FBP* fbp) { model->display_text_3 = "Press OK to start"; }, true); - - - // init gpio?? - // furi_hal_clock_mco_enable(app->mco_src, app->mco_div); - // furi_hal_gpio_init_ex(&gpio_usart_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn0MCO); return motor; } @@ -154,16 +139,6 @@ GPIOSimpleMotor* gpio_simple_motor_alloc(FBP* fbp) { void gpio_simple_motor_free(GPIOSimpleMotor* motor) { furi_assert(motor); furi_hal_pwm_stop(DEFAULT_PWM_OUTPUT_ID); - - // disable gpio?? - // furi_hal_gpio_init_ex( - // &gpio_usart_tx, - // GpioModeAltFunctionPushPull, - // GpioPullUp, - // GpioSpeedVeryHigh, - // GpioAltFn7USART1); - // furi_hal_clock_mco_disable(); - view_free(motor->view); free(motor); }