WIP NW module on Casio - Restoration of correct dwindow and timers at module exit

This commit is contained in:
Sylvain PILLOT 2024-01-30 18:49:17 +01:00
parent 2ac213cae0
commit 0868d96d2b
3 changed files with 399 additions and 376 deletions

View File

@ -4,66 +4,72 @@
//.-'` `---` ' License: MIT (except some files; see LICENSE) //
//---------------------------------------------------------------------------//
#include "py/builtin.h"
#include "py/compile.h"
#include "py/gc.h"
#include "py/stackctrl.h"
#include "py/builtin.h"
#include "py/mphal.h"
#include "py/repl.h"
#include "shared/runtime/gchelper.h"
#include "py/stackctrl.h"
#include "pyexec.h"
#include "shared/runtime/gchelper.h"
#include <gint/display.h>
#include <gint/drivers/keydev.h>
#include <gint/fs.h>
#include <gint/keyboard.h>
#include <gint/kmalloc.h>
#include <gint/fs.h>
#include <gint/timer.h>
#include <justui/jscene.h>
#include <justui/jlabel.h>
#include <justui/jfkeys.h>
#include <justui/jfileselect.h>
#include <justui/jfkeys.h>
#include <justui/jlabel.h>
#include <justui/jpainted.h>
#include <justui/jscene.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mpconfigport.h"
#include "console.h"
#include "widget_shell.h"
#include "debug.h"
#include "mpconfigport.h"
#include "widget_shell.h"
//=== Application globals ===//
struct pe_globals {
/* The terminal data structure (with lines, editing functions, etc). */
console_t *console;
/* The global JustUI scene. */
jscene *scene;
/* The widget shell (which connects the GUI to `console`). */
widget_shell *shell;
/* The file selection widget. */
jfileselect *fileselect;
/* Title widget and whether to show it in the shell. */
jlabel *title;
bool show_title_in_shell;
/* The terminal data structure (with lines, editing functions, etc). */
console_t *console;
/* The global JustUI scene. */
jscene *scene;
/* The widget shell (which connects the GUI to `console`). */
widget_shell *shell;
/* The file selection widget. */
jfileselect *fileselect;
/* Title widget and whether to show it in the shell. */
jlabel *title;
bool show_title_in_shell;
};
// TODO: Put pe_globals in a header for use by the loop hook in mpconfigport.h
widget_shell *pe_shell;
struct pe_globals PE = { 0 };
struct pe_globals PE = {0};
// TODO : make this more clean by putting these globals into pe_globals and
// making this accessible to modules
bool is_dwindowed = false;
bool is_timered = false;
unsigned int timer_altered[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
//=== Hook for redirecting stdout/stderr to the shell ===//
static ssize_t stdouterr_write(void *data, void const *buf, size_t size)
{
console_t *cons = data;
console_write(cons, buf, size);
return size;
static ssize_t stdouterr_write(void *data, void const *buf, size_t size) {
console_t *cons = data;
console_write(cons, buf, size);
return size;
}
fs_descriptor_type_t stdouterr_type = {
@ -75,72 +81,67 @@ fs_descriptor_type_t stdouterr_type = {
//=== File filter for the selection dialog ===//
static bool strendswith(char const *str, char const *suffix)
{
size_t l1 = strlen(str);
size_t l2 = strlen(suffix);
static bool strendswith(char const *str, char const *suffix) {
size_t l1 = strlen(str);
size_t l2 = strlen(suffix);
return l1 >= l2 && strcmp(str + l1 - l2, suffix) == 0;
return l1 >= l2 && strcmp(str + l1 - l2, suffix) == 0;
}
static bool py_file_filter(struct dirent const *ent)
{
if(!jfileselect_default_filter(ent))
return false;
if(ent->d_type == DT_DIR)
return true;
return strendswith(ent->d_name, ".py");
static bool py_file_filter(struct dirent const *ent) {
if (!jfileselect_default_filter(ent))
return false;
if (ent->d_type == DT_DIR)
return true;
return strendswith(ent->d_name, ".py");
}
//=== Module loading utilities ===//
static char *path_to_module(char const *path)
{
if(path[0] == '/')
path++;
static char *path_to_module(char const *path) {
if (path[0] == '/')
path++;
int i, n = strlen(path);
char *module = malloc(n + 1);
if(!module)
return NULL;
int i, n = strlen(path);
char *module = malloc(n + 1);
if (!module)
return NULL;
for(i = 0; i < n; i++) {
if(i == n - 3 && !strcmp(path + i, ".py"))
break;
module[i] = (path[i] == '/') ? '.' : path[i];
}
module[i] = 0;
return module;
for (i = 0; i < n; i++) {
if (i == n - 3 && !strcmp(path + i, ".py"))
break;
module[i] = (path[i] == '/') ? '.' : path[i];
}
module[i] = 0;
return module;
}
//=== AC/ON interrupt mechanism ===//
/* Filter AC/ON push events asynchronously from the keyboard driver and
interrupt MicroPython instead. */
static bool async_filter(key_event_t ev)
{
/* Gobble all events related to AC/ON to make sure that the keyboard driver
treats them as handled. Otherwise, we'd run the risk of filling the
event queue (if the user doesn't read from it) thus preventing the
driver from handling AC/ON releases, which disables further presses. */
if(mp_interrupt_char >= 0 && ev.key == KEY_ACON) {
/* This function supports asynchronous calls, by design. */
if(ev.type == KEYEV_DOWN)
mp_sched_keyboard_interrupt();
return false;
}
static bool async_filter(key_event_t ev) {
/* Gobble all events related to AC/ON to make sure that the keyboard driver
treats them as handled. Otherwise, we'd run the risk of filling the
event queue (if the user doesn't read from it) thus preventing the
driver from handling AC/ON releases, which disables further presses. */
if (mp_interrupt_char >= 0 && ev.key == KEY_ACON) {
/* This function supports asynchronous calls, by design. */
if (ev.type == KEYEV_DOWN)
mp_sched_keyboard_interrupt();
return false;
}
return true;
return true;
}
void pe_after_python_exec(int input_kind, int exec_flags, void *ret_val,
int *ret)
{
(void)input_kind;
(void)exec_flags;
(void)ret_val;
(void)ret;
clearevents();
int *ret) {
(void)input_kind;
(void)exec_flags;
(void)ret_val;
(void)ret;
clearevents();
}
//=== Rendering ===//
@ -155,335 +156,343 @@ extern bopti_image_t const img_modifier_states;
#define _(fx, cg) (cg)
#endif
void pe_enter_graphics_mode(void)
{
/* Cancel any pending update of the shell */
PE.console->render_needed = false;
PE.shell->widget.update = 0;
void pe_enter_graphics_mode(void) {
/* Cancel any pending update of the shell */
PE.console->render_needed = false;
PE.shell->widget.update = 0;
}
void pe_draw(void)
{
dclear(C_WHITE);
jscene_render(PE.scene);
void pe_draw(void) {
dclear(C_WHITE);
jscene_render(PE.scene);
/* Render shell modifiers above the scene in a convenient spot */
int shift, alpha, layer;
bool instant;
widget_shell_get_modifiers(PE.shell, &shift, &alpha);
widget_shell_modifier_info(shift, alpha, &layer, &instant);
int icon = 2 * layer + !instant;
/* Render shell modifiers above the scene in a convenient spot */
int shift, alpha, layer;
bool instant;
widget_shell_get_modifiers(PE.shell, &shift, &alpha);
widget_shell_modifier_info(shift, alpha, &layer, &instant);
int icon = 2 * layer + !instant;
#ifdef FX9860G
dsubimage(118, 58, &img_modifier_states, 9*icon+1, 1, 8, 6,
DIMAGE_NONE);
dsubimage(118, 58, &img_modifier_states, 9 * icon + 1, 1, 8, 6, DIMAGE_NONE);
#else
dsubimage(377, 207, &img_modifier_states, 16*icon, 0, 15, 14,
DIMAGE_NONE);
dsubimage(377, 207, &img_modifier_states, 16 * icon, 0, 15, 14, DIMAGE_NONE);
#endif
dupdate();
dupdate();
}
//=== Application control functions ===//
static void pe_reset_micropython(void)
{
gc_sweep_all();
mp_deinit();
mp_init();
void pe_restore_window_and_timer(void) {
if (is_dwindowed) {
struct dwindow win;
win.left = 0;
win.top = 0;
win.right = DWIDTH;
win.bottom = DHEIGHT;
dwindow_set(win);
is_dwindowed = false; // we mark as not windowed
}
#ifdef FX9860G
char const *msg = "**SHELL INIT.**\n";
#else
char const *msg = "*** SHELL INITIALIZED ***\n";
#endif
console_newline(PE.console);
console_write(PE.console, msg, -1);
pyexec_event_repl_init();
if (is_timered) {
for (int u = 0; u < 9; u++)
if (timer_altered[u] == 1)
timer_stop(u);
is_timered = false;
}
}
static void pe_print_prompt(int which)
{
char const *prompt = NULL;
if(which == 2)
prompt = mp_repl_get_ps2();
else
prompt = mp_repl_get_ps1();
static void pe_reset_micropython(void) {
gc_sweep_all();
mp_deinit();
mp_init();
console_write(PE.console, prompt, -1);
console_lock_prefix(PE.console);
#ifdef FX9860G
char const *msg = "**SHELL INIT.**\n";
#else
char const *msg = "*** SHELL INITIALIZED ***\n";
#endif
console_newline(PE.console);
console_write(PE.console, msg, -1);
pyexec_event_repl_init();
}
static void pe_print_prompt(int which) {
char const *prompt = NULL;
if (which == 2)
prompt = mp_repl_get_ps2();
else
prompt = mp_repl_get_ps1();
console_write(PE.console, prompt, -1);
console_lock_prefix(PE.console);
}
/* Handle a GUI event. If `shell_bound` is true, only actions that have an
effect on the shell are allowed and the return value is any full line that
is entered in the shell. Otherwise, the full GUI is available and the return
value is NULL. */
static char *pe_handle_event(jevent e, bool shell_bound)
{
if(e.type == JSCENE_PAINT)
pe_draw();
static char *pe_handle_event(jevent e, bool shell_bound) {
if (e.type == JSCENE_PAINT)
pe_draw();
if(e.type == WIDGET_SHELL_MOD_CHANGED)
PE.scene->widget.update = true;
if (e.type == WIDGET_SHELL_MOD_CHANGED)
PE.scene->widget.update = true;
if(e.type == WIDGET_SHELL_INPUT) {
char *line = (char *)e.data;
if(shell_bound) {
return line;
}
else {
pyexec_repl_execute(line);
free(line);
pe_print_prompt(1);
}
if (e.type == WIDGET_SHELL_INPUT) {
char *line = (char *)e.data;
if (shell_bound) {
return line;
} else {
pyexec_repl_execute(line);
free(line);
pe_print_prompt(1);
}
}
if(!shell_bound && e.type == JFILESELECT_VALIDATED) {
char const *path = jfileselect_selected_file(PE.fileselect);
char *module = path_to_module(path);
if(module) {
jscene_show_and_focus(PE.scene, PE.shell);
jwidget_set_visible(PE.title, PE.show_title_in_shell);
if (!shell_bound && e.type == JFILESELECT_VALIDATED) {
char const *path = jfileselect_selected_file(PE.fileselect);
char *module = path_to_module(path);
if (module) {
jscene_show_and_focus(PE.scene, PE.shell);
jwidget_set_visible(PE.title, PE.show_title_in_shell);
pe_reset_micropython();
pe_reset_micropython();
char *str = malloc(8 + strlen(module) + 1);
if(str) {
strcpy(str, "import ");
strcat(str, module);
pyexec_repl_execute(str);
free(str);
}
free(module);
char *str = malloc(8 + strlen(module) + 1);
if (str) {
strcpy(str, "import ");
strcat(str, module);
pyexec_repl_execute(str);
free(str);
}
free(module);
pe_print_prompt(1);
}
}
if(e.type != JWIDGET_KEY || e.key.type == KEYEV_UP)
return NULL;
int key = e.key.key;
if(key == KEY_SQUARE && !e.key.shift && e.key.alpha)
pe_debug_screenshot();
if(key == KEY_TAN)
pe_debug_kmalloc();
if(!shell_bound && key == KEY_F1) {
jscene_show_and_focus(PE.scene, PE.fileselect);
jwidget_set_visible(PE.title, true);
}
if(!shell_bound && key == KEY_F2) {
jscene_show_and_focus(PE.scene, PE.shell);
jwidget_set_visible(PE.title, PE.show_title_in_shell);
pe_restore_window_and_timer();
pe_print_prompt(1);
}
}
if (e.type != JWIDGET_KEY || e.key.type == KEYEV_UP)
return NULL;
}
int key = e.key.key;
int pe_readline(vstr_t *line, char const *prompt)
{
console_write(PE.console, prompt, -1);
console_lock_prefix(PE.console);
int c = mp_interrupt_char;
mp_hal_set_interrupt_char(-1);
char *text = NULL;
while(!text) {
jevent e = jscene_run(PE.scene);
text = pe_handle_event(e, true);
}
mp_hal_set_interrupt_char(c);
vstr_reset(line);
vstr_add_str(line, text);
free(text);
return 0; // TODO: return CHAR_CTRL_C on AC/ON instead
}
int main(int argc, char **argv)
{
pe_debug_init();
if (key == KEY_SQUARE && !e.key.shift && e.key.alpha)
pe_debug_screenshot();
if (key == KEY_TAN)
pe_debug_kmalloc();
//=== Init sequence ===//
if (!shell_bound && key == KEY_F1) {
jscene_show_and_focus(PE.scene, PE.fileselect);
jwidget_set_visible(PE.title, true);
}
if (!shell_bound && key == KEY_F2) {
jscene_show_and_focus(PE.scene, PE.shell);
jwidget_set_visible(PE.title, PE.show_title_in_shell);
}
keydev_set_async_filter(keydev_std(), async_filter);
return NULL;
}
/* Make delayed shift/alpha permanent so the stay between calls to
jscene_run() and can be used for delayed key combos */
keydev_transform_t tr = keydev_transform(keydev_std());
tr.enabled |= KEYDEV_TR_DELAYED_SHIFT;
tr.enabled |= KEYDEV_TR_DELAYED_ALPHA;
keydev_set_transform(keydev_std(), tr);
int pe_readline(vstr_t *line, char const *prompt) {
console_write(PE.console, prompt, -1);
console_lock_prefix(PE.console);
PE.console = console_create(8192, 200);
int c = mp_interrupt_char;
mp_hal_set_interrupt_char(-1);
/* Set up standard streams */
close(STDOUT_FILENO);
close(STDERR_FILENO);
open_generic(&stdouterr_type, PE.console, STDOUT_FILENO);
open_generic(&stdouterr_type, PE.console, STDERR_FILENO);
char *text = NULL;
while (!text) {
jevent e = jscene_run(PE.scene);
text = pe_handle_event(e, true);
}
/* Initialize the MicroPython GC with most available memory */
mp_stack_ctrl_init();
mp_hal_set_interrupt_char(c);
vstr_reset(line);
vstr_add_str(line, text);
free(text);
return 0; // TODO: return CHAR_CTRL_C on AC/ON instead
}
int main(int argc, char **argv) {
pe_debug_init();
pe_debug_kmalloc();
//=== Init sequence ===//
keydev_set_async_filter(keydev_std(), async_filter);
/* Make delayed shift/alpha permanent so the stay between calls to
jscene_run() and can be used for delayed key combos */
keydev_transform_t tr = keydev_transform(keydev_std());
tr.enabled |= KEYDEV_TR_DELAYED_SHIFT;
tr.enabled |= KEYDEV_TR_DELAYED_ALPHA;
keydev_set_transform(keydev_std(), tr);
PE.console = console_create(8192, 200);
/* Set up standard streams */
close(STDOUT_FILENO);
close(STDERR_FILENO);
open_generic(&stdouterr_type, PE.console, STDOUT_FILENO);
open_generic(&stdouterr_type, PE.console, STDERR_FILENO);
/* Initialize the MicroPython GC with most available memory */
mp_stack_ctrl_init();
#ifdef FX9860G
/* Put basically all the OS heap into the Python GC. For our own purposes
we'll use gint's _uram arena and the leftover from the OS heap. */
int size = 65536;
bool first = true;
/* Put basically all the OS heap into the Python GC. For our own purposes
we'll use gint's _uram arena and the leftover from the OS heap. */
int size = 65536;
bool first = true;
while(size >= 2048) {
void *area = kmalloc(size, "_os");
if(area) {
if(first)
gc_init(area, area + size);
else
gc_add(area, area + size);
first = false;
}
else size /= 2;
}
while (size >= 2048) {
void *area = kmalloc(size, "_os");
if (area) {
if (first)
gc_init(area, area + size);
else
gc_add(area, area + size);
first = false;
} else
size /= 2;
}
if(first)
pe_debug_panic("No heap!");
if (first)
pe_debug_panic("No heap!");
#if PE_DEBUG
/* Add some Python ram */
// https://www.planet-casio.com/Fr/forums/topic15269-10-khicas-add-in-calcul-formel-pour-graph-90e-et-35eii.html#189284
void *py_ram_start = (void*)0x88053800;
void *py_ram_end = (void*)0x8807f000;
gc_add(py_ram_start, py_ram_end);
/* Add some Python ram */
// https://www.planet-casio.com/Fr/forums/topic15269-10-khicas-add-in-calcul-formel-pour-graph-90e-et-35eii.html#189284
void *py_ram_start = (void *)0x88053800;
void *py_ram_end = (void *)0x8807f000;
gc_add(py_ram_start, py_ram_end);
#endif
#else
/* Get everything from the OS stack (~ 350 ko) */
size_t gc_area_size;
void *gc_area = kmalloc_max(&gc_area_size, "_ostk");
gc_init(gc_area, gc_area + gc_area_size);
/* Get everything from the OS stack (~ 350 ko) */
size_t gc_area_size;
void *gc_area = kmalloc_max(&gc_area_size, "_ostk");
gc_init(gc_area, gc_area + gc_area_size);
/* Other options:
- All of _uram (leaving the OS heap for the shell/GUI/etc)
- The OS' extra VRAM
- Memory past the 2 MB boundary on tested OSes */
// gc_add(start, end)...
/* Other options:
- All of _uram (leaving the OS heap for the shell/GUI/etc)
- The OS' extra VRAM
- Memory past the 2 MB boundary on tested OSes */
// gc_add(start, end)...
#endif
mp_init();
mp_init();
/* TODO: Add an option for the shorter prompt */
/* TODO: Add an option for the shorter prompt */
#ifdef FX9860G
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_PS1]) =
MP_OBJ_NEW_QSTR(qstr_from_str(">"));
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_PS2]) =
MP_OBJ_NEW_QSTR(qstr_from_str("."));
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_PS1]) =
MP_OBJ_NEW_QSTR(qstr_from_str(">"));
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_PS2]) =
MP_OBJ_NEW_QSTR(qstr_from_str("."));
#endif
pyexec_event_repl_init();
pe_print_prompt(1);
pyexec_event_repl_init();
pe_print_prompt(1);
//=== GUI setup ===//
//=== GUI setup ===//
PE.scene = jscene_create_fullscreen(NULL);
PE.title = jlabel_create("PythonExtra", PE.scene);
jwidget *stack = jwidget_create(PE.scene);
jfkeys *fkeys = jfkeys_create2(&img_fkeys_main, "/FILES;/SHELL", PE.scene);
(void)fkeys;
PE.scene = jscene_create_fullscreen(NULL);
PE.title = jlabel_create("PythonExtra", PE.scene);
jwidget *stack = jwidget_create(PE.scene);
jfkeys *fkeys = jfkeys_create2(&img_fkeys_main, "/FILES;/SHELL", PE.scene);
(void)fkeys;
jwidget_set_stretch(PE.title, 1, 0, false);
jwidget_set_stretch(PE.title, 1, 0, false);
jlayout_set_vbox(PE.scene)->spacing = _(0, 3);
jlayout_set_stack(stack);
jwidget_set_stretch(stack, 1, 1, false);
jlayout_set_vbox(PE.scene)->spacing = _(0, 3);
jlayout_set_stack(stack);
jwidget_set_stretch(stack, 1, 1, false);
/* Filesystem tab */
PE.fileselect = jfileselect_create(stack);
jfileselect_set_filter(PE.fileselect, py_file_filter);
jfileselect_set_show_file_size(PE.fileselect, true);
jwidget_set_stretch(PE.fileselect, 1, 1, false);
/* Filesystem tab */
PE.fileselect = jfileselect_create(stack);
jfileselect_set_filter(PE.fileselect, py_file_filter);
jfileselect_set_show_file_size(PE.fileselect, true);
jwidget_set_stretch(PE.fileselect, 1, 1, false);
/* Shell tab */
PE.shell = pe_shell = widget_shell_create(PE.console, stack);
widget_shell_set_line_spacing(PE.shell, _(1, 3));
jwidget_set_stretch(PE.shell, 1, 1, false);
/* Shell tab */
PE.shell = pe_shell = widget_shell_create(PE.console, stack);
widget_shell_set_line_spacing(PE.shell, _(1, 3));
jwidget_set_stretch(PE.shell, 1, 1, false);
#ifdef FX9860G
PE.show_title_in_shell = false;
jwidget_set_padding(PE.title, 0, 0, 1, 0);
widget_shell_set_font(PE.shell, &font_4x6);
PE.show_title_in_shell = false;
jwidget_set_padding(PE.title, 0, 0, 1, 0);
widget_shell_set_font(PE.shell, &font_4x6);
#else
PE.show_title_in_shell = true;
jwidget_set_background(PE.title, C_BLACK);
jlabel_set_text_color(PE.title, C_WHITE);
jwidget_set_padding(PE.title, 3, 6, 3, 6);
jwidget_set_padding(stack, 0, 6, 0, 6);
PE.show_title_in_shell = true;
jwidget_set_background(PE.title, C_BLACK);
jlabel_set_text_color(PE.title, C_WHITE);
jwidget_set_padding(PE.title, 3, 6, 3, 6);
jwidget_set_padding(stack, 0, 6, 0, 6);
#endif
/* Initial state */
jfileselect_browse(PE.fileselect, "/");
jscene_show_and_focus(PE.scene, PE.fileselect);
/* Initial state */
jfileselect_browse(PE.fileselect, "/");
jscene_show_and_focus(PE.scene, PE.fileselect);
//=== Event handling ===//
//=== Event handling ===//
while(1) {
jevent e = jscene_run(PE.scene);
pe_handle_event(e, false);
}
while (1) {
jevent e = jscene_run(PE.scene);
pe_handle_event(e, false);
}
//=== Deinitialization ===//
//=== Deinitialization ===//
gc_sweep_all();
mp_deinit();
console_destroy(PE.console);
return 0;
gc_sweep_all();
mp_deinit();
console_destroy(PE.console);
return 0;
}
/* Handle uncaught exceptions (normally unreachable). */
void nlr_jump_fail(void *val)
{
dclear(C_BLACK);
dtext(2, 2, C_WHITE, "nlr_jump_fail!");
dprint(2, 2, C_WHITE, "val = %p", val);
dupdate();
while(1)
getkey();
void nlr_jump_fail(void *val) {
dclear(C_BLACK);
dtext(2, 2, C_WHITE, "nlr_jump_fail!");
dprint(2, 2, C_WHITE, "val = %p", val);
dupdate();
while (1)
getkey();
}
/* Do a garbage collection cycle. */
void gc_collect(void)
{
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
void gc_collect(void) {
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
}
mp_import_stat_t mp_import_stat(const char *path)
{
struct stat st;
int rc = stat(path, &st);
if(rc < 0)
return MP_IMPORT_STAT_NO_EXIST;
mp_import_stat_t mp_import_stat(const char *path) {
struct stat st;
int rc = stat(path, &st);
if (rc < 0)
return MP_IMPORT_STAT_NO_EXIST;
if(S_ISDIR(st.st_mode))
return MP_IMPORT_STAT_DIR;
else
return MP_IMPORT_STAT_FILE;
if (S_ISDIR(st.st_mode))
return MP_IMPORT_STAT_DIR;
else
return MP_IMPORT_STAT_FILE;
}
// TODO: See branch 'posix-open' for a relevant attempt at using the POSIX API
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs)
{
mp_obj_t *args_items;
size_t len;
mp_obj_get_array(*args, &len, &args_items);
printf("%d %p\n", (int)len, args_items);
if(len != 2)
return mp_const_none;
char const *path = mp_obj_str_get_str(args_items[0]);
char const *mode = mp_obj_str_get_str(args_items[1]);
printf("'%s' '%s'\n", path, mode);
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args,
mp_map_t *kwargs) {
mp_obj_t *args_items;
size_t len;
mp_obj_get_array(*args, &len, &args_items);
printf("%d %p\n", (int)len, args_items);
if (len != 2)
return mp_const_none;
char const *path = mp_obj_str_get_str(args_items[0]);
char const *mode = mp_obj_str_get_str(args_items[1]);
printf("'%s' '%s'\n", path, mode);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

View File

@ -0,0 +1,21 @@
// Data can be found here
// https://github.com/numworks/epsilon/blob/master/escher/include/escher/palette.h
// and here
// https://github.com/numworks/epsilon/blob/master/python/port/port.cpp#L221
#define NW_RGB(r, g, b) (((r >> 3) << 11) | ((g >> 2) << 6) | (b >> 3))
#define NW_BLUE NW_RGB(0x50, 0x75, 0xF2)
#define NW_RED NW_RGB(0xFF, 0x00, 0x0C)
#define NW_GREEN NW_RGB(0x50, 0xC1, 0x02)
#define NW_WHITE NW_RGB(0xF7, 0xF9, 0xFA)
#define NW_BLACK NW_RGB(0x00, 0x00, 0x00)
#define NW_YELLOW NW_RGB(0xFF, 0xCC, 0x7B)
#define NW_PURPLE NW_RGB(0x6E, 0x2D, 0x79)
#define NW_BROWN NW_RGB(0x8D, 0x73, 0x50)
#define NW_CYAN NW_RGB(0x00, 0xFF, 0xFF)
#define NW_ORANGE NW_RGB(0xFE, 0x87, 0x1F)
#define NW_PINK NW_RGB(0xFF, 0xAB, 0xB6)
#define NW_MAGENTA NW_RGB(0xFF, 0x05, 0x88)
#define NW_GRAY NW_RGB(0xA7, 0xA7, 0xA7)

View File

@ -14,8 +14,14 @@
#include <stdlib.h>
#include <string.h>
#include "colorsNW.h"
extern font_t numworks;
extern bool is_dwindowed;
extern bool is_timered;
extern unsigned int timer_altered[9];
static int callback(void) {
dupdate();
return TIMER_CONTINUE;
@ -38,13 +44,22 @@ static mp_obj_t Kandinsky_make_color(color_t color) {
static mp_obj_t Kandinsky_init(void) {
void pe_enter_graphics_mode(void);
pe_enter_graphics_mode();
dclear(NW_WHITE);
dclear(C_WHITE);
struct dwindow nw;
nw.left = 0;
nw.top = 0;
nw.right = 320;
nw.bottom = 240;
dwindow_set(nw);
is_dwindowed = true; // we mark as windowed
int t = timer_configure(TIMER_TMU, 33333, GINT_CALL(callback));
if (t >= 0)
if (t >= 0) {
timer_start(t);
is_timered = true; // there is a timer altered from this module
timer_altered[t] = 1; // we put the corresponding timer at 1 to identify it
}
return mp_const_none;
}
@ -59,57 +74,35 @@ static mp_obj_t Kandinsky_color(size_t n, mp_obj_t const *args) {
int Internal_Get_Color_From_String(const char *str) {
if (strcmp(str, "red") == 0)
return C_RGB(31, 0, 0);
else if (strcmp(str, "r") == 0)
return C_RGB(31, 0, 0);
else if (strcmp(str, "green") == 0)
return C_RGB(0, 31, 0);
else if (strcmp(str, "g") == 0)
return C_RGB(0, 31, 0);
else if (strcmp(str, "blue") == 0)
return C_RGB(0, 0, 31);
else if (strcmp(str, "b") == 0)
return C_RGB(0, 0, 31);
else if (strcmp(str, "black") == 0)
return C_RGB(0, 0, 0);
else if (strcmp(str, "k") == 0)
return C_RGB(0, 0, 0);
else if (strcmp(str, "white") == 0)
return C_RGB(31, 31, 31);
else if (strcmp(str, "w") == 0)
return C_RGB(31, 31, 31);
else if (strcmp(str, "yellow") == 0)
return C_RGB(31, 31, 0);
else if (strcmp(str, "y") == 0)
return C_RGB(31, 31, 0);
// Data can be found here
// https://github.com/numworks/epsilon/blob/master/escher/include/escher/palette.h
// and here
// https://github.com/numworks/epsilon/blob/master/python/port/port.cpp#L221
if (strcmp(str, "red") == 0 || strcmp(str, "r") == 0)
return NW_RED;
else if (strcmp(str, "green") == 0 || strcmp(str, "g") == 0)
return NW_GREEN;
else if (strcmp(str, "blue") == 0 || strcmp(str, "b") == 0)
return NW_BLUE;
else if (strcmp(str, "black") == 0 || strcmp(str, "k") == 0)
return NW_BLACK;
else if (strcmp(str, "white") == 0 || strcmp(str, "w") == 0)
return NW_WHITE;
else if (strcmp(str, "yellow") == 0 || strcmp(str, "y") == 0)
return NW_YELLOW;
else if (strcmp(str, "pink") == 0)
return C_RGB(0xFF >> 3, 0xAB >> 3, 0xB6 >> 3);
return NW_PINK;
else if (strcmp(str, "magenta") == 0)
return C_RGB(31, 0, 31);
else if (strcmp(str, "grey") == 0)
return C_RGB(0xA7 >> 3, 0xA7 >> 3, 0xA7 >> 3);
else if (strcmp(str, "gray") == 0)
return C_RGB(0xA7 >> 3, 0xA7 >> 3, 0xA7 >> 3);
return NW_MAGENTA;
else if (strcmp(str, "grey") == 0 || strcmp(str, "gray") == 0)
return NW_GRAY;
else if (strcmp(str, "purple") == 0)
return C_RGB(15, 0, 31);
return NW_PURPLE;
else if (strcmp(str, "orange") == 0)
return C_RGB(31, 15, 0);
return NW_ORANGE;
else if (strcmp(str, "cyan") == 0)
return C_RGB(31, 15, 0);
return NW_CYAN;
else if (strcmp(str, "brown") == 0)
return NW_BROWN;
else
return C_RGB(0, 0, 0);
return NW_BLACK;
}
int Internal_Treat_Color(mp_obj_t color) {
@ -131,9 +124,9 @@ int Internal_Treat_Color(mp_obj_t color) {
int r = mp_obj_get_int(items[0]) >> 3;
int g = mp_obj_get_int(items[1]) >> 3;
int b = mp_obj_get_int(items[2]) >> 3;
return C_RGB(r, g, b);
return NW_RGB(r, g, b);
} else
return C_BLACK;
return NW_BLACK;
}
static mp_obj_t Kandinsky_fill_rect(size_t n, mp_obj_t const *args) {
@ -157,7 +150,7 @@ static mp_obj_t Kandinsky_set_pixel(size_t n, mp_obj_t const *args) {
if (n == 3)
color = Internal_Treat_Color(args[2]);
else
color = C_BLACK;
color = NW_BLACK;
dpixel(x, y, color);
return mp_const_none;
@ -190,7 +183,7 @@ static mp_obj_t Kandinsky_draw_string(size_t n, mp_obj_t const *args) {
}
}
color_t colortext = C_BLACK;
color_t colortext = NW_BLACK;
if (n >= 4) {
colortext = Internal_Treat_Color(args[3]);
}