diff options
author | Josef Gajdusek <atx@atx.name> | 2015-05-11 21:11:37 +0200 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2015-05-13 00:12:54 +0100 |
commit | 103d12a877f09e5d812f8c9c1fbf13ddbea4f78c (patch) | |
tree | 6ae6fc565aa5064d270d8254bede2c9d24ec7694 /esp8266 | |
parent | b47931978feffc7739fab7261b81caed1622fc9d (diff) | |
download | micropython-103d12a877f09e5d812f8c9c1fbf13ddbea4f78c.tar.gz micropython-103d12a877f09e5d812f8c9c1fbf13ddbea4f78c.zip |
esp8266: Add utime and pyb.RTC
Diffstat (limited to 'esp8266')
-rw-r--r-- | esp8266/Makefile | 4 | ||||
-rw-r--r-- | esp8266/modpyb.c | 1 | ||||
-rw-r--r-- | esp8266/modpyb.h | 1 | ||||
-rw-r--r-- | esp8266/modpybrtc.c | 167 | ||||
-rw-r--r-- | esp8266/modpybrtc.h | 29 | ||||
-rw-r--r-- | esp8266/modutime.c | 132 | ||||
-rw-r--r-- | esp8266/mpconfigport.h | 2 | ||||
-rw-r--r-- | esp8266/qstrdefsport.h | 12 |
8 files changed, 348 insertions, 0 deletions
diff --git a/esp8266/Makefile b/esp8266/Makefile index c891c50dcb..aac37bd2c0 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -18,6 +18,7 @@ INC += -I.. INC += -I../stmhal INC += -I../lib/mp-readline INC += -I../lib/netutils +INC += -I../lib/timeutils INC += -I$(BUILD) INC += -I$(ESP_SDK)/include @@ -52,7 +53,9 @@ SRC_C = \ uart.c \ modpyb.c \ modpybpin.c \ + modpybrtc.c \ modesp.c \ + modutime.c \ utils.c \ $(BUILD)/frozen.c \ @@ -66,6 +69,7 @@ LIB_SRC_C = $(addprefix lib/,\ libc/string0.c \ mp-readline/readline.c \ netutils/netutils.c \ + timeutils/timeutils.c \ ) SRC_S = \ diff --git a/esp8266/modpyb.c b/esp8266/modpyb.c index 57d0a6a9f2..5d57317b73 100644 --- a/esp8266/modpyb.c +++ b/esp8266/modpyb.c @@ -159,6 +159,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pyb_pin_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_obj }, }; STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table); diff --git a/esp8266/modpyb.h b/esp8266/modpyb.h index 87dac5227a..5d5851afb4 100644 --- a/esp8266/modpyb.h +++ b/esp8266/modpyb.h @@ -1 +1,2 @@ extern const mp_obj_type_t pyb_pin_type; +extern const mp_obj_base_t pyb_rtc_obj; diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c new file mode 100644 index 0000000000..c0331760c6 --- /dev/null +++ b/esp8266/modpybrtc.c @@ -0,0 +1,167 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * + * 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 <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include MICROPY_HAL_H +#include "timeutils.h" +#include "user_interface.h" + +typedef struct _pyb_rtc_obj_t { + mp_obj_base_t base; +} pyb_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +#define MEM_DELTA_ADDR 64 +#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2) +#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1) +#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1) +#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1) +#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4) + +STATIC uint64_t pyb_rtc_raw_us(uint64_t cal) { + return system_get_rtc_time() * ((cal >> 12) * 1000 + (cal & 0x0) / 4) / 1000; +}; + +void pyb_rtc_set_us_since_2000(uint64_t nowus) { + uint32_t cal = system_rtc_clock_cali_proc(); + int64_t delta = nowus - pyb_rtc_raw_us(cal); + + // As the calibration value jitters quite a bit, to make the + // clock at least somewhat practially usable, we need to store it + system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); +}; + +uint64_t pyb_rtc_get_us_since_2000() { + uint32_t cal; + int64_t delta; + + system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal)); + system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta)); + + return pyb_rtc_raw_us(cal) + delta; +}; + +STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + uint64_t msecs = pyb_rtc_get_us_since_2000() / 1000; + + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(msecs / 1000, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(msecs % 1000) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + pyb_rtc_set_us_since_2000( + ((uint64_t)timeutils_seconds_since_2000( + mp_obj_get_int(items[0]), + mp_obj_get_int(items[1]), + mp_obj_get_int(items[2]), + mp_obj_get_int(items[4]), + mp_obj_get_int(items[5]), + mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000); + + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime); + +STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + uint8_t rtcram[MEM_USER_MAXLEN]; + uint32_t len; + uint32_t magic; + + if (n_args == 1) { + + system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); + if (magic != MEM_MAGIC) { + return mp_const_none; + } + + system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len)); + system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, len + (4 - len % 4)); + + return mp_obj_new_bytes(rtcram, len); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "buffer too long")); + } + + magic = MEM_MAGIC; + system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(len)); + len = bufinfo.len; + system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); + + int i = 0; + for (; i < bufinfo.len; i++) { + rtcram[i] = ((uint8_t *)bufinfo.buf)[i]; + } + + system_rtc_mem_write(MEM_USER_DATA_ADDR, rtcram, len + (4 - len % 4)); + + return mp_const_none; + } + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory); + +STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); + +STATIC const mp_obj_type_t pyb_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .locals_dict = (mp_obj_t)&pyb_rtc_locals_dict, +}; + +const mp_obj_base_t pyb_rtc_obj = {&pyb_rtc_type}; diff --git a/esp8266/modpybrtc.h b/esp8266/modpybrtc.h new file mode 100644 index 0000000000..2a982d38fa --- /dev/null +++ b/esp8266/modpybrtc.h @@ -0,0 +1,29 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * + * 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. + */ + +void pyb_rtc_set_us_since_2000(uint64_t nowus); + +uint64_t pyb_rtc_get_us_since_2000(); diff --git a/esp8266/modutime.c b/esp8266/modutime.c new file mode 100644 index 0000000000..e5f84e965e --- /dev/null +++ b/esp8266/modutime.c @@ -0,0 +1,132 @@ +/* + * 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 Josef Gajdusek + * + * 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 <stdio.h> +#include <string.h> + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/gc.h" +#include "py/runtime.h" +#include MICROPY_HAL_H +#include "modpyb.h" +#include "modpybrtc.h" +#include "timeutils.h" +#include "user_interface.h" + +/// \module time - time related functions +/// +/// The `time` module provides functions for getting the current time and date, +/// and for sleeping. + +/// \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) +/// If secs is not provided or None, then the current time from the RTC is used. +/// year includes the century (for example 2014) +/// month is 1-12 +/// mday is 1-31 +/// hour is 0-23 +/// minute is 0-59 +/// second is 0-59 +/// weekday is 0-6 for Mon-Sun. +/// yearday is 1-366 +STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000; + } else { + seconds = mp_obj_get_int(args[0]); + } + 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), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +/// \function mktime() +/// This is inverse function of localtime. It's argument is a full 8-tuple +/// which expresses a time as per localtime. It returns an integer which is +/// the number of seconds since Jan 1, 2000. +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + mp_uint_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + 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); + +/// \function sleep(seconds) +/// Sleep for the given number of seconds. +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + HAL_Delay(1000 * mp_obj_get_int(seconds_o)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep); + +/// \function time() +/// Returns the number of seconds, as an integer, since 1/1/2000. +STATIC mp_obj_t time_time(void) { + // get date and time + return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_map_elem_t time_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t utime_module = { + .base = { &mp_type_module }, + .name = MP_QSTR_utime, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 6d70c48e21..1c5932f9de 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -64,10 +64,12 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; // extra built in modules to add to the list of known ones extern const struct _mp_obj_module_t pyb_module; extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t utime_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ #define MP_STATE_PORT MP_STATE_VM diff --git a/esp8266/qstrdefsport.h b/esp8266/qstrdefsport.h index 704cb70c0e..439afdea3b 100644 --- a/esp8266/qstrdefsport.h +++ b/esp8266/qstrdefsport.h @@ -85,3 +85,15 @@ Q(OUT_OD) Q(PULL_NONE) Q(PULL_UP) Q(PULL_DOWN) + +// RTC +Q(RTC) +Q(datetime) +Q(memory) + +// utime +Q(utime) +Q(localtime) +Q(mktime) +Q(sleep) +Q(time) |