Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rtc_calc_auto.py Source File

rtc_calc_auto.py

00001 """
00002 mbed SDK
00003 Copyright (c) 2011-2013 ARM Limited
00004 
00005 Licensed under the Apache License, Version 2.0 (the "License");
00006 you may not use this file except in compliance with the License.
00007 You may obtain a copy of the License at
00008 
00009     http://www.apache.org/licenses/LICENSE-2.0
00010 
00011 Unless required by applicable law or agreed to in writing, software
00012 distributed under the License is distributed on an "AS IS" BASIS,
00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 See the License for the specific language governing permissions and
00015 limitations under the License.
00016 """
00017 
00018 from mbed_host_tests import BaseHostTest
00019 import time
00020 import calendar
00021 import datetime
00022 
00023 class RTC_time_calc_test (BaseHostTest):
00024     """
00025     This is the host part of the test to verify if:
00026     - _rtc_mktime function converts a calendar time into time since UNIX epoch as a time_t,
00027     - _rtc_localtime function converts a given time in seconds since epoch into calendar time.
00028     
00029     The same algoritm to generate next calendar time to be tested is used by both parts of the test.
00030     We will check if correct time since UNIX epoch is calculated for the first and the last day
00031     of each month and across valid years.
00032     
00033     Mbed part of the test sends calculated time since UNIX epoch.
00034     This part validates given value and responds to indicate pass or fail.
00035     Additionally it sends also encoded day of week and day of year which
00036     will be needed to verify _rtc_localtime.
00037     
00038     Support for both types of RTC devices is provided:
00039     - RTCs which handles all leap years in the mentioned year range correctly. Leap year is determined by checking if
00040       the year counter value is divisible by 400, 100, and 4. No problem here.
00041     - RTCs which handles leap years correctly up to 2100. The RTC does a simple bit comparison to see if the two
00042       lowest order bits of the year counter are zero. In this case 2100 year will be considered
00043       incorrectly as a leap year, so the last valid point in time will be 28.02.2100 23:59:59 and next day will be
00044       29.02.2100 (invalid). So after 28.02.2100 the day counter will be off by a day.
00045       
00046     """
00047 
00048     edge_date = datetime.datetime(2100, 2, 28, 0, 0, 0)
00049     
00050     # Test the following years:
00051     # - first - 1970
00052     # - example not leap year (not divisible by 4)
00053     # - example leap year (divisible by 4 and by 100 and by 400) 
00054     # - example leap year (divisible by 4 and not by 100) 
00055     # - example not leap year (divisible by 4 and by 100) 
00056     # - last fully supported  - 2105
00057     years = [1970, 1971, 2000, 2096, 2100, 2105]
00058     year_id = 0
00059              
00060              
00061 
00062     full_leap_year_support = False
00063 
00064     RTC_FULL_LEAP_YEAR_SUPPORT = 0
00065     RTC_PARTIAL_LEAP_YEAR_SUPPORT = 1
00066 
00067     def _set_leap_year_support(self, key, value, timestamp):
00068         if (int(value) == self.RTC_FULL_LEAP_YEAR_SUPPORT ):
00069             self.full_leap_year_support  = True
00070         else:
00071             self.full_leap_year_support  = False
00072 
00073         self.first  = True
00074         self.date  = datetime.datetime(1970, 1, 1, 23, 0, 0)
00075         self.year_id  = 0
00076 
00077     def _verify_timestamp(self, key, value, timestamp):
00078         # week day in python is counted from sunday(0) and on mbed side week day is counted from monday(0).
00079         # year day in python is counted from 1 and on mbed side year day is counted from 0.
00080         week_day = ((self.date .timetuple().tm_wday + 1) % 7)
00081         year_day = self.date .timetuple().tm_yday - 1
00082 
00083         # Fix for RTC which not have full leap year support.
00084         if (not self.full_leap_year_support ):
00085             if self.date  >= self.edge_date :
00086                 # After 28.02.2100 we should be one day off - add this day and store original
00087                 date_org = self.date 
00088                 self.date  += datetime.timedelta(days = 1)
00089                 
00090                 # Adjust week day.
00091                 week_day = ((self.date .timetuple().tm_wday + 1) % 7)
00092 
00093                 # Adjust year day.
00094                 if (self.date .year == 2100):
00095                     year_day = self.date .timetuple().tm_yday - 1
00096                 else:
00097                     year_day = date_org.timetuple().tm_yday - 1
00098 
00099                 # Last day in year
00100                 if (self.date .month == 1 and self.date .day == 1):
00101                     if (self.date .year == 2101):
00102                         # Exception for year 2100 - ivalid handled by RTC without full leap year support
00103                         year_day = 365
00104                     else:
00105                         year_day = date_org.timetuple().tm_yday - 1
00106 
00107         t = (self.date .year , self.date .month, self.date .day, self.date .hour, self.date .minute, self.date .second, 0, 0, 0)
00108         
00109         expected_timestamp = calendar.timegm(t)
00110         actual_timestamp = int(value) & 0xffffffff # convert to unsigned int
00111 
00112         # encode week day and year day in the response
00113         response = (week_day << 16) | year_day
00114         
00115         if (actual_timestamp == expected_timestamp):
00116             # response contains encoded week day and year day
00117             self.send_kv("passed", str(response))
00118         else:
00119             self.send_kv("failed", 0)
00120             print "expected = %d, result = %d" %  (expected_timestamp , actual_timestamp)
00121 
00122         # calculate next date
00123         if (self.first ):
00124             days_range = calendar.monthrange(self.date .year, self.date .month)
00125             self.date  = self.date .replace(day = days_range[1], minute = 59, second = 59)
00126             self.first  = not self.first 
00127         else:
00128             self.date  += datetime.timedelta(days = 1)
00129             if (self.date .month == 1):
00130                 self.year_id  += 1
00131                 if (len(self.years ) == self.year_id ):
00132                     # All years were processed, no need to calc next date
00133                     return
00134                 self.date  = self.date .replace(year = self.years [self.year_id ])
00135             self.date  = self.date .replace(day = 1, minute = 0, second = 0)
00136             self.first  = not self.first 
00137 
00138     def setup(self):
00139         self.register_callback('timestamp', self._verify_timestamp )
00140         self.register_callback('leap_year_setup', self._set_leap_year_support )