parent
db2e29a72d
commit
6fd588e970
@ -0,0 +1,44 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <cstdint> |
||||||
|
#include <functional> |
||||||
|
|
||||||
|
#include "esp_err.h" |
||||||
|
#include "result.hpp" |
||||||
|
|
||||||
|
#include "gpio_expander.hpp" |
||||||
|
#include "touchwheel.hpp" |
||||||
|
|
||||||
|
namespace drivers { |
||||||
|
|
||||||
|
class RelativeWheel { |
||||||
|
public: |
||||||
|
static auto Create(TouchWheel *touch) -> RelativeWheel* { return new RelativeWheel(touch); } |
||||||
|
|
||||||
|
explicit RelativeWheel(TouchWheel *touch); |
||||||
|
|
||||||
|
// Not copyable or movable.
|
||||||
|
RelativeWheel(const RelativeWheel&) = delete; |
||||||
|
RelativeWheel& operator=(const RelativeWheel&) = delete; |
||||||
|
|
||||||
|
auto Update() -> void; |
||||||
|
|
||||||
|
auto is_pressed() -> bool; |
||||||
|
auto ticks() -> std::int_fast16_t; |
||||||
|
|
||||||
|
private: |
||||||
|
TouchWheel *touch_; |
||||||
|
bool is_pressed_; |
||||||
|
bool is_first_read_; |
||||||
|
std::int_fast16_t ticks_; |
||||||
|
uint8_t last_angle_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace drivers
|
@ -0,0 +1,78 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "relative_wheel.hpp" |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "esp_log.h" |
||||||
|
|
||||||
|
namespace drivers { |
||||||
|
|
||||||
|
RelativeWheel::RelativeWheel(TouchWheel *touch)
|
||||||
|
:touch_(touch), |
||||||
|
is_pressed_(false), |
||||||
|
is_first_read_(true), |
||||||
|
ticks_(0), |
||||||
|
last_angle_(0) {} |
||||||
|
|
||||||
|
auto RelativeWheel::Update() -> void { |
||||||
|
touch_->Update(); |
||||||
|
TouchWheelData d = touch_->GetTouchWheelData(); |
||||||
|
is_pressed_ = d.is_touched; |
||||||
|
|
||||||
|
uint8_t new_angle = d.wheel_position; |
||||||
|
if (is_first_read_) { |
||||||
|
is_first_read_ = false; |
||||||
|
last_angle_ = new_angle; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Work out the magnitude of travel.
|
||||||
|
uint8_t change_cw = last_angle_ - new_angle; |
||||||
|
uint8_t change_ccw = new_angle - last_angle_; |
||||||
|
int change = std::min(change_cw, change_ccw); |
||||||
|
|
||||||
|
last_angle_ = new_angle; |
||||||
|
|
||||||
|
// Round to eliminate noise.
|
||||||
|
if (change <= 2) { |
||||||
|
ticks_ = 0; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Quantize into ticks.
|
||||||
|
change /= 4; |
||||||
|
|
||||||
|
// Clamp to reliminate more noise.
|
||||||
|
if (change > 10) { |
||||||
|
change = 0; |
||||||
|
} |
||||||
|
|
||||||
|
// Work out the direction of travel.
|
||||||
|
if (change_cw > change_ccw) { |
||||||
|
change *= -1; |
||||||
|
} |
||||||
|
|
||||||
|
ticks_ = change; |
||||||
|
} |
||||||
|
|
||||||
|
auto RelativeWheel::is_pressed() -> bool { |
||||||
|
return is_pressed_; |
||||||
|
} |
||||||
|
|
||||||
|
auto RelativeWheel::ticks() -> std::int_fast16_t { |
||||||
|
int_fast16_t t = ticks_; |
||||||
|
if (t != 0) { |
||||||
|
ESP_LOGI("teeks", "ticks %d", t); |
||||||
|
} |
||||||
|
ticks_ = 0; |
||||||
|
return t; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} // namespace drivers
|
@ -0,0 +1,28 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "core/lv_obj.h" |
||||||
|
#include "core/lv_obj_tree.h" |
||||||
|
#include "lvgl.h" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
|
||||||
|
class Screen { |
||||||
|
public: |
||||||
|
Screen() : root_(lv_obj_create(NULL)) {} |
||||||
|
virtual ~Screen() { lv_obj_del(root_); } |
||||||
|
|
||||||
|
auto root() -> lv_obj_t* { return root_; } |
||||||
|
|
||||||
|
protected: |
||||||
|
lv_obj_t* const root_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace ui
|
@ -0,0 +1,29 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "lvgl.h" |
||||||
|
|
||||||
|
#include "screen.hpp" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
namespace screens { |
||||||
|
|
||||||
|
class Menu : public Screen { |
||||||
|
public: |
||||||
|
Menu(); |
||||||
|
~Menu(); |
||||||
|
|
||||||
|
private: |
||||||
|
lv_obj_t* container_; |
||||||
|
lv_obj_t* label_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace screens
|
||||||
|
} // namespace ui
|
@ -0,0 +1,30 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "lvgl.h" |
||||||
|
|
||||||
|
#include "screen.hpp" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
namespace screens { |
||||||
|
|
||||||
|
class Splash : public Screen { |
||||||
|
public: |
||||||
|
Splash(); |
||||||
|
~Splash(); |
||||||
|
|
||||||
|
private: |
||||||
|
lv_obj_t* container_; |
||||||
|
lv_obj_t* label_; |
||||||
|
lv_obj_t* spinner_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace screens
|
||||||
|
} // namespace ui
|
@ -0,0 +1,11 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "esp_timer.h" |
||||||
|
|
||||||
|
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (esp_timer_get_time() / 1000) |
@ -0,0 +1,30 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "hal/lv_hal_indev.h" |
||||||
|
|
||||||
|
#include "relative_wheel.hpp" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
|
||||||
|
class TouchWheelEncoder { |
||||||
|
public: |
||||||
|
explicit TouchWheelEncoder(std::weak_ptr<drivers::RelativeWheel> wheel); |
||||||
|
|
||||||
|
auto Read(lv_indev_data_t *data) -> void; |
||||||
|
auto registration() -> lv_indev_t* { return registration_; } |
||||||
|
|
||||||
|
private: |
||||||
|
lv_indev_drv_t driver_; |
||||||
|
lv_indev_t *registration_; |
||||||
|
std::weak_ptr<drivers::RelativeWheel> wheel_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace ui
|
@ -0,0 +1,52 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "screen_menu.hpp" |
||||||
|
|
||||||
|
#include "core/lv_group.h" |
||||||
|
#include "core/lv_obj_pos.h" |
||||||
|
#include "extra/widgets/menu/lv_menu.h" |
||||||
|
#include "extra/widgets/spinner/lv_spinner.h" |
||||||
|
#include "hal/lv_hal_disp.h" |
||||||
|
#include "misc/lv_area.h" |
||||||
|
#include "widgets/lv_label.h" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
namespace screens { |
||||||
|
|
||||||
|
Menu::Menu() { |
||||||
|
lv_obj_t *menu = lv_menu_create(root_); |
||||||
|
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL)); |
||||||
|
lv_obj_center(menu); |
||||||
|
|
||||||
|
lv_obj_t *main_page = lv_menu_page_create(menu, NULL); |
||||||
|
|
||||||
|
lv_obj_t *container; |
||||||
|
lv_obj_t *label; |
||||||
|
|
||||||
|
container = lv_menu_cont_create(main_page); |
||||||
|
label = lv_label_create(container); |
||||||
|
lv_label_set_text(label, "I am an item"); |
||||||
|
|
||||||
|
container = lv_menu_cont_create(main_page); |
||||||
|
label = lv_label_create(container); |
||||||
|
lv_label_set_text(label, "I am also an item"); |
||||||
|
|
||||||
|
container = lv_menu_cont_create(main_page); |
||||||
|
label = lv_label_create(container); |
||||||
|
lv_label_set_text(label, "Item #3"); |
||||||
|
|
||||||
|
container = lv_menu_cont_create(main_page); |
||||||
|
label = lv_label_create(container); |
||||||
|
lv_label_set_text(label, "Yay!"); |
||||||
|
|
||||||
|
lv_menu_set_page(menu, main_page); |
||||||
|
} |
||||||
|
|
||||||
|
Menu::~Menu() {} |
||||||
|
|
||||||
|
} // namespace screens
|
||||||
|
} // namespace ui
|
@ -0,0 +1,38 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "screen_splash.hpp" |
||||||
|
|
||||||
|
#include "core/lv_obj_pos.h" |
||||||
|
#include "extra/widgets/spinner/lv_spinner.h" |
||||||
|
#include "misc/lv_area.h" |
||||||
|
#include "widgets/lv_label.h" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
namespace screens { |
||||||
|
|
||||||
|
Splash::Splash() { |
||||||
|
container_ = lv_obj_create(root_); |
||||||
|
lv_obj_set_align(container_, LV_ALIGN_CENTER); |
||||||
|
lv_obj_set_size(container_, LV_SIZE_CONTENT, LV_SIZE_CONTENT); |
||||||
|
|
||||||
|
label_ = lv_label_create(container_); |
||||||
|
lv_label_set_text_static(label_, "TANGARA"); |
||||||
|
lv_obj_set_align(label_, LV_ALIGN_TOP_MID); |
||||||
|
|
||||||
|
spinner_ = lv_spinner_create(container_, 1000, 60); |
||||||
|
lv_obj_set_size(spinner_, 32, 32); |
||||||
|
lv_obj_align_to(spinner_, label_, LV_ALIGN_OUT_BOTTOM_MID, 0, 8); |
||||||
|
} |
||||||
|
|
||||||
|
Splash::~Splash() { |
||||||
|
lv_obj_del(spinner_); |
||||||
|
lv_obj_del(label_); |
||||||
|
lv_obj_del(container_); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace screens
|
||||||
|
} // namespace ui
|
@ -0,0 +1,39 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-3.0-only |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "wheel_encoder.hpp" |
||||||
|
#include "hal/lv_hal_indev.h" |
||||||
|
|
||||||
|
namespace ui { |
||||||
|
|
||||||
|
void encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){ |
||||||
|
TouchWheelEncoder *instance = reinterpret_cast<TouchWheelEncoder*>(drv->user_data); |
||||||
|
instance->Read(data); |
||||||
|
} |
||||||
|
|
||||||
|
TouchWheelEncoder::TouchWheelEncoder(std::weak_ptr<drivers::RelativeWheel> wheel) : wheel_(wheel) { |
||||||
|
lv_indev_drv_init(&driver_); |
||||||
|
driver_.type = LV_INDEV_TYPE_ENCODER; |
||||||
|
driver_.read_cb = encoder_read; |
||||||
|
driver_.user_data = this; |
||||||
|
|
||||||
|
registration_ = lv_indev_drv_register(&driver_); |
||||||
|
} |
||||||
|
|
||||||
|
auto TouchWheelEncoder::Read(lv_indev_data_t *data) -> void { |
||||||
|
auto lock = wheel_.lock(); |
||||||
|
if (lock == nullptr) { |
||||||
|
data->state = LV_INDEV_STATE_RELEASED; |
||||||
|
data->enc_diff = 0; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
lock->Update(); |
||||||
|
data->state = lock->is_pressed() ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; |
||||||
|
data->enc_diff = lock->ticks(); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace ui
|
Loading…
Reference in new issue