lib: Move time utility functions to common library.

This commit is contained in:
Josef Gajdusek 2015-05-11 02:00:19 +02:00 committed by Damien George
parent 800d5cd16f
commit 1db4253886
12 changed files with 262 additions and 399 deletions

View File

@ -21,6 +21,7 @@ APP_INC += -I$(BUILD)/genhdr
APP_INC += -I../lib/fatfs
APP_INC += -I../lib/mp-readline
APP_INC += -I../lib/netutils
APP_INC += -I../lib/timeutils
APP_INC += -I../stmhal
APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS
@ -144,6 +145,7 @@ APP_LIB_SRC_C = $(addprefix lib/,\
libc/string0.c \
mp-readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
)
APP_STM_SRC_C = $(addprefix stmhal/,\

View File

@ -15,12 +15,12 @@
#if MICROPY_HW_HAS_SDCARD
#include "sd_diskio.h" /* SDCARD disk IO API */
#endif
#include "modutime.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "rom_map.h"
#include "prcm.h"
#include "timeutils.h"
/* Definitions of physical drive number for each drive */
#define SFLASH 0 /* Map SFLASH drive to drive number 0 */
@ -192,13 +192,13 @@ DWORD get_fattime (
void
)
{
mod_struct_time tm;
timeutils_struct_time_t tm;
uint32_t seconds;
uint16_t mseconds;
// Get the time from the on-chip RTC and convert it to struct_time
MAP_PRCMRTCGet(&seconds, &mseconds);
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) |
((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) |

View File

@ -40,7 +40,6 @@
#include "ftp.h"
#include "simplelink.h"
#include "modwlan.h"
#include "modutime.h"
#include "debug.h"
#include "serverstask.h"
#include "ff.h"
@ -49,6 +48,7 @@
#include "diskio.h"
#include "sd_diskio.h"
#include "updater.h"
#include "timeutils.h"
/******************************************************************************
@ -884,7 +884,7 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
uint16_t mseconds;
uint mindex = (((fno->fdate >> 5) & 0x0f) > 0) ? (((fno->fdate >> 5) & 0x0f) - 1) : 0;
uint day = ((fno->fdate & 0x1f) > 0) ? (fno->fdate & 0x1f) : 1;
uint fseconds = mod_time_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f),
uint fseconds = timeutils_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f),
(fno->fdate >> 5) & 0x0f,
fno->fdate & 0x1f,
(fno->ftime >> 11) & 0x1f,
@ -912,12 +912,12 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
}
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name) {
mod_struct_time tm;
timeutils_struct_time_t tm;
uint32_t tseconds;
uint16_t mseconds;
char *type = "d";
mod_time_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm);
timeutils_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm);
MAP_PRCMRTCGet(&tseconds, &mseconds);
if (FTP_UNIX_SECONDS_180_DAYS < tseconds - (FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101)) {

View File

@ -38,11 +38,11 @@
#include "diskio.h"
#include "sflash_diskio.h"
#include "file.h"
#include "modutime.h"
#include "random.h"
#include "sd_diskio.h"
#include "mpexception.h"
#include "version.h"
#include "timeutils.h"
/// \module os - basic "operating system" services
///
@ -285,7 +285,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) {
} else {
mode |= 0x8000; // stat.S_IFREG
}
mp_int_t seconds = mod_time_seconds_since_2000(
mp_int_t seconds = timeutils_seconds_since_2000(
1980 + ((fno.fdate >> 9) & 0x7f),
(fno.fdate >> 5) & 0x0f,
fno.fdate & 0x1f,

View File

@ -32,7 +32,7 @@
#include MICROPY_HAL_H
#include "py/nlr.h"
#include "py/obj.h"
#include "modutime.h"
#include "timeutils.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
@ -41,126 +41,11 @@
#include "pybrtc.h"
#include "mpexception.h"
// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
// after Feb 29. We calculate seconds as a signed integer relative to that.
//
// Our timebase is relative to 2000-01-01.
#define LEAPOCH ((31 + 29) * 86400)
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
/// \module time - time related functions
///
/// The `time` module provides functions for getting the current time and date,
/// and for sleeping.
STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
STATIC bool is_leap_year(mp_uint_t year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
// Month is one based
STATIC mp_uint_t mod_time_days_in_month(mp_uint_t year, mp_uint_t month) {
mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
if (month == 2 && is_leap_year(year)) {
mdays++;
}
return mdays;
}
// compute the day of the year, between 1 and 366
// month should be between 1 and 12, date should start at 1
STATIC mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
mp_uint_t yday = days_since_jan1[month - 1] + date;
if (month >= 3 && is_leap_year(year)) {
yday += 1;
}
return yday;
}
// returns the number of seconds, as an integer, since 2000-01-01
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return
second
+ minute * 60
+ hour * 3600
+ (mod_time_year_day(year, month, date) - 1
+ ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
- ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ (year - 2000) * 31536000;
}
void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) {
// The following algorithm was adapted from musl's __secs_to_tm and adapted
// for differences in Micro Python's timebase.
mp_int_t seconds = t - LEAPOCH;
mp_int_t days = seconds / 86400;
seconds %= 86400;
tm->tm_hour = seconds / 3600;
tm->tm_min = seconds / 60 % 60;
tm->tm_sec = seconds % 60;
mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2)
if (wday < 0) {
wday += 7;
}
tm->tm_wday = wday;
mp_int_t qc_cycles = days / DAYS_PER_400Y;
days %= DAYS_PER_400Y;
if (days < 0) {
days += DAYS_PER_400Y;
qc_cycles--;
}
mp_int_t c_cycles = days / DAYS_PER_100Y;
if (c_cycles == 4) {
c_cycles--;
}
days -= (c_cycles * DAYS_PER_100Y);
mp_int_t q_cycles = days / DAYS_PER_4Y;
if (q_cycles == 25) {
q_cycles--;
}
days -= q_cycles * DAYS_PER_4Y;
mp_int_t years = days / 365;
if (years == 4) {
years--;
}
days -= (years * 365);
tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
// Note: days_in_month[0] corresponds to March
STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
mp_int_t month;
for (month = 0; days_in_month[month] <= days; month++) {
days -= days_in_month[month];
}
tm->tm_mon = month + 2;
if (tm->tm_mon >= 12) {
tm->tm_mon -= 12;
tm->tm_year++;
}
tm->tm_mday = days + 1; // Make one based
tm->tm_mon++; // Make one based
tm->tm_yday = mod_time_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
}
/// \function localtime([secs])
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
@ -175,14 +60,14 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm
/// yearday is 1-366
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0 || args[0] == mp_const_none) {
mod_struct_time tm;
timeutils_struct_time_t tm;
uint32_t seconds;
uint16_t mseconds;
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
mseconds = RTC_CYCLES_U16MS(mseconds);
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
@ -197,8 +82,8 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
return mp_obj_new_tuple(8, tuple);
} else {
mp_int_t seconds = mp_obj_get_int(args[0]);
mod_struct_time tm;
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
timeutils_struct_time_t tm;
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
tuple[0] = mp_obj_new_int(tm.tm_year),
tuple[1] = mp_obj_new_int(tm.tm_mon),
@ -231,64 +116,10 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
}
mp_int_t year = mp_obj_get_int(elem[0]);
mp_int_t month = mp_obj_get_int(elem[1]);
mp_int_t mday = mp_obj_get_int(elem[2]);
mp_int_t hours = mp_obj_get_int(elem[3]);
mp_int_t minutes = mp_obj_get_int(elem[4]);
mp_int_t seconds = mp_obj_get_int(elem[5]);
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
// Normalize the tuple. This allows things like:
//
// tm_tomorrow = list(time.localtime())
// tm_tomorrow[2] += 1 # Adds 1 to mday
// tomorrow = time.mktime(tm_tommorrow)
//
// And not have to worry about all the weird overflows.
//
// You can subtract dates/times this way as well.
minutes += seconds / 60;
if ((seconds = seconds % 60) < 0) {
seconds += 60;
minutes--;
}
hours += minutes / 60;
if ((minutes = minutes % 60) < 0) {
minutes += 60;
hours--;
}
mday += hours / 24;
if ((hours = hours % 24) < 0) {
hours += 24;
mday--;
}
month--; // make month zero based
year += month / 12;
if ((month = month % 12) < 0) {
month += 12;
year--;
}
month++; // back to one based
while (mday < 1) {
if (--month == 0) {
month = 12;
year--;
}
mday += mod_time_days_in_month(year, month);
}
while (mday > mod_time_days_in_month(year, month)) {
mday -= mod_time_days_in_month(year, month);
if (++month == 13) {
month = 1;
year++;
}
}
return mp_obj_new_int_from_uint(mod_time_seconds_since_2000(year, month, mday, hours, minutes, seconds));
}
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);

View File

@ -31,7 +31,6 @@
#include MICROPY_HAL_H
#include "py/obj.h"
#include "py/runtime.h"
#include "modutime.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
@ -40,6 +39,7 @@
#include "pybrtc.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "timeutils.h"
/// \moduleref pyb
/// \class RTC - real time clock
@ -82,7 +82,7 @@ void pybrtc_init(void) {
// fresh reset; configure the RTC Calendar
// set the date to 1st Jan 2015
// set the time to 00:00:00
uint32_t seconds = mod_time_seconds_since_2000(2015, 1, 1, 0, 0, 0);
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
// Mark the RTC in use first
MAP_PRCMRTCInUseSet();
@ -137,7 +137,7 @@ STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
/// `weekday` is 0-6 for Monday through Sunday.
///
mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
mod_struct_time tm;
timeutils_struct_time_t tm;
uint32_t seconds;
uint16_t mseconds;
@ -145,7 +145,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
mseconds = RTC_CYCLES_U16MS(mseconds);
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
@ -172,7 +172,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
tm.tm_sec = mp_obj_get_int(items[6]);
mseconds = mp_obj_get_int(items[7]);
seconds = mod_time_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
mseconds = RTC_U16MS_CYCLES(mseconds);
MAP_PRCMRTCSet(seconds, mseconds);

211
lib/timeutils/timeutils.c Normal file
View File

@ -0,0 +1,211 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2015 Daniel Campora
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/obj.h"
#include "timeutils.h"
// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
// after Feb 29. We calculate seconds as a signed integer relative to that.
//
// Our timebase is is relative to 2000-01-01.
#define LEAPOCH ((31 + 29) * 86400)
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
bool timeutils_is_leap_year(mp_uint_t year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
// month is one based
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month) {
mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
if (month == 2 && timeutils_is_leap_year(year)) {
mdays++;
}
return mdays;
}
// compute the day of the year, between 1 and 366
// month should be between 1 and 12, date should start at 1
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
mp_uint_t yday = days_since_jan1[month - 1] + date;
if (month >= 3 && timeutils_is_leap_year(year)) {
yday += 1;
}
return yday;
}
void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
// The following algorithm was adapted from musl's __secs_to_tm and adapted
// for differences in Micro Python's timebase.
mp_int_t seconds = t - LEAPOCH;
mp_int_t days = seconds / 86400;
seconds %= 86400;
tm->tm_hour = seconds / 3600;
tm->tm_min = seconds / 60 % 60;
tm->tm_sec = seconds % 60;
mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2)
if (wday < 0) {
wday += 7;
}
tm->tm_wday = wday;
mp_int_t qc_cycles = days / DAYS_PER_400Y;
days %= DAYS_PER_400Y;
if (days < 0) {
days += DAYS_PER_400Y;
qc_cycles--;
}
mp_int_t c_cycles = days / DAYS_PER_100Y;
if (c_cycles == 4) {
c_cycles--;
}
days -= (c_cycles * DAYS_PER_100Y);
mp_int_t q_cycles = days / DAYS_PER_4Y;
if (q_cycles == 25) {
q_cycles--;
}
days -= q_cycles * DAYS_PER_4Y;
mp_int_t years = days / 365;
if (years == 4) {
years--;
}
days -= (years * 365);
/* We will compute tm_yday at the very end
mp_int_t leap = !years && (q_cycles || !c_cycles);
tm->tm_yday = days + 31 + 28 + leap;
if (tm->tm_yday >= 365 + leap) {
tm->tm_yday -= 365 + leap;
}
tm->tm_yday++; // Make one based
*/
tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
// Note: days_in_month[0] corresponds to March
STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
mp_int_t month;
for (month = 0; days_in_month[month] <= days; month++) {
days -= days_in_month[month];
}
tm->tm_mon = month + 2;
if (tm->tm_mon >= 12) {
tm->tm_mon -= 12;
tm->tm_year++;
}
tm->tm_mday = days + 1; // Make one based
tm->tm_mon++; // Make one based
tm->tm_yday = timeutils_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
}
// returns the number of seconds, as an integer, since 2000-01-01
mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return
second
+ minute * 60
+ hour * 3600
+ (timeutils_year_day(year, month, date) - 1
+ ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
- ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ (year - 2000) * 31536000;
}
mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday,
mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds) {
// Normalize the tuple. This allows things like:
//
// tm_tomorrow = list(time.localtime())
// tm_tomorrow[2] += 1 # Adds 1 to mday
// tomorrow = time.mktime(tm_tommorrow)
//
// And not have to worry about all the weird overflows.
//
// You can subtract dates/times this way as well.
minutes += seconds / 60;
if ((seconds = seconds % 60) < 0) {
seconds += 60;
minutes--;
}
hours += minutes / 60;
if ((minutes = minutes % 60) < 0) {
minutes += 60;
hours--;
}
mday += hours / 24;
if ((hours = hours % 24) < 0) {
hours += 24;
mday--;
}
month--; // make month zero based
year += month / 12;
if ((month = month % 12) < 0) {
month += 12;
year--;
}
month++; // back to one based
while (mday < 1) {
if (--month == 0) {
month = 12;
year--;
}
mday += timeutils_days_in_month(year, month);
}
while (mday > timeutils_days_in_month(year, month)) {
mday -= timeutils_days_in_month(year, month);
if (++month == 13) {
month = 1;
year++;
}
}
return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds);
}

View File

@ -25,10 +25,10 @@
* THE SOFTWARE.
*/
#ifndef MODUTIME_H_
#define MODUTIME_H_
#ifndef __MICROPY_INCLUDED_LIB_TIMEUTILS_H__
#define __MICROPY_INCLUDED_LIB_TIMEUTILS_H__
typedef struct {
typedef struct _timeutils_struct_time_t {
uint16_t tm_year; // i.e. 2014
uint8_t tm_mon; // 1..12
uint8_t tm_mday; // 1..31
@ -37,12 +37,19 @@ typedef struct {
uint8_t tm_sec; // 0..59
uint8_t tm_wday; // 0..6 0 = Monday
uint16_t tm_yday; // 1..366
} mod_struct_time;
} timeutils_struct_time_t;
bool timeutils_is_leap_year(mp_uint_t year);
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
extern mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date,
mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t,
timeutils_struct_time_t *tm);
extern void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm);
mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
#endif // MODUTIME_H_
mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday,
mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds);
#endif // __MICROPY_INCLUDED_LIB_TIMEUTILS_H__

View File

@ -42,6 +42,7 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc
#INC += -I$(USBHOST_DIR)
INC += -I../lib/mp-readline
INC += -I../lib/netutils
INC += -I../lib/timeutils
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_CORTEX_M4) $(COPT)
@ -94,6 +95,7 @@ SRC_LIB = $(addprefix lib/,\
fatfs/option/ccsbcs.c \
mp-readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
)
SRC_C = \

View File

@ -34,6 +34,7 @@
#include "genhdr/mpversion.h"
#include "lib/fatfs/ff.h"
#include "lib/fatfs/diskio.h"
#include "timeutils.h"
#include "rng.h"
#include "file.h"
#include "sdcard.h"
@ -322,7 +323,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) {
} else {
mode |= 0x8000; // stat.S_IFREG
}
mp_int_t seconds = mod_time_seconds_since_2000(
mp_int_t seconds = timeutils_seconds_since_2000(
1980 + ((fno.fdate >> 9) & 0x7f),
(fno.fdate >> 5) & 0x0f,
fno.fdate & 0x1f,

View File

@ -30,6 +30,7 @@
#include "py/nlr.h"
#include "py/obj.h"
#include "timeutils.h"
#include "portmodules.h"
#include "rtc.h"
@ -38,141 +39,6 @@
/// The `time` module provides functions for getting the current time and date,
/// and for sleeping.
STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
STATIC bool is_leap_year(mp_uint_t year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
// Month is one based
STATIC mp_uint_t mod_time_days_in_month(mp_uint_t year, mp_uint_t month) {
mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
if (month == 2 && is_leap_year(year)) {
mdays++;
}
return mdays;
}
// compute the day of the year, between 1 and 366
// month should be between 1 and 12, date should start at 1
STATIC mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
mp_uint_t yday = days_since_jan1[month - 1] + date;
if (month >= 3 && is_leap_year(year)) {
yday += 1;
}
return yday;
}
// returns the number of seconds, as an integer, since 2000-01-01
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return
second
+ minute * 60
+ hour * 3600
+ (mod_time_year_day(year, month, date) - 1
+ ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
- ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ (year - 2000) * 31536000;
}
// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately
// after Feb 29. We calculate seconds as a signed integer relative to that.
//
// Our timebase is is relative to 2000-01-01.
#define LEAPOCH ((31 + 29) * 86400)
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
typedef struct {
uint16_t tm_year; // i.e. 2014
uint8_t tm_mon; // 1..12
uint8_t tm_mday; // 1..31
uint8_t tm_hour; // 0..23
uint8_t tm_min; // 0..59
uint8_t tm_sec; // 0..59
uint8_t tm_wday; // 0..6 0 = Monday
uint16_t tm_yday; // 1..366
} mod_struct_time;
STATIC void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) {
// The following algorithm was adapted from musl's __secs_to_tm and adapted
// for differences in Micro Python's timebase.
mp_int_t seconds = t - LEAPOCH;
mp_int_t days = seconds / 86400;
seconds %= 86400;
tm->tm_hour = seconds / 3600;
tm->tm_min = seconds / 60 % 60;
tm->tm_sec = seconds % 60;
mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2)
if (wday < 0) {
wday += 7;
}
tm->tm_wday = wday;
mp_int_t qc_cycles = days / DAYS_PER_400Y;
days %= DAYS_PER_400Y;
if (days < 0) {
days += DAYS_PER_400Y;
qc_cycles--;
}
mp_int_t c_cycles = days / DAYS_PER_100Y;
if (c_cycles == 4) {
c_cycles--;
}
days -= (c_cycles * DAYS_PER_100Y);
mp_int_t q_cycles = days / DAYS_PER_4Y;
if (q_cycles == 25) {
q_cycles--;
}
days -= q_cycles * DAYS_PER_4Y;
mp_int_t years = days / 365;
if (years == 4) {
years--;
}
days -= (years * 365);
/* We will compute tm_yday at the very end
mp_int_t leap = !years && (q_cycles || !c_cycles);
tm->tm_yday = days + 31 + 28 + leap;
if (tm->tm_yday >= 365 + leap) {
tm->tm_yday -= 365 + leap;
}
tm->tm_yday++; // Make one based
*/
tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
// Note: days_in_month[0] corresponds to March
STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
mp_int_t month;
for (month = 0; days_in_month[month] <= days; month++) {
days -= days_in_month[month];
}
tm->tm_mon = month + 2;
if (tm->tm_mon >= 12) {
tm->tm_mon -= 12;
tm->tm_year++;
}
tm->tm_mday = days + 1; // Make one based
tm->tm_mon++; // Make one based
tm->tm_yday = mod_time_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
}
/// \function localtime([secs])
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
@ -201,13 +67,13 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
mp_obj_new_int(time.Minutes),
mp_obj_new_int(time.Seconds),
mp_obj_new_int(date.WeekDay - 1),
mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)),
mp_obj_new_int(timeutils_year_day(2000 + date.Year, date.Month, date.Date)),
};
return mp_obj_new_tuple(8, tuple);
} else {
mp_int_t seconds = mp_obj_get_int(args[0]);
mod_struct_time tm;
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
timeutils_struct_time_t tm;
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
tuple[0] = mp_obj_new_int(tm.tm_year),
tuple[1] = mp_obj_new_int(tm.tm_mon),
@ -240,64 +106,9 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len));
}
mp_int_t year = mp_obj_get_int(elem[0]);
mp_int_t month = mp_obj_get_int(elem[1]);
mp_int_t mday = mp_obj_get_int(elem[2]);
mp_int_t hours = mp_obj_get_int(elem[3]);
mp_int_t minutes = mp_obj_get_int(elem[4]);
mp_int_t seconds = mp_obj_get_int(elem[5]);
// Normalise the tuple. This allows things like:
//
// tm_tomorrow = list(time.localtime())
// tm_tomorrow[2] += 1 # Adds 1 to mday
// tomorrow = time.mktime(tm_tommorrow)
//
// And not have to worry about all the weird overflows.
//
// You can subtract dates/times this way as well.
minutes += seconds / 60;
if ((seconds = seconds % 60) < 0) {
seconds += 60;
minutes--;
}
hours += minutes / 60;
if ((minutes = minutes % 60) < 0) {
minutes += 60;
hours--;
}
mday += hours / 24;
if ((hours = hours % 24) < 0) {
hours += 24;
mday--;
}
month--; // make month zero based
year += month / 12;
if ((month = month % 12) < 0) {
month += 12;
year--;
}
month++; // back to one based
while (mday < 1) {
if (--month == 0) {
month = 12;
year--;
}
mday += mod_time_days_in_month(year, month);
}
while (mday > mod_time_days_in_month(year, month)) {
mday -= mod_time_days_in_month(year, month);
if (++month == 13) {
month = 1;
year++;
}
}
return mp_obj_new_int_from_uint(mod_time_seconds_since_2000(year, month, mday, hours, minutes, seconds));
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
}
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
@ -328,7 +139,7 @@ STATIC mp_obj_t time_time(void) {
RTC_TimeTypeDef time;
HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);
HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN);
return mp_obj_new_int(mod_time_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));
}
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);

View File

@ -34,5 +34,3 @@ extern const mp_obj_module_t mp_module_usocket;
// additional helper functions exported by the modules
MP_DECLARE_CONST_FUN_OBJ(mod_os_sync_obj);
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);