Merge branch 'motion-sensor' into develop

This commit is contained in:
Jean-François Milants 2021-04-09 21:17:03 +02:00
commit eb769fb60e
33 changed files with 12471 additions and 255 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(pinetime VERSION 0.15.0 LANGUAGES C CXX ASM)
project(pinetime VERSION 0.16.0 LANGUAGES C CXX ASM)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)

View File

@ -34,6 +34,9 @@ As of now, here is the list of achievements of this project:
- Rich user interface via display, touchscreen and pushbutton
- Time synchronization via BLE
- Notification via BLE
- Heart rate measurements
- Step counting
- Wake-up on wrist rotation
- Multiple 'apps' :
* Clock (displays the date, time, battery level, ble connection status, heart rate)
* System info (displays various info : BLE MAC, build date/time, uptime, version,...)

View File

@ -83,7 +83,7 @@ set(SDK_SOURCE_FILES
"${NRF5_SDK_PATH}/external/fprintf/nrf_fprintf_format.c"
# TWI
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_twi.c"
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_twim.c"
# GPIOTE
"${NRF5_SDK_PATH}/components/libraries/gpiote/app_gpiote.c"
@ -396,11 +396,13 @@ list(APPEND SOURCE_FILES
displayapp/screens/FirmwareUpdate.cpp
displayapp/screens/Music.cpp
displayapp/screens/Navigation.cpp
displayapp/screens/Motion.cpp
displayapp/screens/FirmwareValidation.cpp
displayapp/screens/ApplicationList.cpp
displayapp/screens/Notifications.cpp
displayapp/screens/Twos.cpp
displayapp/screens/HeartRate.cpp
displayapp/screens/Motion.cpp
displayapp/screens/FlashLight.cpp
displayapp/screens/List.cpp
displayapp/screens/BatteryInfo.cpp
@ -429,11 +431,15 @@ list(APPEND SOURCE_FILES
drivers/DebugPins.cpp
drivers/InternalFlash.cpp
drivers/Hrs3300.cpp
drivers/Bma421.cpp
drivers/Bma421_C/bma4.c
drivers/Bma421_C/bma423.c
components/battery/BatteryController.cpp
components/ble/BleController.cpp
components/ble/NotificationManager.cpp
components/datetime/DateTimeController.cpp
components/brightness/BrightnessController.cpp
components/motion/MotionController.cpp
components/ble/NimbleController.cpp
components/ble/DeviceInformationService.cpp
components/ble/CurrentTimeClient.cpp
@ -487,11 +493,15 @@ list(APPEND RECOVERY_SOURCE_FILES
drivers/DebugPins.cpp
drivers/InternalFlash.cpp
drivers/Hrs3300.cpp
drivers/Bma421.cpp
drivers/Bma421_C/bma4.c
drivers/Bma421_C/bma423.c
components/battery/BatteryController.cpp
components/ble/BleController.cpp
components/ble/NotificationManager.cpp
components/datetime/DateTimeController.cpp
components/brightness/BrightnessController.cpp
components/motion/MotionController.cpp
components/ble/NimbleController.cpp
components/ble/DeviceInformationService.cpp
components/ble/CurrentTimeClient.cpp
@ -576,6 +586,7 @@ set(INCLUDE_FILES
displayapp/Apps.h
displayapp/screens/Notifications.h
displayapp/screens/HeartRate.h
displayapp/screens/Motion.h
drivers/St7789.h
drivers/SpiNorFlash.h
drivers/SpiMaster.h
@ -584,11 +595,15 @@ set(INCLUDE_FILES
drivers/DebugPins.h
drivers/InternalFlash.h
drivers/Hrs3300.h
drivers/Bma421.h
drivers/Bma421_C/bma4.c
drivers/Bma421_C/bma423.c
components/battery/BatteryController.h
components/ble/BleController.h
components/ble/NotificationManager.h
components/datetime/DateTimeController.h
components/brightness/BrightnessController.h
components/motion/MotionController.h
components/ble/NimbleController.h
components/ble/DeviceInformationService.h
components/ble/CurrentTimeClient.h

View File

@ -1,9 +1,14 @@
#include "DateTimeController.h"
#include <date/date.h>
#include <libraries/log/nrf_log.h>
#include <systemtask/SystemTask.h>
using namespace Pinetime::Controllers;
DateTime::DateTime(System::SystemTask& systemTask) : systemTask{systemTask} {
}
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute,
uint8_t second, uint32_t systickCounter) {
@ -62,6 +67,14 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
hour = time.hours().count();
minute = time.minutes().count();
second = time.seconds().count();
// Notify new day to SystemTask
if(hour == 0 and not isMidnightAlreadyNotified) {
isMidnightAlreadyNotified = true;
systemTask.PushMessage(System::SystemTask::Messages::OnNewDay);
} else if (hour != 0) {
isMidnightAlreadyNotified = false;
}
}
const char *DateTime::MonthShortToString() {

View File

@ -4,12 +4,17 @@
#include <chrono>
namespace Pinetime {
namespace System {
class SystemTask;
}
namespace Controllers {
class DateTime {
public:
enum class Days : uint8_t {Unknown, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
enum class Months : uint8_t {Unknown, January, February, March, April, May, June, July, August, September, October, November, December};
DateTime(System::SystemTask& systemTask);
void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t dayOfWeek, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter);
void UpdateTime(uint32_t systickCounter);
uint16_t Year() const { return year; }
@ -31,6 +36,7 @@ namespace Pinetime {
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; }
std::chrono::seconds Uptime() const { return uptime; }
private:
System::SystemTask& systemTask;
uint16_t year = 0;
Months month = Months::Unknown;
uint8_t day = 0;
@ -43,6 +49,8 @@ namespace Pinetime {
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
std::chrono::seconds uptime {0};
bool isMidnightAlreadyNotified = false;
static char const *DaysString[];
static char const *DaysStringShort[];
static char const *DaysStringLow[];

View File

@ -0,0 +1,36 @@
#include "MotionController.h"
using namespace Pinetime::Controllers;
void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) {
this->x = x;
this->y = y;
this->z = z;
this->nbSteps = nbSteps;
}
bool MotionController::ShouldWakeUp(bool isSleeping) {
if ((x + 335) <= 670 && z < 0) {
if (not isSleeping) {
if (y <= 0) {
return false;
} else {
lastYForWakeUp = 0;
return false;
}
}
if (y >= 0) {
lastYForWakeUp = 0;
return false;
}
if (y + 230 < lastYForWakeUp) {
lastYForWakeUp = y;
return true;
}
}
return false;
}
void MotionController::IsSensorOk(bool isOk) {
isSensorOk = isOk;
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <cstdint>
namespace Pinetime {
namespace Controllers {
class MotionController {
public:
void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps);
uint16_t X() const { return x; }
uint16_t Y() const { return y; }
uint16_t Z() const { return z; }
uint32_t NbSteps() const { return nbSteps; }
bool ShouldWakeUp(bool isSleeping);
void IsSensorOk(bool isOk);
bool IsSensorOk() const { return isSensorOk; }
private:
uint32_t nbSteps;
int16_t x;
int16_t y;
int16_t z;
int16_t lastYForWakeUp = 0;
bool isSensorOk = false;
};
}
}

View File

@ -2,9 +2,9 @@
namespace Pinetime {
namespace Applications {
enum class Apps {
enum class Apps {
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo,
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch,
Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion,
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp
};
}

View File

@ -1,10 +1,12 @@
#include "DisplayApp.h"
#include <libraries/log/nrf_log.h>
#include <displayapp/screens/HeartRate.h>
#include <displayapp/screens/Motion.h>
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/NotificationManager.h"
#include "components/motion/MotionController.h"
#include "displayapp/screens/ApplicationList.h"
#include "displayapp/screens/Brightness.h"
#include "displayapp/screens/Clock.h"
@ -43,7 +45,8 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController) :
Controllers::Settings &settingsController,
Pinetime::Controllers::MotionController& motionController) :
lcd{lcd},
lvgl{lvgl},
touchPanel{touchPanel},
@ -54,7 +57,8 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
systemTask{systemTask},
notificationManager{notificationManager},
heartRateController{heartRateController},
settingsController{settingsController} {
settingsController{settingsController},
motionController{motionController} {
msgQueue = xQueueCreate(queueSize, itemSize);
// Start clock when smartwatch boots
LoadApp( Apps::Clock, DisplayApp::FullRefreshDirections::None );
@ -174,7 +178,7 @@ void DisplayApp::Refresh() {
break;
case Messages::UpdateDateTime:
// Added to remove warning
// What should happen here?
// What should happen here?
break;
}
}
@ -220,7 +224,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break;
case Apps::None:
case Apps::Clock:
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController);
currentScreen = std::make_unique<Screens::Clock>(this, dateTimeController, batteryController, bleController, notificationManager, settingsController, heartRateController, motionController);
break;
case Apps::FirmwareValidation:
@ -232,7 +236,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
break;
case Apps::Notifications:
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
currentScreen = std::make_unique<Screens::Notifications>(this, notificationManager, systemTask.nimble().alertService(), Screens::Notifications::Modes::Normal);
returnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
break;
case Apps::NotificationsPreview:
@ -245,37 +249,37 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentScreen = std::make_unique<Screens::QuickSettings>(this, batteryController, dateTimeController, brightnessController, settingsController);
returnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
break;
case Apps::Settings:
case Apps::Settings:
currentScreen = std::make_unique<Screens::Settings>(this, settingsController);
returnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SettingWatchFace:
case Apps::SettingWatchFace:
currentScreen = std::make_unique<Screens::SettingWatchFace>(this, settingsController);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SettingTimeFormat:
case Apps::SettingTimeFormat:
currentScreen = std::make_unique<Screens::SettingTimeFormat>(this, settingsController);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SettingWakeUp:
case Apps::SettingWakeUp:
currentScreen = std::make_unique<Screens::SettingWakeUp>(this, settingsController);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SettingDisplay:
case Apps::SettingDisplay:
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::BatteryInfo:
currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::SysInfo:
currentScreen = std::make_unique<Screens::SystemInfo>(this, dateTimeController, batteryController, brightnessController, bleController, watchdog);
returnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
//
case Apps::FlashLight:
case Apps::FlashLight:
currentScreen = std::make_unique<Screens::FlashLight>(this, systemTask, brightnessController);
returnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None);
break;
@ -283,23 +287,27 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentScreen = std::make_unique<Screens::StopWatch>(this);
break;
case Apps::Twos:
currentScreen = std::make_unique<Screens::Twos>(this);
currentScreen = std::make_unique<Screens::Twos>(this);
break;
case Apps::Paint:
currentScreen = std::make_unique<Screens::InfiniPaint>(this, lvgl);
currentScreen = std::make_unique<Screens::InfiniPaint>(this, lvgl);
break;
case Apps::Paddle:
currentScreen = std::make_unique<Screens::Paddle>(this, lvgl);
currentScreen = std::make_unique<Screens::Paddle>(this, lvgl);
break;
case Apps::Music:
currentScreen = std::make_unique<Screens::Music>(this, systemTask.nimble().music());
currentScreen = std::make_unique<Screens::Music>(this, systemTask.nimble().music());
break;
case Apps::Navigation:
currentScreen = std::make_unique<Screens::Navigation>(this, systemTask.nimble().navigation());
currentScreen = std::make_unique<Screens::Navigation>(this, systemTask.nimble().navigation());
break;
case Apps::HeartRate:
currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController, systemTask);
currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController, systemTask);
break;
case Apps::Motion:
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
break;
}
currentApp = app;
}

View File

@ -27,6 +27,7 @@ namespace Pinetime {
class DateTime;
class NotificationManager;
class HeartRateController;
class MotionController;
}
namespace System {
@ -45,7 +46,8 @@ namespace Pinetime {
System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Controllers::Settings &settingsController
Controllers::Settings &settingsController,
Pinetime::Controllers::MotionController& motionController
);
void Start();
void PushMessage(Display::Messages msg);
@ -68,7 +70,8 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::HeartRateController& heartRateController;
Pinetime::Controllers::Settings& settingsController;
Pinetime::Controllers::MotionController& motionController;
Pinetime::Controllers::FirmwareValidator validator;
Controllers::BrightnessController brightnessController;

View File

@ -13,7 +13,8 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Pinetime::Controllers::Settings& settingsController):
Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController):
lcd{lcd}, bleController{bleController} {
msgQueue = xQueueCreate(queueSize, itemSize);

View File

@ -16,6 +16,7 @@
#include <date/date.h>
#include <drivers/Watchdog.h>
#include <components/heartrate/HeartRateController.h>
#include <components/motion/MotionController.h>
#include <components/settings/Settings.h>
#include "TouchEvents.h"
#include "Apps.h"
@ -35,7 +36,8 @@ namespace Pinetime {
System::SystemTask &systemTask,
Pinetime::Controllers::NotificationManager& notificationManager,
Pinetime::Controllers::HeartRateController& heartRateController,
Pinetime::Controllers::Settings& settingsController);
Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::MotionController& motionController);
void Start();
void PushMessage(Pinetime::Applications::Display::Messages msg);

View File

@ -53,6 +53,7 @@ static lv_style_t style_table_cell;
static lv_style_t style_pad_small;
static lv_style_t style_bg_grad;
static lv_style_t style_lmeter;
static lv_style_t style_chart_serie;
static lv_style_t style_cb_bg;
static lv_style_t style_cb_bullet;
@ -277,6 +278,12 @@ static void basic_init(void)
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
style_init_reset(&style_chart_serie);
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
lv_style_reset(&style_cb_bg);
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
@ -500,7 +507,14 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
_lv_style_list_add_style(list, &style_bg);
_lv_style_list_add_style(list, &style_lmeter);
break;
case LV_THEME_CHART:
lv_obj_clean_style_list(obj, LV_CHART_PART_SERIES);
list = lv_obj_get_style_list(obj, LV_CHART_PART_SERIES);
_lv_style_list_add_style(list, &style_btn);
_lv_style_list_add_style(list, &style_chart_serie);
break;
case LV_THEME_CHECKBOX:
list = lv_obj_get_style_list(obj, LV_CHECKBOX_PART_BG);
_lv_style_list_add_style(list, &style_cb_bg);

View File

@ -16,7 +16,7 @@ ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp *app,
settingsController{settingsController},
batteryController{batteryController},
dateTimeController{dateTimeController},
screens{app,
screens{app,
settingsController.GetAppMenu(),
{
[this]() -> std::unique_ptr<Screen> { return CreateScreen1(); },
@ -47,7 +47,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
{Symbols::stopWatch, Apps::StopWatch},
{Symbols::music, Apps::Music},
{Symbols::map, Apps::Navigation},
{Symbols::shoe, Apps::Clock},
{Symbols::shoe, Apps::Motion},
{Symbols::heartBeat, Apps::HeartRate},
{"", Apps::None},
}

View File

@ -8,6 +8,7 @@
#include "NotificationIcon.h"
#include "Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/motion/MotionController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "../DisplayApp.h"
@ -23,12 +24,14 @@ Clock::Clock(DisplayApp* app,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController,
Controllers::HeartRateController& heartRateController) : Screen(app),
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController) : Screen(app),
dateTimeController{dateTimeController}, batteryController{batteryController},
bleController{bleController}, notificatioManager{notificatioManager},
settingsController{settingsController},
heartRateController{heartRateController},
screens{app,
motionController{motionController},
screens{app,
settingsController.GetClockFace(),
{
[this]() -> std::unique_ptr<Screen> { return WatchFaceDigitalScreen(); },
@ -59,7 +62,7 @@ bool Clock::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController);
return std::make_unique<Screens::WatchFaceDigital>(app, dateTimeController, batteryController, bleController, notificatioManager, settingsController, heartRateController, motionController);
}
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {

View File

@ -17,6 +17,7 @@ namespace Pinetime {
class Battery;
class Ble;
class NotificationManager;
class MotionController;
}
namespace Applications {
@ -29,7 +30,8 @@ namespace Pinetime {
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController,
Controllers::HeartRateController& heartRateController);
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~Clock() override;
bool Refresh() override;
@ -44,6 +46,7 @@ namespace Pinetime {
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
ScreenList<2> screens;

View File

@ -0,0 +1,59 @@
#include <libs/lvgl/lvgl.h>
#include "Motion.h"
#include "../DisplayApp.h"
using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_extrabold_compressed;
extern lv_font_t jetbrains_mono_bold_20;
Motion::Motion(Pinetime::Applications::DisplayApp *app, Controllers::MotionController& motionController) : Screen(app), motionController{motionController} {
chart = lv_chart_create(lv_scr_act(), NULL);
lv_obj_set_size(chart, 240, 240);
lv_obj_align(chart, NULL, LV_ALIGN_IN_TOP_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, -1100, 1100);
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
lv_chart_set_point_count(chart, 10);
/*Add 3 data series*/
ser1 = lv_chart_add_series(chart, LV_COLOR_RED);
ser2 = lv_chart_add_series(chart, LV_COLOR_GREEN);
ser3 = lv_chart_add_series(chart, LV_COLOR_YELLOW);
lv_chart_init_points(chart, ser1, 0);
lv_chart_init_points(chart, ser2, 0);
lv_chart_init_points(chart, ser3, 0);
lv_chart_refresh(chart); /*Required after direct set*/
labelStep = lv_label_create(lv_scr_act(), NULL);
lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_label_set_text(labelStep, "Steps: ");
labelStepValue = lv_label_create(lv_scr_act(), NULL);
lv_obj_align(labelStepValue, labelStep, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
lv_label_set_text(labelStepValue, "-");
}
Motion::~Motion() {
lv_obj_clean(lv_scr_act());
}
bool Motion::Refresh() {
lv_chart_set_next(chart, ser1, motionController.X());
lv_chart_set_next(chart, ser2, motionController.Y());
lv_chart_set_next(chart, ser3, motionController.Z());
snprintf(nbStepsBuffer, nbStepsBufferSize, "%lu", motionController.NbSteps());
lv_label_set_text(labelStepValue, nbStepsBuffer);
return running;
}
bool Motion::OnButtonPushed() {
running = false;
return true;
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
#include <chrono>
#include "Screen.h"
#include <bits/unique_ptr.h>
#include <libs/lvgl/src/lv_core/lv_style.h>
#include <libs/lvgl/src/lv_core/lv_obj.h>
#include <components/motion/MotionController.h>
namespace Pinetime {
namespace Applications {
namespace Screens {
class Motion : public Screen{
public:
Motion(DisplayApp* app, Controllers::MotionController& motionController);
~Motion() override;
bool Refresh() override;
bool OnButtonPushed() override;
private:
Controllers::MotionController& motionController;
lv_obj_t * chart;
lv_chart_series_t * ser1;
lv_chart_series_t * ser2;
lv_chart_series_t * ser3;
lv_obj_t* labelStep;
lv_obj_t* labelStepValue;
static constexpr uint8_t nbStepsBufferSize = 9;
char nbStepsBuffer[nbStepsBufferSize+1];
bool running = true;
};
}
}
}

View File

@ -11,6 +11,7 @@
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
#include "../DisplayApp.h"
@ -23,11 +24,13 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController,
Controllers::HeartRateController& heartRateController): Screen(app), currentDateTime{{}},
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController) : Screen(app), currentDateTime{{}},
dateTimeController{dateTimeController}, batteryController{batteryController},
bleController{bleController}, notificatioManager{notificatioManager},
settingsController{settingsController},
heartRateController{heartRateController} {
heartRateController{heartRateController},
motionController{motionController} {
settingsController.SetClockFace(0);
displayedChar[0] = 0;
@ -236,10 +239,14 @@ bool WatchFaceDigital::Refresh() {
lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
}
// TODO stepCount = stepController.GetValue();
if(stepCount.IsUpdated()) {
stepCount = motionController.NbSteps();
motionSensorOk = motionController.IsSensorOk();
if(stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
char stepBuffer[5];
sprintf(stepBuffer, "%lu", stepCount.Get());
if(motionSensorOk.Get())
sprintf(stepBuffer, "%lu", stepCount.Get());
else
sprintf(stepBuffer, "---", stepCount.Get());
lv_label_set_text(stepValue, stepBuffer);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);

View File

@ -15,6 +15,7 @@ namespace Pinetime {
class Ble;
class NotificationManager;
class HeartRateController;
class MotionController;
}
namespace Applications {
@ -28,7 +29,8 @@ namespace Pinetime {
Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings &settingsController,
Controllers::HeartRateController& heartRateController);
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~WatchFaceDigital() override;
bool Refresh() override;
@ -48,6 +50,7 @@ namespace Pinetime {
DirtyValue<int> batteryPercentRemaining {};
DirtyValue<bool> bleState {};
DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime{};
DirtyValue<bool> motionSensorOk {};
DirtyValue<uint32_t> stepCount {};
DirtyValue<uint8_t> heartbeat {};
DirtyValue<bool> heartbeatRunning {};
@ -73,6 +76,7 @@ namespace Pinetime {
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;

116
src/drivers/Bma421.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <libraries/delay/nrf_delay.h>
#include <libraries/log/nrf_log.h>
#include "Bma421.h"
#include "TwiMaster.h"
#include <drivers/Bma421_C/bma423.h>
using namespace Pinetime::Drivers;
namespace {
int8_t user_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t length, void* intf_ptr) {
auto bma421 = static_cast<Bma421*>(intf_ptr);
bma421->Read(reg_addr, reg_data, length);
return 0;
}
int8_t user_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t length, void* intf_ptr) {
auto bma421 = static_cast<Bma421*>(intf_ptr);
bma421->Write(reg_addr, reg_data, length);
return 0;
}
void user_delay(uint32_t period_us, void* intf_ptr) {
nrf_delay_us(period_us);
}
}
Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster{twiMaster}, deviceAddress{twiAddress} {
bma.intf = BMA4_I2C_INTF;
bma.bus_read = user_i2c_read;
bma.bus_write = user_i2c_write;
bma.variant = BMA42X_VARIANT;
bma.intf_ptr = this;
bma.delay_us = user_delay;
bma.read_write_len = 8;
}
void Bma421::Init() {
if(not isResetOk) return; // Call SoftReset (and reset TWI device) first!
auto ret = bma423_init(&bma);
if(ret != BMA4_OK) return;
ret = bma423_write_config_file(&bma);
if(ret != BMA4_OK) return;
ret = bma4_set_interrupt_mode(BMA4_LATCH_MODE, &bma);
if(ret != BMA4_OK) return;
ret = bma423_feature_enable(BMA423_STEP_CNTR, 1, &bma);
if(ret != BMA4_OK) return;
ret = bma423_step_detector_enable(0, &bma);
if(ret != BMA4_OK) return;
ret = bma4_set_accel_enable(1, &bma);
if(ret != BMA4_OK) return;
struct bma4_accel_config accel_conf;
accel_conf.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
accel_conf.range = BMA4_ACCEL_RANGE_2G;
accel_conf.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
accel_conf.perf_mode = BMA4_CIC_AVG_MODE;
ret = bma4_set_accel_config(&accel_conf, &bma);
if(ret != BMA4_OK) return;
isOk = true;
}
void Bma421::Reset() {
uint8_t data = 0xb6;
twiMaster.Write(deviceAddress, 0x7E, &data, 1);
}
void Bma421::Read(uint8_t registerAddress, uint8_t *buffer, size_t size) {
twiMaster.Read(deviceAddress, registerAddress, buffer, size);
}
void Bma421::Write(uint8_t registerAddress, const uint8_t *data, size_t size) {
twiMaster.Write(deviceAddress, registerAddress, data, size);
}
Bma421::Values Bma421::Process() {
if(not isOk) return {};
struct bma4_accel data;
bma4_read_accel_xyz(&data, &bma);
uint32_t steps = 0;
bma423_step_counter_output(&steps, &bma);
int32_t temperature;
bma4_get_temperature(&temperature, BMA4_DEG, &bma);
temperature = temperature / 1000;
uint8_t activity = 0;
bma423_activity_output(&activity, &bma);
NRF_LOG_INFO("MOTION : %d - %d/%d/%d", steps, data.x, data.y, data.z);
// X and Y axis are swapped because of the way the sensor is mounted in the PineTime
return {steps, data.y, data.x, data.z};
}
bool Bma421::IsOk() const {
return isOk;
}
void Bma421::ResetStepCounter() {
bma423_reset_step_counter(&bma);
}
void Bma421::SoftReset() {
auto ret = bma4_soft_reset(&bma);
if(ret == BMA4_OK) {
isResetOk = true;
nrf_delay_ms(1);
}
}

43
src/drivers/Bma421.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <drivers/Bma421_C/bma4_defs.h>
namespace Pinetime {
namespace Drivers {
class TwiMaster;
class Bma421 {
public:
struct Values {
uint32_t steps;
int16_t x;
int16_t y;
int16_t z;
};
Bma421(TwiMaster& twiMaster, uint8_t twiAddress);
Bma421(const Bma421&) = delete;
Bma421& operator=(const Bma421&) = delete;
Bma421(Bma421&&) = delete;
Bma421& operator=(Bma421&&) = delete;
/// The chip freezes the TWI bus after the softreset operation. Softreset is separated from the
/// Init() method to allow the caller to uninit and then reinit the TWI device after the softreset.
void SoftReset();
void Init();
Values Process();
void ResetStepCounter();
void Read(uint8_t registerAddress, uint8_t *buffer, size_t size);
void Write(uint8_t registerAddress, const uint8_t *data, size_t size);
bool IsOk() const;
private:
void Reset();
TwiMaster& twiMaster;
uint8_t deviceAddress = 0x18;
struct bma4_dev bma;
bool isOk = false;
bool isResetOk = false;
};
}
}

5689
src/drivers/Bma421_C/bma4.c Normal file

File diff suppressed because it is too large Load Diff

2281
src/drivers/Bma421_C/bma4.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,196 +2,77 @@
#include <cstring>
#include <hal/nrf_gpio.h>
#include <nrfx_log.h>
#include <nrfx_twim.h>
#include <nrf_drv_twi.h>
using namespace Pinetime::Drivers;
// TODO use shortcut to automatically send STOP when receive LastTX, for example
// TODO use DMA/IRQ
TwiMaster::TwiMaster(const Modules module, const Parameters& params) : module{module}, params{params} {
mutex = xSemaphoreCreateBinary();
ASSERT(mutex != NULL);
TwiMaster::TwiMaster(const Modules module, const Parameters& params) : module{module}, params{params}, mutex{xSemaphoreCreateBinary()} {
ASSERT(mutex != nullptr);
switch(module) {
case Modules::TWIM1:
default:
twim = NRFX_TWIM_INSTANCE(1);
break;
}
}
void TwiMaster::Init() {
NRF_GPIO->PIN_CNF[params.pinScl] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
NRF_GPIO->PIN_CNF[params.pinSda] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
switch(module) {
case Modules::TWIM1: twiBaseAddress = NRF_TWIM1; break;
default:
return;
}
switch(static_cast<Frequencies>(params.frequency)) {
case Frequencies::Khz100 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100; break;
case Frequencies::Khz250 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K250; break;
case Frequencies::Khz400 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400; break;
}
twiBaseAddress->PSEL.SCL = params.pinScl;
twiBaseAddress->PSEL.SDA = params.pinSda;
twiBaseAddress->EVENTS_LASTRX = 0;
twiBaseAddress->EVENTS_STOPPED = 0;
twiBaseAddress->EVENTS_LASTTX = 0;
twiBaseAddress->EVENTS_ERROR = 0;
twiBaseAddress->EVENTS_RXSTARTED = 0;
twiBaseAddress->EVENTS_SUSPENDED = 0;
twiBaseAddress->EVENTS_TXSTARTED = 0;
twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos);
/* // IRQ
NVIC_ClearPendingIRQ(_IRQn);
NVIC_SetPriority(_IRQn, 2);
NVIC_EnableIRQ(_IRQn);
*/
nrfx_twim_config_t config;
config.frequency = static_cast<nrf_twim_frequency_t>(params.frequency);
config.hold_bus_uninit = false;
config.interrupt_priority = 0;
config.scl = params.pinScl;
config.sda = params.pinSda;
nrfx_twim_init(&twim,
&config,
nullptr,
nullptr);
nrfx_twim_enable(&twim);
xSemaphoreGive(mutex);
}
TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
xSemaphoreTake(mutex, portMAX_DELAY);
auto ret = ReadWithRetry(deviceAddress, registerAddress, data, size);
xSemaphoreTake(mutex, portMAX_DELAY);
TwiMaster::ErrorCodes ret;
auto err = nrfx_twim_tx(&twim, deviceAddress, &registerAddress, 1, false);
if(err != 0) {
return TwiMaster::ErrorCodes::TransactionFailed;
}
err = nrfx_twim_rx(&twim, deviceAddress, data, size);
if(err != 0) {
return TwiMaster::ErrorCodes::TransactionFailed;
}
xSemaphoreGive(mutex);
return ret;
return TwiMaster::ErrorCodes::NoError;
}
TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
ASSERT(size <= maxDataSize);
xSemaphoreTake(mutex, portMAX_DELAY);
auto ret = WriteWithRetry(deviceAddress, registerAddress, data, size);
xSemaphoreGive(mutex);
return ret;
}
/* Execute a read transaction (composed of a write and a read operation). If one of these opeartion fails,
* it's retried once. If it fails again, an error is returned */
TwiMaster::ErrorCodes TwiMaster::ReadWithRetry(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
TwiMaster::ErrorCodes ret;
ret = Write(deviceAddress, &registerAddress, 1, false);
if(ret != ErrorCodes::NoError)
ret = Write(deviceAddress, &registerAddress, 1, false);
if(ret != ErrorCodes::NoError) return ret;
ret = Read(deviceAddress, data, size, true);
if(ret != ErrorCodes::NoError)
ret = Read(deviceAddress, data, size, true);
return ret;
}
/* Execute a write transaction. If it fails, it is retried once. If it fails again, an error is returned. */
TwiMaster::ErrorCodes TwiMaster::WriteWithRetry(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
internalBuffer[0] = registerAddress;
std::memcpy(internalBuffer+1, data, size);
auto ret = Write(deviceAddress, internalBuffer, size+1, true);
if(ret != ErrorCodes::NoError)
ret = Write(deviceAddress, internalBuffer, size+1, true);
return ret;
}
TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool stop) {
twiBaseAddress->ADDRESS = deviceAddress;
twiBaseAddress->TASKS_RESUME = 0x1UL;
twiBaseAddress->RXD.PTR = (uint32_t)buffer;
twiBaseAddress->RXD.MAXCNT = size;
twiBaseAddress->TASKS_STARTRX = 1;
while(!twiBaseAddress->EVENTS_RXSTARTED && !twiBaseAddress->EVENTS_ERROR);
twiBaseAddress->EVENTS_RXSTARTED = 0x0UL;
txStartedCycleCount = DWT->CYCCNT;
uint32_t currentCycleCount;
while(!twiBaseAddress->EVENTS_LASTRX && !twiBaseAddress->EVENTS_ERROR) {
currentCycleCount = DWT->CYCCNT;
if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
FixHwFreezed();
return ErrorCodes::TransactionFailed;
}
}
twiBaseAddress->EVENTS_LASTRX = 0x0UL;
if (stop || twiBaseAddress->EVENTS_ERROR) {
twiBaseAddress->TASKS_STOP = 0x1UL;
while(!twiBaseAddress->EVENTS_STOPPED);
twiBaseAddress->EVENTS_STOPPED = 0x0UL;
}
else {
twiBaseAddress->TASKS_SUSPEND = 0x1UL;
while(!twiBaseAddress->EVENTS_SUSPENDED);
twiBaseAddress->EVENTS_SUSPENDED = 0x0UL;
auto err = nrfx_twim_tx(&twim, deviceAddress, internalBuffer , size+1, false);
if(err != 0){
return TwiMaster::ErrorCodes::TransactionFailed;
}
if (twiBaseAddress->EVENTS_ERROR) {
twiBaseAddress->EVENTS_ERROR = 0x0UL;
}
return ErrorCodes::NoError;
}
TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, bool stop) {
twiBaseAddress->ADDRESS = deviceAddress;
twiBaseAddress->TASKS_RESUME = 0x1UL;
twiBaseAddress->TXD.PTR = (uint32_t)data;
twiBaseAddress->TXD.MAXCNT = size;
twiBaseAddress->TASKS_STARTTX = 1;
while(!twiBaseAddress->EVENTS_TXSTARTED && !twiBaseAddress->EVENTS_ERROR);
twiBaseAddress->EVENTS_TXSTARTED = 0x0UL;
txStartedCycleCount = DWT->CYCCNT;
uint32_t currentCycleCount;
while(!twiBaseAddress->EVENTS_LASTTX && !twiBaseAddress->EVENTS_ERROR) {
currentCycleCount = DWT->CYCCNT;
if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
FixHwFreezed();
return ErrorCodes::TransactionFailed;
}
}
twiBaseAddress->EVENTS_LASTTX = 0x0UL;
if (stop || twiBaseAddress->EVENTS_ERROR) {
twiBaseAddress->TASKS_STOP = 0x1UL;
while(!twiBaseAddress->EVENTS_STOPPED);
twiBaseAddress->EVENTS_STOPPED = 0x0UL;
}
else {
twiBaseAddress->TASKS_SUSPEND = 0x1UL;
while(!twiBaseAddress->EVENTS_SUSPENDED);
twiBaseAddress->EVENTS_SUSPENDED = 0x0UL;
}
if (twiBaseAddress->EVENTS_ERROR) {
twiBaseAddress->EVENTS_ERROR = 0x0UL;
uint32_t error = twiBaseAddress->ERRORSRC;
twiBaseAddress->ERRORSRC = error;
}
return ErrorCodes::NoError;
xSemaphoreGive(mutex);
return TwiMaster::ErrorCodes::NoError;
}
void TwiMaster::Sleep() {
while(twiBaseAddress->ENABLE != 0) {
twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos);
}
nrfx_twim_disable(&twim);
nrfx_twim_uninit(&twim);
nrf_gpio_cfg_default(6);
nrf_gpio_cfg_default(7);
NRF_LOG_INFO("[TWIMASTER] Sleep");
@ -201,30 +82,3 @@ void TwiMaster::Wakeup() {
Init();
NRF_LOG_INFO("[TWIMASTER] Wakeup");
}
/* Sometimes, the TWIM device just freeze and never set the event EVENTS_LASTTX.
* This method disable and re-enable the peripheral so that it works again.
* This is just a workaround, and it would be better if we could find a way to prevent
* this issue from happening.
* */
void TwiMaster::FixHwFreezed() {
NRF_LOG_INFO("I2C device frozen, reinitializing it!");
// Disable I²C
uint32_t twi_state = NRF_TWI1->ENABLE;
twiBaseAddress->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
NRF_GPIO->PIN_CNF[params.pinScl] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
NRF_GPIO->PIN_CNF[params.pinSda] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
// Re-enable I²C
twiBaseAddress->ENABLE = twi_state;
}

View File

@ -3,13 +3,13 @@
#include <semphr.h>
#include <drivers/include/nrfx_twi.h> // NRF_TWIM_Type
#include <cstdint>
#include <nrfx_twim.h>
namespace Pinetime {
namespace Drivers {
class TwiMaster {
public:
enum class Modules { TWIM1 };
enum class Frequencies {Khz100, Khz250, Khz400};
enum class ErrorCodes {NoError, TransactionFailed};
struct Parameters {
uint32_t frequency;
@ -27,21 +27,13 @@ namespace Pinetime {
void Wakeup();
private:
ErrorCodes ReadWithRetry(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, size_t size);
ErrorCodes WriteWithRetry(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t* data, size_t size);
ErrorCodes Read(uint8_t deviceAddress, uint8_t* buffer, size_t size, bool stop);
ErrorCodes Write(uint8_t deviceAddress, const uint8_t* data, size_t size, bool stop);
void FixHwFreezed();
NRF_TWIM_Type* twiBaseAddress;
SemaphoreHandle_t mutex;
nrfx_twim_t twim;
const Modules module;
const Parameters params;
SemaphoreHandle_t mutex;
static constexpr uint8_t maxDataSize{8};
static constexpr uint8_t registerSize{1};
uint8_t internalBuffer[maxDataSize + registerSize];
uint32_t txStartedCycleCount = 0;
static constexpr uint32_t HwFreezedDelay{161000};
};
}
}

View File

@ -26,6 +26,7 @@
#include <task.h>
#include <timers.h>
#include <drivers/Hrs3300.h>
#include <drivers/Bma421.h>
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
@ -60,6 +61,7 @@ static constexpr uint8_t pinLcdDataCommand = 18;
static constexpr uint8_t pinTwiScl = 7;
static constexpr uint8_t pinTwiSda = 6;
static constexpr uint8_t touchPanelTwiAddress = 0x15;
static constexpr uint8_t motionSensorTwiAddress = 0x18;
static constexpr uint8_t heartRateSensorTwiAddress = 0x44;
Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {
@ -98,14 +100,13 @@ static constexpr bool isFactory = false;
Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
#endif
Pinetime::Drivers::Bma421 motionSensor{twiMaster, motionSensorTwiAddress};
Pinetime::Drivers::Hrs3300 heartRateSensor {twiMaster, heartRateSensorTwiAddress};
TimerHandle_t debounceTimer;
Pinetime::Controllers::Battery batteryController;
Pinetime::Controllers::Ble bleController;
Pinetime::Controllers::DateTime dateTimeController;
void ble_manager_set_ble_connection_callback(void (*connection)());
void ble_manager_set_ble_disconnection_callback(void (*disconnection)());
static constexpr uint8_t pinTouchIrq = 28;
@ -257,7 +258,7 @@ int main(void) {
debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback);
systemTask = std::make_unique<Pinetime::System::SystemTask>(spi, lcd, spiNorFlash, twiMaster, touchPanel, lvgl, batteryController, bleController,
dateTimeController, motorController, heartRateSensor, settingsController);
motorController, heartRateSensor, motionSensor, settingsController);
systemTask->Start();
nimble_port_init();

View File

@ -4992,7 +4992,7 @@
// <e> NRFX_TWIM_ENABLED - nrfx_twim - TWIM peripheral driver
//==========================================================
#ifndef NRFX_TWIM_ENABLED
#define NRFX_TWIM_ENABLED 0
#define NRFX_TWIM_ENABLED 1
#endif
// <q> NRFX_TWIM0_ENABLED - Enable TWIM0 instance
@ -5005,7 +5005,7 @@
#ifndef NRFX_TWIM1_ENABLED
#define NRFX_TWIM1_ENABLED 0
#define NRFX_TWIM1_ENABLED 1
#endif
// <o> NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY - Frequency

View File

@ -40,16 +40,16 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd,
Drivers::TwiMaster& twiMaster, Drivers::Cst816S &touchPanel,
Components::LittleVgl &lvgl,
Controllers::Battery &batteryController, Controllers::Ble &bleController,
Controllers::DateTime &dateTimeController,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Drivers::Hrs3300& heartRateSensor,
Pinetime::Drivers::Bma421& motionSensor,
Controllers::Settings &settingsController) :
spi{spi}, lcd{lcd}, spiNorFlash{spiNorFlash},
twiMaster{twiMaster}, touchPanel{touchPanel}, lvgl{lvgl}, batteryController{batteryController},
heartRateController{*this},
bleController{bleController}, dateTimeController{dateTimeController},
bleController{bleController}, dateTimeController{*this},
watchdog{}, watchdogView{watchdog},
motorController{motorController}, heartRateSensor{heartRateSensor},
motorController{motorController}, heartRateSensor{heartRateSensor}, motionSensor{motionSensor},
settingsController{settingsController},
nimbleController(*this, bleController,dateTimeController, notificationManager, batteryController, spiNorFlash, heartRateController) {
systemTasksMsgQueue = xQueueCreate(10, 1);
@ -84,13 +84,18 @@ void SystemTask::Work() {
touchPanel.Init();
batteryController.Init();
motorController.Init();
motionSensor.SoftReset();
// Reset the TWI device because the motion sensor chip most probably crashed it...
twiMaster.Sleep();
twiMaster.Init();
motionSensor.Init();
settingsController.Init();
displayApp = std::make_unique<Pinetime::Applications::DisplayApp>(lcd, lvgl, touchPanel, batteryController, bleController,
dateTimeController, watchdogView, *this, notificationManager,
heartRateController, settingsController);
heartRateController, settingsController, motionController);
displayApp->Start();
batteryController.Update();
@ -132,8 +137,10 @@ void SystemTask::Work() {
#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
while(true) {
UpdateMotion();
uint8_t msg;
if (xQueueReceive(systemTasksMsgQueue, &msg, isSleeping ? 2500 : 1000)) {
if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) {
batteryController.Update();
Messages message = static_cast<Messages >(msg);
switch(message) {
@ -148,10 +155,10 @@ void SystemTask::Work() {
break;
case Messages::GoToRunning:
spi.Wakeup();
twiMaster.Wakeup();
// Double Tap needs the touch screen to be in normal mode
if ( settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap ) {
twiMaster.Wakeup();
touchPanel.Wakeup();
}
@ -168,7 +175,9 @@ void SystemTask::Work() {
isWakingUp = false;
break;
case Messages::TouchWakeUp: {
twiMaster.Wakeup();
auto touchInfo = touchPanel.GetTouchInfo();
twiMaster.Sleep();
if( touchInfo.isTouch and
(
( touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and
@ -232,12 +241,17 @@ void SystemTask::Work() {
// Double Tap needs the touch screen to be in normal mode
if ( settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap ) {
touchPanel.Sleep();
twiMaster.Sleep();
}
twiMaster.Sleep();
isSleeping = true;
isGoingToSleep = false;
break;
case Messages::OnNewDay:
// We might be sleeping (with TWI device disabled.
// Remember we'll have to reset the counter next time we're awake
stepCounterMustBeReset = true;
break;
default: break;
}
}
@ -262,6 +276,30 @@ void SystemTask::Work() {
// Clear diagnostic suppression
#pragma clang diagnostic pop
}
void SystemTask::UpdateMotion() {
if(isGoingToSleep or isWakingUp) return;
if(isSleeping)
twiMaster.Wakeup();
if(stepCounterMustBeReset) {
motionSensor.ResetStepCounter();
stepCounterMustBeReset = false;
}
auto motionValues = motionSensor.Process();
if(isSleeping)
twiMaster.Sleep();
motionController.IsSensorOk(motionSensor.IsOk());
motionController.Update(motionValues.x,
motionValues.y,
motionValues.z,
motionValues.steps);
if (motionController.ShouldWakeUp(isSleeping)) {
GoToRunning();
}
}
void SystemTask::OnButtonPushed() {
if(isGoingToSleep) return;
@ -279,6 +317,7 @@ void SystemTask::OnButtonPushed() {
}
void SystemTask::GoToRunning() {
if(isGoingToSleep or (not isSleeping) or isWakingUp) return;
isWakingUp = true;
PushMessage(Messages::GoToRunning);
}

View File

@ -8,6 +8,8 @@
#include <heartratetask/HeartRateTask.h>
#include <components/heartrate/HeartRateController.h>
#include <components/settings/Settings.h>
#include <drivers/Bma421.h>
#include <components/motion/MotionController.h>
#include "SystemMonitor.h"
#include "components/battery/BatteryController.h"
@ -38,7 +40,8 @@ namespace Pinetime {
class SystemTask {
public:
enum class Messages {GoToSleep, GoToRunning, TouchWakeUp, OnNewTime, OnNewNotification, OnNewCall, BleConnected, UpdateTimeOut,
BleFirmwareUpdateStarted, BleFirmwareUpdateFinished, OnTouchEvent, OnButtonEvent, OnDisplayTaskSleeping, EnableSleeping, DisableSleeping
BleFirmwareUpdateStarted, BleFirmwareUpdateFinished, OnTouchEvent, OnButtonEvent, OnDisplayTaskSleeping, EnableSleeping, DisableSleeping,
OnNewDay
};
SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd,
@ -46,9 +49,9 @@ namespace Pinetime {
Drivers::TwiMaster& twiMaster, Drivers::Cst816S &touchPanel,
Components::LittleVgl &lvgl,
Controllers::Battery &batteryController, Controllers::Ble &bleController,
Controllers::DateTime &dateTimeController,
Pinetime::Controllers::MotorController& motorController,
Pinetime::Drivers::Hrs3300& heartRateSensor,
Pinetime::Drivers::Bma421& motionSensor,
Controllers::Settings &settingsController);
@ -77,7 +80,7 @@ namespace Pinetime {
std::unique_ptr<Pinetime::Applications::HeartRateTask> heartRateApp;
Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::DateTime dateTimeController;
QueueHandle_t systemTasksMsgQueue;
std::atomic<bool> isSleeping{false};
std::atomic<bool> isGoingToSleep{false};
@ -87,9 +90,11 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager notificationManager;
Pinetime::Controllers::MotorController& motorController;
Pinetime::Drivers::Hrs3300& heartRateSensor;
Pinetime::Drivers::Bma421& motionSensor;
Pinetime::Controllers::Settings& settingsController;
Pinetime::Controllers::NimbleController nimbleController;
Controllers::BrightnessController brightnessController;
Pinetime::Controllers::MotionController motionController;
static constexpr uint8_t pinSpiSck = 2;
static constexpr uint8_t pinSpiMosi = 3;
@ -108,6 +113,8 @@ namespace Pinetime {
bool doNotGoToSleep = false;
void GoToRunning();
void UpdateMotion();
bool stepCounterMustBeReset = false;
#if configUSE_TRACE_FACILITY == 1
SystemMonitor<FreeRtosMonitor> monitor;