[FL-2797] Signal Generator app (#1793)
* Signal Generator app * MCO pin initialization in app * furi_hal_pwm documentation Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const signal_gen_scene_on_enter_handlers[])(void*) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const signal_gen_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const signal_gen_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "signal_gen_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers signal_gen_scene_handlers = {
|
||||
.on_enter_handlers = signal_gen_scene_on_enter_handlers,
|
||||
.on_event_handlers = signal_gen_scene_on_event_handlers,
|
||||
.on_exit_handlers = signal_gen_scene_on_exit_handlers,
|
||||
.scene_num = SignalGenSceneNum,
|
||||
};
|
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SignalGenScene##id,
|
||||
typedef enum {
|
||||
#include "signal_gen_scene_config.h"
|
||||
SignalGenSceneNum,
|
||||
} SignalGenScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers signal_gen_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "signal_gen_scene_config.h"
|
||||
#undef ADD_SCENE
|
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(signal_gen, start, Start)
|
||||
ADD_SCENE(signal_gen, pwm, Pwm)
|
||||
ADD_SCENE(signal_gen, mco, Mco)
|
@@ -0,0 +1,132 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
LineIndexSource,
|
||||
LineIndexDivision,
|
||||
} LineIndex;
|
||||
|
||||
static const char* const mco_source_names[] = {
|
||||
"32768",
|
||||
"64MHz",
|
||||
"~100K",
|
||||
"~200K",
|
||||
"~400K",
|
||||
"~800K",
|
||||
"~1MHz",
|
||||
"~2MHz",
|
||||
"~4MHz",
|
||||
"~8MHz",
|
||||
"~16MHz",
|
||||
"~24MHz",
|
||||
"~32MHz",
|
||||
"~48MHz",
|
||||
};
|
||||
|
||||
static const FuriHalClockMcoSourceId mco_sources[] = {
|
||||
FuriHalClockMcoLse,
|
||||
FuriHalClockMcoSysclk,
|
||||
FuriHalClockMcoMsi100k,
|
||||
FuriHalClockMcoMsi200k,
|
||||
FuriHalClockMcoMsi400k,
|
||||
FuriHalClockMcoMsi800k,
|
||||
FuriHalClockMcoMsi1m,
|
||||
FuriHalClockMcoMsi2m,
|
||||
FuriHalClockMcoMsi4m,
|
||||
FuriHalClockMcoMsi8m,
|
||||
FuriHalClockMcoMsi16m,
|
||||
FuriHalClockMcoMsi24m,
|
||||
FuriHalClockMcoMsi32m,
|
||||
FuriHalClockMcoMsi48m,
|
||||
};
|
||||
|
||||
static const char* const mco_divisor_names[] = {
|
||||
"1",
|
||||
"2",
|
||||
"4",
|
||||
"8",
|
||||
"16",
|
||||
};
|
||||
|
||||
static const FuriHalClockMcoDivisorId mco_divisors[] = {
|
||||
FuriHalClockMcoDiv1,
|
||||
FuriHalClockMcoDiv2,
|
||||
FuriHalClockMcoDiv4,
|
||||
FuriHalClockMcoDiv8,
|
||||
FuriHalClockMcoDiv16,
|
||||
};
|
||||
|
||||
static void mco_source_list_change_callback(VariableItem* item) {
|
||||
SignalGenApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, mco_source_names[index]);
|
||||
|
||||
app->mco_src = mco_sources[index];
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenMcoEventUpdate);
|
||||
}
|
||||
|
||||
static void mco_divisor_list_change_callback(VariableItem* item) {
|
||||
SignalGenApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, mco_divisor_names[index]);
|
||||
|
||||
app->mco_div = mco_divisors[index];
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenMcoEventUpdate);
|
||||
}
|
||||
|
||||
void signal_gen_scene_mco_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
VariableItemList* var_item_list = app->var_item_list;
|
||||
|
||||
VariableItem* item;
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "Source", COUNT_OF(mco_source_names), mco_source_list_change_callback, app);
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, mco_source_names[0]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
"Division",
|
||||
COUNT_OF(mco_divisor_names),
|
||||
mco_divisor_list_change_callback,
|
||||
app);
|
||||
variable_item_set_current_value_index(item, 0);
|
||||
variable_item_set_current_value_text(item, mco_divisor_names[0]);
|
||||
|
||||
variable_item_list_set_selected_item(var_item_list, LineIndexSource);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewVarItemList);
|
||||
|
||||
app->mco_src = FuriHalClockMcoLse;
|
||||
app->mco_div = FuriHalClockMcoDiv1;
|
||||
furi_hal_clock_mco_enable(app->mco_src, app->mco_div);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn0MCO);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_mco_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SignalGenMcoEventUpdate) {
|
||||
consumed = true;
|
||||
furi_hal_clock_mco_enable(app->mco_src, app->mco_div);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_mco_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_usart_tx,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn7USART1);
|
||||
furi_hal_clock_mco_disable();
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
static const FuriHalPwmOutputId pwm_ch_id[] = {
|
||||
FuriHalPwmOutputIdTim1PA7,
|
||||
FuriHalPwmOutputIdLptim2PA4,
|
||||
};
|
||||
|
||||
#define DEFAULT_FREQ 1000
|
||||
#define DEFAULT_DUTY 50
|
||||
|
||||
static void
|
||||
signal_gen_pwm_callback(uint8_t channel_id, uint32_t freq, uint8_t duty, void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
app->pwm_freq = freq;
|
||||
app->pwm_duty = duty;
|
||||
|
||||
if(app->pwm_ch != pwm_ch_id[channel_id]) {
|
||||
app->pwm_ch_prev = app->pwm_ch;
|
||||
app->pwm_ch = pwm_ch_id[channel_id];
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventChannelChange);
|
||||
} else {
|
||||
app->pwm_ch = pwm_ch_id[channel_id];
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SignalGenPwmEventUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_gen_scene_pwm_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewPwm);
|
||||
|
||||
signal_gen_pwm_set_callback(app->pwm_view, signal_gen_pwm_callback, app);
|
||||
|
||||
signal_gen_pwm_set_params(app->pwm_view, 0, DEFAULT_FREQ, DEFAULT_DUTY);
|
||||
furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SignalGenPwmEventUpdate) {
|
||||
consumed = true;
|
||||
furi_hal_pwm_set_params(app->pwm_ch, app->pwm_freq, app->pwm_duty);
|
||||
} else if(event.event == SignalGenPwmEventChannelChange) {
|
||||
consumed = true;
|
||||
furi_hal_pwm_stop(app->pwm_ch_prev);
|
||||
furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_pwm_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
furi_hal_pwm_stop(app->pwm_ch);
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
#include "../signal_gen_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexPwm,
|
||||
SubmenuIndexClockOutput,
|
||||
} SubmenuIndex;
|
||||
|
||||
void signal_gen_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void signal_gen_scene_start_on_enter(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu, "PWM", SubmenuIndexPwm, signal_gen_scene_start_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Clock Output",
|
||||
SubmenuIndexClockOutput,
|
||||
signal_gen_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SignalGenSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SignalGenViewSubmenu);
|
||||
}
|
||||
|
||||
bool signal_gen_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
SignalGenApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexPwm) {
|
||||
scene_manager_next_scene(app->scene_manager, SignalGenScenePwm);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexClockOutput) {
|
||||
scene_manager_next_scene(app->scene_manager, SignalGenSceneMco);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, SignalGenSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void signal_gen_scene_start_on_exit(void* context) {
|
||||
SignalGenApp* app = context;
|
||||
|
||||
submenu_reset(app->submenu);
|
||||
}
|
Reference in New Issue
Block a user