Skip to content

Commit

Permalink
Merge branch 'InfiniTimeOrg:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
SadAlexa authored Jun 10, 2024
2 parents 4da590f + f9a16fe commit a07289b
Show file tree
Hide file tree
Showing 20 changed files with 215 additions and 119 deletions.
1 change: 1 addition & 0 deletions src/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configUSE_TASK_NOTIFICATIONS 0

/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
Expand Down
2 changes: 1 addition & 1 deletion src/components/ble/SimpleWeatherService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int WeatherCallback(uint16_t /*connHandle*/, uint16_t /*attrHandle*/, struct ble
return static_cast<Pinetime::Controllers::SimpleWeatherService*>(arg)->OnCommand(ctxt);
}

SimpleWeatherService::SimpleWeatherService(const DateTime& dateTimeController) : dateTimeController(dateTimeController) {
SimpleWeatherService::SimpleWeatherService(DateTime& dateTimeController) : dateTimeController(dateTimeController) {
}

void SimpleWeatherService::Init() {
Expand Down
4 changes: 2 additions & 2 deletions src/components/ble/SimpleWeatherService.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace Pinetime {

class SimpleWeatherService {
public:
explicit SimpleWeatherService(const DateTime& dateTimeController);
explicit SimpleWeatherService(DateTime& dateTimeController);

void Init();

Expand Down Expand Up @@ -140,7 +140,7 @@ namespace Pinetime {

uint16_t eventHandle {};

const Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::DateTime& dateTimeController;

std::optional<CurrentWeather> currentWeather;
std::optional<Forecast> forecast;
Expand Down
44 changes: 31 additions & 13 deletions src/components/datetime/DateTimeController.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "components/datetime/DateTimeController.h"
#include <libraries/log/nrf_log.h>
#include <systemtask/SystemTask.h>
#include <hal/nrf_rtc.h>
#include "nrf_assert.h"

using namespace Pinetime::Controllers;

Expand All @@ -12,11 +14,16 @@ namespace {
}

DateTime::DateTime(Controllers::Settings& settingsController) : settingsController {settingsController} {
mutex = xSemaphoreCreateMutex();
ASSERT(mutex != nullptr);
xSemaphoreGive(mutex);
}

void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
xSemaphoreTake(mutex, portMAX_DELAY);
this->currentDateTime = t;
UpdateTime(previousSystickCounter); // Update internal state without updating the time
UpdateTime(previousSystickCounter, true); // Update internal state without updating the time
xSemaphoreGive(mutex);
}

void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
Expand All @@ -29,13 +36,15 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
/* .tm_year = */ year - 1900,
};

tm.tm_isdst = -1; // Use DST value from local time zone
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));

NRF_LOG_INFO("%d %d %d ", day, month, year);
NRF_LOG_INFO("%d %d %d ", hour, minute, second);

UpdateTime(previousSystickCounter);
tm.tm_isdst = -1; // Use DST value from local time zone

xSemaphoreTake(mutex, portMAX_DELAY);
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
UpdateTime(previousSystickCounter, true);
xSemaphoreGive(mutex);

systemTask->PushMessage(System::Messages::OnNewTime);
}
Expand All @@ -45,25 +54,34 @@ void DateTime::SetTimeZone(int8_t timezone, int8_t dst) {
dstOffset = dst;
}

void DateTime::UpdateTime(uint32_t systickCounter) {
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> DateTime::CurrentDateTime() {
xSemaphoreTake(mutex, portMAX_DELAY);
UpdateTime(nrf_rtc_counter_get(portNRF_RTC_REG), false);
xSemaphoreGive(mutex);
return currentDateTime;
}

void DateTime::UpdateTime(uint32_t systickCounter, bool forceUpdate) {
// Handle systick counter overflow
uint32_t systickDelta = 0;
if (systickCounter < previousSystickCounter) {
systickDelta = 0xffffff - previousSystickCounter;
systickDelta = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - previousSystickCounter;
systickDelta += systickCounter + 1;
} else {
systickDelta = systickCounter - previousSystickCounter;
}

/*
* 1000 ms = 1024 ticks
*/
auto correctedDelta = systickDelta / 1024;
auto rest = systickDelta % 1024;
auto correctedDelta = systickDelta / configTICK_RATE_HZ;
// If a second hasn't passed, there is nothing to do
// If the time has been changed, set forceUpdate to trigger internal state updates
if (correctedDelta == 0 && !forceUpdate) {
return;
}
auto rest = systickDelta % configTICK_RATE_HZ;
if (systickCounter >= rest) {
previousSystickCounter = systickCounter - rest;
} else {
previousSystickCounter = 0xffffff - (rest - systickCounter);
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter - 1);
}

currentDateTime += std::chrono::seconds(correctedDelta);
Expand Down
16 changes: 9 additions & 7 deletions src/components/datetime/DateTimeController.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <ctime>
#include <string>
#include "components/settings/Settings.h"
#include <FreeRTOS.h>
#include <semphr.h>

namespace Pinetime {
namespace System {
Expand Down Expand Up @@ -45,8 +47,6 @@ namespace Pinetime {
*/
void SetTimeZone(int8_t timezone, int8_t dst);

void UpdateTime(uint32_t systickCounter);

uint16_t Year() const {
return 1900 + localTime.tm_year;
}
Expand Down Expand Up @@ -124,12 +124,10 @@ namespace Pinetime {
static const char* MonthShortToStringLow(Months month);
static const char* DayOfWeekShortToStringLow(Days day);

std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
}
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime();

std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const {
return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() {
return CurrentDateTime() - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
}

std::chrono::seconds Uptime() const {
Expand All @@ -141,10 +139,14 @@ namespace Pinetime {
std::string FormattedTime();

private:
void UpdateTime(uint32_t systickCounter, bool forceUpdate);

std::tm localTime;
int8_t tzOffset = 0;
int8_t dstOffset = 0;

SemaphoreHandle_t mutex = nullptr;

uint32_t previousSystickCounter = 0;
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
std::chrono::seconds uptime {0};
Expand Down
41 changes: 41 additions & 0 deletions src/components/datetime/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Refactoring needed

## Context

The [PR #2041 - Continuous time updates](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041) highlighted some
limitations in the design of DateTimeController: the granularity of the time returned by `DateTime::CurrentDateTime()`
is limited by the frequency at which SystemTask calls `DateTime::UpdateTime()`, which is currently set to 100ms.

@mark9064 provided more details
in [this comment](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041#issuecomment-2048528967).

The [PR #2041 - Continuous time updates](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041) provided some changes
to `DateTime` controller that improves the granularity of the time returned by `DateTime::CurrentDateTime()`.

However, the review showed that `DateTime` cannot be `const` anymore, even when it's only used to get the current time,
since `DateTime::CurrentDateTime()` changes the internal state of the instance.

We tried to identify alternative implementation that would have maintained the "const correctness" but we eventually
figured that this would lead to a re-design of `DateTime` which was out of scope of the initial PR (Continuous time
updates and always on display).

So we decided to merge this PR #2041 and agree to fix/improve `DateTime` later on.

## What needs to be done?

Improve/redesign `DateTime` so that it

* provides a very granular (ideally down to the millisecond) date and time via `CurrentDateTime()`.
* can be declared/passed as `const` when it's only used to **get** the time.
* limits the use of mutex as much as possible (an ideal implementation would not use any mutex, but this might not be
possible).
* improves the design of `DateTime::Seconds()`, `DateTime::Minutes()`, `DateTime::Hours()`, etc as
explained [in this comment](https://github.com/InfiniTimeOrg/InfiniTime/pull/2054#pullrequestreview-2037033105).

Once this redesign is implemented, all instances/references to `DateTime` should be reviewed and updated to use `const`
where appropriate.

Please check the following PR to get more context about this redesign:

* [#2041 - Continuous time updates by @mark9064](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041)
* [#2054 - Continuous time update - Alternative implementation to #2041 by @JF002](https://github.com/InfiniTimeOrg/InfiniTime/pull/2054)
5 changes: 1 addition & 4 deletions src/displayapp/DisplayApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ void DisplayApp::Start(System::BootErrors error) {
bootError = error;

lvgl.Init();
motorController.Init();

if (error == System::BootErrors::TouchController) {
LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None);
Expand All @@ -142,9 +143,6 @@ void DisplayApp::Process(void* instance) {
NRF_LOG_INFO("displayapp task started!");
app->InitHw();

// Send a dummy notification to unlock the lvgl display driver for the first iteration
xTaskNotifyGive(xTaskGetCurrentTaskHandle());

while (true) {
app->Refresh();
}
Expand All @@ -153,7 +151,6 @@ void DisplayApp::Process(void* instance) {
void DisplayApp::InitHw() {
brightnessController.Init();
ApplyBrightness();
motorController.Init();
lcd.Init();
}

Expand Down
5 changes: 0 additions & 5 deletions src/displayapp/DisplayAppRecovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ void DisplayApp::Process(void* instance) {
auto* app = static_cast<DisplayApp*>(instance);
NRF_LOG_INFO("displayapp task started!");

// Send a dummy notification to unlock the lvgl display driver for the first iteration
xTaskNotifyGive(xTaskGetCurrentTaskHandle());

app->InitHw();
while (true) {
app->Refresh();
Expand Down Expand Up @@ -94,7 +91,6 @@ void DisplayApp::DisplayLogo(uint16_t color) {
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack);
for (int i = 0; i < displayWidth; i++) {
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
ulTaskNotifyTake(pdTRUE, 500);
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
}
}
Expand All @@ -103,7 +99,6 @@ void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) {
const uint8_t barHeight = 20;
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
for (int i = 0; i < barHeight; i++) {
ulTaskNotifyTake(pdTRUE, 500);
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
}
Expand Down
5 changes: 0 additions & 5 deletions src/displayapp/LittleVgl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,6 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) {
void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {
uint16_t y1, y2, width, height = 0;

ulTaskNotifyTake(pdTRUE, 200);
// Notification is still needed (even if there is a mutex on SPI) because of the DataCommand pin
// which cannot be set/clear during a transfer.

if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) {
writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines;
} else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) {
Expand Down Expand Up @@ -219,7 +215,6 @@ void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) {

if (height > 0) {
lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast<const uint8_t*>(color_p), width * height * 2);
ulTaskNotifyTake(pdTRUE, 100);
}

uint16_t pixOffset = width * height;
Expand Down
2 changes: 1 addition & 1 deletion src/displayapp/screens/WatchFaceAnalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace Pinetime {

BatteryIcon batteryIcon;

const Controllers::DateTime& dateTimeController;
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificationManager;
Expand Down
7 changes: 0 additions & 7 deletions src/drivers/Bma421.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,6 @@ Bma421::Values Bma421::Process() {
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);

// 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};
}
Expand Down
4 changes: 2 additions & 2 deletions src/drivers/Spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn {
nrf_gpio_pin_set(pinCsn);
}

bool Spi::Write(const uint8_t* data, size_t size) {
return spiMaster.Write(pinCsn, data, size);
bool Spi::Write(const uint8_t* data, size_t size, const std::function<void()>& preTransactionHook) {
return spiMaster.Write(pinCsn, data, size, preTransactionHook);
}

bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) {
Expand Down
3 changes: 2 additions & 1 deletion src/drivers/Spi.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <functional>
#include "drivers/SpiMaster.h"

namespace Pinetime {
Expand All @@ -14,7 +15,7 @@ namespace Pinetime {
Spi& operator=(Spi&&) = delete;

bool Init();
bool Write(const uint8_t* data, size_t size);
bool Write(const uint8_t* data, size_t size, const std::function<void()>& preTransactionHook);
bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize);
bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize);
void Sleep();
Expand Down
Loading

0 comments on commit a07289b

Please sign in to comment.