diff --git a/lua/settings.lua b/lua/settings.lua index 07f1e4d2..0ae4e73d 100644 --- a/lua/settings.lua +++ b/lua/settings.lua @@ -451,6 +451,11 @@ settings.InputSettings = SettingsScreen:new { local controls_locked = make_scheme_control(self, controls.locked_schemes(), controls.locked_scheme) local controls_locked_desc = widgets.Description(controls_locked, "Control scheme when locked") + theme.set_subject(self.content:Label { + text = "Haptics Mode", + }, "settings_title") + make_scheme_control(self, controls.haptics_modes(), controls.haptics_mode) + controls_chooser:focus() theme.set_subject(self.content:Label { diff --git a/src/drivers/include/drivers/nvs.hpp b/src/drivers/include/drivers/nvs.hpp index 18bc5de6..e3a105f8 100644 --- a/src/drivers/include/drivers/nvs.hpp +++ b/src/drivers/include/drivers/nvs.hpp @@ -110,6 +110,15 @@ class NvsStorage { auto OutputMode() -> Output; auto OutputMode(Output) -> void; + enum class HapticsModes : uint8_t { + kDisabled = 0, + kMinimal = 1, + kStrong = 2, + }; + auto HapticsMode() -> HapticsModes; + auto HapticsMode(HapticsModes) -> void; + static auto intToHapticsMode(int raw) -> HapticsModes; + auto ScreenBrightness() -> uint_fast8_t; auto ScreenBrightness(uint_fast8_t) -> void; @@ -177,6 +186,7 @@ class NvsStorage { Setting input_mode_; Setting locked_input_mode_; Setting output_mode_; + Setting haptics_mode_; Setting theme_; diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp index 02a0058b..04a93fd9 100644 --- a/src/drivers/nvs.cpp +++ b/src/drivers/nvs.cpp @@ -35,6 +35,7 @@ static constexpr char kKeyAmpCurrentVolume[] = "hp_vol"; static constexpr char kKeyAmpLeftBias[] = "hp_bias"; static constexpr char kKeyPrimaryInput[] = "in_pri"; static constexpr char kKeyLockedInput[] = "in_locked"; +static constexpr char kKeyHaptics[] = "haptic_mode"; static constexpr char kKeyScrollSensitivity[] = "scroll"; static constexpr char kKeyLockPolarity[] = "lockpol"; static constexpr char kKeyDisplayCols[] = "dispcols"; @@ -275,6 +276,7 @@ NvsStorage::NvsStorage(nvs_handle_t handle) input_mode_(kKeyPrimaryInput), locked_input_mode_(kKeyLockedInput), output_mode_(kKeyOutput), + haptics_mode_(kKeyHaptics), theme_{kKeyInterfaceTheme}, bt_preferred_(kKeyBluetoothPreferred), bt_names_(kKeyBluetoothNames), @@ -304,6 +306,7 @@ auto NvsStorage::Read() -> void { input_mode_.read(handle_); locked_input_mode_.read(handle_); output_mode_.read(handle_); + haptics_mode_.read(handle_); theme_.read(handle_); bt_preferred_.read(handle_); bt_names_.read(handle_); @@ -328,6 +331,7 @@ auto NvsStorage::Write() -> bool { input_mode_.write(handle_); locked_input_mode_.write(handle_); output_mode_.write(handle_); + haptics_mode_.write(handle_); theme_.write(handle_); bt_preferred_.write(handle_); bt_names_.write(handle_); @@ -483,6 +487,31 @@ auto NvsStorage::OutputMode(Output out) -> void { nvs_commit(handle_); } +auto NvsStorage::HapticsMode() -> HapticsModes { + std::lock_guard lock{mutex_}; + int val = haptics_mode_.get().value_or(static_cast(HapticsModes::kMinimal)); + return intToHapticsMode(val); +} + +auto NvsStorage::intToHapticsMode(int raw) -> HapticsModes { + switch (raw) { + case static_cast(HapticsModes::kDisabled): + return HapticsModes::kDisabled; + case static_cast(HapticsModes::kMinimal): + return HapticsModes::kMinimal; + case static_cast(HapticsModes::kStrong): + return HapticsModes::kStrong; + default: + return HapticsModes::kStrong; + } +} + +auto NvsStorage::HapticsMode(HapticsModes mode) -> void { + std::lock_guard lock{mutex_}; + haptics_mode_.set(static_cast(mode)); +} + + auto NvsStorage::FastCharge() -> bool { std::lock_guard lock{mutex_}; return fast_charge_.get().value_or(true); diff --git a/src/tangara/input/device_factory.cpp b/src/tangara/input/device_factory.cpp index 22df4ebe..fe2e2485 100644 --- a/src/tangara/input/device_factory.cpp +++ b/src/tangara/input/device_factory.cpp @@ -56,7 +56,7 @@ auto DeviceFactory::createInputs(drivers::NvsStorage::InputModes mode) auto DeviceFactory::createFeedbacks() -> std::vector> { return { - std::make_shared(services_->haptics()), + std::make_shared(services_->haptics(), services_), std::make_shared(services_->tts()), }; } diff --git a/src/tangara/input/feedback_device.hpp b/src/tangara/input/feedback_device.hpp index 8253642f..31ad1fb1 100644 --- a/src/tangara/input/feedback_device.hpp +++ b/src/tangara/input/feedback_device.hpp @@ -8,6 +8,7 @@ #include #include "core/lv_group.h" +#include "input/input_events.hpp" namespace input { @@ -25,6 +26,7 @@ class IFeedbackDevice { virtual ~IFeedbackDevice() {} virtual auto feedback(lv_group_t* group, uint8_t event_type) -> void = 0; + virtual auto feedback(lv_group_t* group, InputEvent event) -> void = 0; // TODO: Add configuration; likely the same shape of interface that // IInputDevice uses. diff --git a/src/tangara/input/feedback_haptics.cpp b/src/tangara/input/feedback_haptics.cpp index a447a69d..fb203915 100644 --- a/src/tangara/input/feedback_haptics.cpp +++ b/src/tangara/input/feedback_haptics.cpp @@ -18,21 +18,64 @@ namespace input { using Effect = drivers::Haptics::Effect; -Haptics::Haptics(drivers::Haptics& haptics_) : haptics_(haptics_) {} +Haptics::Haptics(drivers::Haptics& haptics_, + std::shared_ptr services) + : haptics_(haptics_), services_(services) {} auto Haptics::feedback(lv_group_t* group, uint8_t event_type) -> void { lv_obj_t* obj = lv_group_get_focused(group); - if (obj == last_selection_) { + + auto haptics_mode = services_->nvs().HapticsMode(); + if (haptics_mode == drivers::NvsStorage::HapticsModes::kDisabled ) { return; } - last_selection_ = obj; switch (event_type) { case LV_EVENT_FOCUSED: - haptics_.PlayWaveformEffect(Effect::kMediumClick1_100Pct); + if (obj == last_selection_) { + return; + } + last_selection_ = obj; + if (haptics_mode == drivers::NvsStorage::HapticsModes::kMinimal) { + haptics_.PlayWaveformEffect(Effect::kStrongClick_30Pct); + } else { + haptics_.PlayWaveformEffect(Effect::kMediumClick1_100Pct); + } break; case LV_EVENT_CLICKED: - haptics_.PlayWaveformEffect(Effect::kSharpClick_100Pct); + if (haptics_mode == drivers::NvsStorage::HapticsModes::kMinimal) { + haptics_.PlayWaveformEffect(Effect::kSharpClick_30Pct); + } else { + haptics_.PlayWaveformEffect(Effect::kSharpClick_100Pct); + } + break; + default: + break; + } +} + +auto Haptics::feedback(lv_group_t* group, InputEvent event) -> void { + lv_obj_t* obj = lv_group_get_focused(group); + + auto haptics_mode = services_->nvs().HapticsMode(); + if (haptics_mode == drivers::NvsStorage::HapticsModes::kDisabled) { + return; + } + + switch (event) { + case InputEvent::kOnPress: + if (haptics_mode == drivers::NvsStorage::HapticsModes::kMinimal) { + haptics_.PlayWaveformEffect(Effect::kSoftBump_30Pct); + } else { + haptics_.PlayWaveformEffect(Effect::kSharpTick2_80Pct); + } + break; + case InputEvent::kOnLongPress: + if (haptics_mode == drivers::NvsStorage::HapticsModes::kMinimal) { + haptics_.PlayWaveformEffect(Effect::kShortDoubleClickStrong4_30Pct); + } else { + haptics_.PlayWaveformEffect(Effect::kShortDoubleSharpTick3_60Pct); + } break; default: break; diff --git a/src/tangara/input/feedback_haptics.hpp b/src/tangara/input/feedback_haptics.hpp index 91d7ec3a..90ed5ff2 100644 --- a/src/tangara/input/feedback_haptics.hpp +++ b/src/tangara/input/feedback_haptics.hpp @@ -12,17 +12,23 @@ #include "drivers/haptics.hpp" #include "input/feedback_device.hpp" +#include "input/input_events.hpp" +#include "drivers/nvs.hpp" +#include "system_fsm/service_locator.hpp" namespace input { class Haptics : public IFeedbackDevice { public: - Haptics(drivers::Haptics& haptics_); + Haptics(drivers::Haptics& haptics_, + std::shared_ptr services); auto feedback(lv_group_t*, uint8_t event_type) -> void override; + auto feedback(lv_group_t*, InputEvent event) -> void override; private: drivers::Haptics& haptics_; + std::shared_ptr services_; lv_obj_t* last_selection_; }; diff --git a/src/tangara/input/feedback_tts.cpp b/src/tangara/input/feedback_tts.cpp index e7e167c6..04c2830d 100644 --- a/src/tangara/input/feedback_tts.cpp +++ b/src/tangara/input/feedback_tts.cpp @@ -22,6 +22,7 @@ #include "tts/events.hpp" #include "tts/provider.hpp" +#include "feedback_tts.hpp" namespace input { @@ -50,6 +51,10 @@ auto TextToSpeech::feedback(lv_group_t* group, uint8_t event_type) -> void { } } +auto TextToSpeech::feedback(lv_group_t*, InputEvent event) -> void { + return; +} + auto TextToSpeech::describe(lv_obj_t& obj) -> void { if (lv_obj_check_type(&obj, &lv_button_class) || lv_obj_check_type(&obj, &lv_list_button_class)) { @@ -94,4 +99,5 @@ auto TextToSpeech::findDescription(lv_obj_t& obj) return {}; } + } // namespace input diff --git a/src/tangara/input/feedback_tts.hpp b/src/tangara/input/feedback_tts.hpp index ddd83ff0..00fbf06d 100644 --- a/src/tangara/input/feedback_tts.hpp +++ b/src/tangara/input/feedback_tts.hpp @@ -22,6 +22,7 @@ class TextToSpeech : public IFeedbackDevice { TextToSpeech(tts::Provider&); auto feedback(lv_group_t*, uint8_t event_type) -> void override; + auto feedback(lv_group_t*, InputEvent event) -> void override; private: tts::Provider& tts_; diff --git a/src/tangara/input/input_device.hpp b/src/tangara/input/input_device.hpp index 424c0da3..7b8d993d 100644 --- a/src/tangara/input/input_device.hpp +++ b/src/tangara/input/input_device.hpp @@ -12,6 +12,7 @@ #include "drivers/nvs.hpp" #include "indev/lv_indev.h" +#include "input/input_events.hpp" #include "input/input_hook.hpp" #include "lua/property.hpp" @@ -27,7 +28,7 @@ class IInputDevice { public: virtual ~IInputDevice() {} - virtual auto read(lv_indev_data_t* data) -> void = 0; + virtual auto read(lv_indev_data_t* data, std::vector& events) -> void = 0; virtual auto name() -> std::string = 0; virtual auto triggers() -> std::vector> { diff --git a/src/tangara/input/input_events.hpp b/src/tangara/input/input_events.hpp new file mode 100644 index 00000000..e9826c67 --- /dev/null +++ b/src/tangara/input/input_events.hpp @@ -0,0 +1,18 @@ + +/* + * Copyright 2025 ailurux + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +namespace input { + +enum class InputEvent { + kNone = 0, + kOnPress = 1, + kOnLongPress = 2, +}; + +} // namespace input \ No newline at end of file diff --git a/src/tangara/input/input_hard_reset.cpp b/src/tangara/input/input_hard_reset.cpp index 7fcca3eb..44de500c 100644 --- a/src/tangara/input/input_hard_reset.cpp +++ b/src/tangara/input/input_hard_reset.cpp @@ -14,7 +14,7 @@ namespace input { HardReset::HardReset(drivers::IGpios& gpios) : gpios_(gpios) {} -auto HardReset::read(lv_indev_data_t* data) -> void { +auto HardReset::read(lv_indev_data_t* data, std::vector& events) -> void { bool buttons_pressed = !gpios_.Get(drivers::IGpios::Pin::kKeyUp) && !gpios_.Get(drivers::IGpios::Pin::kKeyDown); if (!buttons_pressed) { diff --git a/src/tangara/input/input_hard_reset.hpp b/src/tangara/input/input_hard_reset.hpp index 00f218bf..93be56c5 100644 --- a/src/tangara/input/input_hard_reset.hpp +++ b/src/tangara/input/input_hard_reset.hpp @@ -20,7 +20,7 @@ class HardReset : public IInputDevice { public: HardReset(drivers::IGpios&); - auto read(lv_indev_data_t* data) -> void override; + auto read(lv_indev_data_t* data, std::vector& events) -> void override; auto name() -> std::string override; auto triggers() -> std::vector> override; diff --git a/src/tangara/input/input_hook.cpp b/src/tangara/input/input_hook.cpp index 0867bb39..9be1be7c 100644 --- a/src/tangara/input/input_hook.cpp +++ b/src/tangara/input/input_hook.cpp @@ -50,8 +50,9 @@ TriggerHooks::TriggerHooks(std::string name, long_press_("long_press", long_press), repeat_("repeat", repeat) {} -auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { - switch (trigger_.update(pressed)) { +auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> Trigger::State { + auto state = trigger_.update(pressed); + switch (state) { case Trigger::State::kClick: click_.invoke(d); break; @@ -68,6 +69,7 @@ auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { default: break; } + return state; } auto TriggerHooks::override(Trigger::State s, std::optional cb) diff --git a/src/tangara/input/input_hook.hpp b/src/tangara/input/input_hook.hpp index 94a35850..67122e1f 100644 --- a/src/tangara/input/input_hook.hpp +++ b/src/tangara/input/input_hook.hpp @@ -52,7 +52,7 @@ class TriggerHooks { std::optional long_press, std::optional repeat); - auto update(bool, lv_indev_data_t*) -> void; + auto update(bool, lv_indev_data_t*) -> Trigger::State; auto override(Trigger::State, std::optional) -> void; auto name() const -> const std::string&; diff --git a/src/tangara/input/input_nav_buttons.cpp b/src/tangara/input/input_nav_buttons.cpp index a5e10013..ede6b714 100644 --- a/src/tangara/input/input_nav_buttons.cpp +++ b/src/tangara/input/input_nav_buttons.cpp @@ -20,7 +20,7 @@ NavButtons::NavButtons(drivers::IGpios& gpios) down_("lower", {}, actions::scrollDown(), actions::select(), {}), locked_(false) {} -auto NavButtons::read(lv_indev_data_t* data) -> void { +auto NavButtons::read(lv_indev_data_t* data, std::vector& events) -> void { bool up = !gpios_.Get(drivers::IGpios::Pin::kKeyUp); bool down = !gpios_.Get(drivers::IGpios::Pin::kKeyDown); diff --git a/src/tangara/input/input_nav_buttons.hpp b/src/tangara/input/input_nav_buttons.hpp index c9575fe0..c28cce91 100644 --- a/src/tangara/input/input_nav_buttons.hpp +++ b/src/tangara/input/input_nav_buttons.hpp @@ -23,7 +23,7 @@ class NavButtons : public IInputDevice { public: NavButtons(drivers::IGpios&); - auto read(lv_indev_data_t* data) -> void override; + auto read(lv_indev_data_t* data, std::vector& events) -> void override; auto name() -> std::string override; auto triggers() -> std::vector> override; diff --git a/src/tangara/input/input_touch_dpad.cpp b/src/tangara/input/input_touch_dpad.cpp index 25c2315b..c866f37c 100644 --- a/src/tangara/input/input_touch_dpad.cpp +++ b/src/tangara/input/input_touch_dpad.cpp @@ -28,7 +28,7 @@ TouchDPad::TouchDPad(drivers::TouchWheel& wheel) left_("left", actions::goBack(), {}, {}, {}), locked_(false) {} -auto TouchDPad::read(lv_indev_data_t* data) -> void { +auto TouchDPad::read(lv_indev_data_t* data, std::vector& events) -> void { if (locked_) { return; } diff --git a/src/tangara/input/input_touch_dpad.hpp b/src/tangara/input/input_touch_dpad.hpp index 086f556e..82de26bf 100644 --- a/src/tangara/input/input_touch_dpad.hpp +++ b/src/tangara/input/input_touch_dpad.hpp @@ -22,7 +22,7 @@ class TouchDPad : public IInputDevice { public: TouchDPad(drivers::TouchWheel&); - auto read(lv_indev_data_t* data) -> void override; + auto read(lv_indev_data_t* data, std::vector& events) -> void override; auto name() -> std::string override; auto triggers() -> std::vector> override; diff --git a/src/tangara/input/input_touch_wheel.cpp b/src/tangara/input/input_touch_wheel.cpp index 1aee6fae..29153396 100644 --- a/src/tangara/input/input_touch_wheel.cpp +++ b/src/tangara/input/input_touch_wheel.cpp @@ -57,7 +57,7 @@ TouchWheel::TouchWheel(drivers::NvsStorage& nvs, drivers::TouchWheel& wheel) last_angle_(0), last_wheel_touch_time_(0) {} -auto TouchWheel::read(lv_indev_data_t* data) -> void { +auto TouchWheel::read(lv_indev_data_t* data, std::vector& events) -> void { if (locked_) { return; } @@ -88,9 +88,14 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void { bool wheel_touch_timed_out = esp_timer_get_time() - last_wheel_touch_time_ > SCROLL_TIMEOUT_US; - centre_.update(wheel_touch_timed_out && wheel_data.is_button_touched && + auto centre_state = centre_.update(wheel_touch_timed_out && wheel_data.is_button_touched && !wheel_data.is_wheel_touched, data); + if (centre_state == input::Trigger::State::kPress) { + events.push_back(InputEvent::kOnPress); + } else if (centre_state == input::Trigger::State::kLongPress) { + events.push_back(InputEvent::kOnLongPress); + } // If the user is touching the wheel but not scrolling, then they may be // clicking on one of the wheel's cardinal directions. diff --git a/src/tangara/input/input_touch_wheel.hpp b/src/tangara/input/input_touch_wheel.hpp index 420454b8..b2583e85 100644 --- a/src/tangara/input/input_touch_wheel.hpp +++ b/src/tangara/input/input_touch_wheel.hpp @@ -25,7 +25,7 @@ class TouchWheel : public IInputDevice { public: TouchWheel(drivers::NvsStorage&, drivers::TouchWheel&); - auto read(lv_indev_data_t* data) -> void override; + auto read(lv_indev_data_t* data, std::vector& events) -> void override; auto name() -> std::string override; auto triggers() -> std::vector> override; diff --git a/src/tangara/input/input_trigger.cpp b/src/tangara/input/input_trigger.cpp index eb67bcca..6c97f08c 100644 --- a/src/tangara/input/input_trigger.cpp +++ b/src/tangara/input/input_trigger.cpp @@ -44,7 +44,7 @@ auto Trigger::update(bool is_pressed) -> State { was_double_click_ = false; times_long_pressed_ = 0; was_pressed_ = true; - return State::kNone; + return State::kPress; } // The key was released. If there were no long-press events fired during the diff --git a/src/tangara/input/input_trigger.hpp b/src/tangara/input/input_trigger.hpp index 9f0b7e19..5bf8e13c 100644 --- a/src/tangara/input/input_trigger.hpp +++ b/src/tangara/input/input_trigger.hpp @@ -23,6 +23,7 @@ class Trigger { kDoubleClick, kLongPress, kRepeatPress, + kPress }; Trigger(); diff --git a/src/tangara/input/input_volume_buttons.cpp b/src/tangara/input/input_volume_buttons.cpp index 5c814ffa..ffeea18f 100644 --- a/src/tangara/input/input_volume_buttons.cpp +++ b/src/tangara/input/input_volume_buttons.cpp @@ -17,7 +17,7 @@ VolumeButtons::VolumeButtons(drivers::IGpios& gpios) down_("lower", actions::volumeDown()), locked_() {} -auto VolumeButtons::read(lv_indev_data_t* data) -> void { +auto VolumeButtons::read(lv_indev_data_t* data, std::vector& events) -> void { bool up = !gpios_.Get(drivers::IGpios::Pin::kKeyUp); bool down = !gpios_.Get(drivers::IGpios::Pin::kKeyDown); diff --git a/src/tangara/input/input_volume_buttons.hpp b/src/tangara/input/input_volume_buttons.hpp index 35a44390..17f60d7e 100644 --- a/src/tangara/input/input_volume_buttons.hpp +++ b/src/tangara/input/input_volume_buttons.hpp @@ -22,7 +22,7 @@ class VolumeButtons : public IInputDevice { public: VolumeButtons(drivers::IGpios&); - auto read(lv_indev_data_t* data) -> void override; + auto read(lv_indev_data_t* data, std::vector& events) -> void override; auto name() -> std::string override; auto triggers() -> std::vector> override; diff --git a/src/tangara/input/lvgl_input_driver.cpp b/src/tangara/input/lvgl_input_driver.cpp index 2859c6a8..03d5cbb7 100644 --- a/src/tangara/input/lvgl_input_driver.cpp +++ b/src/tangara/input/lvgl_input_driver.cpp @@ -112,6 +112,15 @@ LvglInputDriver::LvglInputDriver(drivers::NvsStorage& nvs, nvs.LockedInput(*mode); return true; }), + haptics_mode_(static_cast(nvs.HapticsMode()), + [&](const lua::LuaValue& val) { + if (!std::holds_alternative(val)) { + return false; + } + auto mode = drivers::NvsStorage::intToHapticsMode(std::get(val)); + nvs.HapticsMode(mode); + return true; + }), inputs_(factory.createInputs(nvs.PrimaryInput())), feedbacks_(factory.createFeedbacks()), is_locked_(false) { @@ -141,8 +150,14 @@ auto LvglInputDriver::setGroup(lv_group_t* g) -> void { } auto LvglInputDriver::read(lv_indev_data_t* data) -> void { + std::vector events; for (auto&& device : inputs_) { - device->read(data); + device->read(data, events); + } + for (auto event: events) { + for (auto&& device : feedbacks_) { + device->feedback(lv_indev_get_group(device_), event); + } } } diff --git a/src/tangara/input/lvgl_input_driver.hpp b/src/tangara/input/lvgl_input_driver.hpp index ce950621..629a0a78 100644 --- a/src/tangara/input/lvgl_input_driver.hpp +++ b/src/tangara/input/lvgl_input_driver.hpp @@ -37,6 +37,7 @@ class LvglInputDriver { auto mode() -> lua::Property& { return mode_; } auto lockedMode() -> lua::Property& { return locked_mode_; } + auto hapticsMode() -> lua::Property& { return haptics_mode_; } auto setGroup(lv_group_t*) -> void; auto read(lv_indev_data_t* data) -> void; @@ -51,6 +52,7 @@ class LvglInputDriver { lua::Property mode_; lua::Property locked_mode_; + lua::Property haptics_mode_; lv_indev_t* device_; std::vector> inputs_; diff --git a/src/tangara/lua/lua_controls.cpp b/src/tangara/lua/lua_controls.cpp index 87b7ca16..bc2588ac 100644 --- a/src/tangara/lua/lua_controls.cpp +++ b/src/tangara/lua/lua_controls.cpp @@ -58,8 +58,28 @@ static auto locked_controls_schemes(lua_State* L) -> int { return 1; } +static auto haptics_modes(lua_State* L) -> int { + lua_newtable(L); + + lua_pushliteral(L, "Disabled"); + lua_rawseti(L, -2, + static_cast(drivers::NvsStorage::HapticsModes::kDisabled)); + + lua_pushliteral(L, "Minimal"); + lua_rawseti( + L, -2, + static_cast(drivers::NvsStorage::HapticsModes::kMinimal)); + + lua_pushliteral(L, "Strong"); + lua_rawseti( + L, -2, static_cast(drivers::NvsStorage::HapticsModes::kStrong)); + + return 1; +} + static const struct luaL_Reg kControlsFuncs[] = {{"schemes", controls_schemes}, {"locked_schemes", locked_controls_schemes}, + {"haptics_modes", haptics_modes}, {NULL, NULL}}; static auto lua_controls(lua_State* state) -> int { diff --git a/src/tangara/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp index 1823f780..b974da53 100644 --- a/src/tangara/ui/ui_fsm.cpp +++ b/src/tangara/ui/ui_fsm.cpp @@ -668,6 +668,7 @@ void Lua::entry() { { {"scheme", &sInput->mode()}, {"locked_scheme", &sInput->lockedMode()}, + {"haptics_mode", &sInput->hapticsMode()}, {"lock_switch", &sLockSwitch}, {"hooks", [&](lua_State* L) { return sInput->pushHooks(L); }}, });