[Update] Upstream

This commit is contained in:
Quentin
2020-06-18 19:25:17 +02:00
96 changed files with 1051 additions and 660 deletions

View File

@@ -487,6 +487,7 @@ Q(st)
Q(hideturtle)
Q(ht)
Q(isvisible)
Q(colormode)
// utime QSTRs
Q(time)

View File

@@ -1,33 +1,17 @@
extern "C" {
#include "modkandinsky.h"
#include <py/objtuple.h>
#include <py/runtime.h>
}
#include <kandinsky.h>
#include <ion.h>
#include "port.h"
static KDColor ColorForTuple(mp_obj_t tuple) {
size_t len;
mp_obj_t * elem;
mp_obj_get_array(tuple, &len, &elem);
if (len != 3) {
mp_raise_TypeError("color needs 3 components");
}
return KDColor::RGB888(
mp_obj_get_int(elem[0]),
mp_obj_get_int(elem[1]),
mp_obj_get_int(elem[2])
);
}
static mp_obj_t TupleForRGB(uint8_t r, uint8_t g, uint8_t b) {
static mp_obj_t TupleForKDColor(KDColor c) {
mp_obj_tuple_t * t = static_cast<mp_obj_tuple_t *>(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)));
t->items[0] = MP_OBJ_NEW_SMALL_INT(r);
t->items[1] = MP_OBJ_NEW_SMALL_INT(g);
t->items[2] = MP_OBJ_NEW_SMALL_INT(b);
t->items[0] = MP_OBJ_NEW_SMALL_INT(c.red());
t->items[1] = MP_OBJ_NEW_SMALL_INT(c.green());
t->items[2] = MP_OBJ_NEW_SMALL_INT(c.blue());
return MP_OBJ_FROM_PTR(t);
}
@@ -37,12 +21,18 @@ static mp_obj_t TupleForRGB(uint8_t r, uint8_t g, uint8_t b) {
* the stackViewController and forces the window to redraw itself.
* KDIonContext::sharedContext is set to the frame of the last object drawn. */
mp_obj_t modkandinsky_color(mp_obj_t red, mp_obj_t green, mp_obj_t blue) {
return TupleForRGB(
mp_obj_get_int(red),
mp_obj_get_int(green),
mp_obj_get_int(blue)
);
mp_obj_t modkandinsky_color(size_t n_args, const mp_obj_t *args) {
mp_obj_t color;
if (n_args == 1) {
color = args[0];
} else if (n_args == 2) {
mp_raise_TypeError("color takes 1 or 3 arguments");
return mp_const_none;
} else {
assert(n_args == 3);
color = mp_obj_new_tuple(n_args, args);
}
return TupleForKDColor(MicroPython::ColorParser::ParseColor(color));
}
/* Calling ExecutionEnvironment::displaySandbox() hides the console and switches
@@ -54,22 +44,23 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y) {
KDPoint point(mp_obj_get_int(x), mp_obj_get_int(y));
KDColor c;
KDIonContext::sharedContext()->getPixel(point, &c);
return TupleForRGB(c.red(), c.green(), c.blue());
return TupleForKDColor(c);
}
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t color) {
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t input) {
KDPoint point(mp_obj_get_int(x), mp_obj_get_int(y));
KDColor kdColor = ColorForTuple(color);
KDColor kdColor = MicroPython::ColorParser::ParseColor(input);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->setPixel(point, kdColor);
return mp_const_none;
}
//TODO Use good colors
mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t * args) {
const char * text = mp_obj_str_get_str(args[0]);
KDPoint point(mp_obj_get_int(args[1]), mp_obj_get_int(args[2]));
KDColor textColor = (n_args >= 4) ? ColorForTuple(args[3]) : KDColorBlack;
KDColor backgroundColor = (n_args >= 5) ? ColorForTuple(args[4]) : KDColorWhite;
KDColor textColor = (n_args >= 4) ? MicroPython::ColorParser::ParseColor(args[3]) : KDColorBlack;
KDColor backgroundColor = (n_args >= 5) ? MicroPython::ColorParser::ParseColor(args[4]) : KDColorWhite;
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, textColor, backgroundColor);
/* Before and after execution of "modkandinsky_draw_string",
@@ -99,8 +90,7 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
y = y - height;
}
KDRect rect(x, y, width, height);
KDColor color = ColorForTuple(args[4]);
KDColor color = MicroPython::ColorParser::ParseColor(args[4]);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->fillRect(rect, color);
// Cf comment on modkandinsky_draw_string

View File

@@ -1,6 +1,6 @@
#include <py/obj.h>
mp_obj_t modkandinsky_color(mp_obj_t red, mp_obj_t green, mp_obj_t blue);
mp_obj_t modkandinsky_color(size_t n_args, const mp_obj_t *args);
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);

View File

@@ -1,6 +1,6 @@
#include "modkandinsky.h"
STATIC MP_DEFINE_CONST_FUN_OBJ_3(modkandinsky_color_obj, modkandinsky_color);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_color_obj, 1, 3, modkandinsky_color);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(modkandinsky_get_pixel_obj, modkandinsky_get_pixel);
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, 5, modkandinsky_draw_string);

View File

@@ -1,6 +1,8 @@
extern "C" {
#include "modturtle.h"
#include <py/gc.h>
#include <py/objtuple.h>
#include <py/runtime.h>
}
#include "turtle.h"
#include "../../port.h"
@@ -130,42 +132,54 @@ mp_obj_t modturtle_isdown() {
return sTurtle.isPenDown() ? mp_const_true : mp_const_false;
}
mp_float_t uint8tColorToDouble(uint8_t c) { return static_cast<double>(c)/255.0; }
mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// pencolor()
KDColor c = sTurtle.color();
mp_obj_t mp_col[3];
mp_col[0] = mp_obj_new_int_from_uint(c.red());
mp_col[1] = mp_obj_new_int_from_uint(c.green());
mp_col[2] = mp_obj_new_int_from_uint(c.blue());
if(sTurtle.colorMode() == MicroPython::ColorParser::ColorMode::MaxIntensity255){
mp_col[0] = mp_obj_new_int_from_uint(c.red());
mp_col[1] = mp_obj_new_int_from_uint(c.green());
mp_col[2] = mp_obj_new_int_from_uint(c.blue());
} else {
mp_col[0] = mp_obj_new_float(uint8tColorToDouble(c.red()));
mp_col[1] = mp_obj_new_float(uint8tColorToDouble(c.green()));
mp_col[2] = mp_obj_new_float(uint8tColorToDouble(c.blue()));
}
return mp_obj_new_tuple(3, mp_col);
}
if (n_args == 1) {
if (MP_OBJ_IS_STR(args[0])) {
// pencolor("blue")
size_t l;
sTurtle.setColor(mp_obj_str_get_data(args[0], &l));
} else {
// pencolor((r, g, b))
mp_obj_t * rgb;
mp_obj_get_array_fixed_n(args[0], 3, &rgb);
sTurtle.setColor(
KDColor::RGB888(
mp_obj_get_int(rgb[0]),
mp_obj_get_int(rgb[1]),
mp_obj_get_int(rgb[2])));
}
} else if (n_args == 3) {
// pencolor(r, g, b)
sTurtle.setColor(
KDColor::RGB888(
mp_obj_get_int(args[0]),
mp_obj_get_int(args[1]),
mp_obj_get_int(args[2])));
if (n_args == 2) {
mp_raise_TypeError("pencolor() takes 0, 1 or 3 arguments");
return mp_const_none;
}
mp_obj_t color;
if (n_args == 1) {
color = args[0];
} else {
assert(n_args == 3);
color = mp_obj_new_tuple(n_args, args);
}
sTurtle.setColor(MicroPython::ColorParser::ParseColor(color, sTurtle.colorMode()));
return mp_const_none;
}
mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args) {
if(n_args == 0){
return mp_obj_new_int_from_uint(static_cast<int>(sTurtle.colorMode()));
} else{
int colorMode = mp_obj_get_int(args[0]);
if (colorMode != static_cast<int>(MicroPython::ColorParser::ColorMode::MaxIntensity1) &&
colorMode != static_cast<int>(MicroPython::ColorParser::ColorMode::MaxIntensity255)) {
mp_raise_ValueError("Colormode can be 1 or 255");
return mp_const_none;
}
sTurtle.setColorMode(static_cast<MicroPython::ColorParser::ColorMode>(colorMode));
return mp_const_none;
}
}
mp_obj_t modturtle_showturtle() {
sTurtle.setVisible(true);
return mp_const_none;

View File

@@ -25,6 +25,7 @@ mp_obj_t modturtle_pensize(size_t n_args, const mp_obj_t *args);
mp_obj_t modturtle_isvisible();
mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args);
mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args);
mp_obj_t modturtle_showturtle();
mp_obj_t modturtle_hideturtle();

View File

@@ -18,6 +18,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pensize_obj, 0, 1, modturtl
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_isdown_obj, modturtle_isdown);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pencolor_obj, 0, 3, modturtle_pencolor);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_colormode_obj, 0, 1, modturtle_colormode);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_reset_obj, modturtle_reset);
@@ -64,6 +65,7 @@ STATIC const mp_rom_map_elem_t modturtle_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_color), (mp_obj_t)&modturtle_pencolor_obj },
{ MP_ROM_QSTR(MP_QSTR_pencolor), (mp_obj_t)&modturtle_pencolor_obj },
{ MP_ROM_QSTR(MP_QSTR_colormode), (mp_obj_t)&modturtle_colormode_obj },
{ MP_ROM_QSTR(MP_QSTR_reset), (mp_obj_t)&modturtle_reset_obj },

View File

@@ -175,27 +175,6 @@ void Turtle::setVisible(bool visible) {
}
}
void Turtle::setColor(const char * color) {
constexpr NameColorPair pairs[] = {
NameColorPair("blue", KDColorBlue),
NameColorPair("red", KDColorRed),
NameColorPair("green", Palette::Green),
NameColorPair("yellow", KDColorYellow),
NameColorPair("brown", Palette::Brown),
NameColorPair("black", KDColorBlack),
NameColorPair("white", KDColorWhite),
NameColorPair("pink", Palette::Pink),
NameColorPair("orange", Palette::Orange),
NameColorPair("purple", Palette::Purple),
NameColorPair("grey", Palette::GreyDark)
};
for (NameColorPair p : pairs) {
if (strcmp(p.name(), color) == 0) {
m_color = p.color();
return;
}
}
}
void Turtle::viewDidDisappear() {
m_drawn = false;

View File

@@ -8,6 +8,7 @@ extern "C" {
#include <escher/metric.h>
#include <kandinsky.h>
#include <math.h>
#include <python/port/port.h>
/* We check for keyboard interruptions using micropython_port_vm_hook_loop and
* micropython_port_interruptible_msleep, but even if we catch an interruption,
@@ -29,6 +30,7 @@ public:
m_y(0),
m_heading(0),
m_color(k_defaultColor),
m_colorMode(MicroPython::ColorParser::ColorMode::MaxIntensity255),
m_penDown(true),
m_visible(true),
m_speed(k_defaultSpeed),
@@ -71,7 +73,10 @@ public:
void setColor(uint8_t r, uint8_t g, uint8_t b) {
m_color = KDColor::RGB888(r, g, b);
}
void setColor(const char * color);
MicroPython::ColorParser::ColorMode colorMode() const {return m_colorMode; }
void setColorMode(MicroPython::ColorParser::ColorMode colorMode){
m_colorMode = colorMode;
}
void viewDidDisappear();
@@ -102,19 +107,6 @@ private:
Forward = 2
};
class NameColorPair {
public:
constexpr NameColorPair(const char * name, KDColor color) :
m_name(name),
m_color(color)
{}
const char * name() const { return m_name; }
KDColor color() const { return m_color; }
private:
const char * m_name;
KDColor m_color;
};
void setHeadingPrivate(mp_float_t angle);
KDPoint position(mp_float_t x, mp_float_t y) const;
KDPoint position() const { return position(m_x, m_y); }
@@ -149,6 +141,7 @@ private:
mp_float_t m_heading;
KDColor m_color;
MicroPython::ColorParser::ColorMode m_colorMode;
bool m_penDown;
bool m_visible;

View File

@@ -1,12 +1,19 @@
#include "port.h"
#include <ion/keyboard.h>
#include <ion.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <setjmp.h>
/* 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. */
#ifdef __cplusplus
#define restrict // disable
#endif
extern "C" {
#include "py/builtin.h"
#include "py/compile.h"
@@ -15,6 +22,7 @@ extern "C" {
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/nlr.h"
#include "py/parsenum.h"
#include "py/repl.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
@@ -23,6 +31,8 @@ extern "C" {
#include "mod/matplotlib/pyplot/modpyplot.h"
}
#include <escher/palette.h>
static MicroPython::ScriptProvider * sScriptProvider = nullptr;
static MicroPython::ExecutionEnvironment * sCurrentExecutionEnvironment = nullptr;
@@ -145,85 +155,130 @@ void MicroPython::registerScriptProvider(ScriptProvider * s) {
}
void MicroPython::collectRootsAtAddress(char * address, int byteLength) {
#if __EMSCRIPTEN__
// All objects are aligned, as asserted.
/* All addresses stored on the stack are aligned on sizeof(void *), as
* asserted. This is a consequence of the alignment requirements of compilers
* (Cf http://www.catb.org/esr/structure-packing/). */
assert(((unsigned long)address) % ((unsigned long)sizeof(void *)) == 0);
assert(byteLength % sizeof(void *) == 0);
gc_collect_root((void **)address, byteLength / sizeof(void *));
#else
for (size_t i = 0; i < sizeof(void *); i++) {
/* Objects on the stack are not necessarily aligned on sizeof(void *),
* which is also true for pointers refering to the heap. MicroPython
* gc_collect_root expects a table of void * that will be scanned every
* sizeof(void *) step. So we have to scan the stack repetitively with a
* increasing offset to be sure to check every byte for a heap address.
* If some memory can be reinterpreted as a pointer in the heap, gc_collect_root
* will prevent the destruction of the pointed heap memory. At worst (if
* the interpreted pointer was in fact an unaligned object or uninitialized
* memory), we will just keep extra objects in the heap which is not optimal
* but does not cause any crash. */
char * addressWithOffset = address + i;
// Ensure to round the length to the ceiling
size_t lengthInAddressSize = (byteLength - i + sizeof(void *) - 1)/sizeof(void *);
gc_collect_root((void **)addressWithOffset, lengthInAddressSize);
}
#endif
}
void gc_collect(void) {
KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorMode ColorMode){
static constexpr int maxColorIntensity = static_cast<int>(ColorMode::MaxIntensity255);
if (mp_obj_is_str(input)) {
size_t l;
const char * color = mp_obj_str_get_data(input, &l);
// TODO add cyan
constexpr NameColorPair pairs[] = {
NameColorPair("blue", KDColorBlue),
NameColorPair("b", KDColorBlue),
NameColorPair("red", KDColorRed),
NameColorPair("r", KDColorRed),
NameColorPair("green", Palette::Green),
NameColorPair("g", Palette::Green),
NameColorPair("yellow", KDColorYellow),
NameColorPair("y", KDColorYellow),
NameColorPair("brown", Palette::Brown),
NameColorPair("black", KDColorBlack),
NameColorPair("k", KDColorBlack),
NameColorPair("white", KDColorWhite),
NameColorPair("w", KDColorWhite),
NameColorPair("pink", Palette::Pink),
NameColorPair("orange", Palette::Orange),
NameColorPair("purple", Palette::Purple),
NameColorPair("grey", Palette::GreyDark)
};
for (NameColorPair p : pairs) {
if (strcmp(p.name(), color) == 0) {
return p.color();
}
}
if (color[0] == '#') {
// TODO handle #abc as #aabbcc (see matplotlib spec)
if (l != 7) {
mp_raise_ValueError("RGB hex values are 6 bytes long");
}
uint32_t colorInt = mp_obj_get_int(mp_parse_num_integer(color+1, strlen(color+1), 16, NULL));
return KDColor::RGB24(colorInt);
}
mp_float_t greyLevel = mp_obj_float_get(mp_parse_num_decimal(color, strlen(color), false, false, NULL));
if (greyLevel >= 0.0 && greyLevel <= 1.0) {
uint8_t color = maxColorIntensity * (float) greyLevel;
return KDColor::RGB888(color, color, color);
}
mp_raise_ValueError("Grey levels are between 0.0 and 1.0");
} else if(mp_obj_is_int(input)) {
mp_raise_TypeError("Int are not colors");
//See https://github.com/numworks/epsilon/issues/1533#issuecomment-618443492
} else {
size_t len;
mp_obj_t * elem;
mp_obj_get_array(input, &len, &elem);
if (len != 3) {
mp_raise_TypeError("Color needs 3 components");
}
int intensityFactor = maxColorIntensity/static_cast<int>(ColorMode);
return KDColor::RGB888(
intensityFactor * mp_obj_get_float(elem[0]),
intensityFactor * mp_obj_get_float(elem[1]),
intensityFactor * mp_obj_get_float(elem[2])
);
}
mp_raise_TypeError("Color couldn't be parsed");
}
void gc_collect_regs_and_stack(void) {
// get the registers and the sp
jmp_buf regs;
uintptr_t sp = Ion::collectRegisters(regs);
void * python_stack_top = MP_STATE_THREAD(stack_top);
assert(python_stack_top != NULL);
gc_collect_start();
modturtle_gc_collect();
modpyplot_gc_collect();
/* get the registers.
* regs is the also the last object on the stack so the stack is bound by
* &regs and python_stack_top. */
jmp_buf regs;
/* TODO: we use setjmp to get the registers values to look for python heap
* root. However, the 'setjmp' does not guarantee that it gets all registers
* values. We should check our setjmp implementation for the device and
* ensure that it also works for other platforms. */
setjmp(regs);
void **regs_ptr = (void**)&regs;
/* On the device, the stack is stored in reverse order, but it might not be
* the case on a computer. We thus have to take the absolute value of the
* addresses difference. */
size_t stackLengthInByte;
void ** scanStart;
if ((uintptr_t)python_stack_top > (uintptr_t)regs_ptr) {
if ((uintptr_t)python_stack_top > sp) {
/* To compute the stack length:
* regs
* registers
* <----------->
* STACK <- ...| | | | | |--|--|--|--| | | | | | |
* ^&regs ^python_stack_top
* ^sp ^python_stack_top
* */
stackLengthInByte = (uintptr_t)python_stack_top - (uintptr_t)regs_ptr;
scanStart = regs_ptr;
stackLengthInByte = (uintptr_t)python_stack_top - sp;
scanStart = (void **)sp;
} else {
/* When computing the stack length, take into account regs' size.
* regs
* registers
* <----------->
* STACK -> | | | | | | | | | | | |--|--|--|--| | | |...
* ^python_stack_top ^&regs
* ^python_stack_top ^sp
* */
stackLengthInByte = (uintptr_t)regs_ptr - (uintptr_t)python_stack_top + sizeof(regs);
stackLengthInByte = sp - (uintptr_t)python_stack_top + sizeof(regs);
scanStart = (void **)python_stack_top;
}
/* Memory error detectors might find an error here as they might split regs
* and stack memory zones. */
MicroPython::collectRootsAtAddress((char *)scanStart, stackLengthInByte);
}
void gc_collect(void) {
gc_collect_start();
modturtle_gc_collect();
modpyplot_gc_collect();
gc_collect_regs_and_stack();
gc_collect_end();
}
@@ -260,3 +315,4 @@ const char * mp_hal_input(const char * prompt) {
assert(sCurrentExecutionEnvironment != nullptr);
return sCurrentExecutionEnvironment->inputText(prompt);
}

View File

@@ -3,9 +3,11 @@
extern "C" {
#include <stddef.h>
#include <py/obj.h>
}
#include <escher/view_controller.h>
namespace MicroPython {
class ScriptProvider {
@@ -39,6 +41,31 @@ void deinit();
void registerScriptProvider(ScriptProvider * s);
void collectRootsAtAddress(char * address, int len);
class ColorParser {
private:
class NameColorPair {
public:
constexpr NameColorPair(const char * name, KDColor color) :
m_name(name),
m_color(color)
{}
const char * name() const { return m_name; }
KDColor color() const { return m_color; }
private:
const char * m_name;
KDColor m_color;
};
public:
enum class ColorMode {
MaxIntensity1 = 1,
MaxIntensity255 = 255,
};
static KDColor ParseColor(mp_obj_t input, ColorMode ColorMode = ColorMode::MaxIntensity255);
};
}
#endif