diff options
| author | Michele Bini <michele.bini@gmail.com> | 2022-04-10 13:50:02 (GMT) |
|---|---|---|
| committer | Michele Bini <michele.bini@gmail.com> | 2022-04-10 14:07:49 (GMT) |
| commit | 34a6369f793bb36a3f66eba87535159819c65f2b (patch) | |
| tree | 65e206128ee042de8372d915966c8981246be9fb | |
| parent | 4d8a0d3300345b71dcbd7e86d1e7c4cfcc3cf200 (diff) | |
Add jumpscore app
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/displayapp/Apps.h | 1 | ||||
| -rw-r--r-- | src/displayapp/DisplayApp.cpp | 4 | ||||
| -rw-r--r-- | src/displayapp/screens/ApplicationList.cpp | 43 | ||||
| -rw-r--r-- | src/displayapp/screens/ApplicationList.h | 4 | ||||
| -rw-r--r-- | src/displayapp/screens/Jumpscore.cpp | 201 | ||||
| -rw-r--r-- | src/displayapp/screens/Jumpscore.h | 69 | ||||
| -rw-r--r-- | src/systemtask/SystemTask.h | 14 |
8 files changed, 313 insertions, 25 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e33a9bc..86460c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -420,6 +420,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Navigation.cpp displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp + displayapp/screens/Jumpscore.cpp displayapp/screens/FirmwareValidation.cpp displayapp/screens/ApplicationList.cpp displayapp/screens/Notifications.cpp @@ -643,6 +644,7 @@ set(INCLUDE_FILES displayapp/screens/Metronome.h displayapp/screens/Motion.h displayapp/screens/Timer.h + displayapp/screens/Jumpscore.h displayapp/screens/Alarm.h displayapp/Colors.h drivers/St7789.h diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 8aad953..4f9fdcc 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -24,6 +24,7 @@ namespace Pinetime { StopWatch, Metronome, Motion, + Jumpscore, Steps, Weather, PassKey, diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 990e469..9c0af35 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -1,6 +1,7 @@ #include "displayapp/DisplayApp.h" #include <libraries/log/nrf_log.h> #include "displayapp/screens/HeartRate.h" +#include "displayapp/screens/Jumpscore.h" #include "displayapp/screens/Motion.h" #include "displayapp/screens/Timer.h" #include "displayapp/screens/Alarm.h" @@ -483,6 +484,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Motion: currentScreen = std::make_unique<Screens::Motion>(this, motionController); break; + case Apps::Jumpscore: + currentScreen = std::make_unique<Screens::Jumpscore>(this, *systemTask, motionController, motorController); + break; case Apps::Steps: currentScreen = std::make_unique<Screens::Steps>(this, motionController, settingsController); break; diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp index 29c8aff..e2b5322 100644 --- a/src/displayapp/screens/ApplicationList.cpp +++ b/src/displayapp/screens/ApplicationList.cpp @@ -19,13 +19,9 @@ ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app, screens {app, settingsController.GetAppMenu(), { - [this]() -> std::unique_ptr<Screen> { - return CreateScreen1(); - }, - [this]() -> std::unique_ptr<Screen> { - return CreateScreen2(); - }, - //[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); } + [this]() -> std::unique_ptr<Screen> { return CreateScreen1(); }, + [this]() -> std::unique_ptr<Screen> { return CreateScreen2(); }, + [this]() -> std::unique_ptr<Screen> { return CreateScreen3(); } }, Screens::ScreenListModes::UpDown} { } @@ -40,40 +36,41 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) { std::unique_ptr<Screen> ApplicationList::CreateScreen1() { std::array<Screens::Tile::Applications, 6> applications {{ - {Symbols::stopWatch, Apps::StopWatch}, {Symbols::music, Apps::Music}, - {Symbols::map, Apps::Navigation}, {Symbols::shoe, Apps::Steps}, + {Symbols::stopWatch, Apps::StopWatch}, {Symbols::heartBeat, Apps::HeartRate}, {Symbols::hourGlass, Apps::Timer}, + {Symbols::clock, Apps::Alarm}, }}; - return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications); + return std::make_unique<Screens::Tile>(0, 3, app, settingsController, batteryController, dateTimeController, applications); } std::unique_ptr<Screen> ApplicationList::CreateScreen2() { std::array<Screens::Tile::Applications, 6> applications {{ + {Symbols::drum, Apps::Jumpscore}, + {Symbols::map, Apps::Navigation}, + {Symbols::drum, Apps::Metronome}, {Symbols::paintbrush, Apps::Paint}, {Symbols::paddle, Apps::Paddle}, {"2", Apps::Twos}, - {Symbols::chartLine, Apps::Motion}, - {Symbols::drum, Apps::Metronome}, - {Symbols::clock, Apps::Alarm}, }}; - return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications); + return std::make_unique<Screens::Tile>(1, 3, app, settingsController, batteryController, dateTimeController, applications); } -/*std::unique_ptr<Screen> ApplicationList::CreateScreen3() { +std::unique_ptr<Screen> ApplicationList::CreateScreen3() { std::array<Screens::Tile::Applications, 6> applications { - {{"A", Apps::Meter}, - {"B", Apps::Navigation}, - {"C", Apps::Clock}, - {"D", Apps::Music}, - {"E", Apps::SysInfo}, - {"F", Apps::Brightness} - } + {Symbols::chartLine, Apps::Motion}, + // {{"A", Apps::Meter}, + // {"B", Apps::Navigation}, + // {"C", Apps::Clock}, + // {"D", Apps::Music}, + // {"E", Apps::SysInfo}, + // {"F", Apps::Brightness} + // } }; return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications); -}*/ +} diff --git a/src/displayapp/screens/ApplicationList.h b/src/displayapp/screens/ApplicationList.h index f430a89..27ebbac 100644 --- a/src/displayapp/screens/ApplicationList.h +++ b/src/displayapp/screens/ApplicationList.h @@ -25,10 +25,10 @@ namespace Pinetime { Pinetime::Controllers::Battery& batteryController; Controllers::DateTime& dateTimeController; - ScreenList<2> screens; + ScreenList<3> screens; std::unique_ptr<Screen> CreateScreen1(); std::unique_ptr<Screen> CreateScreen2(); - // std::unique_ptr<Screen> CreateScreen3(); + std::unique_ptr<Screen> CreateScreen3(); }; } } diff --git a/src/displayapp/screens/Jumpscore.cpp b/src/displayapp/screens/Jumpscore.cpp new file mode 100644 index 0000000..3ec6bcb --- /dev/null +++ b/src/displayapp/screens/Jumpscore.cpp @@ -0,0 +1,201 @@ +#include "displayapp/screens/Jumpscore.h" +#include <lvgl/lvgl.h> +#include "displayapp/DisplayApp.h" + +// #if (portTICK_PERIOD_MS == 0) +#define APX_TICK_PERIOD_MS 1 +// #else +// #define APX_TICK_PERIOD_MS portTICK_PERIOD_MS +// #endif + +#if configTICK_RATE_HZ == 1024 +#define FRAME_HZ 100 +#define FRAME_MS 10 +#define FRAME_TICKS 10 +#define REDRAW_FRAME_HZ 40 +#define REDRAW_FRAME_MS (1024 / REDRAW_FRAME_HZ) +#define REDRAW_FRAME_TICKS REDRAW_FRAME_MS +#else +#error "Unsupported configTICK_RATE_HZ" +#endif +#define G_SCALE 0.001 + +using namespace Pinetime::Applications::Screens; + +Jumpscore::Jumpscore(Pinetime::Applications::DisplayApp* app, System::SystemTask& systemTask, Controllers::MotionController& motionController, Controllers::MotorController& motorController) + : Screen(app), motionController {motionController}, motorController {motorController}, systemTask {systemTask} { + + bar = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(bar, 8, 200); + lv_obj_align(bar, nullptr, LV_ALIGN_IN_RIGHT_MID, -20, 0); + lv_obj_set_style_local_radius(bar, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_style_local_bg_color(bar, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + +#ifdef JUMPSCORE_ICON + icon = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(icon, 20, 20); + lv_obj_align(icon, bar, LV_ALIGN_OUT_RIGHT_BOTTOM, 0, -200); + lv_obj_set_style_local_radius(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_style_local_bg_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); +#endif + + systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); +#ifndef JUMPSCORE_NO_CHART + chart = lv_chart_create(lv_scr_act(), NULL); + lv_obj_set_size(chart, 100, 100); + lv_obj_align(chart, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/ + // lv_chart_set_series_opa(chart, LV_OPA_70); /*Opacity of the data series*/ + // lv_chart_set_series_width(chart, 4); /*Line width and point radious*/ + + lv_chart_set_range(chart, 0, 1000); + lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT); + lv_chart_set_point_count(chart, 6); + + /*Add 3 data series*/ + ser1 = lv_chart_add_series(chart, LV_COLOR_RED); + + lv_chart_init_points(chart, ser1, 0); + lv_chart_refresh(chart); /*Required after direct set*/ +#endif + + label = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text_static(label, labelText); + // lv_label_set_text_fmt(label, "X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#", 0, 0, 0); + // lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + // lv_label_set_recolor(label, true); + + lastLabel = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text_static(lastLabel, "?.???"); + lv_obj_align(lastLabel, bar, LV_ALIGN_OUT_BOTTOM_RIGHT, -8, 0); + + recordLabel = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text_static(recordLabel, "?.???"); + lv_obj_align(recordLabel, bar, LV_ALIGN_OUT_LEFT_BOTTOM, 0, -200); + +#ifdef DEBUG_JUMPSCORE_APP + infoLabel = lv_label_create(lv_scr_act(), NULL); + lv_label_set_text_static(recordLabel, "???? ???"); + lv_obj_align(infoLabel, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); +#endif + + taskRefresh = lv_task_create(RefreshTaskCallback, FRAME_MS, LV_TASK_PRIO_MID, this); +} + +Jumpscore::~Jumpscore() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); + systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); +} + +void Jumpscore::Refresh() { + double X; double Y; double_t Z; + double G = systemTask.ReadGXYZ(X,Y,Z); + TickType_t current_time = xTaskGetTickCount(); + if (started) { + TickType_t current_frame_ms = current_time - last_frame_time; +#ifdef DEBUG_JUMPSCORE_APP + frame_count++; + total_frames_ms += current_frame_ms; + if (current_frame_ms > max_frame_ms) { + max_frame_ms = current_frame_ms; + } + if (frame_count % 300 == 0) { + avg_frame_ms = total_frames_ms/300; + lv_label_set_text_fmt(infoLabel, "%dM %dA", max_frame_ms, avg_frame_ms); + total_frames_ms = 0; + max_frame_ms = 0; + } +#endif + double G_scaled = G * G_SCALE; + if (G_scaled < 1.000) { + if (!jumping) { + current_jump_speed = 0; + current_jump_length = 0; + jumping = true; + color = LV_COLOR_CYAN; + } + double jump_ratio = 1.0 - G_scaled; + double current_jump_accel = jump_ratio * 9.8; + double current_frame_s = current_frame_ms * 0.001; + current_jump_speed += current_jump_accel * current_frame_s; + current_jump_length += current_jump_speed * current_frame_s * jump_ratio; + } else { + if (jumping) { + if (current_jump_length * 100 > best_jump_length) { + last_jump_length = current_jump_length; + if (current_jump_length >= best_jump_length) { + records[4] = records[3]; + records[3] = records[2]; + records[2] = records[1]; + records[1] = records[0]; + records[0].jump_length = best_jump_length = current_jump_length; + new_record = 1; + } + } + jumping = false; + color = LV_COLOR_ORANGE; + } + } + } + last_frame_time = current_time; + if (started) { + if (((TickType_t)(current_time - last_redraw_frame_time)) < REDRAW_FRAME_TICKS) { + return; + } + } else { + started = true; + } + last_redraw_frame_time = current_time; + uint16_t G_uint16 = G < 0xffff ? G : 0xffff; +#ifdef JUMPSCORE_ICON + lv_obj_set_style_local_bg_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color); + if (G_uint16 < 1000) { + lv_obj_set_size(icon, 20, 21 - G_uint16 / 50); + lv_obj_align(icon, bar, LV_ALIGN_OUT_RIGHT_BOTTOM, 0, + best_jump_length > 0 ? + current_jump_length > best_jump_length ? + -200 : -200*(current_jump_length / best_jump_length) + : 0 + ); + } else { + lv_obj_set_size(icon, 20, G_uint16 / 50 - 19); + lv_obj_align(icon, bar, LV_ALIGN_OUT_RIGHT_TOP, 0, 200); + } +#endif +#ifndef JUMPSCORE_NO_CHART + lv_chart_set_next(chart, ser1, 1000 - ((int16_t)G_uint16)); +#endif + labelText[4] = '0'+(G_uint16%10); G_uint16 /= 10; + labelText[3] = '0'+(G_uint16%10); G_uint16 /= 10; + labelText[2] = '0'+(G_uint16%10); G_uint16 /= 10; + labelText[1] = '0'+(G_uint16%10); G_uint16 /= 10; + labelText[0] = '0'+G_uint16; + lv_label_set_text_static(label, labelText); + if (new_record) { + uint32_t a = (best_jump_length*100000.0); + lv_label_set_text_fmt(recordLabel, "%d.%03d", a/1000, a%1000); + if (best_jump_length > 0.01) { + motorController.RunForDuration(35); + } + } + if (last_jump_length > 0) { + uint32_t a = (last_jump_length*100000.0); + lv_label_set_text_fmt(lastLabel, "%d.%03d", a/1000, a%1000); + if (!new_record && last_jump_length > 0.05) { + motorController.RunForDuration(14); + } + last_jump_length = 0; + } + new_record = false; + lv_obj_set_style_local_text_color(lastLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color); +#if 0 + lv_label_set_text_fmt(label, + "X #FF0000 %d# Y #008000 %d# Z #FFFF00 %d#", + motionController.X() / 0x10, + motionController.Y() / 0x10, + motionController.Z() / 0x10); + lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); +#endif +} diff --git a/src/displayapp/screens/Jumpscore.h b/src/displayapp/screens/Jumpscore.h new file mode 100644 index 0000000..0785254 --- /dev/null +++ b/src/displayapp/screens/Jumpscore.h @@ -0,0 +1,69 @@ +#pragma once + +#include <cstdint> +#include <chrono> +#include "systemtask/SystemTask.h" +#include "displayapp/screens/Screen.h" +#include <lvgl/src/lv_core/lv_style.h> +#include <lvgl/src/lv_core/lv_obj.h> +#include <components/motor/MotorController.h> +#include <components/motion/MotionController.h> + +#define DEBUG_JUMPSCORE_APP 1 +#define JUMPSCORE_NO_CHART 1 +#define JUMPSCORE_ICON 1 + +namespace Pinetime { + namespace Applications { + namespace Screens { + + class Jumpscore : public Screen { + public: + Jumpscore(DisplayApp* app, System::SystemTask& systemTask, Controllers::MotionController& motionController, Controllers::MotorController& motorController); + ~Jumpscore() override; + + void Refresh() override; + + private: + Controllers::MotionController& motionController; + Controllers::MotorController& motorController; + System::SystemTask& systemTask; + // bool calibrating = true; + bool started = false; + bool jumping = false; + bool new_record = true; + TickType_t last_frame_time = 0; + TickType_t last_redraw_frame_time = 0; + // uint8_t dropped_frames = 0; + double last_jump_length = 0; + double best_jump_length = 0; // Best jump length in this session + lv_color_t color; + double current_jump_length; + double current_jump_speed; + struct Record { + double jump_length; + }; + Record records[5] = { {-1}, {-1}, {-1}, {-1}, {-1} }; + char labelText[6] = { '0', '0', '0', '0', '0', 0 }; +#ifndef JUMPSCORE_NO_CHART + lv_obj_t* chart; + lv_chart_series_t* ser1; +#endif + lv_obj_t* icon; + lv_obj_t* bar; + lv_obj_t* label; + lv_obj_t* recordLabel; + lv_obj_t* lastLabel; + + lv_task_t* taskRefresh; +#ifdef DEBUG_JUMPSCORE_APP + lv_obj_t* infoLabel; + int32_t frame_count = 0; + int32_t max_frame_ms = 0; + int32_t avg_frame_ms = 0; + int32_t total_frames_ms = 0; +#endif + }; + } + } +} diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 5ce8a8e..f141b01 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -151,6 +151,20 @@ namespace Pinetime { static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000); SystemMonitor monitor; + + public: + inline double ReadGXYZ(double &X, double &Y, double &Z) const { + auto motionValues = motionSensor.Process(); + // motionController.Update(motionValues.x, motionValues.y, motionValues.z); + X = motionValues.x; Y = motionValues.y; Z = motionValues.z; + return std::sqrt(X*X + Y*Y + Z*Z); + } + + inline double ReadG() const { + double x, y, z; + return ReadGXYZ(x,y,z); + } + }; } } |
