bd36873362
ESP8266 port uses SDK 2.0, has more heap, has support for 512k devices This release brings some code size reductions to the core as well as more tests and improved coverage which is now at 94.3%. The time.ticks_diff(a, b) function has changed: the order of the arguments has been swapped so that it behaves like "a - b", and it can now return a negative number if "a" came before "b" (modulo the period of the ticks functions). For the ESP8266 port the Espressif SDK has been updated to 2.0.0, the heap has been increased from 28k to 36k, and there is support for 512k devices via "make 512k". upip is included by default as frozen bytecode. The network module now allows access-point reconnection without WiFi credentials, and exposes configuration for the station DHCP hostname. The DS18B20 driver now handles negative temperatures, and NeoPixel and APA102 drivers handle 4 bytes-per-pixel LEDs. For the CC3200 port there is now support for loading of precompiled .mpy files and threading now works properly with interrupts. A detailed list of changes follows. py core: - py.mk: automatically add frozen.c to source list if FROZEN_DIR is defined - be more specific with MP_DECLARE_CONST_FUN_OBJ macros - specialise builtin funcs to use separate type for fixed arg count - {modbuiltins,obj}: use MP_PYTHON_PRINTER where possible - modbuiltins: add builtin "slice", pointing to existing slice type - add "delattr" builtin, conditional on MICROPY_CPYTHON_COMPAT - sequence: fix reverse slicing of lists - fix null pointer dereference in mpz.c, fix missing va_end in warning.c - remove asserts that are always true in emitbc.c - fix wrong assumption that m_renew will not move if shrinking - change config default so m_malloc0 uses memset if GC not enabled - add MICROPY_FLOAT_CONST macro for defining float constants - move frozen bytecode Makefile rules from ports to common mk files - strip leading dirs from frozen mpy files, so any path can be used extmod: - vfs_fat_file: check fatfs f_sync() and f_close() returns for errors - vfs_fat_file: make file.close() a no-op if file already closed - utime_mphal: ticks_diff(): switch arg order, return signed value - utime_mphal: add MP_THREAD_GIL_EXIT/ENTER warppers for sleep functions - utime_mphal: implement ticks_add(), add to all maintained ports - utime_mphal: allow ticks functions period be configurable by a port lib: - utils/pyhelp.c: use mp_printf() instead of printf() - utils/pyexec: add mp_hal_set_interrupt_char() prototype - libm: move Thumb-specific sqrtf function to separate file drivers: - add "from micropython import const" when const is used tools: - upgrade upip to 1.1.4: fix error on unix when installing to non-existing absolute path - pip-micropython: remove deprecated wrapper tool - check_code_size.sh: code size validation script for CI - replace upip tarball with just source file, to make its inclusion as frozen modules in multiple ports less magic tests: - extmod/vfs_fat: improve VFS test coverage - basics/builtin_slice: add test for "slice" builtin name - basics: add test for builtin "delattr" - extmod/vfs_fat_fsusermount: improve fsusermount test coverage - extmod/vfs_fat_oldproto: test old block device protocol - basics/gc1: garbage collector threshold() coverage - extmod/uhashlib_sha1: coverage for SHA1 algorithm - extmod/uhashlib_sha256: rename sha256.py test - btree1: fix out of memory error running on esp8266 - extmod/ticks_diff: test for new semantics of ticks_diff() - extmod/framebuf1: test framebuffer pixel clear, and text function minimal port: - Makefile: split rule for firmware.bin generation unix port: - Makefile: remove references to deprecated pip-micropython - modtime: use ticks_diff() implementation from extmod/utime_mphal.c - mphalport.h: add warning of mp_hal_delay_ms() implementation - modtime: switch ticks/sleep_ms/us() to utime_mphal - fix symbol references for x86 Mac - replace upip tarball with just source file windows port: - enable utime_mphal following unix, define mp_hal_ticks_* - fix utime_mphal compilation for msvc - implement mp_hal_ticks_cpu in terms of QueryPerformanceCounter qemu-arm port: - exclude ticks_diff test for qemu-arm port - exclude extmod/vfs_fat_fileio.py test - exclude new vfs_fat tests - enable software floating point support, and float tests stmhal port: - modutime: refactor to use extmod's version of ticks_cpu - refactor pin usage to use mp_hal_pin API - led: refactor LED to use mp_hal_pin_output() init function - Makefile: use standard rules for frozen module generation - modutime: consistently convert to MP_ROM_QSTR/MP_ROM_PTR - enable SD power save (disable CLK on idle) cc3200 port: - use mp_raise_XXX helper functions to reduce code size - mods/pybspi: allow "write" arg of read/readinto to be positional - enable loading of precompiled .mpy files - fix thread mutex's so threading works with interrupts teensy port: - update to provide new mp_hal_pin_XXX functions following stmhal esp8266 port: - Makefile: use latest esptool.py flash size auto-detection - esp_init_data: auto-initialize system params with vendor SDK 2.0.0 - esp8266.ld: move help.o to iROM - esp8266.ld: move modmachine.o to iROM - esp8266.ld: move main.o to iROM - add MP_FASTCODE modifier to put a function to iRAM - main: mark nlr_jump_fail() as MP_FASTCODE - modules/webrepl: enforce only one concurrent WebREPL connection - etshal.h: add few more ESP8266 vendor lib prototypes - modesp: add flash_user_start() function - add support for building firmware version for 512K modules - scripts: make neopixel/apa102 handle 4bpp LEDs with common code - modutime: consistently convert to MP_ROM_QSTR/MP_ROM_PTR - modnetwork: config(): fix copy-paste error in setting "mac" - scripts/port_diag: add descriptions for esf_buf types - modnetwork.c: allows AP reconnection without WiFi credentials - main: bump heap size to 36K - etshal.h: add prototypes for SPIRead/SPIWrite/SPIEraseSector - etshal.h: adjust size of MD5_CTX structure - modules: fix negative temperature in ds18x20 driver - rename "machine" module implementation to use contemporary naming - rework webrepl_setup to run over wired REPL - espneopixel.c: solve glitching LED issues with cpu at 80MHz - include upip as a standard frozen bytecode module - update docs for esptool 1.2.1/SDK 2.0 (--flash_size=detect) - modnetwork.c: expose configuration for station DHCP hostname zephyr port: - implement utime module - use board/SoC values for startup banner based on Zephyr config - initial implementation of machine.Pin - zephyr_getchar: update for recent Zephyr refactor of console hooks - support time -> utime module "weaklink" - README: update for the current featureset, add more info - mpconfigport.h: move less important params to the bottom - Makefile: allow to adjust heap size from make command line - Makefile: update comments to the current state of affairs - Makefile: allow to override Zephyr config from make command line - Makefile: add minimal port - Makefile: add -fomit-frame-pointer to reduce code size - mphalport.h: update for new "unified" kernal API (sleep functions) docs: - machine.SPI: bring up to date with Hardware API, make vendor-neutral - machine.SPI: improve descriptions of xfer methods - library/builtins: add docs for delattr and slice - library/network: reword intro paragraph - library/network: typo fixes, consistent acronym capitalization - library/index: update TOCs so builtins sorted before modules - utime: document ticks_cpu() in more detail - utime: describe new semantics of ticks_diff() (signed ring arithmetics) - utime: add docs for ticks_add(), improvements for other ticks_*() - esp8266: update for new WebREPL setup procedure - */quickref.rst: use new semantics of ticks_diff() - library/machine.Pin: update Pin docs to align with new HW API travis: - integrate tools/check_code_size.sh - minimal: Use CROSS=1, for binary size check examples: - http_server_simplistic: add "not suitable for real use" note - hwapi: example showing best practices for HW API usage in apps - hwapi: add hwconfig for DragonBoard 410c
540 lines
18 KiB
C
540 lines
18 KiB
C
/*
|
|
* This file is part of the Micro Python project, http://micropython.org/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2013, 2014 Damien P. George
|
|
*
|
|
* 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "py/nlr.h"
|
|
#include "py/compile.h"
|
|
#include "py/runtime.h"
|
|
#include "py/repl.h"
|
|
#include "py/gc.h"
|
|
#include "py/frozenmod.h"
|
|
#include "py/mphal.h"
|
|
#if defined(USE_DEVICE_MODE)
|
|
#include "irq.h"
|
|
#include "usb.h"
|
|
#endif
|
|
#include "lib/mp-readline/readline.h"
|
|
#include "lib/utils/pyexec.h"
|
|
#include "genhdr/mpversion.h"
|
|
|
|
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
|
int pyexec_system_exit = 0;
|
|
STATIC bool repl_display_debugging_info = 0;
|
|
|
|
#define EXEC_FLAG_PRINT_EOF (1)
|
|
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
|
|
#define EXEC_FLAG_IS_REPL (4)
|
|
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8)
|
|
|
|
// parses, compiles and executes the code in the lexer
|
|
// frees the lexer before returning
|
|
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
|
|
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
|
|
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
|
|
STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int exec_flags) {
|
|
int ret = 0;
|
|
uint32_t start = 0;
|
|
|
|
// by default a SystemExit exception returns 0
|
|
pyexec_system_exit = 0;
|
|
|
|
nlr_buf_t nlr;
|
|
if (nlr_push(&nlr) == 0) {
|
|
mp_obj_t module_fun;
|
|
#if MICROPY_MODULE_FROZEN_MPY
|
|
if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {
|
|
// source is a raw_code object, create the function
|
|
module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);
|
|
} else
|
|
#endif
|
|
{
|
|
// source is a lexer, parse and compile the script
|
|
mp_lexer_t *lex = source;
|
|
qstr source_name = lex->source_name;
|
|
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
|
module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);
|
|
}
|
|
|
|
// execute code
|
|
mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
|
|
start = mp_hal_ticks_ms();
|
|
mp_call_function_0(module_fun);
|
|
mp_hal_set_interrupt_char(-1); // disable interrupt
|
|
nlr_pop();
|
|
ret = 1;
|
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
|
mp_hal_stdout_tx_strn("\x04", 1);
|
|
}
|
|
} else {
|
|
// uncaught exception
|
|
// FIXME it could be that an interrupt happens just before we disable it here
|
|
mp_hal_set_interrupt_char(-1); // disable interrupt
|
|
// print EOF after normal output
|
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
|
mp_hal_stdout_tx_strn("\x04", 1);
|
|
}
|
|
// check for SystemExit
|
|
if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
|
|
// at the moment, the value of SystemExit is unused
|
|
ret = pyexec_system_exit;
|
|
} else if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_KeyboardInterrupt)) {
|
|
ret = PYEXEC_FORCED_EXIT;
|
|
} else {
|
|
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
// display debugging info if wanted
|
|
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
|
|
mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly
|
|
printf("took " UINT_FMT " ms\n", ticks);
|
|
// qstr info
|
|
{
|
|
size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
|
|
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
|
|
printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n "
|
|
"n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n",
|
|
(unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes);
|
|
}
|
|
|
|
#if MICROPY_ENABLE_GC
|
|
// run collection and print GC info
|
|
gc_collect();
|
|
gc_dump_info();
|
|
#endif
|
|
}
|
|
|
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
|
mp_hal_stdout_tx_strn("\x04", 1);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if MICROPY_REPL_EVENT_DRIVEN
|
|
|
|
typedef struct _repl_t {
|
|
// This structure originally also held current REPL line,
|
|
// but it was moved to MP_STATE_VM(repl_line) as containing
|
|
// root pointer. Still keep structure in case more state
|
|
// will be added later.
|
|
//vstr_t line;
|
|
bool cont_line;
|
|
} repl_t;
|
|
|
|
repl_t repl;
|
|
|
|
STATIC int pyexec_raw_repl_process_char(int c);
|
|
STATIC int pyexec_friendly_repl_process_char(int c);
|
|
|
|
void pyexec_event_repl_init(void) {
|
|
MP_STATE_VM(repl_line) = vstr_new(32);
|
|
repl.cont_line = false;
|
|
readline_init(MP_STATE_VM(repl_line), ">>> ");
|
|
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
|
pyexec_raw_repl_process_char(CHAR_CTRL_A);
|
|
} else {
|
|
pyexec_friendly_repl_process_char(CHAR_CTRL_B);
|
|
}
|
|
}
|
|
|
|
STATIC int pyexec_raw_repl_process_char(int c) {
|
|
if (c == CHAR_CTRL_A) {
|
|
// reset raw REPL
|
|
mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
|
|
goto reset;
|
|
} else if (c == CHAR_CTRL_B) {
|
|
// change to friendly REPL
|
|
pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
|
repl.cont_line = false;
|
|
pyexec_friendly_repl_process_char(CHAR_CTRL_B);
|
|
return 0;
|
|
} else if (c == CHAR_CTRL_C) {
|
|
// clear line
|
|
vstr_reset(MP_STATE_VM(repl_line));
|
|
return 0;
|
|
} else if (c == CHAR_CTRL_D) {
|
|
// input finished
|
|
} else {
|
|
// let through any other raw 8-bit value
|
|
vstr_add_byte(MP_STATE_VM(repl_line), c);
|
|
return 0;
|
|
}
|
|
|
|
// indicate reception of command
|
|
mp_hal_stdout_tx_str("OK");
|
|
|
|
if (MP_STATE_VM(repl_line)->len == 0) {
|
|
// exit for a soft reset
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(MP_STATE_VM(repl_line));
|
|
return PYEXEC_FORCED_EXIT;
|
|
}
|
|
|
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, MP_STATE_VM(repl_line)->buf, MP_STATE_VM(repl_line)->len, 0);
|
|
if (lex == NULL) {
|
|
mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04");
|
|
} else {
|
|
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
reset:
|
|
vstr_reset(MP_STATE_VM(repl_line));
|
|
mp_hal_stdout_tx_str(">");
|
|
|
|
return 0;
|
|
}
|
|
|
|
STATIC int pyexec_friendly_repl_process_char(int c) {
|
|
int ret = readline_process_char(c);
|
|
|
|
if (!repl.cont_line) {
|
|
|
|
if (ret == CHAR_CTRL_A) {
|
|
// change to raw REPL
|
|
pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
pyexec_raw_repl_process_char(CHAR_CTRL_A);
|
|
return 0;
|
|
} else if (ret == CHAR_CTRL_B) {
|
|
// reset friendly REPL
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
mp_hal_stdout_tx_str("Adafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
|
|
// mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
|
|
goto input_restart;
|
|
} else if (ret == CHAR_CTRL_C) {
|
|
// break
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
goto input_restart;
|
|
} else if (ret == CHAR_CTRL_D) {
|
|
// exit for a soft reset
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(MP_STATE_VM(repl_line));
|
|
return PYEXEC_FORCED_EXIT;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (!mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {
|
|
goto exec;
|
|
}
|
|
|
|
vstr_add_byte(MP_STATE_VM(repl_line), '\n');
|
|
repl.cont_line = true;
|
|
readline_note_newline("... ");
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if (ret == CHAR_CTRL_C) {
|
|
// cancel everything
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
repl.cont_line = false;
|
|
goto input_restart;
|
|
} else if (ret == CHAR_CTRL_D) {
|
|
// stop entering compound statement
|
|
goto exec;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) {
|
|
vstr_add_byte(MP_STATE_VM(repl_line), '\n');
|
|
readline_note_newline("... ");
|
|
return 0;
|
|
}
|
|
|
|
exec: ;
|
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(MP_STATE_VM(repl_line)), vstr_len(MP_STATE_VM(repl_line)), 0);
|
|
if (lex == NULL) {
|
|
printf("MemoryError\n");
|
|
} else {
|
|
int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
input_restart:
|
|
vstr_reset(MP_STATE_VM(repl_line));
|
|
repl.cont_line = false;
|
|
readline_init(MP_STATE_VM(repl_line), ">>> ");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t pyexec_repl_active;
|
|
int pyexec_event_repl_process_char(int c) {
|
|
pyexec_repl_active = 1;
|
|
int res;
|
|
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
|
res = pyexec_raw_repl_process_char(c);
|
|
} else {
|
|
res = pyexec_friendly_repl_process_char(c);
|
|
}
|
|
pyexec_repl_active = 0;
|
|
return res;
|
|
}
|
|
|
|
#else // MICROPY_REPL_EVENT_DRIVEN
|
|
|
|
int pyexec_raw_repl(void) {
|
|
vstr_t line;
|
|
vstr_init(&line, 32);
|
|
|
|
raw_repl_reset:
|
|
mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
|
|
|
|
for (;;) {
|
|
vstr_reset(&line);
|
|
mp_hal_stdout_tx_str(">");
|
|
for (;;) {
|
|
int c = mp_hal_stdin_rx_chr();
|
|
if (c == CHAR_CTRL_A) {
|
|
// reset raw REPL
|
|
goto raw_repl_reset;
|
|
} else if (c == CHAR_CTRL_B) {
|
|
// change to friendly REPL
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(&line);
|
|
pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
|
return 0;
|
|
} else if (c == CHAR_CTRL_C) {
|
|
// clear line
|
|
vstr_reset(&line);
|
|
} else if (c == CHAR_CTRL_D) {
|
|
// input finished
|
|
break;
|
|
} else {
|
|
// let through any other raw 8-bit value
|
|
vstr_add_byte(&line, c);
|
|
}
|
|
}
|
|
|
|
// indicate reception of command
|
|
mp_hal_stdout_tx_str("OK");
|
|
|
|
if (line.len == 0) {
|
|
// exit for a soft reset
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(&line);
|
|
return PYEXEC_FORCED_EXIT;
|
|
}
|
|
|
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0);
|
|
if (lex == NULL) {
|
|
printf("\x04MemoryError\n\x04");
|
|
} else {
|
|
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int pyexec_friendly_repl(void) {
|
|
vstr_t line;
|
|
vstr_init(&line, 32);
|
|
|
|
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
|
|
// in host mode, we enable the LCD for the repl
|
|
mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD")));
|
|
mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
|
|
#endif
|
|
|
|
friendly_repl_reset:
|
|
mp_hal_stdout_tx_str("Adafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
|
|
// mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
|
|
|
|
// to test ctrl-C
|
|
/*
|
|
{
|
|
uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
|
|
for (;;) {
|
|
nlr_buf_t nlr;
|
|
printf("pyexec_repl: %p\n", x);
|
|
mp_hal_set_interrupt_char(CHAR_CTRL_C);
|
|
if (nlr_push(&nlr) == 0) {
|
|
for (;;) {
|
|
}
|
|
} else {
|
|
printf("break\n");
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
for (;;) {
|
|
input_restart:
|
|
|
|
#if defined(USE_DEVICE_MODE)
|
|
if (usb_vcp_is_enabled()) {
|
|
// If the user gets to here and interrupts are disabled then
|
|
// they'll never see the prompt, traceback etc. The USB REPL needs
|
|
// interrupts to be enabled or no transfers occur. So we try to
|
|
// do the user a favor and reenable interrupts.
|
|
if (query_irq() == IRQ_STATE_DISABLED) {
|
|
enable_irq(IRQ_STATE_ENABLED);
|
|
mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
vstr_reset(&line);
|
|
int ret = readline(&line, ">>> ");
|
|
mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
|
|
|
|
if (ret == CHAR_CTRL_A) {
|
|
// change to raw REPL
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(&line);
|
|
pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
|
|
return 0;
|
|
} else if (ret == CHAR_CTRL_B) {
|
|
// reset friendly REPL
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
goto friendly_repl_reset;
|
|
} else if (ret == CHAR_CTRL_C) {
|
|
// break
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
continue;
|
|
} else if (ret == CHAR_CTRL_D) {
|
|
// exit for a soft reset
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
vstr_clear(&line);
|
|
return PYEXEC_FORCED_EXIT;
|
|
} else if (ret == CHAR_CTRL_E) {
|
|
// paste mode
|
|
mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== ");
|
|
vstr_reset(&line);
|
|
for (;;) {
|
|
char c = mp_hal_stdin_rx_chr();
|
|
if (c == CHAR_CTRL_C) {
|
|
// cancel everything
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
goto input_restart;
|
|
} else if (c == CHAR_CTRL_D) {
|
|
// end of input
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
break;
|
|
} else {
|
|
// add char to buffer and echo
|
|
vstr_add_byte(&line, c);
|
|
if (c == '\r') {
|
|
mp_hal_stdout_tx_str("\r\n=== ");
|
|
} else {
|
|
mp_hal_stdout_tx_strn(&c, 1);
|
|
}
|
|
}
|
|
}
|
|
parse_input_kind = MP_PARSE_FILE_INPUT;
|
|
} else if (vstr_len(&line) == 0) {
|
|
continue;
|
|
} else {
|
|
// got a line with non-zero length, see if it needs continuing
|
|
while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
|
|
vstr_add_byte(&line, '\n');
|
|
ret = readline(&line, "... ");
|
|
if (ret == CHAR_CTRL_C) {
|
|
// cancel everything
|
|
mp_hal_stdout_tx_str("\r\n");
|
|
goto input_restart;
|
|
} else if (ret == CHAR_CTRL_D) {
|
|
// stop entering compound statement
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
|
|
if (lex == NULL) {
|
|
printf("MemoryError\n");
|
|
} else {
|
|
ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // MICROPY_REPL_EVENT_DRIVEN
|
|
|
|
int pyexec_file(const char *filename) {
|
|
mp_lexer_t *lex = mp_lexer_new_from_file(filename);
|
|
|
|
if (lex == NULL) {
|
|
printf("could not open file '%s' for reading\n", filename);
|
|
return false;
|
|
}
|
|
|
|
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0);
|
|
}
|
|
|
|
#if MICROPY_MODULE_FROZEN
|
|
int pyexec_frozen_module(const char *name) {
|
|
void *frozen_data;
|
|
int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data);
|
|
|
|
switch (frozen_type) {
|
|
#if MICROPY_MODULE_FROZEN_STR
|
|
case MP_FROZEN_STR:
|
|
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0);
|
|
#endif
|
|
|
|
#if MICROPY_MODULE_FROZEN_MPY
|
|
case MP_FROZEN_MPY:
|
|
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE);
|
|
#endif
|
|
|
|
default:
|
|
printf("could not find module '%s'\n", name);
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
|
repl_display_debugging_info = mp_obj_get_int(o_value);
|
|
return mp_const_none;
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
|