375 lines
9.0 KiB
C
375 lines
9.0 KiB
C
//
|
|
// Created by cfif on 17.11.22.
|
|
//
|
|
#include "RtcFC7240.h"
|
|
#include <SystemDelayInterface.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include "fc7xxx_driver_csc.h"
|
|
#include "fc7xxx_driver_scg.h"
|
|
#include "fc7xxx_driver_rtc.h"
|
|
|
|
#define SECONDS_DAY 86400UL
|
|
#define SECONDS_HOUR 3600UL
|
|
#define SECONDS_MINUTE 60UL
|
|
#define MINUTES_HOUR 60UL
|
|
#define HOURS_DAY 24UL
|
|
#define DAYS_LEAP_YEAR 366UL
|
|
#define DAYS_COM_YEAR 365UL
|
|
#define START_YEAR 1970UL
|
|
#define END_YEAR 2099UL
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t u16Year; /**< Year */
|
|
uint8_t u8Month; /**< Month */
|
|
uint8_t u8Day; /**< Day */
|
|
uint8_t u8Hour; /**< Hour */
|
|
uint8_t u8Minute; /**< Minute */
|
|
uint8_t u8Second; /**< Second */
|
|
} RTC_TimeDate;
|
|
|
|
/* Table of month length (in days) for the Common-year*/
|
|
static const uint8_t ComYear[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
|
|
|
|
/* Table of month length (in days) for the Leap-year*/
|
|
static const uint8_t LeapYear[] = {0U, 31U, 29U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
|
|
|
|
|
|
static bool RTC_IsLeapYear(uint16_t u16Year)
|
|
{
|
|
bool bYearLeap = false;
|
|
|
|
if ((u16Year % 4U) > 0U)
|
|
{
|
|
bYearLeap = false;
|
|
}
|
|
else if ((u16Year % 100U) > 0U)
|
|
{
|
|
bYearLeap = true;
|
|
}
|
|
else if ((u16Year % 400U) > 0U)
|
|
{
|
|
bYearLeap = false;
|
|
}
|
|
else
|
|
{
|
|
bYearLeap = true;
|
|
}
|
|
|
|
/* Return the exit code */
|
|
return bYearLeap;
|
|
}
|
|
|
|
static bool RTC_CheckTimeDate(const RTC_TimeDate * const pTimeDate)
|
|
{
|
|
bool bCheckReturn = true;
|
|
const uint8_t * pMonth;
|
|
pMonth = RTC_IsLeapYear(pTimeDate->u16Year) ? LeapYear : ComYear;
|
|
|
|
if (pTimeDate->u16Year < START_YEAR || pTimeDate->u16Year > END_YEAR
|
|
|| pTimeDate->u8Month < 1U || pTimeDate->u8Month > 12U
|
|
|| pTimeDate->u8Day < 1U || pTimeDate->u8Day > pMonth[pTimeDate->u8Month]
|
|
|| pTimeDate->u8Hour >= 24
|
|
|| pTimeDate->u8Minute >= 60
|
|
|| pTimeDate->u8Second >= 60)
|
|
{
|
|
bCheckReturn = false;
|
|
}
|
|
return bCheckReturn;
|
|
}
|
|
|
|
static void RTC_TimeDate_To_Second(RTC_TimeDate * const pTimeDate, uint32_t u32Second)
|
|
{
|
|
uint32_t u32CountDays;
|
|
uint32_t u32TempCount;
|
|
uint32_t u32TempDays;
|
|
|
|
u32CountDays = u32Second / SECONDS_DAY;
|
|
u32TempCount = u32Second % SECONDS_DAY;
|
|
|
|
pTimeDate->u8Hour = (uint8_t)(u32TempCount / SECONDS_HOUR);
|
|
u32TempCount = u32TempCount % SECONDS_HOUR;
|
|
|
|
pTimeDate->u8Minute = (uint8_t)(u32TempCount / SECONDS_MINUTE);
|
|
pTimeDate->u8Second = (uint8_t)(u32TempCount % SECONDS_MINUTE);
|
|
|
|
pTimeDate->u16Year = (uint16_t)START_YEAR;
|
|
|
|
u32TempDays = DAYS_COM_YEAR;
|
|
while (u32CountDays >= u32TempDays)
|
|
{
|
|
pTimeDate->u16Year++;
|
|
u32CountDays -= u32TempDays;
|
|
u32TempDays = (RTC_IsLeapYear(pTimeDate->u16Year)) ? DAYS_LEAP_YEAR : DAYS_COM_YEAR;
|
|
}
|
|
|
|
u32TempDays += 1;
|
|
|
|
for (uint8_t u8TempMonth = 1; u8TempMonth <= 12; u8TempMonth++)
|
|
{
|
|
u32TempCount = (RTC_IsLeapYear(pTimeDate->u16Year)) ? (uint32_t)LeapYear[u8TempMonth] : (uint32_t)ComYear[u8TempMonth];
|
|
if (u32TempDays <= u32TempCount)
|
|
{
|
|
pTimeDate->u8Month = (uint8_t)u8TempMonth;
|
|
pTimeDate->u8Day = (uint8_t)u32TempDays;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
u32TempDays -= u32TempCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32_t RTC_Second_To_TimeDate(const RTC_TimeDate * const pTimeDate)
|
|
{
|
|
uint32_t u32Second;
|
|
|
|
uint32_t u32TempDay;
|
|
|
|
u32Second = (pTimeDate->u16Year - START_YEAR) * SECONDS_DAY * DAYS_COM_YEAR;
|
|
|
|
for (uint32_t u32TempYear = START_YEAR; u32TempYear < pTimeDate->u16Year; u32TempYear++)
|
|
{
|
|
if (RTC_IsLeapYear((uint16_t)u32TempYear))
|
|
{
|
|
u32Second += SECONDS_DAY;
|
|
}
|
|
}
|
|
|
|
for (uint8_t u8TempMonth = 1; u8TempMonth < pTimeDate->u8Month; u8TempMonth++)
|
|
{
|
|
u32TempDay = (RTC_IsLeapYear(pTimeDate->u16Year)) ? (uint32_t)LeapYear[u8TempMonth] : (uint32_t)ComYear[u8TempMonth];
|
|
u32Second += (u32TempDay * SECONDS_DAY);
|
|
}
|
|
|
|
u32Second += ((uint32_t)((pTimeDate->u8Day - 1U) * SECONDS_DAY) + \
|
|
pTimeDate->u8Hour * SECONDS_HOUR + \
|
|
pTimeDate->u8Minute * SECONDS_MINUTE + \
|
|
pTimeDate->u8Second);
|
|
|
|
return u32Second;
|
|
}
|
|
|
|
/**
|
|
* @brief Set time and date
|
|
*
|
|
* @param pRtcHandle the RTC instance
|
|
* @param pTimeDate the structure of time and date
|
|
*/
|
|
static void RTC_SetTimeDate(const RTC_TimeDate *const pTimeDate) {
|
|
uint32_t u32Second;
|
|
|
|
if (true == RTC_CheckTimeDate(pTimeDate)) {
|
|
u32Second = RTC_Second_To_TimeDate(pTimeDate);
|
|
RTC_SetSecondCounterValue(u32Second);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Get time and date
|
|
*
|
|
* @param pRtcHandle the RTC instance
|
|
* @param pTimeDate the structure of time and date
|
|
*/
|
|
void RTC_GetTimeDate(RTC_TimeDate * const pTimeDate)
|
|
{
|
|
uint32_t u32Second;
|
|
|
|
u32Second = RTC_GetTime();
|
|
RTC_TimeDate_To_Second(pTimeDate, u32Second);
|
|
}
|
|
|
|
tRtcFlagchip vRtcInit() {
|
|
tRtcFlagchip rtcFlagchip;
|
|
RtcFlagchip_Init(&rtcFlagchip);
|
|
return rtcFlagchip;
|
|
}
|
|
|
|
void RtcFlagchip_Init(tRtcFlagchip *env) {
|
|
|
|
// enable SIRC32K clock source
|
|
SCG_Sirc32kType tSIRC32KStruct =
|
|
{
|
|
.bLock = true
|
|
};
|
|
SCG_EnableSIRC32K(&tSIRC32KStruct);
|
|
// set RTC clock source is SIRC32K clock
|
|
CSC0_AONCLKSRType tAONCLKStruct;
|
|
tAONCLKStruct.eRtcSel = CSC0_RTC_SIRC32K_CLK;
|
|
tAONCLKStruct.eAon32KSel = CSC0_AON32K_SIRCDIV_32K_CLK;
|
|
tAONCLKStruct.eAonSel = CSC0_AON_SIRCDIV_128K_CLK;
|
|
CSC0_SetAonClkSrc(&tAONCLKStruct, true);
|
|
|
|
|
|
RTC_InitType tInitStruct = {0};
|
|
tInitStruct.eSecIntAndClkoutFreq = RTC_FREQ_1HZ; // set interrupt frequency to 1HZ
|
|
RTC_Init(&tInitStruct);
|
|
|
|
RTC_Start();
|
|
|
|
#ifdef ACCESS_RTC
|
|
|
|
*env = (tRtcFlagchip) {
|
|
.access = osMutexNew(NULL)
|
|
};
|
|
|
|
#else
|
|
*env = (tRtcFlagchip) {
|
|
|
|
};
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
static uint16_t vRtcSet(tRtcFlagchip *env, time_t *timestamp) {
|
|
struct tm dateTime;
|
|
|
|
RTC_TimeDate tTimeDate;
|
|
|
|
localtime_r(timestamp, &dateTime);
|
|
|
|
tTimeDate.u16Year = dateTime.tm_year + 1900;
|
|
tTimeDate.u8Month = dateTime.tm_mon + 1;
|
|
tTimeDate.u8Day = dateTime.tm_mday;
|
|
tTimeDate.u8Hour = dateTime.tm_hour;
|
|
tTimeDate.u8Minute = dateTime.tm_min;
|
|
tTimeDate.u8Second = dateTime.tm_sec;
|
|
|
|
#ifdef ACCESS_RTC
|
|
if (osMutexAcquire(env->access, 1000) == osOK) {
|
|
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
|
|
osMutexRelease(env->access);
|
|
} else {
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
}
|
|
#else
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
#endif
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint16_t vRtcSetTM(tRtcFlagchip *env, struct tm *timestampTM) {
|
|
|
|
RTC_TimeDate tTimeDate;
|
|
|
|
tTimeDate.u16Year = timestampTM->tm_year + 1900;
|
|
tTimeDate.u8Month = timestampTM->tm_mon + 1;
|
|
tTimeDate.u8Day = timestampTM->tm_mday;
|
|
tTimeDate.u8Hour = timestampTM->tm_hour;
|
|
tTimeDate.u8Minute = timestampTM->tm_min;
|
|
tTimeDate.u8Second = timestampTM->tm_sec;
|
|
|
|
#ifdef ACCESS_RTC
|
|
if (osMutexAcquire(env->access, 1000) == osOK) {
|
|
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
|
|
osMutexRelease(env->access);
|
|
} else {
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
}
|
|
#else
|
|
RTC_SetTimeDate(&tTimeDate);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void v_RtcGet(time_t *timestamp) {
|
|
|
|
RTC_TimeDate tTimeDate;
|
|
|
|
RTC_GetTimeDate(&tTimeDate);
|
|
|
|
struct tm dateTime;
|
|
|
|
memset(&dateTime, 0, sizeof(dateTime));
|
|
|
|
dateTime.tm_year = tTimeDate.u16Year - 1900;
|
|
dateTime.tm_mon = tTimeDate.u8Month - 1;
|
|
dateTime.tm_mday = tTimeDate.u8Day;
|
|
dateTime.tm_hour = tTimeDate.u8Hour;
|
|
dateTime.tm_min = tTimeDate.u8Minute;
|
|
dateTime.tm_sec = tTimeDate.u8Second;
|
|
|
|
*timestamp = mktime(&dateTime);
|
|
*timestamp &= 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
static uint16_t vRtcGet(tRtcFlagchip *env, time_t *timestamp) {
|
|
|
|
|
|
#ifdef ACCESS_RTC
|
|
if (osMutexAcquire(env->access, 1000) == osOK) {
|
|
memset(timestamp, 0, sizeof(time_t));
|
|
v_RtcGet(timestamp);
|
|
osMutexRelease(env->access);
|
|
} else {
|
|
v_RtcGet(timestamp);
|
|
}
|
|
#else
|
|
|
|
v_RtcGet(timestamp);
|
|
|
|
#endif
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void v_RtcGetTM(struct tm *timestampTM) {
|
|
|
|
RTC_TimeDate tTimeDate;
|
|
|
|
RTC_GetTimeDate(&tTimeDate);
|
|
|
|
|
|
memset(timestampTM, 0, sizeof(struct tm));
|
|
|
|
timestampTM->tm_year = tTimeDate.u16Year - 1900;
|
|
timestampTM->tm_mon = tTimeDate.u8Month - 1;
|
|
timestampTM->tm_mday = tTimeDate.u8Day;
|
|
timestampTM->tm_hour = tTimeDate.u8Hour;
|
|
timestampTM->tm_min = tTimeDate.u8Minute;
|
|
timestampTM->tm_sec = tTimeDate.u8Second;
|
|
|
|
}
|
|
|
|
static uint16_t vRtcGetTM(tRtcFlagchip *env, struct tm *timestampTM) {
|
|
|
|
#ifdef ACCESS_RTC
|
|
if (osMutexAcquire(env->access, 1000) == osOK) {
|
|
|
|
v_RtcGetTM(timestampTM);
|
|
|
|
osMutexRelease(env->access);
|
|
} else {
|
|
v_RtcGetTM(timestampTM);
|
|
}
|
|
#else
|
|
|
|
v_RtcGetTM(timestampTM);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
tRtcIO RtcFlagchip_GetIo(tRtcFlagchip *env) {
|
|
tRtcIO io = {
|
|
.env = env,
|
|
.get = (RtcIOTransaction) vRtcGet,
|
|
.set = (RtcIOTransaction) vRtcSet,
|
|
.getTM = (RtcIOTransactionTM) vRtcGetTM,
|
|
.setTM = (RtcIOTransactionTM) vRtcSetTM
|
|
};
|
|
return io;
|
|
} |