Merge branch 'motion-sensor' into develop
This commit is contained in:
commit
eb769fb60e
|
@ -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)
|
||||
|
|
|
@ -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,...)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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[];
|
||||
|
|
36
src/components/motion/MotionController.cpp
Normal file
36
src/components/motion/MotionController.cpp
Normal 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;
|
||||
}
|
29
src/components/motion/MotionController.h
Normal file
29
src/components/motion/MotionController.h
Normal 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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Pinetime {
|
|||
namespace Applications {
|
||||
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
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
@ -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:
|
||||
|
@ -300,6 +304,10 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
case Apps::HeartRate:
|
||||
currentScreen = std::make_unique<Screens::HeartRate>(this, heartRateController, systemTask);
|
||||
break;
|
||||
case Apps::Motion:
|
||||
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
|
||||
break;
|
||||
|
||||
}
|
||||
currentApp = app;
|
||||
}
|
||||
|
|
|
@ -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,6 +70,7 @@ 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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
@ -501,6 +508,13 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
|
|||
_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);
|
||||
|
|
|
@ -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},
|
||||
}
|
||||
|
|
|
@ -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,11 +24,13 @@ 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},
|
||||
motionController{motionController},
|
||||
screens{app,
|
||||
settingsController.GetClockFace(),
|
||||
{
|
||||
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
59
src/displayapp/screens/Motion.cpp
Normal file
59
src/displayapp/screens/Motion.cpp
Normal 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;
|
||||
}
|
39
src/displayapp/screens/Motion.h
Normal file
39
src/displayapp/screens/Motion.h
Normal 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;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
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);
|
||||
|
|
|
@ -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
116
src/drivers/Bma421.cpp
Normal 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
43
src/drivers/Bma421.h
Normal 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
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
2281
src/drivers/Bma421_C/bma4.h
Normal file
File diff suppressed because it is too large
Load Diff
1688
src/drivers/Bma421_C/bma423.c
Normal file
1688
src/drivers/Bma421_C/bma423.c
Normal file
File diff suppressed because it is too large
Load Diff
1115
src/drivers/Bma421_C/bma423.h
Normal file
1115
src/drivers/Bma421_C/bma423.h
Normal file
File diff suppressed because it is too large
Load Diff
1144
src/drivers/Bma421_C/bma4_defs.h
Normal file
1144
src/drivers/Bma421_C/bma4_defs.h
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
TwiMaster::ErrorCodes ret;
|
||||
|
||||
auto err = nrfx_twim_tx(&twim, deviceAddress, ®isterAddress, 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, ®isterAddress, 1, false);
|
||||
if(ret != ErrorCodes::NoError)
|
||||
ret = Write(deviceAddress, ®isterAddress, 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;
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user