From cc8be1f27880add1a9b0f7e54dac316de97d68bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Sat, 28 Nov 2020 15:17:52 +0100 Subject: [PATCH] application: RTC + date/time added --- application.c | 152 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 27 deletions(-) diff --git a/application.c b/application.c index da00360..2d457bc 100644 --- a/application.c +++ b/application.c @@ -94,39 +94,114 @@ static void command_uptime(void* argument) static void command_datetime(void* argument) { char* datetime = (char*)argument; // argument is optional date time - if (NULL == argument) { // no date and time provided, just show the current day and time - // TODO wait until date/time is synchronised + const char* days[] = { "??", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}; // the days of the week + + // set date + if (datetime) { // date has been provided + // parse date + const char* malformed = "date and time malformed, expecting YYYY-MM-DD WD HH:MM:SS\n"; + if (strlen(datetime) != (4 + 1 + 2 + 1 + 2) + 1 + 2 + 1 + (2 + 1 + 2 + 1 + 2)) { // verify date/time is long enough + printf(malformed); + return; + } + if (!(isdigit((int8_t)datetime[0]) && isdigit((int8_t)datetime[1]) && isdigit((int8_t)datetime[2]) && isdigit((int8_t)datetime[3]) && \ + '-' == datetime[4] && \ + isdigit((int8_t)datetime[5]) && isdigit((int8_t)datetime[6]) && \ + '-' == datetime[7] && \ + isdigit((int8_t)datetime[8]) && isdigit((int8_t)datetime[9]) && \ + ' ' == datetime[10] && \ + isalpha((int8_t)datetime[11]) && isalpha((int8_t)datetime[12]) && \ + ' ' == datetime[13] && \ + isdigit((int8_t)datetime[14]) && isdigit((int8_t)datetime[15]) && \ + ':' == datetime[16] && \ + isdigit((int8_t)datetime[17]) && isdigit((int8_t)datetime[18]) && \ + ':' == datetime[19] && \ + isdigit((int8_t)datetime[20]) && isdigit((int8_t)datetime[21]))) { // verify format (good enough to not fail parsing) + printf(malformed); + return; + } + const uint16_t year = strtol(&datetime[0], NULL, 10); // parse year + if (year <= 2000 || year > 2099) { + puts("year out of range\n"); + return; + } + const uint8_t month = strtol(&datetime[5], NULL, 10); // parse month + if (month < 1 || month > 12) { + puts("month out of range\n"); + return; + } + const uint8_t day = strtol(&datetime[8], NULL, 10); // parse day + if (day < 1 || day > 31) { + puts("day out of range\n"); + return; + } + const uint8_t hour = strtol(&datetime[14], NULL, 10); // parse hour + if (hour > 24) { + puts("hour out of range\n"); + return; + } + const uint8_t minute = strtol(&datetime[17], NULL, 10); // parse minutes + if (minute > 59) { + puts("minute out of range\n"); + return; + } + const uint8_t second = strtol(&datetime[30], NULL, 10); // parse seconds + if (second > 59) { + puts("second out of range\n"); + return; + } + uint8_t week_day = 0; + for (uint8_t i = 1; i < LENGTH(days) && 0 == week_day; i++) { + if (days[i][0] == toupper(datetime[11]) && days[i][1] == tolower(datetime[12])) { + week_day = i; + break; + } + } + if (0 == week_day) { + puts("unknown week day\n"); + return; + } + uint32_t date = 0; // to build the date + date |= (((year - 2000) / 10) & RTC_DR_YT_MASK) << RTC_DR_YT_SHIFT; // set year tenth + date |= (((year - 2000) % 10) & RTC_DR_YU_MASK) << RTC_DR_YU_SHIFT; // set year unit + date |= ((month / 10) & RTC_DR_MT_MASK) << RTC_DR_MT_SHIFT; // set month tenth + date |= ((month % 10) & RTC_DR_MU_MASK) << RTC_DR_MU_SHIFT; // set month unit + date |= ((day / 10) & RTC_DR_DT_MASK) << RTC_DR_DT_SHIFT; // set day tenth + date |= ((day % 10) & RTC_DR_DU_MASK) << RTC_DR_DU_SHIFT; // set day unit + date |= (week_day & RTC_DR_WDU_MASK) << RTC_DR_WDU_SHIFT; // time day of the week + uint32_t time = 0; // to build the time + time = 0; // reset time + time |= ((hour / 10) & RTC_TR_HT_MASK) << RTC_TR_HT_SHIFT; // set hour tenth + time |= ((hour % 10) & RTC_TR_HU_MASK) << RTC_TR_HU_SHIFT; // set hour unit + time |= ((minute / 10) & RTC_TR_MNT_MASK) << RTC_TR_MNT_SHIFT; // set minute tenth + time |= ((minute % 10) & RTC_TR_MNU_MASK) << RTC_TR_MNU_SHIFT; // set minute unit + time |= ((second / 10) & RTC_TR_ST_MASK) << RTC_TR_ST_SHIFT; // set second tenth + time |= ((second % 10) & RTC_TR_SU_MASK) << RTC_TR_SU_SHIFT; // set second unit + // write date + pwr_disable_backup_domain_write_protect(); // disable backup protection so we can set the RTC clock source + rtc_unlock(); // enable writing RTC registers + RTC_ISR |= RTC_ISR_INIT; // enter initialisation mode + while (!(RTC_ISR & RTC_ISR_INITF)); // wait to enter initialisation mode + RTC_DR = date; // set date + RTC_TR = time; // set time + RTC_ISR &= ~RTC_ISR_INIT; // exit initialisation mode + rtc_lock(); // protect RTC register against writing + pwr_enable_backup_domain_write_protect(); // re-enable protection now that we configured the RTC clock + } + + // show date + if (!(RTC_ISR & RTC_ISR_INITS)) { // date has not been set yet + puts("date/time not initialized\n"); + } else { + rtc_wait_for_synchro(); // wait until date/time is synchronised const uint8_t year = ((RTC_DR >> RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK) * 10 + ((RTC_DR >> RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK); // get year const uint8_t month = ((RTC_DR >> RTC_DR_MT_SHIFT) & RTC_DR_MT_MASK) * 10 + ((RTC_DR >> RTC_DR_MU_SHIFT) & RTC_DR_MU_MASK); // get month const uint8_t day = ((RTC_DR >> RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) * 10 + ((RTC_DR >> RTC_DR_DU_SHIFT) & RTC_DR_DU_MASK); // get day const uint8_t week_day = ((RTC_DR >> RTC_DR_WDU_SHIFT) & RTC_DR_WDU_MASK); // get week day - const char* days[] = { "??", "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; // the days of the week - const uint8_t hour = ((RTC_TR >> RTC_TR_HT_SHIFT) * RTC_TR_HT_MASK) * 10 + ((RTC_TR >> RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK); // get hours + const uint8_t hour = ((RTC_TR >> RTC_TR_HT_SHIFT) & RTC_TR_HT_MASK) * 10 + ((RTC_TR >> RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK); // get hours const uint8_t minute = ((RTC_TR >> RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) * 10 + ((RTC_TR >> RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK); // get minutes const uint8_t second = ((RTC_TR >> RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) * 10 + ((RTC_TR >> RTC_TR_SU_SHIFT) & RTC_TR_SU_MASK); // get seconds - printf("date: %s 20%02d-%02d-%02d %02d:%02d:%02d\n", days[week_day], year, month, day, hour, minute, second); - } else { // date and time provided, set it - const char* malformed = "date and time malformed, expecting YYYY-MM-DD HH:MM:SS\n"; - if (strlen(datetime) != (4 + 1 + 2 + 1 + 2) + 1 + (2 + 1 + 2 + 1 + 2)) { // verify date/time is long enough - printf(malformed); - return; - } - if (!(isdigit((int8_t)datetime[0]) && isdigit((int8_t)datetime[1]) && isdigit((int8_t)datetime[2]) && isdigit((int8_t)datetime[3]) && '-' == datetime[4] && isdigit((int8_t)datetime[5]) && isdigit((int8_t)datetime[6]) && '-' == datetime[7] && isdigit((int8_t)datetime[8]) && isdigit((int8_t)datetime[9]) && ' ' == datetime[10] && isdigit((int8_t)datetime[11]) && isdigit((int8_t)datetime[12]) && ':' == datetime[13] && isdigit((int8_t)datetime[14]) && isdigit((int8_t)datetime[15]) && ':' == datetime[16] && isdigit((int8_t)datetime[17]) && isdigit((int8_t)datetime[18]))) { // verify format (good enough to not fail parsing) - printf(malformed); - return; - } - /* - time_tm.tm_year = strtol(&datetime[0], NULL, 10) - 1900; // parse year - time_tm.tm_mon = strtol(&datetime[5], NULL, 10) - 1; // parse month - time_tm.tm_mday = strtol(&datetime[8], NULL, 10); // parse day - time_tm.tm_hour = strtol(&datetime[11], NULL, 10); // parse hour - time_tm.tm_min = strtol(&datetime[14], NULL, 10); // parse minutes - time_tm.tm_sec = strtol(&datetime[17], NULL, 10); // parse seconds - time_t time_rtc = mktime(&time_tm); // get back seconds - time_rtc -= rtc_offset; // remove start offset - time_start = time_rtc * RTC_TICKS_SECOND + (rtc_get_counter_val() - time_start); // update uptime with current date - rtc_set_counter_val(time_rtc * RTC_TICKS_SECOND); // save date/time to internal RTC - */ + printf("date: 20%02d-%02d-%02d %s %02d:%02d:%02d\n", year, month, day, days[week_day], hour, minute, second); } } @@ -310,6 +385,29 @@ void main(void) } #endif + // setup RTC + puts("setup RTC: "); + rcc_periph_clock_enable(RCC_RTC); // enable clock for RTC peripheral + if (!(RCC_BDCR && RCC_BDCR_RTCEN)) { // the RTC has not been configured yet + pwr_disable_backup_domain_write_protect(); // disable backup protection so we can set the RTC clock source + rtc_unlock(); // enable writing RTC registers +#if defined(MINIF401) + rcc_osc_on(RCC_LSE); // enable LSE clock + while (!rcc_is_osc_ready(RCC_LSE)); // wait until clock is ready + rtc_set_prescaler(256, 128); // set clock prescaler to 32768 + RCC_BDCR = (RCC_BDCR & ~(RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT)) | (RCC_BDCR_RTCSEL_LSE << RCC_BDCR_RTCSEL_SHIFT); // select LSE as RTC clock source +#else + rcc_osc_on(RCC_LSI); // enable LSI clock + while (!rcc_is_osc_ready(RCC_LSI)); // wait until clock is ready + rtc_set_prescaler(250, 128); // set clock prescaler to 32000 + RCC_BDCR = (RCC_BDCR & ~(RCC_BDCR_RTCSEL_MASK << RCC_BDCR_RTCSEL_SHIFT)) | (RCC_BDCR_RTCSEL_LSI << RCC_BDCR_RTCSEL_SHIFT); // select LSI as RTC clock source +#endif + RCC_BDCR |= RCC_BDCR_RTCEN; // enable RTC + rtc_lock(); // protect RTC register against writing + pwr_enable_backup_domain_write_protect(); // re-enable protection now that we configured the RTC clock + } + puts("OK\n"); + // setup terminal terminal_prefix = ""; // set default prefix terminal_process = &process_command; // set central function to process commands