mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[ion] Add RTC subsystem
This commit is contained in:
@@ -25,6 +25,7 @@ apps_src += $(addprefix apps/,\
|
||||
backlight_dimming_timer.cpp \
|
||||
battery_timer.cpp \
|
||||
battery_view.cpp \
|
||||
clock_timer.cpp \
|
||||
empty_battery_window.cpp \
|
||||
exam_pop_up_controller.cpp \
|
||||
exam_mode_configuration_official.cpp:+official \
|
||||
|
||||
@@ -31,6 +31,7 @@ AppsContainer::AppsContainer() :
|
||||
m_batteryTimer(),
|
||||
m_suspendTimer(),
|
||||
m_backlightDimmingTimer(),
|
||||
m_clockTimer(ClockTimer(this)),
|
||||
m_homeSnapshot(),
|
||||
m_onBoardingSnapshot(),
|
||||
m_hardwareTestSnapshot(),
|
||||
@@ -304,6 +305,10 @@ void AppsContainer::run() {
|
||||
switchTo(nullptr);
|
||||
}
|
||||
|
||||
bool AppsContainer::updateClock() {
|
||||
return m_window.updateClock();
|
||||
}
|
||||
|
||||
bool AppsContainer::updateBatteryState() {
|
||||
bool batteryLevelUpdated = m_window.updateBatteryLevel();
|
||||
bool pluggedStateUpdated = m_window.updatePluggedState();
|
||||
@@ -409,11 +414,11 @@ Window * AppsContainer::window() {
|
||||
}
|
||||
|
||||
int AppsContainer::numberOfContainerTimers() {
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
Timer * AppsContainer::containerTimerAtIndex(int i) {
|
||||
Timer * timers[3] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer};
|
||||
Timer * timers[4] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_clockTimer};
|
||||
return timers[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "backlight_dimming_timer.h"
|
||||
#include "shared/global_context.h"
|
||||
#include "on_boarding/pop_up_controller.h"
|
||||
#include "clock_timer.h"
|
||||
|
||||
#include <ion/events.h>
|
||||
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
bool dispatchEvent(Ion::Events::Event event) override;
|
||||
bool switchTo(App::Snapshot * snapshot) override;
|
||||
void run() override;
|
||||
bool updateClock();
|
||||
bool updateBatteryState();
|
||||
void refreshPreferences();
|
||||
void reloadTitleBarView();
|
||||
@@ -76,6 +78,7 @@ private:
|
||||
BatteryTimer m_batteryTimer;
|
||||
SuspendTimer m_suspendTimer;
|
||||
BacklightDimmingTimer m_backlightDimmingTimer;
|
||||
ClockTimer m_clockTimer;
|
||||
Home::App::Snapshot m_homeSnapshot;
|
||||
OnBoarding::App::Snapshot m_onBoardingSnapshot;
|
||||
HardwareTest::App::Snapshot m_hardwareTestSnapshot;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
}
|
||||
#include <ion/rtc.h>
|
||||
|
||||
AppsWindow::AppsWindow() :
|
||||
Window(),
|
||||
@@ -19,6 +20,11 @@ bool AppsWindow::updateBatteryLevel() {
|
||||
return m_titleBarView.setChargeState(Ion::Battery::level());
|
||||
}
|
||||
|
||||
bool AppsWindow::updateClock() {
|
||||
Ion::RTC::DateTime dateTime = Ion::RTC::dateTime();
|
||||
return m_titleBarView.setClock(dateTime.tm_hour, dateTime.tm_min);
|
||||
}
|
||||
|
||||
bool AppsWindow::updateIsChargingState() {
|
||||
return m_titleBarView.setIsCharging(Ion::Battery::isCharging());
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ public:
|
||||
AppsWindow();
|
||||
void setTitle(I18n::Message title);
|
||||
bool updateBatteryLevel();
|
||||
bool updateClock();
|
||||
bool updateIsChargingState();
|
||||
bool updatePluggedState();
|
||||
void refreshPreferences();
|
||||
|
||||
12
apps/clock_timer.cpp
Normal file
12
apps/clock_timer.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "clock_timer.h"
|
||||
#include "apps_container.h"
|
||||
|
||||
ClockTimer::ClockTimer(AppsContainer * container) :
|
||||
Timer(1),
|
||||
m_container(container)
|
||||
{
|
||||
}
|
||||
|
||||
bool ClockTimer::fire() {
|
||||
return m_container->updateClock();
|
||||
}
|
||||
16
apps/clock_timer.h
Normal file
16
apps/clock_timer.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef APPS_CLOCK_TIMER_H
|
||||
#define APPS_CLOCK_TIMER_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
class AppsContainer;
|
||||
|
||||
class ClockTimer : public Timer {
|
||||
public:
|
||||
ClockTimer(AppsContainer * container);
|
||||
private:
|
||||
bool fire() override;
|
||||
AppsContainer * m_container;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,8 +10,12 @@ using namespace Poincare;
|
||||
TitleBarView::TitleBarView() :
|
||||
View(),
|
||||
m_titleView(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, Palette::ToolbarText, Palette::Toolbar),
|
||||
m_preferenceView(KDFont::SmallFont, 1.0f, 0.5, Palette::ToolbarText, Palette::Toolbar)
|
||||
m_preferenceView(KDFont::SmallFont, 1.0f, 0.5, Palette::ToolbarText, Palette::Toolbar),
|
||||
m_clockView(KDFont::SmallFont, 0.5f, 0.5f, Palette::ToolbarText, Palette::Toolbar),
|
||||
m_hours(-1),
|
||||
m_mins(-1)
|
||||
{
|
||||
setClock(0, 0);
|
||||
m_examModeIconView.setImage(ImageStore::ExamIcon);
|
||||
}
|
||||
|
||||
@@ -25,6 +29,25 @@ void TitleBarView::setTitle(I18n::Message title) {
|
||||
m_titleView.setMessage(title);
|
||||
}
|
||||
|
||||
bool TitleBarView::setClock(int hours, int mins) {
|
||||
if (m_hours != hours || m_mins != mins) {
|
||||
char buf[6], *ptr = buf;
|
||||
*ptr++ = (hours / 10) + '0';
|
||||
*ptr++ = (hours % 10) + '0';
|
||||
*ptr++ = ':';
|
||||
*ptr++ = (mins / 10) + '0';
|
||||
*ptr++ = (mins % 10) + '0';
|
||||
*ptr = '\0';
|
||||
m_clockView.setText(buf);
|
||||
|
||||
m_hours = hours;
|
||||
m_mins = mins;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TitleBarView::setChargeState(Ion::Battery::Charge chargeState) {
|
||||
return m_batteryView.setChargeState(chargeState);
|
||||
}
|
||||
@@ -42,7 +65,7 @@ bool TitleBarView::setShiftAlphaLockStatus(Ion::Events::ShiftAlphaStatus status)
|
||||
}
|
||||
|
||||
int TitleBarView::numberOfSubviews() const {
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
View * TitleBarView::subviewAtIndex(int index) {
|
||||
@@ -58,6 +81,9 @@ View * TitleBarView::subviewAtIndex(int index) {
|
||||
if (index == 3) {
|
||||
return &m_shiftAlphaLockView;
|
||||
}
|
||||
if (index == 4) {
|
||||
return &m_clockView;
|
||||
}
|
||||
return &m_batteryView;
|
||||
}
|
||||
|
||||
@@ -69,19 +95,21 @@ void TitleBarView::layoutSubviews(bool force) {
|
||||
* translate the frame of the title downwards.*/
|
||||
m_titleView.setFrame(KDRect(0, 2, bounds().width(), bounds().height()-2), force);
|
||||
m_preferenceView.setFrame(KDRect(Metric::TitleBarExternHorizontalMargin, 0, m_preferenceView.minimalSizeForOptimalDisplay().width(), bounds().height()), force);
|
||||
KDSize clockSize = m_clockView.minimalSizeForOptimalDisplay();
|
||||
m_clockView.setFrame(KDRect(bounds().width() - clockSize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- clockSize.height())/2, clockSize), force);
|
||||
KDSize batterySize = m_batteryView.minimalSizeForOptimalDisplay();
|
||||
m_batteryView.setFrame(KDRect(bounds().width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize), force);
|
||||
m_batteryView.setFrame(KDRect(bounds().width() - clockSize.width() - batterySize.width() - Metric::TitleBarExternHorizontalMargin, (bounds().height()- batterySize.height())/2, batterySize), force);
|
||||
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
|
||||
m_examModeIconView.setFrame(KDRect(bounds().width() - batterySize.width() - k_examIconWidth - k_alphaRightMargin - Metric::TitleBarExternHorizontalMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight), force);
|
||||
m_examModeIconView.setFrame(KDRect(bounds().width() - clockSize.width() - batterySize.width() - k_examIconWidth - k_alphaRightMargin - Metric::TitleBarExternHorizontalMargin, (bounds().height() - k_examIconHeight)/2, k_examIconWidth, k_examIconHeight), force);
|
||||
} else {
|
||||
m_examModeIconView.setFrame(KDRectZero, force);
|
||||
}
|
||||
KDSize shiftAlphaLockSize = m_shiftAlphaLockView.minimalSizeForOptimalDisplay();
|
||||
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
|
||||
// The Shift/Alpha frame is shifted when examination mode is active
|
||||
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-k_examIconWidth-Metric::TitleBarExternHorizontalMargin-2*k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
|
||||
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-clockSize.width()-batterySize.width()-k_examIconWidth-Metric::TitleBarExternHorizontalMargin-2*k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
|
||||
} else {
|
||||
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
|
||||
m_shiftAlphaLockView.setFrame(KDRect(bounds().width()-clockSize.width()-batterySize.width()-Metric::TitleBarExternHorizontalMargin-k_alphaRightMargin-shiftAlphaLockSize.width(), (bounds().height()- shiftAlphaLockSize.height())/2, shiftAlphaLockSize), force);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ public:
|
||||
TitleBarView();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setTitle(I18n::Message title);
|
||||
bool setClock(int hours, int mins);
|
||||
bool setChargeState(Ion::Battery::Charge chargeState);
|
||||
bool setIsCharging(bool isCharging);
|
||||
bool setIsPlugged(bool isPlugged);
|
||||
@@ -30,6 +31,9 @@ private:
|
||||
ShiftAlphaLockView m_shiftAlphaLockView;
|
||||
BufferTextView m_preferenceView;
|
||||
ImageView m_examModeIconView;
|
||||
BufferTextView m_clockView;
|
||||
int m_hours;
|
||||
int m_mins;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,7 @@ ion_src += $(addprefix ion/src/shared/, \
|
||||
events_keyboard.cpp \
|
||||
events_modifier.cpp \
|
||||
platform_info.cpp \
|
||||
rtc.cpp \
|
||||
storage.cpp \
|
||||
unicode/utf8_decoder.cpp\
|
||||
unicode/utf8_helper.cpp\
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion/led.h>
|
||||
#include <ion/power.h>
|
||||
#include <ion/rtc.h>
|
||||
#include <ion/storage.h>
|
||||
#include <ion/timing.h>
|
||||
#include <ion/usb.h>
|
||||
|
||||
38
ion/include/ion/rtc.h
Normal file
38
ion/include/ion/rtc.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef ION_RTC_H
|
||||
#define ION_RTC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace RTC {
|
||||
|
||||
struct DateTime {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour; // 0-23
|
||||
int tm_mday; // 1-31
|
||||
int tm_mon; // 1-12
|
||||
int tm_year;
|
||||
int tm_wday; // 0-6, 0 is Monday
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
Disabled = 0,
|
||||
LSI = 1,
|
||||
HSE = 2,
|
||||
} ;
|
||||
|
||||
void setMode(Mode mode);
|
||||
Mode mode();
|
||||
void setDateTime(DateTime dateTime);
|
||||
DateTime dateTime();
|
||||
|
||||
bool parseDate(const char * text, DateTime & target);
|
||||
bool parseTime(const char * text, DateTime & target);
|
||||
void toStringDate(DateTime dateTime, char *text);
|
||||
void toStringTime(DateTime dateTime, char *text);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@ ion_src += $(addprefix ion/src/shared/, \
|
||||
timing.cpp \
|
||||
dummy/backlight.cpp \
|
||||
dummy/battery.cpp \
|
||||
dummy/rtc.cpp \
|
||||
dummy/display.cpp \
|
||||
dummy/events_modifier.cpp \
|
||||
dummy/exam_mode.cpp \
|
||||
|
||||
@@ -121,6 +121,7 @@ void initClocks() {
|
||||
// We're using TIM3 for the LEDs
|
||||
RCC.APB1ENR()->setTIM3EN(true);
|
||||
RCC.APB1ENR()->setPWREN(true);
|
||||
RCC.APB1ENR()->setRTCAPB(true);
|
||||
|
||||
// APB2 bus
|
||||
class RCC::APB2ENR apb2enr(0x00008000); // Reset value
|
||||
|
||||
@@ -251,6 +251,8 @@ void initClocks() {
|
||||
// APB1 bus
|
||||
// We're using TIM3 for the LEDs
|
||||
RCC.APB1ENR()->setTIM3EN(true);
|
||||
RCC.APB1ENR()->setPWREN(true);
|
||||
RCC.APB1ENR()->setRTCAPB(true);
|
||||
|
||||
// APB2 bus
|
||||
class RCC::APB2ENR apb2enr(0); // Reset value
|
||||
|
||||
33
ion/src/device/regs/pwr.h
Normal file
33
ion/src/device/regs/pwr.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef REGS_PWR_H
|
||||
#define REGS_PWR_H
|
||||
|
||||
#include "register.h"
|
||||
|
||||
class PWR {
|
||||
public:
|
||||
class CR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(LPDS, 0);
|
||||
REGS_BOOL_FIELD(PPDS, 1);
|
||||
REGS_BOOL_FIELD(DBP, 8);
|
||||
REGS_BOOL_FIELD(FPDS, 9);
|
||||
};
|
||||
|
||||
class CSR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(BRE, 9);
|
||||
REGS_BOOL_FIELD_R(BRR, 3);
|
||||
};
|
||||
|
||||
constexpr PWR() {};
|
||||
REGS_REGISTER_AT(CR, 0x00);
|
||||
REGS_REGISTER_AT(CSR, 0x04);
|
||||
private:
|
||||
constexpr uint32_t Base() const {
|
||||
return 0x40007000;
|
||||
};
|
||||
};
|
||||
|
||||
constexpr PWR PWR;
|
||||
|
||||
#endif
|
||||
133
ion/src/device/regs/rcc.h
Normal file
133
ion/src/device/regs/rcc.h
Normal file
@@ -0,0 +1,133 @@
|
||||
#ifndef REGS_RCC_H
|
||||
#define REGS_RCC_H
|
||||
|
||||
#include "register.h"
|
||||
|
||||
class RCC {
|
||||
public:
|
||||
class CR : public Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(PLLRDY, 25);
|
||||
REGS_BOOL_FIELD(PLLON, 24);
|
||||
};
|
||||
|
||||
class PLLCFGR : public Register32 {
|
||||
public:
|
||||
REGS_FIELD(PLLM, uint8_t, 5, 0);
|
||||
REGS_FIELD(PLLN, uint16_t, 14, 6);
|
||||
REGS_FIELD(PLLP, uint8_t, 17, 16);
|
||||
enum class PLLSRC {
|
||||
HSI = 0,
|
||||
HSE = 1
|
||||
};
|
||||
void setPLLSRC(PLLSRC s) volatile { setBitRange(22, 22, (uint8_t)s); }
|
||||
REGS_FIELD(PLLQ, uint8_t, 27, 24);
|
||||
REGS_FIELD(PLLR, uint8_t, 30, 28);
|
||||
};
|
||||
|
||||
class CFGR : public Register32 {
|
||||
public:
|
||||
enum class SW {
|
||||
HSI = 0,
|
||||
HSE = 1,
|
||||
PLL = 2
|
||||
};
|
||||
void setSW(SW s) volatile { setBitRange(1, 0, (uint8_t)s); }
|
||||
SW getSWS() volatile { return (SW)getBitRange(3,2); }
|
||||
enum class AHBRatio {
|
||||
One = 0,
|
||||
DivideBy2 = 4,
|
||||
DivideBy4 = 5,
|
||||
DivideBy8 = 6,
|
||||
DivideBy16 = 7
|
||||
};
|
||||
void setPPRE1(AHBRatio r) volatile { setBitRange(12, 10, (uint32_t)r); }
|
||||
};
|
||||
|
||||
class AHB1ENR : public Register32 {
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_BOOL_FIELD(GPIOAEN, 0);
|
||||
REGS_BOOL_FIELD(GPIOBEN, 1);
|
||||
REGS_BOOL_FIELD(GPIOCEN, 2);
|
||||
REGS_BOOL_FIELD(GPIODEN, 3);
|
||||
REGS_BOOL_FIELD(GPIOEEN, 4);
|
||||
REGS_BOOL_FIELD(GPIOFEN, 5);
|
||||
REGS_BOOL_FIELD(GPIOGEN, 6);
|
||||
REGS_BOOL_FIELD(GPIOHEN, 7);
|
||||
REGS_BOOL_FIELD(CRCEN, 12);
|
||||
REGS_BOOL_FIELD(DMA1EN, 21);
|
||||
REGS_BOOL_FIELD(DMA2EN, 22);
|
||||
};
|
||||
|
||||
class AHB2ENR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(RNGEN, 6);
|
||||
};
|
||||
|
||||
class AHB3ENR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(FSMCEN, 0);
|
||||
REGS_BOOL_FIELD(QSPIEN, 1);
|
||||
};
|
||||
|
||||
class APB1ENR : public Register32 {
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_BOOL_FIELD(TIM3EN, 1);
|
||||
REGS_BOOL_FIELD(RTCAPB, 10);
|
||||
REGS_BOOL_FIELD(SPI3EN, 15);
|
||||
REGS_BOOL_FIELD(USART3EN, 18);
|
||||
REGS_BOOL_FIELD(PWREN, 28);
|
||||
};
|
||||
|
||||
class APB2ENR : public Register32 {
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_BOOL_FIELD(TIM1EN, 0);
|
||||
REGS_BOOL_FIELD(USART1EN, 4);
|
||||
REGS_BOOL_FIELD(ADC1EN, 8);
|
||||
REGS_BOOL_FIELD(SDIOEN, 11);
|
||||
REGS_BOOL_FIELD(SYSCFGEN, 14);
|
||||
};
|
||||
|
||||
class BDCR : public Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(BDRST, 16);
|
||||
REGS_BOOL_FIELD(RTCEN, 15);
|
||||
REGS_FIELD(RTCSEL, uint8_t, 9, 8);
|
||||
};
|
||||
|
||||
class CSR : public Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(LSION, 0);
|
||||
REGS_BOOL_FIELD_R(LSIRDY, 1);
|
||||
};
|
||||
|
||||
class DCKCFGR2 : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(CK48MSEL, 27);
|
||||
REGS_BOOL_FIELD(CKSDIOSEL, 28);
|
||||
};
|
||||
|
||||
constexpr RCC() {};
|
||||
REGS_REGISTER_AT(CR, 0x00);
|
||||
REGS_REGISTER_AT(PLLCFGR, 0x04);
|
||||
REGS_REGISTER_AT(CFGR, 0x08);
|
||||
REGS_REGISTER_AT(AHB1ENR, 0x30);
|
||||
REGS_REGISTER_AT(AHB2ENR, 0x34);
|
||||
REGS_REGISTER_AT(AHB3ENR, 0x38);
|
||||
REGS_REGISTER_AT(APB1ENR, 0x40);
|
||||
REGS_REGISTER_AT(APB2ENR, 0x44);
|
||||
REGS_REGISTER_AT(BDCR, 0x70);
|
||||
REGS_REGISTER_AT(CSR, 0x74);
|
||||
REGS_REGISTER_AT(DCKCFGR2, 0x94);
|
||||
private:
|
||||
constexpr uint32_t Base() const {
|
||||
return 0x40023800;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr RCC RCC;
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <ion.h>
|
||||
#include "../drivers/board.h"
|
||||
#include "../drivers/rtc.h"
|
||||
#include "../drivers/reset.h"
|
||||
#include "../drivers/timing.h"
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ ion_device_src += $(addprefix ion/src/device/shared/drivers/, \
|
||||
power.cpp\
|
||||
random.cpp\
|
||||
reset.cpp \
|
||||
rtc.cpp \
|
||||
serial_number.cpp \
|
||||
swd.cpp \
|
||||
timing.cpp \
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <drivers/external_flash.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/led.h>
|
||||
#include <drivers/rtc.h>
|
||||
#include <drivers/swd.h>
|
||||
#include <drivers/timing.h>
|
||||
#include <drivers/usb.h>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <ion/battery.h>
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion/led.h>
|
||||
#include <ion/rtc.h>
|
||||
#include <ion/usb.h>
|
||||
#include <drivers/board.h>
|
||||
#include <drivers/battery.h>
|
||||
@@ -39,7 +40,7 @@ void suspend(bool checkIfOnOffKeyReleased) {
|
||||
isLEDActive = LED::updateColorWithPlugAndCharge() != KDColorBlack;
|
||||
|
||||
// Configure low-power mode
|
||||
if (isLEDActive) {
|
||||
if (isLEDActive || Ion::RTC::mode() == Ion::RTC::Mode::HSE) {
|
||||
Device::Power::sleepConfiguration();
|
||||
} else {
|
||||
Device::Power::stopConfiguration();
|
||||
|
||||
169
ion/src/device/shared/drivers/rtc.cpp
Normal file
169
ion/src/device/shared/drivers/rtc.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <ion/rtc.h>
|
||||
#include <ion/timing.h>
|
||||
#include <drivers/rtc.h>
|
||||
#include <drivers/config/clocks.h>
|
||||
#include "regs/regs.h"
|
||||
|
||||
constexpr int yearEpoch = 2000;
|
||||
|
||||
static int bcdToBinary(int tens, int units) {
|
||||
return tens * 10 + units;
|
||||
}
|
||||
|
||||
static int dayOfWeek(int y, int m, int d)
|
||||
{
|
||||
const static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||
y -= m < 3;
|
||||
return ((y + y/4 - y/100 + y/400 + t[m-1] + (d-1)) % 7) + 1;
|
||||
}
|
||||
|
||||
// Public Ion methods
|
||||
|
||||
namespace Ion {
|
||||
namespace RTC {
|
||||
|
||||
static void rtcSetWriteEnable(bool status) {
|
||||
if (status) {
|
||||
Device::Regs::PWR.CR()->setDBP(true);
|
||||
Device::Regs::RTC.WPR()->setKEY(0xCA);
|
||||
Device::Regs::RTC.WPR()->setKEY(0x53);
|
||||
}
|
||||
else {
|
||||
Device::Regs::RTC.WPR()->setKEY(0xFF);
|
||||
Device::Regs::PWR.CR()->setDBP(false);
|
||||
}
|
||||
}
|
||||
|
||||
void setMode(Mode mode) {
|
||||
DateTime prevDateTime = dateTime();
|
||||
Ion::Device::RTC::init(mode != Mode::Disabled, mode == Mode::HSE);
|
||||
setDateTime(prevDateTime);
|
||||
}
|
||||
|
||||
Mode mode() {
|
||||
if (!Ion::Device::Regs::RCC.BDCR()->getRTCEN()) {
|
||||
return Mode::Disabled;
|
||||
}
|
||||
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() == 0x3) {
|
||||
return Mode::HSE;
|
||||
}
|
||||
return Mode::LSI;
|
||||
}
|
||||
|
||||
DateTime dateTime() {
|
||||
if (mode() == Mode::Disabled) {
|
||||
return DateTime { 0, 0, 0, 1, 1, 2000, 6 };
|
||||
}
|
||||
|
||||
Device::Regs::RTC.ISR()->setRSF(false);
|
||||
for (int cpt = 0; cpt < 100; cpt++) {
|
||||
if (Device::Regs::RTC.ISR()->getRSF() == true)
|
||||
break;
|
||||
Ion::Timing::usleep(5);
|
||||
}
|
||||
|
||||
return DateTime {
|
||||
bcdToBinary(Device::Regs::RTC.TR()->getST(), Device::Regs::RTC.TR()->getSU()),
|
||||
bcdToBinary(Device::Regs::RTC.TR()->getMNT(), Device::Regs::RTC.TR()->getMNU()),
|
||||
bcdToBinary(Device::Regs::RTC.TR()->getHT(), Device::Regs::RTC.TR()->getHU()),
|
||||
bcdToBinary(Device::Regs::RTC.DR()->getDT(), Device::Regs::RTC.DR()->getDU()),
|
||||
bcdToBinary(Device::Regs::RTC.DR()->getMT(), Device::Regs::RTC.DR()->getMU()),
|
||||
bcdToBinary(Device::Regs::RTC.DR()->getYT(), Device::Regs::RTC.DR()->getYU()) + yearEpoch,
|
||||
Device::Regs::RTC.DR()->getWDU() - 1,
|
||||
};
|
||||
}
|
||||
|
||||
void setDateTime(DateTime dateTime) {
|
||||
if (mode() == Mode::Disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
rtcSetWriteEnable(true);
|
||||
|
||||
Device::Regs::RTC.ISR()->setINIT(true);
|
||||
for (int cpt = 0; cpt < 100; cpt++) {
|
||||
if (Device::Regs::RTC.ISR()->getINITF() == true)
|
||||
break;
|
||||
Ion::Timing::usleep(10);
|
||||
}
|
||||
|
||||
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() == 0x2) {
|
||||
// LSI is ~32 kHz
|
||||
Device::Regs::RTC.PRER()->setPREDIV_S(249);
|
||||
Device::Regs::RTC.PRER()->setPREDIV_A(127);
|
||||
}
|
||||
else {
|
||||
// HSE's divided down to 1 MHz
|
||||
Device::Regs::RTC.PRER()->setPREDIV_S(7999);
|
||||
Device::Regs::RTC.PRER()->setPREDIV_A(124);
|
||||
}
|
||||
Device::Regs::RTC.CR()->setFMT(false);
|
||||
|
||||
class Device::Regs::RTC::TR tr(0);
|
||||
tr.setPM(false);
|
||||
tr.setHT(dateTime.tm_hour / 10);
|
||||
tr.setHU(dateTime.tm_hour % 10);
|
||||
tr.setMNT(dateTime.tm_min / 10);
|
||||
tr.setMNU(dateTime.tm_min % 10);
|
||||
tr.setST(dateTime.tm_sec / 10);
|
||||
tr.setSU(dateTime.tm_sec % 10);
|
||||
Device::Regs::RTC.TR()->set(tr);
|
||||
|
||||
class Device::Regs::RTC::DR dr(0);
|
||||
dr.setYT((dateTime.tm_year - yearEpoch) / 10);
|
||||
dr.setYU((dateTime.tm_year - yearEpoch) % 10);
|
||||
dr.setWDU(dayOfWeek(dateTime.tm_year, dateTime.tm_mon, dateTime.tm_mday));
|
||||
dr.setMT(dateTime.tm_mon / 10);
|
||||
dr.setMU(dateTime.tm_mon % 10);
|
||||
dr.setDT(dateTime.tm_mday / 10);
|
||||
dr.setDU(dateTime.tm_mday % 10);
|
||||
Device::Regs::RTC.DR()->set(dr);
|
||||
|
||||
Device::Regs::RTC.ISR()->setINIT(true);
|
||||
rtcSetWriteEnable(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Private Ion::Device::RTC methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace RTC {
|
||||
|
||||
void init(bool enable, bool useHighPrecisionClock) {
|
||||
const int rtcSource = useHighPrecisionClock ? 0x3 : 0x2;
|
||||
|
||||
Ion::Device::Regs::RCC.CFGR()->setRTCPRE(Ion::Device::Clocks::Config::HSE);
|
||||
|
||||
Ion::RTC::rtcSetWriteEnable(true);
|
||||
|
||||
if (Ion::Device::Regs::RCC.BDCR()->getRTCSEL() != rtcSource) {
|
||||
// Initialize backup domain for RTC
|
||||
Ion::Device::Regs::RCC.BDCR()->setBDRST(true);
|
||||
Ion::Timing::usleep(250);
|
||||
Ion::Device::Regs::RCC.BDCR()->setBDRST(false);
|
||||
Ion::Timing::usleep(250);
|
||||
|
||||
Ion::RTC::rtcSetWriteEnable(true);
|
||||
}
|
||||
|
||||
Ion::Device::Regs::RCC.BDCR()->setRTCSEL(rtcSource);
|
||||
Ion::Device::Regs::RCC.BDCR()->setRTCEN(enable);
|
||||
|
||||
// Enable/disable LSI clock
|
||||
if (enable && useHighPrecisionClock) {
|
||||
Ion::Device::Regs::RCC.CSR()->setLSION(false);
|
||||
}
|
||||
else {
|
||||
Ion::Device::Regs::RCC.CSR()->setLSION(true);
|
||||
while (Ion::Device::Regs::RCC.CSR()->getLSIRDY() != true);
|
||||
}
|
||||
|
||||
Ion::RTC::rtcSetWriteEnable(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
16
ion/src/device/shared/drivers/rtc.h
Normal file
16
ion/src/device/shared/drivers/rtc.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef ION_DEVICE_RTC_H
|
||||
#define ION_DEVICE_RTC_H
|
||||
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace RTC {
|
||||
|
||||
void init(bool enabled, bool useHighPrecisionClock);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
REGS_BOOL_FIELD(LPDS, 0);
|
||||
REGS_BOOL_FIELD(PPDS, 1);
|
||||
REGS_BOOL_FIELD(CSBF, 3);
|
||||
REGS_BOOL_FIELD(DBP, 8);
|
||||
REGS_BOOL_FIELD(FPDS, 9);
|
||||
REGS_BOOL_FIELD(LPUDS, 10); // Called LPLVDS in N0100
|
||||
REGS_BOOL_FIELD(MRUDS, 11); // Called MRLVDS in N100
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
public:
|
||||
REGS_BOOL_FIELD_R(WUIF, 0);
|
||||
REGS_BOOL_FIELD_R(SBF, 1);
|
||||
REGS_BOOL_FIELD_R(BRR, 3);
|
||||
REGS_BOOL_FIELD_W(EIWUP, 8);
|
||||
REGS_BOOL_FIELD_W(BRE, 9);
|
||||
REGS_BOOL_FIELD_R(VOSRDY, 14);
|
||||
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
};
|
||||
void setPPRE1(APBPrescaler r) volatile { setBitRange(12, 10, (uint32_t)r); }
|
||||
void setPPRE2(APBPrescaler r) volatile { setBitRange(15, 13, (uint32_t)r); }
|
||||
REGS_FIELD(RTCPRE, uint8_t, 20, 16);
|
||||
};
|
||||
|
||||
class AHB3RSTR : Register32 {
|
||||
@@ -111,6 +112,7 @@ public:
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_BOOL_FIELD(TIM3EN, 1);
|
||||
REGS_BOOL_FIELD(RTCAPB, 10);
|
||||
REGS_BOOL_FIELD(SPI3EN, 15);
|
||||
REGS_BOOL_FIELD(USART3EN, 18);
|
||||
REGS_BOOL_FIELD(PWREN, 28);
|
||||
@@ -264,6 +266,19 @@ public:
|
||||
REGS_BOOL_FIELD(SSCGEN, 31);
|
||||
};
|
||||
|
||||
class BDCR : public Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(BDRST, 16);
|
||||
REGS_BOOL_FIELD(RTCEN, 15);
|
||||
REGS_FIELD(RTCSEL, uint8_t, 9, 8);
|
||||
};
|
||||
|
||||
class CSR : public Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(LSION, 0);
|
||||
REGS_BOOL_FIELD_R(LSIRDY, 1);
|
||||
};
|
||||
|
||||
class DCKCFGR2 : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(CK48MSEL, 27);
|
||||
@@ -285,6 +300,8 @@ public:
|
||||
REGS_REGISTER_AT(AHB3LPENR, 0x58);
|
||||
REGS_REGISTER_AT(APB1LPENR, 0x60);
|
||||
REGS_REGISTER_AT(APB2LPENR, 0x64);
|
||||
REGS_REGISTER_AT(BDCR, 0x70);
|
||||
REGS_REGISTER_AT(CSR, 0x74);
|
||||
REGS_REGISTER_AT(SSCGR, 0x80);
|
||||
REGS_REGISTER_AT(DCKCFGR2, 0x94);
|
||||
private:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "rng.h"
|
||||
#include "otg.h"
|
||||
#include "quadspi.h"
|
||||
#include "rtc.h"
|
||||
#include "sdio.h"
|
||||
#include "spi.h"
|
||||
#include "syscfg.h"
|
||||
|
||||
99
ion/src/device/shared/regs/rtc.h
Normal file
99
ion/src/device/shared/regs/rtc.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef REGS_RTC_H
|
||||
#define REGS_RTC_H
|
||||
|
||||
#include "register.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
namespace Regs {
|
||||
|
||||
class RTC {
|
||||
public:
|
||||
class TR : public Register32 {
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_BOOL_FIELD(PM, 22);
|
||||
REGS_FIELD(HT, uint8_t, 21, 20);
|
||||
REGS_FIELD(HU, uint8_t, 19, 16);
|
||||
REGS_FIELD(MNT, uint8_t, 14, 12);
|
||||
REGS_FIELD(MNU, uint8_t, 11, 8);
|
||||
REGS_FIELD(ST, uint8_t, 6, 4);
|
||||
REGS_FIELD(SU, uint8_t, 3, 0);
|
||||
};
|
||||
|
||||
class DR : public Register32 {
|
||||
public:
|
||||
using Register32::Register32;
|
||||
REGS_FIELD(YT, uint8_t, 23, 20);
|
||||
REGS_FIELD(YU, uint8_t, 19, 16);
|
||||
REGS_FIELD(WDU, uint8_t, 15, 13);
|
||||
REGS_FIELD(MT, uint8_t, 12, 12);
|
||||
REGS_FIELD(MU, uint8_t, 11, 8);
|
||||
REGS_FIELD(DT, uint8_t, 5, 4);
|
||||
REGS_FIELD(DU, uint8_t, 3, 0);
|
||||
};
|
||||
|
||||
class CR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(COE, 23);
|
||||
REGS_FIELD(OSEL, uint8_t, 22, 21);
|
||||
REGS_BOOL_FIELD(POL, 20);
|
||||
REGS_BOOL_FIELD(COSEL, 19);
|
||||
REGS_BOOL_FIELD(BKP, 18);
|
||||
REGS_BOOL_FIELD_W(SUB1H, 17);
|
||||
REGS_BOOL_FIELD_W(ADD1H, 16);
|
||||
REGS_BOOL_FIELD(TSIE, 15);
|
||||
REGS_BOOL_FIELD(WUTIE, 14);
|
||||
REGS_BOOL_FIELD(ALRBIE, 13);
|
||||
REGS_BOOL_FIELD(ALRAIE, 12);
|
||||
REGS_BOOL_FIELD(TSE, 11);
|
||||
REGS_BOOL_FIELD(WUTE, 10);
|
||||
REGS_BOOL_FIELD(ALRBE, 9);
|
||||
REGS_BOOL_FIELD(ALRAE, 8);
|
||||
REGS_BOOL_FIELD(DCE, 7);
|
||||
REGS_BOOL_FIELD(FMT, 6);
|
||||
REGS_BOOL_FIELD(BYPSHAD, 5);
|
||||
REGS_BOOL_FIELD(REFCKON, 4);
|
||||
REGS_BOOL_FIELD(TSEDGE, 3);
|
||||
REGS_FIELD(WUCKSEL, uint8_t, 2, 0);
|
||||
};
|
||||
|
||||
class ISR : Register32 {
|
||||
public:
|
||||
REGS_BOOL_FIELD(INIT, 7);
|
||||
REGS_BOOL_FIELD_R(INITF, 6);
|
||||
REGS_BOOL_FIELD(RSF, 5);
|
||||
REGS_BOOL_FIELD_R(INITS, 4);
|
||||
};
|
||||
|
||||
class PRER : Register32 {
|
||||
public:
|
||||
REGS_FIELD(PREDIV_A, uint8_t, 22, 16);
|
||||
REGS_FIELD(PREDIV_S, uint16_t, 14, 0);
|
||||
};
|
||||
|
||||
class WPR : Register32 {
|
||||
public:
|
||||
REGS_FIELD_W(KEY, uint8_t, 7, 0);
|
||||
};
|
||||
|
||||
constexpr RTC() {}
|
||||
REGS_REGISTER_AT(TR, 0x00);
|
||||
REGS_REGISTER_AT(DR, 0x04);
|
||||
REGS_REGISTER_AT(CR, 0x08);
|
||||
REGS_REGISTER_AT(ISR, 0x0C);
|
||||
REGS_REGISTER_AT(PRER, 0x10);
|
||||
REGS_REGISTER_AT(WPR, 0x24);
|
||||
private:
|
||||
constexpr uint32_t Base() const {
|
||||
return 0x40002800;
|
||||
};
|
||||
};
|
||||
|
||||
constexpr RTC RTC;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
18
ion/src/shared/dummy/rtc.cpp
Normal file
18
ion/src/shared/dummy/rtc.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <ion/rtc.h>
|
||||
|
||||
static Ion::RTC::Mode s_mode = Ion::RTC::Mode::HSE;
|
||||
|
||||
void Ion::RTC::setMode(Ion::RTC::Mode mode) {
|
||||
s_mode = mode;
|
||||
}
|
||||
|
||||
Ion::RTC::Mode Ion::RTC::mode() {
|
||||
return s_mode;
|
||||
}
|
||||
|
||||
void Ion::RTC::setDateTime(Ion::RTC::DateTime dateTime) {
|
||||
}
|
||||
|
||||
Ion::RTC::DateTime Ion::RTC::dateTime() {
|
||||
return Ion::RTC::DateTime { 0, 0, 0, 1, 1, 2000, 6 };
|
||||
}
|
||||
89
ion/src/shared/rtc.cpp
Normal file
89
ion/src/shared/rtc.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <ion/rtc.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace RTC {
|
||||
|
||||
static bool consumeDigit(char text, int & target)
|
||||
{
|
||||
if (text < '0' || text > '9') {
|
||||
return false;
|
||||
}
|
||||
target = target * 10 + (text - '0');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseDate(const char * text, DateTime & target)
|
||||
{
|
||||
target.tm_mday = 0;
|
||||
target.tm_mon = 0;
|
||||
target.tm_year = 0;
|
||||
|
||||
if (!consumeDigit(*text++, target.tm_mday)) return false;
|
||||
if (*text != '/') {
|
||||
if (!consumeDigit(*text++, target.tm_mday)) return false;
|
||||
}
|
||||
if (*text++ != '/') return false;
|
||||
if (!consumeDigit(*text++, target.tm_mon)) return false;
|
||||
if (*text != '/') {
|
||||
if (!consumeDigit(*text++, target.tm_mon)) return false;
|
||||
}
|
||||
if (*text++ != '/') return false;
|
||||
if (!consumeDigit(*text++, target.tm_year)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_year)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_year)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_year)) return false;
|
||||
if (*text++ != '\0') return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseTime(const char * text, DateTime & target)
|
||||
{
|
||||
target.tm_sec = 0;
|
||||
target.tm_min = 0;
|
||||
target.tm_hour = 0;
|
||||
|
||||
if (!consumeDigit(*text++, target.tm_hour)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_hour)) return false;
|
||||
if (*text++ != ':') return false;
|
||||
if (!consumeDigit(*text++, target.tm_min)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_min)) return false;
|
||||
if (*text == '\0') return true;
|
||||
if (*text++ != ':') return false;
|
||||
if (!consumeDigit(*text++, target.tm_sec)) return false;
|
||||
if (!consumeDigit(*text++, target.tm_sec)) return false;
|
||||
if (*text++ != '\0') return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void toStringDate(DateTime dateTime, char *text)
|
||||
{
|
||||
*text++ = ((dateTime.tm_mday / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_mday / 1) % 10) + '0';
|
||||
*text++ = '/';
|
||||
*text++ = ((dateTime.tm_mon / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_mon / 1) % 10) + '0';
|
||||
*text++ = '/';
|
||||
*text++ = ((dateTime.tm_year / 1000) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_year / 100) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_year / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_year / 1) % 10) + '0';
|
||||
*text++ = '\0';
|
||||
}
|
||||
|
||||
void toStringTime(DateTime dateTime, char *text)
|
||||
{
|
||||
*text++ = ((dateTime.tm_hour / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_hour / 1) % 10) + '0';
|
||||
*text++ = ':';
|
||||
*text++ = ((dateTime.tm_min / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_min / 1) % 10) + '0';
|
||||
*text++ = ':';
|
||||
*text++ = ((dateTime.tm_sec / 10) % 10) + '0';
|
||||
*text++ = ((dateTime.tm_sec / 1) % 10) + '0';
|
||||
*text++ = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \
|
||||
dummy/stack.cpp \
|
||||
dummy/usb.cpp \
|
||||
console_stdio.cpp:-consoledisplay \
|
||||
rtc.cpp \
|
||||
crc32.cpp \
|
||||
display.cpp:-headless \
|
||||
events_keyboard.cpp:-headless \
|
||||
|
||||
32
ion/src/simulator/shared/rtc.cpp
Normal file
32
ion/src/simulator/shared/rtc.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <ion/rtc.h>
|
||||
#include <time.h>
|
||||
#include <cstdio>
|
||||
|
||||
static Ion::RTC::Mode s_mode = Ion::RTC::Mode::HSE;
|
||||
|
||||
void Ion::RTC::setMode(Ion::RTC::Mode mode) {
|
||||
s_mode = mode;
|
||||
}
|
||||
|
||||
Ion::RTC::Mode Ion::RTC::mode() {
|
||||
return s_mode;
|
||||
}
|
||||
|
||||
void Ion::RTC::setDateTime(Ion::RTC::DateTime dateTime) {
|
||||
printf("Ion::RTC::setDateTime(%02d:%02d:%02d %02d/%02d/%04d)\n", dateTime.tm_hour, dateTime.tm_min, dateTime.tm_sec, dateTime.tm_mday, dateTime.tm_mon, dateTime.tm_year);
|
||||
}
|
||||
|
||||
Ion::RTC::DateTime Ion::RTC::dateTime() {
|
||||
time_t localTime = time(nullptr);
|
||||
struct tm *localTm = localtime(&localTime);
|
||||
|
||||
return DateTime {
|
||||
localTm->tm_sec,
|
||||
localTm->tm_min,
|
||||
localTm->tm_hour,
|
||||
localTm->tm_mday,
|
||||
localTm->tm_mon + 1,
|
||||
localTm->tm_year + 1900,
|
||||
localTm->tm_wday != 0 ? localTm->tm_wday - 1 : 6,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user