mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #7365 from jeromecoutant/PR_RTC_SHADOW
STM32 RTC : bypass shadow registerspull/7498/head
commit
e1df16e843
|
|
@ -33,6 +33,14 @@
|
||||||
#include "rtc_api_hal.h"
|
#include "rtc_api_hal.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
#include "mbed_error.h"
|
#include "mbed_error.h"
|
||||||
|
#include "mbed_critical.h"
|
||||||
|
|
||||||
|
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
|
||||||
|
volatile uint32_t LP_continuous_time = 0;
|
||||||
|
volatile uint32_t LP_last_RTC_time = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int RTC_inited = 0;
|
||||||
|
|
||||||
static RTC_HandleTypeDef RtcHandle;
|
static RTC_HandleTypeDef RtcHandle;
|
||||||
|
|
||||||
|
|
@ -41,18 +49,15 @@ void rtc_init(void)
|
||||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||||
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
|
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
|
||||||
|
|
||||||
|
if (RTC_inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RTC_inited = 1;
|
||||||
|
|
||||||
// Enable access to Backup domain
|
// Enable access to Backup domain
|
||||||
__HAL_RCC_PWR_CLK_ENABLE();
|
__HAL_RCC_PWR_CLK_ENABLE();
|
||||||
HAL_PWR_EnableBkUpAccess();
|
HAL_PWR_EnableBkUpAccess();
|
||||||
|
|
||||||
#if DEVICE_LPTICKER
|
|
||||||
if ((rtc_isenabled()) && ((RTC->PRER & RTC_PRER_PREDIV_S) == PREDIV_S_VALUE)) {
|
|
||||||
#else /* DEVICE_LPTICKER */
|
|
||||||
if (rtc_isenabled()) {
|
|
||||||
#endif /* DEVICE_LPTICKER */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MBED_CONF_TARGET_LSE_AVAILABLE
|
#if MBED_CONF_TARGET_LSE_AVAILABLE
|
||||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
|
||||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
|
||||||
|
|
@ -114,48 +119,20 @@ void rtc_init(void)
|
||||||
error("RTC initialization failed");
|
error("RTC initialization failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_synchronize(); // Wait for RSF
|
#if !(TARGET_STM32F1) && !(TARGET_STM32F2)
|
||||||
|
/* STM32F1 : there are no shadow registers */
|
||||||
if (!rtc_isenabled()) {
|
/* STM32F2 : shadow registers can not be bypassed */
|
||||||
rtc_write(0);
|
if (HAL_RTCEx_EnableBypassShadow(&RtcHandle) != HAL_OK) {
|
||||||
|
error("EnableBypassShadow error");
|
||||||
}
|
}
|
||||||
|
#endif /* TARGET_STM32F1 || TARGET_STM32F2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_free(void)
|
void rtc_free(void)
|
||||||
{
|
{
|
||||||
// Disable access to Backup domain
|
/* RTC clock can not be reset */
|
||||||
HAL_PWR_DisableBkUpAccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
ST RTC_DateTypeDef structure
|
|
||||||
WeekDay 1=monday, 2=tuesday, ..., 7=sunday
|
|
||||||
Month 0x1=january, 0x2=february, ..., 0x12=december
|
|
||||||
Date day of the month 1-31
|
|
||||||
Year year 0-99
|
|
||||||
|
|
||||||
ST RTC_TimeTypeDef structure
|
|
||||||
Hours 0-12 if the RTC_HourFormat_12 is selected during init
|
|
||||||
0-23 if the RTC_HourFormat_24 is selected during init
|
|
||||||
Minutes 0-59
|
|
||||||
Seconds 0-59
|
|
||||||
TimeFormat RTC_HOURFORMAT12_AM/RTC_HOURFORMAT12_PM
|
|
||||||
SubSeconds time unit range between [0-1] Second with [1 Sec / SecondFraction +1] granularity
|
|
||||||
SecondFraction range or granularity of Sub Second register content corresponding to Synchronous pre-scaler factor value (PREDIV_S)
|
|
||||||
DayLightSaving RTC_DAYLIGHTSAVING_SUB1H/RTC_DAYLIGHTSAVING_ADD1H/RTC_DAYLIGHTSAVING_NONE
|
|
||||||
StoreOperation RTC_STOREOPERATION_RESET/RTC_STOREOPERATION_SET
|
|
||||||
|
|
||||||
struct tm
|
|
||||||
tm_sec seconds after the minute 0-61
|
|
||||||
tm_min minutes after the hour 0-59
|
|
||||||
tm_hour hours since midnight 0-23
|
|
||||||
tm_mday day of the month 1-31
|
|
||||||
tm_mon months since January 0-11
|
|
||||||
tm_year years since 1900
|
|
||||||
tm_wday days since Sunday 0-6
|
|
||||||
tm_yday days since January 1 0-365
|
|
||||||
tm_isdst Daylight Saving Time flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Information about STM32F0, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L4:
|
Information about STM32F0, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L4:
|
||||||
|
|
@ -172,7 +149,7 @@ Information about STM32F1:
|
||||||
For date, there is no specific register, only a software structure.
|
For date, there is no specific register, only a software structure.
|
||||||
It is then not a problem to not use shifts.
|
It is then not a problem to not use shifts.
|
||||||
*/
|
*/
|
||||||
|
#if TARGET_STM32F1
|
||||||
time_t rtc_read(void)
|
time_t rtc_read(void)
|
||||||
{
|
{
|
||||||
RTC_DateTypeDef dateStruct = {0};
|
RTC_DateTypeDef dateStruct = {0};
|
||||||
|
|
@ -186,7 +163,6 @@ time_t rtc_read(void)
|
||||||
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
|
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
|
||||||
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
|
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
|
||||||
|
|
||||||
#if TARGET_STM32F1
|
|
||||||
/* date information is null before first write procedure */
|
/* date information is null before first write procedure */
|
||||||
/* set 01/01/1970 as default values */
|
/* set 01/01/1970 as default values */
|
||||||
if (dateStruct.Year == 0) {
|
if (dateStruct.Year == 0) {
|
||||||
|
|
@ -194,7 +170,6 @@ time_t rtc_read(void)
|
||||||
dateStruct.Month = 1 ;
|
dateStruct.Month = 1 ;
|
||||||
dateStruct.Date = 1 ;
|
dateStruct.Date = 1 ;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Setup a tm structure based on the RTC
|
// Setup a tm structure based on the RTC
|
||||||
/* tm_wday information is ignored by _rtc_maketime */
|
/* tm_wday information is ignored by _rtc_maketime */
|
||||||
|
|
@ -215,11 +190,57 @@ time_t rtc_read(void)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else /* TARGET_STM32F1 */
|
||||||
|
|
||||||
|
time_t rtc_read(void)
|
||||||
|
{
|
||||||
|
struct tm timeinfo;
|
||||||
|
|
||||||
|
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
|
||||||
|
uint32_t Read_time = RTC->TR & RTC_TR_RESERVED_MASK;
|
||||||
|
uint32_t Read_date = RTC->DR & RTC_DR_RESERVED_MASK;
|
||||||
|
|
||||||
|
while ((Read_time != (RTC->TR & RTC_TR_RESERVED_MASK)) || (Read_date != (RTC->DR & RTC_DR_RESERVED_MASK))) {
|
||||||
|
Read_time = RTC->TR & RTC_TR_RESERVED_MASK;
|
||||||
|
Read_date = RTC->DR & RTC_DR_RESERVED_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup a tm structure based on the RTC
|
||||||
|
struct tm :
|
||||||
|
tm_sec seconds after the minute 0-61
|
||||||
|
tm_min minutes after the hour 0-59
|
||||||
|
tm_hour hours since midnight 0-23
|
||||||
|
tm_mday day of the month 1-31
|
||||||
|
tm_mon months since January 0-11
|
||||||
|
tm_year years since 1900
|
||||||
|
tm_yday information is ignored by _rtc_maketime
|
||||||
|
tm_wday information is ignored by _rtc_maketime
|
||||||
|
tm_isdst information is ignored by _rtc_maketime
|
||||||
|
*/
|
||||||
|
timeinfo.tm_mday = RTC_Bcd2ToByte((uint8_t)(Read_date & (RTC_DR_DT | RTC_DR_DU)));
|
||||||
|
timeinfo.tm_mon = RTC_Bcd2ToByte((uint8_t)((Read_date & (RTC_DR_MT | RTC_DR_MU)) >> 8)) - 1;
|
||||||
|
timeinfo.tm_year = RTC_Bcd2ToByte((uint8_t)((Read_date & (RTC_DR_YT | RTC_DR_YU)) >> 16)) + 68;
|
||||||
|
timeinfo.tm_hour = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_HT | RTC_TR_HU)) >> 16));
|
||||||
|
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
|
||||||
|
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
|
||||||
|
|
||||||
|
// Convert to timestamp
|
||||||
|
time_t t;
|
||||||
|
if (_rtc_maketime(&timeinfo, &t, RTC_4_YEAR_LEAP_YEAR_SUPPORT) == false) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TARGET_STM32F1 */
|
||||||
|
|
||||||
void rtc_write(time_t t)
|
void rtc_write(time_t t)
|
||||||
{
|
{
|
||||||
RTC_DateTypeDef dateStruct = {0};
|
RTC_DateTypeDef dateStruct = {0};
|
||||||
RTC_TimeTypeDef timeStruct = {0};
|
RTC_TimeTypeDef timeStruct = {0};
|
||||||
|
|
||||||
|
core_util_critical_section_enter();
|
||||||
RtcHandle.Instance = RTC;
|
RtcHandle.Instance = RTC;
|
||||||
|
|
||||||
// Convert the time into a tm
|
// Convert the time into a tm
|
||||||
|
|
@ -247,6 +268,17 @@ void rtc_write(time_t t)
|
||||||
timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;
|
timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;
|
||||||
#endif /* TARGET_STM32F1 */
|
#endif /* TARGET_STM32F1 */
|
||||||
|
|
||||||
|
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
|
||||||
|
/* Need to update LP_continuous_time value before new RTC time */
|
||||||
|
uint32_t current_lp_time = rtc_read_lp();
|
||||||
|
|
||||||
|
/* LP_last_RTC_time value is updated with the new RTC time */
|
||||||
|
LP_last_RTC_time = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60;
|
||||||
|
|
||||||
|
/* Save current SSR */
|
||||||
|
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
|
||||||
|
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
|
||||||
|
|
||||||
// Change the RTC current date/time
|
// Change the RTC current date/time
|
||||||
if (HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN) != HAL_OK) {
|
if (HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN) != HAL_OK) {
|
||||||
error("HAL_RTC_SetDate error\n");
|
error("HAL_RTC_SetDate error\n");
|
||||||
|
|
@ -254,24 +286,24 @@ void rtc_write(time_t t)
|
||||||
if (HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN) != HAL_OK) {
|
if (HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN) != HAL_OK) {
|
||||||
error("HAL_RTC_SetTime error\n");
|
error("HAL_RTC_SetTime error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
|
||||||
|
while (Read_SubSeconds != (RTC->SSR)) {
|
||||||
|
}
|
||||||
|
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
|
||||||
|
|
||||||
|
core_util_critical_section_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtc_isenabled(void)
|
int rtc_isenabled(void)
|
||||||
{
|
{
|
||||||
#if !(TARGET_STM32F1)
|
#if !(TARGET_STM32F1)
|
||||||
return (((RTC->ISR & RTC_ISR_INITS) == RTC_ISR_INITS) && ((RTC->ISR & RTC_ISR_RSF) == RTC_ISR_RSF));
|
return ((RTC->ISR & RTC_ISR_INITS) == RTC_ISR_INITS);
|
||||||
#else /* TARGET_STM32F1 */
|
#else /* TARGET_STM32F1 */
|
||||||
return ((RTC->CRL & RTC_CRL_RSF) == RTC_CRL_RSF);
|
return ((RTC->CRL & RTC_CRL_RSF) == RTC_CRL_RSF);
|
||||||
#endif /* TARGET_STM32F1 */
|
#endif /* TARGET_STM32F1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_synchronize(void)
|
|
||||||
{
|
|
||||||
RtcHandle.Instance = RTC;
|
|
||||||
if (HAL_RTC_WaitForSynchro(&RtcHandle) != HAL_OK) {
|
|
||||||
error("rtc_synchronize error\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
|
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
|
||||||
|
|
||||||
|
|
@ -279,8 +311,6 @@ static void RTC_IRQHandler(void);
|
||||||
static void (*irq_handler)(void);
|
static void (*irq_handler)(void);
|
||||||
|
|
||||||
volatile uint8_t lp_Fired = 0;
|
volatile uint8_t lp_Fired = 0;
|
||||||
volatile uint32_t LP_continuous_time = 0;
|
|
||||||
volatile uint32_t LP_last_RTC_time = 0;
|
|
||||||
|
|
||||||
static void RTC_IRQHandler(void)
|
static void RTC_IRQHandler(void)
|
||||||
{
|
{
|
||||||
|
|
@ -311,31 +341,34 @@ static void RTC_IRQHandler(void)
|
||||||
|
|
||||||
uint32_t rtc_read_lp(void)
|
uint32_t rtc_read_lp(void)
|
||||||
{
|
{
|
||||||
RTC_TimeTypeDef timeStruct = {0};
|
struct tm timeinfo;
|
||||||
RTC_DateTypeDef dateStruct = {0};
|
|
||||||
|
|
||||||
RtcHandle.Instance = RTC;
|
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
|
||||||
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
|
/* We don't have to read date as we bypass shadow registers */
|
||||||
|
uint32_t Read_SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);
|
||||||
|
uint32_t Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||||
|
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
|
||||||
|
|
||||||
/* Reading RTC current time locks the values in calendar shadow registers until Current date is read
|
while ((Read_time != (RTC->TR & RTC_TR_RESERVED_MASK)) || (Read_SubSeconds != (RTC->SSR))) {
|
||||||
to ensure consistency between the time and date values */
|
Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
|
||||||
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
|
Read_SubSeconds = (uint32_t)(RTC->SSR);
|
||||||
|
|
||||||
if (timeStruct.SubSeconds > timeStruct.SecondFraction) {
|
|
||||||
/* SS can be larger than PREDIV_S only after a shift operation. In that case, the correct
|
|
||||||
time/date is one second less than as indicated by RTC_TR/RTC_DR. */
|
|
||||||
timeStruct.Seconds -= 1;
|
|
||||||
}
|
}
|
||||||
uint32_t RTC_time_s = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
|
|
||||||
|
timeinfo.tm_hour = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_HT | RTC_TR_HU)) >> 16));
|
||||||
|
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
|
||||||
|
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
|
||||||
|
|
||||||
|
uint32_t RTC_time_s = timeinfo.tm_sec + timeinfo.tm_min * 60 + timeinfo.tm_hour * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
|
||||||
|
|
||||||
if (LP_last_RTC_time <= RTC_time_s) {
|
if (LP_last_RTC_time <= RTC_time_s) {
|
||||||
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
|
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
|
||||||
} else {
|
} else {
|
||||||
|
/* Add 24h */
|
||||||
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
|
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
|
||||||
}
|
}
|
||||||
LP_last_RTC_time = RTC_time_s;
|
LP_last_RTC_time = RTC_time_s;
|
||||||
|
|
||||||
return LP_continuous_time * PREDIV_S_VALUE + timeStruct.SecondFraction - timeStruct.SubSeconds;
|
return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_set_wake_up_timer(timestamp_t timestamp)
|
void rtc_set_wake_up_timer(timestamp_t timestamp)
|
||||||
|
|
@ -377,7 +410,11 @@ void rtc_fire_interrupt(void)
|
||||||
void rtc_deactivate_wake_up_timer(void)
|
void rtc_deactivate_wake_up_timer(void)
|
||||||
{
|
{
|
||||||
RtcHandle.Instance = RTC;
|
RtcHandle.Instance = RTC;
|
||||||
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
|
__HAL_RTC_WRITEPROTECTION_DISABLE(&RtcHandle);
|
||||||
|
__HAL_RTC_WAKEUPTIMER_DISABLE(&RtcHandle);
|
||||||
|
__HAL_RTC_WAKEUPTIMER_DISABLE_IT(&RtcHandle, RTC_IT_WUT);
|
||||||
|
__HAL_RTC_WRITEPROTECTION_ENABLE(&RtcHandle);
|
||||||
|
NVIC_DisableIRQ(RTC_WKUP_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
|
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
#include "mbed_critical.h"
|
#include "mbed_critical.h"
|
||||||
#include "mbed_error.h"
|
#include "mbed_error.h"
|
||||||
|
|
||||||
extern void rtc_synchronize(void);
|
|
||||||
extern void save_timer_ctx(void);
|
extern void save_timer_ctx(void);
|
||||||
extern void restore_timer_ctx(void);
|
extern void restore_timer_ctx(void);
|
||||||
|
|
||||||
|
|
@ -203,17 +202,6 @@ void hal_deepsleep(void)
|
||||||
|
|
||||||
restore_timer_ctx();
|
restore_timer_ctx();
|
||||||
|
|
||||||
#if DEVICE_RTC
|
|
||||||
/* Wait for RTC RSF bit synchro if RTC is configured */
|
|
||||||
#if (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7)
|
|
||||||
if (READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL)) {
|
|
||||||
#else /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
|
|
||||||
if (__HAL_RCC_GET_RTC_SOURCE()) {
|
|
||||||
#endif /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
|
|
||||||
rtc_synchronize();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Enable IRQs
|
// Enable IRQs
|
||||||
core_util_critical_section_exit();
|
core_util_critical_section_exit();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue