| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- /*
- summer.c
-
- stm32l0 daylight savings time (DST) calculation
-
- US:
- Der Energy Policy Act of 2005 (Public Law 109-58) bestimmt in Sec. 110 mit dem Titel Daylight Savings,
- dass ab 2007 die Sommerzeit am zweiten Sonntag im März beginnt und am ersten Sonntag im November endet.
-
- EU:
- Central European Summer Time (CEST, britisch) oder Central European Daylight Saving Time
- (applies to almost all european countries)
-
- Die mitteleuropäische Sommerzeit beginnt jeweils am letzten Sonntag im März um 2:00 Uhr MEZ,
- indem die Stundenzählung um eine Stunde von 2:00 Uhr auf 3:00 Uhr vorgestellt wird. Sie endet jeweils am letzten Sonntag im Oktober um
- 3:00 Uhr MESZ, indem die Stundenzählung um eine Stunde von 3:00 Uhr auf 2:00 Uhr zurückgestellt wird. Die Stunde von 2:00 Uhr bis 3:00 Uhr erscheint im Herbst also zweimal.
- */
- #ifdef __unix
- #include <stdio.h>
- #include <stdint.h>
- static uint8_t is_leap_year(uint16_t y)
- {
- if (
- ((y % 4 == 0) && (y % 100 != 0)) ||
- (y % 400 == 0)
- )
- return 1;
- return 0;
- }
- uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
- {
- uint8_t tmp1;
- uint16_t tmp2;
- tmp1 = 0;
- if ( m >= 3 )
- tmp1++;
- tmp2 = m;
- tmp2 +=2;
- tmp2 *=611;
- tmp2 /= 20;
- tmp2 += d;
- tmp2 -= 91;
- tmp1 <<=1;
- tmp2 -= tmp1;
- if ( tmp1 != 0 )
- tmp2 += is_leap_year(y);
- return tmp2;
- }
- uint8_t get_weekday_by_year_day_number(uint16_t y, uint16_t ydn)
- {
- uint8_t j, c, tmp8;
- uint16_t tmp16;
- y--;
- j = y % 100;
- c = y / 100;
- tmp16 = c;
- tmp16 *= 5;
- tmp16 += ydn;
- tmp8 = j;
- j >>= 2;
- c >>= 2;
- tmp8 += j;
- tmp8 += c;
- tmp8 += 28;
- tmp16 += tmp8;
- tmp16 %= 7;
- return tmp16;
- }
- uint16_t year;
- uint16_t month;
- uint16_t day;
- uint16_t hour;
- #else
- #include "datecalc.h"
- #include "stm32l031xx.h"
- #endif
- /*
- this function does not require gui_date_adjust() to be called
- 0: no DST (Wintertime)
- 1: DST (Summertime)
- -1: unknown (last sunday in oct, between 2am and 3am )
-
- region
- 0: do nothing
- 1: EU
- 2: US
-
- */
- int is_dst_by_date(uint8_t region)
- {
- uint16_t ydn;
- uint16_t ydn_change_to_wintertime;
- uint16_t ydn_change_to_summertime;
- #ifndef __unix
-
- uint16_t year;
- uint16_t month;
- uint16_t day;
- uint16_t hour;
- /* read date from date register */
-
- year = ((RTC->DR >> 20) & 15);
- year *= 10;
- year += ((RTC->DR >> 16) & 15);
- year += 2000;
-
- month = ((RTC->DR >> 12) & 1);
- month *= 10;
- month += ((RTC->DR >> 8) & 15);
-
- day = ((RTC->DR >> 4) & 3);
- day *= 10;
- day += ((RTC->DR) & 15);
-
- /* also get the hour for later comparison */
-
- hour = ((RTC->TR >> 20) & 3); /* assuming 24-hour clock, not sure about PM flag */
- hour *= 10;
- hour += ((RTC->TR >> 16) & 15);
-
- #endif
- /* convert all dates to date numbers of the current year*/
-
- if ( region == 1 ) /* EU */
- {
- /* European Summer Time: Last Sunday in March and last Sunday in October */
- ydn_change_to_summertime = get_year_day_number(year, 3, 31);
- ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
- }
- else if ( region == 2 ) /* US */
- {
- /* US DST rules: Second Sunday in March and First Sunday in November */
- ydn_change_to_summertime = get_year_day_number(year, 2, 28+is_leap_year(year));
- ydn_change_to_summertime += 14;
- ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
- ydn_change_to_wintertime += 7;
- }
- else
- {
- return 0;
- }
-
- ydn_change_to_summertime -= get_weekday_by_year_day_number(year, ydn_change_to_summertime);
- ydn_change_to_wintertime -= get_weekday_by_year_day_number(year, ydn_change_to_wintertime);
- ydn = get_year_day_number(year, month, day);
-
- if ( ydn == ydn_change_to_summertime )
- if ( hour >= 2 )
- return 1; /* yes, it is DST */
- if ( ydn == ydn_change_to_wintertime )
- {
- if ( hour < 2 )
- return 1; /* still DST */
- if ( hour > 3 )
- return 0; /* not DST any more */
- return -1; /* not sure whether DST or not */
- }
- if ( ydn > ydn_change_to_summertime && ydn < ydn_change_to_wintertime )
- return 1; /* within DST */
-
- return 0;
- }
- #ifdef __unix
- int main()
- {
- int dd;
- int d = -2;
- for( year = 2000; year < 2030; year++ )
- {
- printf("%d: ", year);
- for( month = 3; month <= 11; month ++ )
- {
- for( day = 1; day<= 31; day++ )
- {
- hour = 2;
- dd = is_dst_by_date(1);
- if ( d == 0 && dd == 1 )
- {
- printf("%d.%d.%d", day, month, year);
- }
- switch(dd)
- {
- //case -1: printf("%d.%d.%d", day, month, year); break;
- //case 0: printf("w"); break;
- //case 1: printf("s"); break;
- }
- d = dd;
- }
- }
- printf("\n");
- }
- }
- #else
- /*
- region
- 0: do nothing
- 1: EU
- 2: US
-
- */
- void adjustDST(uint8_t region)
- {
- int is_dst;
- int dst_state;
-
- is_dst = is_dst_by_date(region);
-
- if ( is_dst >= 0 )
- {
- dst_state = 0;
- if ( RTC->CR & RTC_CR_BCK ) /* BKP flag in the CR register */
- dst_state = 1;
-
- if ( is_dst != dst_state )
- {
- __disable_irq();
-
- PWR->CR |= PWR_CR_DBP; /* disable write protection (step 1) */
- RTC->WPR = 0x0ca; /* disable RTC write protection (step 2) */
- RTC->WPR = 0x053;
-
- if ( is_dst != 0 )
- {
- RTC->CR |= RTC_CR_BCK; /* the RTC will now run in summer time (set DST flag) */
- RTC->CR |= RTC_CR_ADD1H; /* change to DST (Summertime): add one hour */
- }
- else
- {
- RTC->CR &= ~RTC_CR_BCK; /* the RTC will now run in winter time (turn off DST flag) */
- RTC->CR |= RTC_CR_SUB1H; /* change back to none DST (Wintertime): subtract one hour */
- }
- RTC->WPR = 0; /* enable RTC write protection (step 2) */
- RTC->WPR = 0;
- __enable_irq();
-
- }
- }
- }
- #endif
|