Merge branch 'omega-dev' into DrawStringFont

This commit is contained in:
Maxime FRIESS
2021-03-15 19:31:16 +01:00
committed by GitHub
640 changed files with 38996 additions and 1307 deletions

View File

@@ -1,6 +1,7 @@
SFLAGS += -Ipython/src
SFLAGS += -Ipython/port
SFLAGS += -I$(BUILD_DIR)/python/port
SFLAGS += -DEPSILON_VERSION="$(EPSILON_VERSION)" -DOMEGA_VERSION="$(OMEGA_VERSION)"
# How to maintain this Makefile
# - Copy PY_CORE_O_BASENAME from py.mk into py_src
@@ -136,6 +137,7 @@ port_src += $(addprefix python/port/,\
helpers.c \
mod/ion/modion.cpp \
mod/ion/modion_table.cpp \
mod/ion/file.cpp \
mod/kandinsky/modkandinsky.cpp \
mod/kandinsky/modkandinsky_table.c \
mod/matplotlib/modmatplotlib.cpp \
@@ -147,6 +149,8 @@ port_src += $(addprefix python/port/,\
mod/matplotlib/pyplot/plot_view.cpp \
mod/time/modtime.c \
mod/time/modtime_table.c \
mod/os/modos.cpp \
mod/os/modos_table.c \
mod/turtle/modturtle.cpp \
mod/turtle/modturtle_table.c \
mod/turtle/turtle.cpp \

View File

@@ -1,9 +1,19 @@
#include "py/builtin.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "mod/ion/file.h"
#include <string.h>
#include "mphalport.h"
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
mp_arg_check_num(n_args, kwargs->used, 1, 2, false);
if (n_args == 2) {
return file_open_mode(args[0], args[1]);
} else {
return file_open(args[0]);
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

View File

@@ -379,6 +379,63 @@ Q(get_pixel)
Q(set_pixel)
Q(large_font)
Q(small_font)
Q(wait_vblank)
Q(get_keys)
// Keys QSTRs
Q(left)
Q(up)
Q(down)
Q(right)
Q(OK)
Q(back)
Q(home)
Q(onOff)
Q(shift)
Q(alpha)
Q(xnt)
Q(var)
Q(toolbox)
Q(backspace)
Q(exp)
Q(ln)
Q(log)
Q(imaginary)
Q(comma)
Q(power)
Q(sin)
Q(cos)
Q(tan)
Q(pi)
Q(sqrt)
Q(square)
Q(7)
Q(8)
Q(9)
Q(()
Q())
Q(4)
Q(5)
Q(6)
Q(*)
Q(/)
Q(1)
Q(2)
Q(3)
Q(+)
Q(-)
Q(0)
Q(.)
Q(EE)
Q(Ans)
Q(EXE)
// Matplotlib QSTRs
Q(arrow)
@@ -437,6 +494,53 @@ Q(isvisible)
Q(colormode)
// utime QSTRs
Q(localtime)
Q(mktime)
Q(time)
Q(setlocaltime)
Q(setrtcmode)
Q(sleep)
Q(rtcmode)
Q(monotonic)
// file QSTRs
Q(file)
Q(close)
Q(closed)
Q(flush)
Q(isatty)
Q(readable)
Q(readline)
Q(readlines)
Q(seekable)
Q(tell)
Q(writable)
Q(writelines)
Q(fileno)
Q(seek)
Q(truncate)
Q(write)
Q(read)
Q(name)
Q(mode)
Q(SEEK_SET)
Q(SEEK_CUR)
Q(SEEK_END)
// os QSTRs
Q(os)
Q(uname)
Q(sysname)
Q(nodename)
Q(release)
Q(version)
Q(machine)
Q(rename)
Q(listdir)

1016
python/port/mod/ion/file.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
#ifndef MP_MOD_FILE_H
#define MP_MOD_FILE_H
#include <py/obj.h>
mp_obj_t file_open(mp_obj_t file_name);
mp_obj_t file_open_mode(mp_obj_t file_name, mp_obj_t file_mode);
#endif

View File

@@ -1,3 +1,4 @@
#include <py/obj.h>
mp_obj_t modion_keyboard_keydown(mp_obj_t key_o);
extern const mp_obj_type_t file_type;

View File

@@ -65,6 +65,8 @@ STATIC const mp_rom_map_elem_t modion_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_KEY_EE), MP_OBJ_NEW_SMALL_INT(Ion::Keyboard::Key::EE) },
{ MP_ROM_QSTR(MP_QSTR_KEY_ANS), MP_OBJ_NEW_SMALL_INT(Ion::Keyboard::Key::Ans) },
{ MP_ROM_QSTR(MP_QSTR_KEY_EXE), MP_OBJ_NEW_SMALL_INT(Ion::Keyboard::Key::EXE) },
{ MP_ROM_QSTR(MP_QSTR_file), (mp_obj_t)&file_type}
};
STATIC MP_DEFINE_CONST_DICT(modion_module_globals, modion_module_globals_table);

View File

@@ -3,6 +3,7 @@ extern "C" {
#include <py/runtime.h>
}
#include <kandinsky.h>
#include <ion.h>
#include "port.h"
@@ -85,3 +86,88 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
KDIonContext::sharedContext()->fillRect(rect, color);
return mp_const_none;
}
mp_obj_t modkandinsky_wait_vblank() {
micropython_port_interrupt_if_needed();
Ion::Display::waitForVBlank();
return mp_const_none;
}
struct key2mp
{
Ion::Keyboard::Key key;
mp_obj_t string;
};
const static key2mp keyMapping[] =
{
{ Ion::Keyboard::Key::Left, MP_ROM_QSTR(MP_QSTR_left) },
{ Ion::Keyboard::Key::Right, MP_ROM_QSTR(MP_QSTR_right) },
{ Ion::Keyboard::Key::Down, MP_ROM_QSTR(MP_QSTR_down) },
{ Ion::Keyboard::Key::Up, MP_ROM_QSTR(MP_QSTR_up) },
{ Ion::Keyboard::Key::OK, MP_ROM_QSTR(MP_QSTR_OK) },
{ Ion::Keyboard::Key::Back, MP_ROM_QSTR(MP_QSTR_back) },
{ Ion::Keyboard::Key::Home, MP_ROM_QSTR(MP_QSTR_home) },
{ Ion::Keyboard::Key::OnOff, MP_ROM_QSTR(MP_QSTR_onOff) },
{ Ion::Keyboard::Key::Shift, MP_ROM_QSTR(MP_QSTR_shift) },
{ Ion::Keyboard::Key::Alpha, MP_ROM_QSTR(MP_QSTR_alpha) },
{ Ion::Keyboard::Key::XNT, MP_ROM_QSTR(MP_QSTR_xnt) },
{ Ion::Keyboard::Key::Var, MP_ROM_QSTR(MP_QSTR_var) },
{ Ion::Keyboard::Key::Toolbox, MP_ROM_QSTR(MP_QSTR_toolbox) },
{ Ion::Keyboard::Key::Backspace, MP_ROM_QSTR(MP_QSTR_backspace) },
{ Ion::Keyboard::Key::Exp, MP_ROM_QSTR(MP_QSTR_exp) },
{ Ion::Keyboard::Key::Ln, MP_ROM_QSTR(MP_QSTR_ln) },
{ Ion::Keyboard::Key::Log, MP_ROM_QSTR(MP_QSTR_log) },
{ Ion::Keyboard::Key::Imaginary, MP_ROM_QSTR(MP_QSTR_imaginary) },
{ Ion::Keyboard::Key::Comma, MP_ROM_QSTR(MP_QSTR_comma) },
{ Ion::Keyboard::Key::Power, MP_ROM_QSTR(MP_QSTR_power) },
{ Ion::Keyboard::Key::Sine, MP_ROM_QSTR(MP_QSTR_sin) },
{ Ion::Keyboard::Key::Cosine, MP_ROM_QSTR(MP_QSTR_cos) },
{ Ion::Keyboard::Key::Tangent, MP_ROM_QSTR(MP_QSTR_tan) },
{ Ion::Keyboard::Key::Pi, MP_ROM_QSTR(MP_QSTR_pi) },
{ Ion::Keyboard::Key::Sqrt, MP_ROM_QSTR(MP_QSTR_sqrt) },
{ Ion::Keyboard::Key::Square, MP_ROM_QSTR(MP_QSTR_square) },
{ Ion::Keyboard::Key::Seven, MP_ROM_QSTR(MP_QSTR_7) },
{ Ion::Keyboard::Key::Eight, MP_ROM_QSTR(MP_QSTR_8) },
{ Ion::Keyboard::Key::Nine, MP_ROM_QSTR(MP_QSTR_9) },
{ Ion::Keyboard::Key::RightParenthesis, MP_ROM_QSTR(MP_QSTR__paren_open_) },
{ Ion::Keyboard::Key::LeftParenthesis, MP_ROM_QSTR(MP_QSTR__paren_close_) },
{ Ion::Keyboard::Key::Four, MP_ROM_QSTR(MP_QSTR_4) },
{ Ion::Keyboard::Key::Five, MP_ROM_QSTR(MP_QSTR_5) },
{ Ion::Keyboard::Key::Six, MP_ROM_QSTR(MP_QSTR_6) },
{ Ion::Keyboard::Key::Multiplication, MP_ROM_QSTR(MP_QSTR__star_) },
{ Ion::Keyboard::Key::Division, MP_ROM_QSTR(MP_QSTR__slash_) },
{ Ion::Keyboard::Key::One, MP_ROM_QSTR(MP_QSTR_1) },
{ Ion::Keyboard::Key::Two, MP_ROM_QSTR(MP_QSTR_2) },
{ Ion::Keyboard::Key::Three, MP_ROM_QSTR(MP_QSTR_3) },
{ Ion::Keyboard::Key::Plus, MP_ROM_QSTR(MP_QSTR__plus_) },
{ Ion::Keyboard::Key::Minus, MP_ROM_QSTR(MP_QSTR__hyphen_) },
{ Ion::Keyboard::Key::Zero, MP_ROM_QSTR(MP_QSTR_0) },
{ Ion::Keyboard::Key::Dot, MP_ROM_QSTR(MP_QSTR__dot_) },
{ Ion::Keyboard::Key::EE, MP_ROM_QSTR(MP_QSTR_EE) },
{ Ion::Keyboard::Key::Ans, MP_ROM_QSTR(MP_QSTR_Ans) },
{ Ion::Keyboard::Key::EXE, MP_ROM_QSTR(MP_QSTR_EXE) },
};
mp_obj_t modkandinsky_get_keys() {
micropython_port_interrupt_if_needed();
Ion::Keyboard::State keys = Ion::Keyboard::scan();
mp_obj_t result = mp_obj_new_set(0, nullptr);
for (unsigned i = 0; i < sizeof(keyMapping)/sizeof(key2mp); i++) {
if (keys.keyDown(keyMapping[i].key)) {
mp_obj_set_store(result, keyMapping[i].string);
}
}
return result;
}

View File

@@ -5,3 +5,5 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y);
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t color);
mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_wait_vblank();
mp_obj_t modkandinsky_get_keys();

View File

@@ -5,6 +5,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(modkandinsky_get_pixel_obj, modkandinsky_get_pi
STATIC MP_DEFINE_CONST_FUN_OBJ_3(modkandinsky_set_pixel_obj, modkandinsky_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_string_obj, 3, 6, modkandinsky_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_fill_rect_obj, 5, 5, modkandinsky_fill_rect);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_wait_vblank_obj, modkandinsky_wait_vblank);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_get_keys_obj, modkandinsky_get_keys);
STATIC const mp_rom_map_elem_t modkandinsky_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_kandinsky) },
@@ -15,6 +17,8 @@ STATIC const mp_rom_map_elem_t modkandinsky_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_fill_rect), (mp_obj_t)&modkandinsky_fill_rect_obj },
{ MP_ROM_QSTR(MP_QSTR_large_font), mp_const_true },
{ MP_ROM_QSTR(MP_QSTR_small_font), mp_const_false },
{ MP_ROM_QSTR(MP_QSTR_wait_vblank), (mp_obj_t)&modkandinsky_wait_vblank_obj },
{ MP_ROM_QSTR(MP_QSTR_get_keys), (mp_obj_t)&modkandinsky_get_keys_obj },
};
STATIC MP_DEFINE_CONST_DICT(modkandinsky_module_globals, modkandinsky_module_globals_table);

View File

@@ -0,0 +1,115 @@
extern "C" {
#include "modos.h"
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/objstr.h>
#include <py/objtuple.h>
}
#include <ion/storage.h>
#ifndef OMEGA_VERSION
#error This file expects OMEGA_VERSION to be defined
#endif
#ifndef EPSILON_VERSION
#error This file expects EPSILON_VERSION to be defined
#endif
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_sysname_obj, "NumWorks");
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_nodename_obj, "");
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_release_obj, "O" MP_STRINGIFY(OMEGA_VERSION) "E-" MP_STRINGIFY(EPSILON_VERSION));
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_version_obj, MICROPY_VERSION_STRING);
#if defined(DEVICE_N0110)
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_machine_obj, "NumWorks N0110");
#elif defined(DEVICE_N0100)
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_machine_obj, "NumWorks N0100");
#else
STATIC const MP_DEFINE_STR_OBJ(modos_uname_info_machine_obj, "NumWorks Simulator");
#endif
STATIC const mp_rom_map_elem_t modos_uname_info_table[] = {
{ MP_ROM_QSTR(MP_QSTR_sysname), &modos_uname_info_sysname_obj },
{ MP_ROM_QSTR(MP_QSTR_nodename), &modos_uname_info_nodename_obj },
{ MP_ROM_QSTR(MP_QSTR_release), &modos_uname_info_release_obj },
{ MP_ROM_QSTR(MP_QSTR_version), &modos_uname_info_version_obj },
{ MP_ROM_QSTR(MP_QSTR_machine), &modos_uname_info_machine_obj },
};
STATIC MP_DEFINE_CONST_DICT(modos_uname_info_obj, modos_uname_info_table);
mp_obj_t modos_uname(void) {
return (mp_obj_t)&modos_uname_info_obj;
}
mp_obj_t modos_remove(mp_obj_t o_file_name) {
size_t len;
const char* file_name;
file_name = mp_obj_str_get_data(o_file_name, &len);
Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(file_name);
if (record == Ion::Storage::Record()) {
mp_raise_OSError(2);
}
record.destroy();
return mp_const_none;
}
mp_obj_t modos_rename(mp_obj_t o_old_name, mp_obj_t o_new_name) {
size_t len;
const char* old_name;
const char* new_name;
old_name = mp_obj_str_get_data(o_old_name, &len);
new_name = mp_obj_str_get_data(o_new_name, &len);
Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(old_name);
if (record == Ion::Storage::Record()) {
mp_raise_OSError(2);
}
Ion::Storage::Record::ErrorStatus status = record.setName(new_name);
switch (status) {
case Ion::Storage::Record::ErrorStatus::NameTaken:
mp_raise_OSError(17);
break;
case Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable:
mp_raise_OSError(28);
break;
case Ion::Storage::Record::ErrorStatus::NonCompliantName:
mp_raise_OSError(22);
break;
case Ion::Storage::Record::ErrorStatus::RecordDoesNotExist:
mp_raise_OSError(2);
break;
default:
break;
}
return mp_const_none;
}
mp_obj_t modos_listdir(void) {
mp_obj_t list = mp_obj_new_list(0, NULL);
for(size_t i = 0; i < (size_t)Ion::Storage::sharedStorage()->numberOfRecords(); i++) {
Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordAtIndex(i);
size_t file_name_length = strlen(record.fullName());
mp_obj_t file_name = mp_obj_new_str(record.fullName(), file_name_length);
mp_obj_list_append(list, file_name);
}
return list;
}

View File

@@ -0,0 +1,6 @@
#include <py/obj.h>
mp_obj_t modos_uname();
mp_obj_t modos_remove(mp_obj_t o_file_name);
mp_obj_t modos_rename(mp_obj_t o_old_name, mp_obj_t o_new_name);
mp_obj_t modos_listdir();

View File

@@ -0,0 +1,21 @@
#include "modos.h"
MP_DEFINE_CONST_FUN_OBJ_0(modos_uname_obj, modos_uname);
MP_DEFINE_CONST_FUN_OBJ_1(modos_remove_obj, modos_remove);
MP_DEFINE_CONST_FUN_OBJ_2(modos_rename_obj, modos_rename);
MP_DEFINE_CONST_FUN_OBJ_0(modos_listdir_obj, modos_listdir);
STATIC const mp_rom_map_elem_t modos_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
{ MP_ROM_QSTR(MP_QSTR_uname), &modos_uname_obj},
{ MP_ROM_QSTR(MP_QSTR_remove), &modos_remove_obj},
{ MP_ROM_QSTR(MP_QSTR_rename), &modos_rename_obj},
{ MP_ROM_QSTR(MP_QSTR_listdir), &modos_listdir_obj},
};
STATIC MP_DEFINE_CONST_DICT(modos_module_globals, modos_module_globals_table);
const mp_obj_module_t modos_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&modos_module_globals,
};

View File

@@ -1,10 +1,11 @@
extern "C" {
#include "modtime.h"
#include <py/runtime.h>
#include <py/smallint.h>
}
#include <ion/rtc.h>
#include <ion/timing.h>
#include "../../helpers.h"
#include <py/smallint.h>
#include <py/runtime.h>
mp_obj_t modtime_sleep(mp_obj_t seconds_o) {
#if MICROPY_PY_BUILTINS_FLOAT
@@ -18,3 +19,265 @@ mp_obj_t modtime_sleep(mp_obj_t seconds_o) {
mp_obj_t modtime_monotonic() {
return mp_obj_new_float(Ion::Timing::millis() / 1000.0);
}
//
// Omega extensions, based off MicroPython's modutime.c
//
// 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.
constexpr int LEAPOCH = ((31 + 29) * 86400);
constexpr int DAYS_PER_400Y = (365 * 400 + 97);
constexpr int DAYS_PER_100Y = (365 * 100 + 24);
constexpr int 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;
}
Ion::RTC::DateTime timeutils_seconds_since_2000_to_struct_time(mp_uint_t t) {
Ion::RTC::DateTime tm;
// The following algorithm was adapted from musl's __secs_to_tm and adapted
// for differences in MicroPython's timebase.
mp_int_t seconds = t - LEAPOCH;
mp_int_t days = seconds / 86400;
seconds %= 86400;
if (seconds < 0) {
seconds += 86400;
days -= 1;
}
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
return tm;
}
// returns the number of seconds, as an integer, since 2000-01-01
mp_uint_t timeutils_seconds_since_2000(Ion::RTC::DateTime tm) {
return
tm.tm_sec
+ tm.tm_min * 60
+ tm.tm_hour * 3600
+ (timeutils_year_day(tm.tm_year, tm.tm_mon, tm.tm_mday) - 1
+ ((tm.tm_year - 2000 + 3) / 4) // add a day each 4 years starting with 2001
- ((tm.tm_year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001
+ ((tm.tm_year - 2000 + 399) / 400) // add a day each 400 years starting with 2001
) * 86400
+ (tm.tm_year - 2000) * 31536000;
}
mp_uint_t timeutils_mktime(Ion::RTC::DateTime tm) {
// Normalize the tuple. This allows things like:
//
// tm_tomorrow = list(time.localtime())
// tm_tomorrow[2] += 1 # Adds 1 to mday
// tomorrow = time.mktime(tm_tomorrow)
//
// And not have to worry about all the weird overflows.
//
// You can subtract dates/times this way as well.
tm.tm_min += tm.tm_sec / 60;
if ((tm.tm_sec = tm.tm_sec % 60) < 0) {
tm.tm_sec += 60;
tm.tm_min--;
}
tm.tm_hour += tm.tm_min / 60;
if ((tm.tm_min = tm.tm_min % 60) < 0) {
tm.tm_min += 60;
tm.tm_hour--;
}
tm.tm_mday += tm.tm_hour / 24;
if ((tm.tm_hour = tm.tm_hour % 24) < 0) {
tm.tm_hour += 24;
tm.tm_mday--;
}
tm.tm_mon--; // make month zero based
tm.tm_year += tm.tm_mon / 12;
if ((tm.tm_mon = tm.tm_mon % 12) < 0) {
tm.tm_mon += 12;
tm.tm_year--;
}
tm.tm_mon++; // back to one based
while (tm.tm_mday < 1) {
if (--tm.tm_mon == 0) {
tm.tm_mon = 12;
tm.tm_year--;
}
tm.tm_mday += timeutils_days_in_month(tm.tm_year, tm.tm_mon);
}
while ((mp_uint_t)tm.tm_mday > timeutils_days_in_month(tm.tm_year, tm.tm_mon)) {
tm.tm_mday -= timeutils_days_in_month(tm.tm_year, tm.tm_mon);
if (++tm.tm_mon == 13) {
tm.tm_mon = 1;
tm.tm_year++;
}
}
return timeutils_seconds_since_2000(tm);
}
mp_obj_t modtime_localtime(size_t n_args, const mp_obj_t *args) {
Ion::RTC::DateTime tm;
if (n_args == 0 || args[0] == mp_const_none) {
tm = Ion::RTC::dateTime();
} else {
mp_int_t seconds = mp_obj_get_int(args[0]);
tm = timeutils_seconds_since_2000_to_struct_time(seconds);
}
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(timeutils_year_day(tm.tm_year, tm.tm_mon, tm.tm_mday)),
};
return mp_obj_new_tuple(8, tuple);
}
mp_obj_t modtime_mktime(mp_obj_t tuple) {
size_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) {
mp_raise_TypeError("mktime needs a tuple of length 8 or 9");
}
Ion::RTC::DateTime tm {
(int)mp_obj_get_int(elem[5]),
(int)mp_obj_get_int(elem[4]),
(int)mp_obj_get_int(elem[3]),
(int)mp_obj_get_int(elem[2]),
(int)mp_obj_get_int(elem[1]),
(int)mp_obj_get_int(elem[0]),
};
return mp_obj_new_int_from_uint(timeutils_mktime(tm));
}
mp_obj_t modtime_time(void) {
return mp_obj_new_int(timeutils_seconds_since_2000(Ion::RTC::dateTime()));
}
// Omega private extensions.
mp_obj_t modtime_rtcmode(void) {
return mp_obj_new_int((int)Ion::RTC::mode());
}
mp_obj_t modtime_setrtcmode(mp_obj_t mode) {
mp_int_t intMode = mp_obj_get_int(mode);
if (intMode < (int)Ion::RTC::Mode::Disabled || intMode > (int)Ion::RTC::Mode::HSE) {
mp_raise_ValueError("mode must be between 0 and 2");
}
Ion::RTC::setMode((Ion::RTC::Mode)intMode);
return mp_const_none;
}
mp_obj_t modtime_setlocaltime(mp_obj_t tuple) {
size_t len;
mp_obj_t *elem;
mp_obj_get_array(tuple, &len, &elem);
if (len < 5) {
mp_raise_TypeError("setlocaltime needs a tuple of length >= 5");
}
Ion::RTC::DateTime tm {
len > 5 ? (int)mp_obj_get_int(elem[5]) : 0,
(int)mp_obj_get_int(elem[4]),
(int)mp_obj_get_int(elem[3]),
(int)mp_obj_get_int(elem[2]),
(int)mp_obj_get_int(elem[1]),
(int)mp_obj_get_int(elem[0]),
};
Ion::RTC::setDateTime(tm);
return mp_const_none;
}

View File

@@ -2,3 +2,17 @@
mp_obj_t modtime_sleep(mp_obj_t seconds_o);
mp_obj_t modtime_monotonic();
//
// Omega extensions.
//
mp_obj_t modtime_localtime(size_t n_args, const mp_obj_t *args);
mp_obj_t modtime_mktime(mp_obj_t tuple);
mp_obj_t modtime_time(void);
// Omega private extensions.
mp_obj_t modtime_rtcmode(void);
mp_obj_t modtime_setrtcmode(mp_obj_t mode);
mp_obj_t modtime_setlocaltime(mp_obj_t tuple);

View File

@@ -3,10 +3,26 @@
MP_DEFINE_CONST_FUN_OBJ_1(modtime_sleep_obj, modtime_sleep);
MP_DEFINE_CONST_FUN_OBJ_0(modtime_monotonic_obj, modtime_monotonic);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modtime_localtime_obj, 0, 1, modtime_localtime);
MP_DEFINE_CONST_FUN_OBJ_1(modtime_mktime_obj, modtime_mktime);
MP_DEFINE_CONST_FUN_OBJ_0(modtime_time_obj, modtime_time);
MP_DEFINE_CONST_FUN_OBJ_0(modtime_rtcmode_obj, modtime_rtcmode);
MP_DEFINE_CONST_FUN_OBJ_1(modtime_setrtcmode_obj, modtime_setrtcmode);
MP_DEFINE_CONST_FUN_OBJ_1(modtime_setlocaltime_obj, modtime_setlocaltime);
STATIC const mp_rom_map_elem_t modtime_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) },
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&modtime_sleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_monotonic), MP_ROM_PTR(&modtime_monotonic_obj) },
{ MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&modtime_localtime_obj) },
{ MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&modtime_mktime_obj) },
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_rtcmode), MP_ROM_PTR(&modtime_rtcmode_obj) },
{ MP_ROM_QSTR(MP_QSTR_setrtcmode), MP_ROM_PTR(&modtime_setrtcmode_obj) },
{ MP_ROM_QSTR(MP_QSTR_setlocaltime), MP_ROM_PTR(&modtime_setlocaltime_obj) },
};
STATIC MP_DEFINE_CONST_DICT(modtime_module_globals, modtime_module_globals_table);

View File

@@ -134,6 +134,7 @@ extern const struct _mp_obj_module_t modkandinsky_module;
extern const struct _mp_obj_module_t modmatplotlib_module;
extern const struct _mp_obj_module_t modpyplot_module;
extern const struct _mp_obj_module_t modtime_module;
extern const struct _mp_obj_module_t modos_module;
extern const struct _mp_obj_module_t modturtle_module;
#define MICROPY_PORT_BUILTIN_MODULES \
@@ -142,5 +143,13 @@ extern const struct _mp_obj_module_t modturtle_module;
{ MP_ROM_QSTR(MP_QSTR_matplotlib), MP_ROM_PTR(&modmatplotlib_module) }, \
{ MP_ROM_QSTR(MP_QSTR_matplotlib_dot_pyplot), MP_ROM_PTR(&modpyplot_module) }, \
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \
{ MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&modos_module) }, \
{ MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \
// Enable setjmp in debug mode. This is to avoid some optimizations done
// specifically for x86_64 using inline assembly, which makes the debug binary
// crash with an illegal instruction
#ifndef NDEBUG
#define MICROPY_NLR_SETJMP 1
#endif

View File

@@ -7,6 +7,38 @@
#include <string.h>
#include <setjmp.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
void python_error_start(const char* type) {
EM_ASM({
Module.___temp_python_error = new Object();
Module.___temp_python_error["stacktrace"] = new Array();
Module.___temp_python_error["type"] = Module.UTF8ToString($0);
}, type);
}
void python_error_add_trace(const char* file, int line, const char* block) {
EM_ASM({
var temp_obj = new Object();
temp_obj["file"] = Module.UTF8ToString($0);
temp_obj["line"] = $1;
temp_obj["block"] = Module.UTF8ToString($2);
Module.___temp_python_error.stacktrace.push(temp_obj);
}, file, line, block);
}
void python_error_end() {
EM_ASM({
if (typeof Module.onPythonError === "function") {
Module.onPythonError(Module.___temp_python_error);
}
delete Module.___temp_python_error;
});
}
#endif
/* py/parsenum.h is a C header which uses C keyword restrict.
* It does not exist in C++ so we define it here in order to be able to include
* py/parsenum.h header. */
@@ -65,6 +97,10 @@ bool MicroPython::ExecutionEnvironment::runCode(const char * str) {
* because we want to print custom information, we copied and modified the
* content of mp_obj_print_exception instead of calling it. */
if (mp_obj_is_exception_instance((mp_obj_t)nlr.ret_val)) {
#ifdef __EMSCRIPTEN__
mp_obj_exception_t* the_exception = (mp_obj_exception_t*) MP_OBJ_TO_PTR((mp_obj_t)nlr.ret_val);
python_error_start(qstr_str(the_exception->base.type->name));
#endif
size_t n, *values;
mp_obj_exception_get_traceback((mp_obj_t)nlr.ret_val, &n, &values);
if (n > 0) {
@@ -74,6 +110,9 @@ bool MicroPython::ExecutionEnvironment::runCode(const char * str) {
if (values[i] == 0) {
mp_printf(&mp_plat_print, " Last command\n");
} else {
#ifdef __EMSCRIPTEN__
python_error_add_trace((const char*) qstr_str(values[i]), (int) values[i + 1], (const char*) qstr_str(values[i+2]));
#endif
#if MICROPY_ENABLE_SOURCE_LINE
mp_printf(&mp_plat_print, " File \"%q\", line %d", values[i], (int)values[i + 1]);
#else
@@ -90,6 +129,9 @@ bool MicroPython::ExecutionEnvironment::runCode(const char * str) {
}
}
}
#ifdef __EMSCRIPTEN__
python_error_end();
#endif
}
mp_obj_print_helper(&mp_plat_print, (mp_obj_t)nlr.ret_val, PRINT_EXC);
mp_print_str(&mp_plat_print, "\n");