summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Bini <michele.bini@gmail.com>2022-04-10 13:50:02 (GMT)
committerMichele Bini <michele.bini@gmail.com>2022-04-10 14:07:49 (GMT)
commit34a6369f793bb36a3f66eba87535159819c65f2b (patch)
tree65e206128ee042de8372d915966c8981246be9fb
parent4d8a0d3300345b71dcbd7e86d1e7c4cfcc3cf200 (diff)
Add jumpscore app
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/displayapp/Apps.h1
-rw-r--r--src/displayapp/DisplayApp.cpp4
-rw-r--r--src/displayapp/screens/ApplicationList.cpp43
-rw-r--r--src/displayapp/screens/ApplicationList.h4
-rw-r--r--src/displayapp/screens/Jumpscore.cpp201
-rw-r--r--src/displayapp/screens/Jumpscore.h69
-rw-r--r--src/systemtask/SystemTask.h14
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);
+ }
+
};
}
}