// // Created by cfif on 17.11.22. // #include "RtcFC7240.h" #include #include #include #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; }