Merge MicroPython 1.14 into CircuitPython

This commit is contained in:
Scott Shawcroft 2021-05-10 15:20:47 -07:00
commit e02a26453c
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
166 changed files with 4551 additions and 2402 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2013-2020 Damien P. George Copyright (c) 2013-2021 Damien P. George
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -14,13 +14,11 @@ Functions
.. function:: hexlify(data, [sep]) .. function:: hexlify(data, [sep])
Convert binary data to hexadecimal representation. Returns bytes string. Convert the bytes in the *data* object to a hexadecimal representation.
Returns a bytes object.
.. admonition:: Difference to CPython If the additional argument *sep* is supplied it is used as a separator
:class: attention between hexadecimal values.
If additional argument, *sep* is supplied, it is used as a separator
between hexadecimal values.
.. function:: unhexlify(data) .. function:: unhexlify(data)

View File

@ -120,7 +120,7 @@ Methods
.. method:: btree.__getitem__(key) .. method:: btree.__getitem__(key)
btree.get(key, default=None, /) btree.get(key, default=None, /)
btree.__setitem__(key, val) btree.__setitem__(key, val)
btree.__detitem__(key) btree.__delitem__(key)
btree.__contains__(key) btree.__contains__(key)
Standard dictionary methods. Standard dictionary methods.

View File

@ -1,5 +1,5 @@
:mod:`sys` -- system specific functions :mod:`sys` -- system specific functions
======================================= ========================================
.. include:: ../templates/unsupported_in_circuitpython.inc .. include:: ../templates/unsupported_in_circuitpython.inc

View File

@ -0,0 +1,34 @@
// Include MicroPython API.
#include "py/runtime.h"
// This is the function which will be called from Python as cexample.add_ints(a, b).
STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// Extract the ints from the micropython input objects.
int a = mp_obj_get_int(a_obj);
int b = mp_obj_get_int(b_obj);
// Calculate the addition and convert to MicroPython object.
return mp_obj_new_int(a + b);
}
// Define a Python reference to the function above.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
// Define module object.
const mp_obj_module_t example_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);

View File

@ -0,0 +1,9 @@
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)

View File

@ -0,0 +1,17 @@
extern "C" {
#include <examplemodule.h>
// Here we implement the function using C++ code, but since it's
// declaration has to be compatible with C everything goes in extern "C" scope.
mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj) {
// Prove we have (at least) C++11 features.
const auto a = mp_obj_get_int(a_obj);
const auto b = mp_obj_get_int(b_obj);
const auto sum = [&]() {
return mp_obj_new_int(a + b);
} ();
// Prove we're being scanned for QSTRs.
mp_obj_t tup[] = {sum, MP_ROM_QSTR(MP_QSTR_hellocpp)};
return mp_obj_new_tuple(2, tup);
}
}

View File

@ -0,0 +1,25 @@
#include <examplemodule.h>
// Define a Python reference to the function we'll make available.
// See example.cpp for the definition.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t cppexample_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cppexample) },
{ MP_ROM_QSTR(MP_QSTR_cppfunc), MP_ROM_PTR(&cppfunc_obj) },
};
STATIC MP_DEFINE_CONST_DICT(cppexample_module_globals, cppexample_module_globals_table);
// Define module object.
const mp_obj_module_t cppexample_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&cppexample_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, MODULE_CPPEXAMPLE_ENABLED);

View File

@ -0,0 +1,5 @@
// Include MicroPython API.
#include "py/runtime.h"
// Declare the function we'll make available in Python as cppexample.cppfunc().
extern mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj);

View File

@ -0,0 +1,12 @@
CPPEXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add our source files to the respective variables.
SRC_USERMOD += $(CPPEXAMPLE_MOD_DIR)/examplemodule.c
SRC_USERMOD_CXX += $(CPPEXAMPLE_MOD_DIR)/example.cpp
# Add our module directory to the include path.
CFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
# We use C++ features so have to link against the standard library.
LDFLAGS_USERMOD += -lstdc++

View File

@ -1,57 +0,0 @@
# Makefile directives for BlueKitchen BTstack
ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
MICROPY_BLUETOOTH_BTSTACK_USB ?= 0
BTSTACK_EXTMOD_DIR = extmod/btstack
EXTMOD_SRC_C += extmod/btstack/modbluetooth_btstack.c
INC += -I$(TOP)/$(BTSTACK_EXTMOD_DIR)
CFLAGS_MOD += -DMICROPY_BLUETOOTH_BTSTACK=1
BTSTACK_DIR = $(TOP)/lib/btstack
ifneq ($(wildcard $(BTSTACK_DIR)/src),)
include $(BTSTACK_DIR)/src/Makefile.inc
include $(BTSTACK_DIR)/src/ble/Makefile.inc
INC += -I$(BTSTACK_DIR)/src
INC += -I$(BTSTACK_DIR)/3rd-party/bluedroid/decoder/include
INC += -I$(BTSTACK_DIR)/3rd-party/bluedroid/encoder/include
INC += -I$(BTSTACK_DIR)/3rd-party/md5
INC += -I$(BTSTACK_DIR)/3rd-party/yxml
SRC_BTSTACK = \
$(addprefix lib/btstack/src/, $(SRC_FILES)) \
$(addprefix lib/btstack/src/ble/, $(filter-out %_tlv.c, $(SRC_BLE_FILES))) \
lib/btstack/platform/embedded/btstack_run_loop_embedded.c
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_USB),1)
SRC_BTSTACK += \
lib/btstack/platform/libusb/hci_transport_h2_libusb.c
CFLAGS += $(shell pkg-config libusb-1.0 --cflags)
LDFLAGS += $(shell pkg-config libusb-1.0 --libs)
endif
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_ENABLE_CLASSIC),1)
include $(BTSTACK_DIR)/src/classic/Makefile.inc
SRC_BTSTACK += \
$(addprefix lib/btstack/src/classic/, $(SRC_CLASSIC_FILES))
endif
LIB_SRC_C += $(SRC_BTSTACK)
# Suppress some warnings.
BTSTACK_WARNING_CFLAGS = -Wno-old-style-definition -Wno-unused-variable -Wno-unused-parameter
ifneq ($(CC),clang)
BTSTACK_WARNING_CFLAGS += -Wno-format
endif
$(BUILD)/lib/btstack/src/%.o: CFLAGS += $(BTSTACK_WARNING_CFLAGS)
endif
endif

View File

@ -1,47 +0,0 @@
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
// BTstack features that can be enabled
#define ENABLE_BLE
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_CENTRAL
// #define ENABLE_CLASSIC
#define ENABLE_LE_DATA_CHANNELS
// #define ENABLE_LOG_INFO
#define ENABLE_LOG_ERROR
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 1021
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS 1
#define MAX_NR_L2CAP_SERVICES 3
#define MAX_NR_L2CAP_CHANNELS 3
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
#define MAX_NR_RFCOMM_SERVICES 1
#define MAX_NR_RFCOMM_CHANNELS 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BNEP_CHANNELS 1
#define MAX_NR_HFP_CONNECTIONS 1
#define MAX_NR_WHITELIST_ENTRIES 1
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_SERVICE_RECORD_ITEMS 1
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
#define MAX_NR_AVDTP_CONNECTIONS 1
#define MAX_NR_AVRCP_CONNECTIONS 1
#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
// #define NVM_NUM_DEVICE_DB_ENTRIES 16
// We don't give btstack a malloc, so use a fixed-size ATT DB.
#define MAX_ATT_DB_SIZE 512
// BTstack HAL configuration
#define HAVE_EMBEDDED_TIME_MS
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 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.
*/
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
#include "extmod/modbluetooth.h"
#include "lib/btstack/src/btstack.h"
typedef struct _mp_btstack_pending_op_t mp_btstack_pending_op_t;
typedef struct _mp_bluetooth_btstack_root_pointers_t {
// This stores both the advertising data and the scan response data, concatenated together.
uint8_t *adv_data;
// Total length of both.
size_t adv_data_alloc;
// Characteristic (and descriptor) value storage.
mp_gatts_db_t gatts_db;
btstack_linked_list_t pending_ops;
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
// Registration for notify/indicate events.
gatt_client_notification_t notification;
#endif
} mp_bluetooth_btstack_root_pointers_t;
enum {
MP_BLUETOOTH_BTSTACK_STATE_OFF,
MP_BLUETOOTH_BTSTACK_STATE_STARTING,
MP_BLUETOOTH_BTSTACK_STATE_ACTIVE,
MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT,
};
extern volatile int mp_bluetooth_btstack_state;
void mp_bluetooth_btstack_port_init(void);
void mp_bluetooth_btstack_port_deinit(void);
void mp_bluetooth_btstack_port_start(void);
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H

View File

@ -41,6 +41,8 @@ SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\
) )
else else
CFLAGS_MOD += -DMICROPY_VFS_LFS2=0 CFLAGS_MOD += -DMICROPY_VFS_LFS2=0
$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-missing-field-initializers
endif endif
################################################################################ ################################################################################

View File

@ -26,9 +26,9 @@ typedef struct _mp_obj_framebuf_t {
STATIC const mp_obj_type_t mp_type_framebuf; STATIC const mp_obj_type_t mp_type_framebuf;
#endif #endif
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t); typedef void (*setpixel_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int, uint32_t);
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int); typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int);
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t); typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int, unsigned int, unsigned int, uint32_t);
typedef struct _mp_framebuf_p_t { typedef struct _mp_framebuf_p_t {
setpixel_t setpixel; setpixel_t setpixel;
@ -47,25 +47,25 @@ typedef struct _mp_framebuf_p_t {
// Functions for MHLSB and MHMSB // Functions for MHLSB and MHMSB
STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
size_t index = (x + y * fb->stride) >> 3; size_t index = (x + y * fb->stride) >> 3;
int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); unsigned int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset); ((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);
} }
STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
size_t index = (x + y * fb->stride) >> 3; size_t index = (x + y * fb->stride) >> 3;
int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); unsigned int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
return (((uint8_t *)fb->buf)[index] >> (offset)) & 0x01; return (((uint8_t *)fb->buf)[index] >> (offset)) & 0x01;
} }
STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
int reverse = fb->format == FRAMEBUF_MHMSB; unsigned int reverse = fb->format == FRAMEBUF_MHMSB;
int advance = fb->stride >> 3; unsigned int advance = fb->stride >> 3;
while (w--) { while (w--) {
uint8_t *b = &((uint8_t *)fb->buf)[(x >> 3) + y * advance]; uint8_t *b = &((uint8_t *)fb->buf)[(x >> 3) + y * advance];
int offset = reverse ? x & 7 : 7 - (x & 7); unsigned int offset = reverse ? x & 7 : 7 - (x & 7);
for (int hh = h; hh; --hh) { for (unsigned int hh = h; hh; --hh) {
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset); *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
b += advance; b += advance;
} }
@ -75,21 +75,21 @@ STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int
// Functions for MVLSB format // Functions for MVLSB format
STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
size_t index = (y >> 3) * fb->stride + x; size_t index = (y >> 3) * fb->stride + x;
uint8_t offset = y & 0x07; uint8_t offset = y & 0x07;
((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset); ((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);
} }
STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
return (((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01; return (((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;
} }
STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
while (h--) { while (h--) {
uint8_t *b = &((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x]; uint8_t *b = &((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x];
uint8_t offset = y & 0x07; uint8_t offset = y & 0x07;
for (int ww = w; ww; --ww) { for (unsigned int ww = w; ww; --ww) {
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset); *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
++b; ++b;
} }
@ -99,18 +99,18 @@ STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, in
// Functions for RGB565 format // Functions for RGB565 format
STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
((uint16_t *)fb->buf)[x + y * fb->stride] = col; ((uint16_t *)fb->buf)[x + y * fb->stride] = col;
} }
STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
return ((uint16_t *)fb->buf)[x + y * fb->stride]; return ((uint16_t *)fb->buf)[x + y * fb->stride];
} }
STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
uint16_t *b = &((uint16_t *)fb->buf)[x + y * fb->stride]; uint16_t *b = &((uint16_t *)fb->buf)[x + y * fb->stride];
while (h--) { while (h--) {
for (int ww = w; ww; --ww) { for (unsigned int ww = w; ww; --ww) {
*b++ = col; *b++ = col;
} }
b += fb->stride - w; b += fb->stride - w;
@ -119,7 +119,7 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i
// Functions for GS2_HMSB format // Functions for GS2_HMSB format
STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2]; uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2];
uint8_t shift = (x & 0x3) << 1; uint8_t shift = (x & 0x3) << 1;
uint8_t mask = 0x3 << shift; uint8_t mask = 0x3 << shift;
@ -127,15 +127,15 @@ STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_
*pixel = color | (*pixel & (~mask)); *pixel = color | (*pixel & (~mask));
} }
STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
uint8_t pixel = ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2]; uint8_t pixel = ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2];
uint8_t shift = (x & 0x3) << 1; uint8_t shift = (x & 0x3) << 1;
return (pixel >> shift) & 0x3; return (pixel >> shift) & 0x3;
} }
STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
for (int xx = x; xx < x + w; xx++) { for (unsigned int xx = x; xx < x + w; xx++) {
for (int yy = y; yy < y + h; yy++) { for (unsigned int yy = y; yy < y + h; yy++) {
gs2_hmsb_setpixel(fb, xx, yy, col); gs2_hmsb_setpixel(fb, xx, yy, col);
} }
} }
@ -143,7 +143,7 @@ STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w,
// Functions for GS4_HMSB format // Functions for GS4_HMSB format
STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1]; uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1];
if (x % 2) { if (x % 2) {
@ -153,7 +153,7 @@ STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_
} }
} }
STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
if (x % 2) { if (x % 2) {
return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f; return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f;
} }
@ -161,16 +161,16 @@ STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] >> 4; return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] >> 4;
} }
STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
col &= 0x0f; col &= 0x0f;
uint8_t *pixel_pair = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1]; uint8_t *pixel_pair = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1];
uint8_t col_shifted_left = col << 4; uint8_t col_shifted_left = col << 4;
uint8_t col_pixel_pair = col_shifted_left | col; uint8_t col_pixel_pair = col_shifted_left | col;
int pixel_count_till_next_line = (fb->stride - w) >> 1; unsigned int pixel_count_till_next_line = (fb->stride - w) >> 1;
bool odd_x = (x % 2 == 1); bool odd_x = (x % 2 == 1);
while (h--) { while (h--) {
int ww = w; unsigned int ww = w;
if (odd_x && ww > 0) { if (odd_x && ww > 0) {
*pixel_pair = (*pixel_pair & 0xf0) | col; *pixel_pair = (*pixel_pair & 0xf0) | col;
@ -194,16 +194,16 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w,
// Functions for GS8 format // Functions for GS8 format
STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)]; uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)];
*pixel = col & 0xff; *pixel = col & 0xff;
} }
STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
return ((uint8_t *)fb->buf)[(x + y * fb->stride)]; return ((uint8_t *)fb->buf)[(x + y * fb->stride)];
} }
STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)]; uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)];
while (h--) { while (h--) {
memset(pixel, col, w); memset(pixel, col, w);
@ -221,11 +221,11 @@ STATIC const mp_framebuf_p_t formats[] = {
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
}; };
static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { static inline void setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
formats[fb->format].setpixel(fb, x, y, col); formats[fb->format].setpixel(fb, x, y, col);
} }
static inline uint32_t getpixel(const mp_obj_framebuf_t *fb, int x, int y) { static inline uint32_t getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
return formats[fb->format].getpixel(fb, x, y); return formats[fb->format].getpixel(fb, x, y);
} }

View File

@ -23,10 +23,10 @@
#define TIMING_WRITE3 (10) #define TIMING_WRITE3 (10)
STATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) { STATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) {
mp_hal_pin_write(pin, 0); mp_hal_pin_od_low(pin);
mp_hal_delay_us(TIMING_RESET1); mp_hal_delay_us(TIMING_RESET1);
uint32_t i = mp_hal_quiet_timing_enter(); uint32_t i = mp_hal_quiet_timing_enter();
mp_hal_pin_write(pin, 1); mp_hal_pin_od_high(pin);
mp_hal_delay_us_fast(TIMING_RESET2); mp_hal_delay_us_fast(TIMING_RESET2);
int status = !mp_hal_pin_read(pin); int status = !mp_hal_pin_read(pin);
mp_hal_quiet_timing_exit(i); mp_hal_quiet_timing_exit(i);
@ -35,11 +35,11 @@ STATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) {
} }
STATIC int onewire_bus_readbit(mp_hal_pin_obj_t pin) { STATIC int onewire_bus_readbit(mp_hal_pin_obj_t pin) {
mp_hal_pin_write(pin, 1); mp_hal_pin_od_high(pin);
uint32_t i = mp_hal_quiet_timing_enter(); uint32_t i = mp_hal_quiet_timing_enter();
mp_hal_pin_write(pin, 0); mp_hal_pin_od_low(pin);
mp_hal_delay_us_fast(TIMING_READ1); mp_hal_delay_us_fast(TIMING_READ1);
mp_hal_pin_write(pin, 1); mp_hal_pin_od_high(pin);
mp_hal_delay_us_fast(TIMING_READ2); mp_hal_delay_us_fast(TIMING_READ2);
int value = mp_hal_pin_read(pin); int value = mp_hal_pin_read(pin);
mp_hal_quiet_timing_exit(i); mp_hal_quiet_timing_exit(i);
@ -49,13 +49,13 @@ STATIC int onewire_bus_readbit(mp_hal_pin_obj_t pin) {
STATIC void onewire_bus_writebit(mp_hal_pin_obj_t pin, int value) { STATIC void onewire_bus_writebit(mp_hal_pin_obj_t pin, int value) {
uint32_t i = mp_hal_quiet_timing_enter(); uint32_t i = mp_hal_quiet_timing_enter();
mp_hal_pin_write(pin, 0); mp_hal_pin_od_low(pin);
mp_hal_delay_us_fast(TIMING_WRITE1); mp_hal_delay_us_fast(TIMING_WRITE1);
if (value) { if (value) {
mp_hal_pin_write(pin, 1); mp_hal_pin_od_high(pin);
} }
mp_hal_delay_us_fast(TIMING_WRITE2); mp_hal_delay_us_fast(TIMING_WRITE2);
mp_hal_pin_write(pin, 1); mp_hal_pin_od_high(pin);
mp_hal_delay_us_fast(TIMING_WRITE3); mp_hal_delay_us_fast(TIMING_WRITE3);
mp_hal_quiet_timing_exit(i); mp_hal_quiet_timing_exit(i);
} }

View File

@ -146,6 +146,9 @@ STATIC const mp_obj_type_t task_queue_type = {
/******************************************************************************/ /******************************************************************************/
// Task class // Task class
// For efficiency, the task object is stored to the coro entry when the task is done.
#define TASK_IS_DONE(task) ((task)->coro == MP_OBJ_FROM_PTR(task))
// This is the core uasyncio context with cur_task, _task_queue and CancelledError. // This is the core uasyncio context with cur_task, _task_queue and CancelledError.
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL; STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
@ -164,10 +167,16 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, const mp
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }
STATIC mp_obj_t task_done(mp_obj_t self_in) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(TASK_IS_DONE(self));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_done_obj, task_done);
STATIC mp_obj_t task_cancel(mp_obj_t self_in) { STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
// Check if task is already finished. // Check if task is already finished.
if (self->coro == mp_const_none) { if (TASK_IS_DONE(self)) {
return mp_const_false; return mp_const_false;
} }
// Can't cancel self (not supported yet). // Can't cancel self (not supported yet).
@ -209,6 +218,24 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel); STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
STATIC mp_obj_t task_throw(mp_obj_t self_in, mp_obj_t value_in) {
// This task raised an exception which was uncaught; handle that now.
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
// Set the data because it was cleared by the main scheduling loop.
self->data = value_in;
if (self->waiting == mp_const_none) {
// Nothing await'ed on the task so call the exception handler.
mp_obj_t _exc_context = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__exc_context));
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_exception), value_in);
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_future), self_in);
mp_obj_t Loop = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_Loop));
mp_obj_t call_exception_handler = mp_load_attr(Loop, MP_QSTR_call_exception_handler);
mp_call_function_1(call_exception_handler, _exc_context);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_throw_obj, task_throw);
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) { if (dest[0] == MP_OBJ_NULL) {
@ -218,12 +245,18 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
} else if (attr == MP_QSTR_data) { } else if (attr == MP_QSTR_data) {
dest[0] = self->data; dest[0] = self->data;
} else if (attr == MP_QSTR_waiting) { } else if (attr == MP_QSTR_waiting) {
if (self->waiting != mp_const_none) { if (self->waiting != mp_const_none && self->waiting != mp_const_false) {
dest[0] = self->waiting; dest[0] = self->waiting;
} }
} else if (attr == MP_QSTR_done) {
dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
dest[1] = self_in;
} else if (attr == MP_QSTR_cancel) { } else if (attr == MP_QSTR_cancel) {
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj); dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
dest[1] = self_in; dest[1] = self_in;
} else if (attr == MP_QSTR_throw) {
dest[0] = MP_OBJ_FROM_PTR(&task_throw_obj);
dest[1] = self_in;
} else if (attr == MP_QSTR_ph_key) { } else if (attr == MP_QSTR_ph_key) {
dest[0] = self->ph_key; dest[0] = self->ph_key;
} }
@ -246,14 +279,21 @@ STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
(void)iter_buf; (void)iter_buf;
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (self->waiting == mp_const_none) { if (self->waiting == mp_const_none) {
self->waiting = task_queue_make_new(&task_queue_type, 0, NULL, NULL); // The is the first access of the "waiting" entry.
if (TASK_IS_DONE(self)) {
// Signal that the completed-task has been await'ed on.
self->waiting = mp_const_false;
} else {
// Lazily allocate the waiting queue.
self->waiting = task_queue_make_new(&task_queue_type, 0, 0, NULL);
}
} }
return self_in; return self_in;
} }
STATIC mp_obj_t task_iternext(mp_obj_t self_in) { STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (self->coro == mp_const_none) { if (TASK_IS_DONE(self)) {
// Task finished, raise return value to caller so it can continue. // Task finished, raise return value to caller so it can continue.
nlr_raise(self->data); nlr_raise(self->data);
} else { } else {

View File

@ -19,8 +19,8 @@ static void check_not_unicode(const mp_obj_t arg) {
} }
STATIC mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
// Second argument is for an extension to allow a separator to be used // First argument is the data to convert.
// between values. // Second argument is an optional separator to be used between values.
const char *sep = NULL; const char *sep = NULL;
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
check_not_unicode(args[0]); check_not_unicode(args[0]);

View File

@ -380,7 +380,7 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
((uint64_t *)p)[index] = (uint64_t)v; ((uint64_t *)p)[index] = (uint64_t)v;
} else { } else {
// TODO: Doesn't offer atomic store semantics, but should at least try // TODO: Doesn't offer atomic store semantics, but should at least try
set_unaligned(val_type, p, MP_ENDIANNESS_BIG, val); set_unaligned(val_type, (void *)&((uint64_t *)p)[index], MP_ENDIANNESS_BIG, val);
} }
return; return;
default: default:
@ -487,6 +487,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset); return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset);
} }
// Fall thru to return uctypes struct object // Fall thru to return uctypes struct object
MP_FALLTHROUGH
} }
case PTR: { case PTR: {
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
@ -608,7 +609,7 @@ STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
return mp_obj_new_int((mp_int_t)(uintptr_t)p); return mp_obj_new_int((mp_int_t)(uintptr_t)p);
} }
} }
/* fallthru */ MP_FALLTHROUGH
default: default:
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported

View File

@ -10,15 +10,29 @@
#if MICROPY_PY_URANDOM #if MICROPY_PY_URANDOM
// Work out if the seed will be set on import or not.
#if MICROPY_MODULE_BUILTIN_INIT && defined(MICROPY_PY_URANDOM_SEED_INIT_FUNC)
#define SEED_ON_IMPORT (1)
#else
#define SEED_ON_IMPORT (0)
#endif
// Yasmarang random number generator // Yasmarang random number generator
// by Ilya Levin // by Ilya Levin
// http://www.literatecode.com/yasmarang // http://www.literatecode.com/yasmarang
// Public Domain // Public Domain
#if !MICROPY_ENABLE_DYNRUNTIME #if !MICROPY_ENABLE_DYNRUNTIME
#if SEED_ON_IMPORT
// If the state is seeded on import then keep these variables in the BSS.
STATIC uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
STATIC uint8_t yasmarang_dat;
#else
// Without seed-on-import these variables must be initialised via the data section.
STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233; STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
STATIC uint8_t yasmarang_dat = 0; STATIC uint8_t yasmarang_dat = 0;
#endif #endif
#endif
STATIC uint32_t yasmarang(void) { STATIC uint32_t yasmarang(void) {
yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n; yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;
@ -62,15 +76,24 @@ STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits);
STATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) { STATIC mp_obj_t mod_urandom_seed(size_t n_args, const mp_obj_t *args) {
mp_uint_t seed = mp_obj_get_int_truncated(seed_in); mp_uint_t seed;
if (n_args == 0 || args[0] == mp_const_none) {
#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
seed = MICROPY_PY_URANDOM_SEED_INIT_FUNC;
#else
mp_raise_ValueError(MP_ERROR_TEXT("no default seed"));
#endif
} else {
seed = mp_obj_get_int_truncated(args[0]);
}
yasmarang_pad = seed; yasmarang_pad = seed;
yasmarang_n = 69; yasmarang_n = 69;
yasmarang_d = 233; yasmarang_d = 233;
yasmarang_dat = 0; yasmarang_dat = 0;
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_seed_obj, mod_urandom_seed); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_seed_obj, 0, 1, mod_urandom_seed);
#if MICROPY_PY_URANDOM_EXTRA_FUNCS #if MICROPY_PY_URANDOM_EXTRA_FUNCS
@ -168,9 +191,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC #if SEED_ON_IMPORT
STATIC mp_obj_t mod_urandom___init__() { STATIC mp_obj_t mod_urandom___init__() {
mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC)); // This module may be imported by more than one name so need to ensure
// that it's only ever seeded once.
static bool seeded = false;
if (!seeded) {
seeded = true;
mod_urandom_seed(0, NULL);
}
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__);
@ -179,7 +208,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__)
#if !MICROPY_ENABLE_DYNRUNTIME #if !MICROPY_ENABLE_DYNRUNTIME
STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC #if SEED_ON_IMPORT
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) }, { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) },
#endif #endif
{ MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) }, { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },

View File

@ -354,6 +354,9 @@ STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
const char *end_match = match->caps[match_no * 2 + 1]; const char *end_match = match->caps[match_no * 2 + 1];
vstr_add_strn(&vstr_return, start_match, end_match - start_match); vstr_add_strn(&vstr_return, start_match, end_match - start_match);
} }
} else if (*repl == '\\') {
// Add the \ character
vstr_add_byte(&vstr_return, *repl++);
} }
} else { } else {
// Just add the current byte from the replacement string // Just add the current byte from the replacement string

View File

@ -22,7 +22,7 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n
case Char: case Char:
if(*sp != *pc++) if(*sp != *pc++)
return 0; return 0;
/* FALLTHROUGH */ MP_FALLTHROUGH
case Any: case Any:
sp++; sp++;
continue; continue;

View File

@ -185,8 +185,6 @@ def run_until_complete(main_task=None):
if isinstance(er, StopIteration): if isinstance(er, StopIteration):
return er.value return er.value
raise er raise er
# Save return value of coro to pass up to caller
t.data = er
# Schedule any other tasks waiting on the completion of this task # Schedule any other tasks waiting on the completion of this task
waiting = False waiting = False
if hasattr(t, "waiting"): if hasattr(t, "waiting"):
@ -194,13 +192,15 @@ def run_until_complete(main_task=None):
_task_queue.push_head(t.waiting.pop_head()) _task_queue.push_head(t.waiting.pop_head())
waiting = True waiting = True
t.waiting = None # Free waiting queue head t.waiting = None # Free waiting queue head
# Print out exception for detached tasks
if not waiting and not isinstance(er, excs_stop): if not waiting and not isinstance(er, excs_stop):
_exc_context["exception"] = er # An exception ended this detached task, so queue it for later
_exc_context["future"] = t # execution to handle the uncaught exception if no other task retrieves
Loop.call_exception_handler(_exc_context) # the exception in the meantime (this is handled by Task.throw).
# Indicate task is done _task_queue.push_head(t)
t.coro = None # Indicate task is done by setting coro to the task object itself
t.coro = t
# Save return value of coro to pass up to caller
t.data = er
# Create a new task from a coroutine and run it until it finishes # Create a new task from a coroutine and run it until it finishes

View File

@ -9,24 +9,44 @@ async def wait_for(aw, timeout, sleep=core.sleep):
if timeout is None: if timeout is None:
return await aw return await aw
def cancel(aw, timeout, sleep): def runner(waiter, aw):
await sleep(timeout) nonlocal status, result
aw.cancel() try:
result = await aw
s = True
except BaseException as er:
s = er
if status is None:
# The waiter is still waiting, set status for it and cancel it.
status = s
waiter.cancel()
# Run aw in a separate runner task that manages its exceptions.
status = None
result = None
runner_task = core.create_task(runner(core.cur_task, aw))
cancel_task = core.create_task(cancel(aw, timeout, sleep))
try: try:
ret = await aw # Wait for the timeout to elapse.
except core.CancelledError: await sleep(timeout)
# Ignore CancelledError from aw, it's probably due to timeout except core.CancelledError as er:
pass if status is True:
finally: # aw completed successfully and cancelled the sleep, so return aw's result.
# Cancel the "cancel" task if it's still active (optimisation instead of cancel_task.cancel()) return result
if cancel_task.coro is not None: elif status is None:
core._task_queue.remove(cancel_task) # This wait_for was cancelled externally, so cancel aw and re-raise.
if cancel_task.coro is None: status = True
# Cancel task ran to completion, ie there was a timeout runner_task.cancel()
raise core.TimeoutError raise er
return ret else:
# aw raised an exception, propagate it out to the caller.
raise status
# The sleep finished before aw, so cancel aw and raise TimeoutError.
status = True
runner_task.cancel()
await runner_task
raise core.TimeoutError
def wait_for_ms(aw, timeout): def wait_for_ms(aw, timeout):

View File

@ -130,13 +130,16 @@ class Task:
self.ph_rightmost_parent = None # Paring heap self.ph_rightmost_parent = None # Paring heap
def __iter__(self): def __iter__(self):
if not hasattr(self, "waiting"): if self.coro is self:
# Signal that the completed-task has been await'ed on.
self.waiting = None
elif not hasattr(self, "waiting"):
# Lazily allocated head of linked list of Tasks waiting on completion of this task. # Lazily allocated head of linked list of Tasks waiting on completion of this task.
self.waiting = TaskQueue() self.waiting = TaskQueue()
return self return self
def __next__(self): def __next__(self):
if not self.coro: if self.coro is self:
# Task finished, raise return value to caller so it can continue. # Task finished, raise return value to caller so it can continue.
raise self.data raise self.data
else: else:
@ -145,9 +148,12 @@ class Task:
# Set calling task's data to this task that it waits on, to double-link it. # Set calling task's data to this task that it waits on, to double-link it.
core.cur_task.data = self core.cur_task.data = self
def done(self):
return self.coro is self
def cancel(self): def cancel(self):
# Check if task is already finished. # Check if task is already finished.
if self.coro is None: if self.coro is self:
return False return False
# Can't cancel self (not supported yet). # Can't cancel self (not supported yet).
if self is core.cur_task: if self is core.cur_task:
@ -166,3 +172,13 @@ class Task:
core._task_queue.push_head(self) core._task_queue.push_head(self)
self.data = core.CancelledError self.data = core.CancelledError
return True return True
def throw(self, value):
# This task raised an exception which was uncaught; handle that now.
# Set the data because it was cleared by the main scheduling loop.
self.data = value
if not hasattr(self, "waiting"):
# Nothing await'ed on the task so call the exception handler.
core._exc_context["exception"] = value
core._exc_context["future"] = self
core.Loop.call_exception_handler(core._exc_context)

View File

@ -78,4 +78,10 @@ STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {
} }
MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add);
// Returns the number of nanoseconds since the Epoch, as an integer.
STATIC mp_obj_t time_time_ns(void) {
return mp_obj_new_int_from_ull(mp_hal_time_ns());
}
MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_time_ns_obj, time_time_ns);
#endif // MICROPY_PY_UTIME_MP_HAL #endif // MICROPY_PY_UTIME_MP_HAL

View File

@ -17,5 +17,6 @@ MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj);
MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj); MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj);
MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj);
MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj);
MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_time_ns_obj);
#endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H #endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H

View File

@ -62,12 +62,8 @@ mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) {
} }
} }
// if we get here then there's nothing mounted on / // if we get here then there's nothing mounted on /, so the path doesn't exist
return MP_VFS_NONE;
if (is_abs) {
// path began with / and was not found
return MP_VFS_NONE;
}
} }
// a relative path within a mounted device // a relative path within a mounted device
@ -144,27 +140,30 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_obj_t vfs = MP_OBJ_NULL; // The superblock for littlefs is in both block 0 and 1, but block 0 may be erased
// or partially written, so search both blocks 0 and 1 for the littlefs signature.
mp_vfs_blockdev_t blockdev; mp_vfs_blockdev_t blockdev;
mp_vfs_blockdev_init(&blockdev, bdev_obj); mp_vfs_blockdev_init(&blockdev, bdev_obj);
uint8_t buf[44]; uint8_t buf[44];
mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf); for (size_t block_num = 0; block_num <= 1; ++block_num) {
#if MICROPY_VFS_LFS1 mp_vfs_blockdev_read_ext(&blockdev, block_num, 8, sizeof(buf), buf);
if (memcmp(&buf[32], "littlefs", 8) == 0) { #if MICROPY_VFS_LFS1
// LFS1 if (memcmp(&buf[32], "littlefs", 8) == 0) {
vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL); // LFS1
nlr_pop(); mp_obj_t vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL);
return vfs; nlr_pop();
return vfs;
}
#endif
#if MICROPY_VFS_LFS2
if (memcmp(&buf[0], "littlefs", 8) == 0) {
// LFS2
mp_obj_t vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, &bdev_obj, NULL);
nlr_pop();
return vfs;
}
#endif
} }
#endif
#if MICROPY_VFS_LFS2
if (memcmp(&buf[0], "littlefs", 8) == 0) {
// LFS2
vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, &bdev_obj, NULL);
nlr_pop();
return vfs;
}
#endif
nlr_pop(); nlr_pop();
} else { } else {
// Ignore exception (eg block device doesn't support extended readblocks) // Ignore exception (eg block device doesn't support extended readblocks)
@ -175,7 +174,8 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, &bdev_obj, NULL); return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, &bdev_obj, NULL);
#endif #endif
return bdev_obj; // no filesystem found
mp_raise_OSError(MP_ENODEV);
} }
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {

View File

@ -26,6 +26,7 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "lib/timeutils/timeutils.h"
#include "extmod/vfs.h" #include "extmod/vfs.h"
#include "extmod/vfs_lfs.h" #include "extmod/vfs_lfs.h"
@ -34,7 +35,7 @@
enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime }; enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime };
static const mp_arg_t lfs_make_allowed_args[] = { static const mp_arg_t lfs_make_allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
@ -126,7 +127,8 @@ const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in);
mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in); mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in);
STATIC void lfs_get_mtime(uint8_t buf[8]) { STATIC void lfs_get_mtime(uint8_t buf[8]) {
uint64_t ns = mp_hal_time_ns(); // On-disk storage of timestamps uses 1970 as the Epoch, so convert from host's Epoch.
uint64_t ns = timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(mp_hal_time_ns());
// Store "ns" to "buf" in little-endian format (essentially htole64). // Store "ns" to "buf" in little-endian format (essentially htole64).
for (size_t i = 0; i < 8; ++i) { for (size_t i = 0; i < 8; ++i) {
buf[i] = ns; buf[i] = ns;

View File

@ -365,10 +365,8 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
for (size_t i = sizeof(mtime_buf); i > 0; --i) { for (size_t i = sizeof(mtime_buf); i > 0; --i) {
ns = ns << 8 | mtime_buf[i - 1]; ns = ns << 8 | mtime_buf[i - 1];
} }
mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns); // On-disk storage of timestamps uses 1970 as the Epoch, so convert to host's Epoch.
#if MICROPY_EPOCH_IS_1970 mtime = timeutils_seconds_since_epoch_from_nanoseconds_since_1970(ns);
mtime += TIMEUTILS_SECONDS_1970_TO_2000;
#endif
} }
#endif #endif
@ -425,10 +423,16 @@ STATIC mp_obj_t MP_VFS_LFSx(statvfs)(mp_obj_t self_in, mp_obj_t path_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(statvfs_obj), MP_VFS_LFSx(statvfs)); STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(statvfs_obj), MP_VFS_LFSx(statvfs));
STATIC mp_obj_t MP_VFS_LFSx(mount)(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { STATIC mp_obj_t MP_VFS_LFSx(mount)(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
(void)self_in; MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
(void)readonly;
(void)mkfs; (void)mkfs;
// already called LFSx_API(mount) in MP_VFS_LFSx(make_new)
// Make block device read-only if requested.
if (mp_obj_is_true(readonly)) {
self->blockdev.writeblocks[0] = MP_OBJ_NULL;
}
// Already called LFSx_API(mount) in MP_VFS_LFSx(make_new) so the filesystem is ready.
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(mount_obj), MP_VFS_LFSx(mount)); STATIC MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(mount_obj), MP_VFS_LFSx(mount));

View File

@ -2,7 +2,7 @@ littlefs library
================ ================
The upstream source for the files in this directory is The upstream source for the files in this directory is
https://github.com/ARMmbed/littlefs https://github.com/littlefs-project/littlefs
To generate the separate files with lfs1 and lfs2 prefixes run the following To generate the separate files with lfs1 and lfs2 prefixes run the following
commands in the top-level directory of the littlefs repository (replace the commands in the top-level directory of the littlefs repository (replace the
@ -13,7 +13,7 @@ version tags with the latest/desired ones, and set `$MPY_DIR`):
cp lfs1*.[ch] $MPY_DIR/lib/littlefs cp lfs1*.[ch] $MPY_DIR/lib/littlefs
git reset --hard HEAD git reset --hard HEAD
git checkout v2.1.3 git checkout v2.3.0
python2 ./scripts/prefix.py lfs2 python2 ./scripts/prefix.py lfs2
cp lfs2*.[ch] $MPY_DIR/lib/littlefs cp lfs2*.[ch] $MPY_DIR/lib/littlefs
git reset --hard HEAD git reset --hard HEAD

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "lfs2_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@ -21,7 +22,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS2_VERSION 0x00020002 #define LFS2_VERSION 0x00020003
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
@ -123,20 +124,25 @@ enum lfs2_type {
enum lfs2_open_flags { enum lfs2_open_flags {
// open flags // open flags
LFS2_O_RDONLY = 1, // Open a file as read only LFS2_O_RDONLY = 1, // Open a file as read only
#ifndef LFS2_READONLY
LFS2_O_WRONLY = 2, // Open a file as write only LFS2_O_WRONLY = 2, // Open a file as write only
LFS2_O_RDWR = 3, // Open a file as read and write LFS2_O_RDWR = 3, // Open a file as read and write
LFS2_O_CREAT = 0x0100, // Create a file if it does not exist LFS2_O_CREAT = 0x0100, // Create a file if it does not exist
LFS2_O_EXCL = 0x0200, // Fail if a file already exists LFS2_O_EXCL = 0x0200, // Fail if a file already exists
LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS2_O_APPEND = 0x0800, // Move to end of file on every write LFS2_O_APPEND = 0x0800, // Move to end of file on every write
#endif
// internally used flags // internally used flags
#ifndef LFS2_READONLY
LFS2_F_DIRTY = 0x010000, // File does not match storage LFS2_F_DIRTY = 0x010000, // File does not match storage
LFS2_F_WRITING = 0x020000, // File has been written since last flush LFS2_F_WRITING = 0x020000, // File has been written since last flush
#endif
LFS2_F_READING = 0x040000, // File has been read since last flush LFS2_F_READING = 0x040000, // File has been read since last flush
LFS2_F_ERRED = 0x080000, // An error occured during write #ifndef LFS2_READONLY
LFS2_F_ERRED = 0x080000, // An error occurred during write
#endif
LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry
LFS2_F_OPENED = 0x200000, // File has been opened
}; };
// File seek flags // File seek flags
@ -174,6 +180,16 @@ struct lfs2_config {
// are propogated to the user. // are propogated to the user.
int (*sync)(const struct lfs2_config *c); int (*sync)(const struct lfs2_config *c);
#ifdef LFS2_THREADSAFE
// Lock the underlying block device. Negative error codes
// are propogated to the user.
int (*lock)(const struct lfs2_config *c);
// Unlock the underlying block device. Negative error codes
// are propogated to the user.
int (*unlock)(const struct lfs2_config *c);
#endif
// Minimum size of a block read. All read operations will be a // Minimum size of a block read. All read operations will be a
// multiple of this value. // multiple of this value.
lfs2_size_t read_size; lfs2_size_t read_size;
@ -399,6 +415,7 @@ typedef struct lfs2 {
/// Filesystem functions /// /// Filesystem functions ///
#ifndef LFS2_READONLY
// Format a block device with the littlefs // Format a block device with the littlefs
// //
// Requires a littlefs object and config struct. This clobbers the littlefs // Requires a littlefs object and config struct. This clobbers the littlefs
@ -407,6 +424,7 @@ typedef struct lfs2 {
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config); int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config);
#endif
// Mounts a littlefs // Mounts a littlefs
// //
@ -426,12 +444,15 @@ int lfs2_unmount(lfs2_t *lfs2);
/// General operations /// /// General operations ///
#ifndef LFS2_READONLY
// Removes a file or directory // Removes a file or directory
// //
// If removing a directory, the directory must be empty. // If removing a directory, the directory must be empty.
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_remove(lfs2_t *lfs2, const char *path); int lfs2_remove(lfs2_t *lfs2, const char *path);
#endif
#ifndef LFS2_READONLY
// Rename or move a file or directory // Rename or move a file or directory
// //
// If the destination exists, it must match the source in type. // If the destination exists, it must match the source in type.
@ -439,6 +460,7 @@ int lfs2_remove(lfs2_t *lfs2, const char *path);
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath); int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath);
#endif
// Find info about a file or directory // Find info about a file or directory
// //
@ -461,6 +483,7 @@ int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info);
lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path,
uint8_t type, void *buffer, lfs2_size_t size); uint8_t type, void *buffer, lfs2_size_t size);
#ifndef LFS2_READONLY
// Set custom attributes // Set custom attributes
// //
// Custom attributes are uniquely identified by an 8-bit type and limited // Custom attributes are uniquely identified by an 8-bit type and limited
@ -470,13 +493,16 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path,
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_setattr(lfs2_t *lfs2, const char *path, int lfs2_setattr(lfs2_t *lfs2, const char *path,
uint8_t type, const void *buffer, lfs2_size_t size); uint8_t type, const void *buffer, lfs2_size_t size);
#endif
#ifndef LFS2_READONLY
// Removes a custom attribute // Removes a custom attribute
// //
// If an attribute is not found, nothing happens. // If an attribute is not found, nothing happens.
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type); int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type);
#endif
/// File operations /// /// File operations ///
@ -525,6 +551,7 @@ int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file);
lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file,
void *buffer, lfs2_size_t size); void *buffer, lfs2_size_t size);
#ifndef LFS2_READONLY
// Write data to file // Write data to file
// //
// Takes a buffer and size indicating the data to write. The file will not // Takes a buffer and size indicating the data to write. The file will not
@ -533,6 +560,7 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file,
// Returns the number of bytes written, or a negative error code on failure. // Returns the number of bytes written, or a negative error code on failure.
lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file,
const void *buffer, lfs2_size_t size); const void *buffer, lfs2_size_t size);
#endif
// Change the position of the file // Change the position of the file
// //
@ -541,10 +569,12 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file,
lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file,
lfs2_soff_t off, int whence); lfs2_soff_t off, int whence);
#ifndef LFS2_READONLY
// Truncates the size of the file to the specified size // Truncates the size of the file to the specified size
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size); int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size);
#endif
// Return the position of the file // Return the position of the file
// //
@ -567,10 +597,12 @@ lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file);
/// Directory operations /// /// Directory operations ///
#ifndef LFS2_READONLY
// Create a directory // Create a directory
// //
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_mkdir(lfs2_t *lfs2, const char *path); int lfs2_mkdir(lfs2_t *lfs2, const char *path);
#endif
// Open a directory // Open a directory
// //
@ -632,6 +664,7 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
#ifndef LFS2_READONLY
#ifdef LFS2_MIGRATE #ifdef LFS2_MIGRATE
// Attempts to migrate a previous version of littlefs // Attempts to migrate a previous version of littlefs
// //
@ -646,6 +679,7 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
// Returns a negative error code on failure. // Returns a negative error code on failure.
int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg); int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg);
#endif #endif
#endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -261,7 +261,7 @@ int readline_process_char(int c) {
#endif #endif
} else if (32 <= c) { } else if (32 <= c) {
// printable character // printable character
char lcp = rl.line->buf[rl.cursor_pos]; uint8_t lcp = rl.line->buf[rl.cursor_pos];
uint8_t cont_need = 0; uint8_t cont_need = 0;
if (!UTF8_IS_CONT(c)) { if (!UTF8_IS_CONT(c)) {
// ASCII or Lead code point // ASCII or Lead code point

View File

@ -4,7 +4,7 @@
* The MIT License (MIT) * The MIT License (MIT)
* *
* SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2015 Daniel Campora * SPDX-FileCopyrightText: Copyright (c) 2015 Daniel Campora
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -158,18 +158,7 @@ mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
+ (year - 2000) * 31536000; + (year - 2000) * 31536000;
} }
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) { mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday,
t -= TIMEUTILS_SECONDS_1970_TO_2000;
timeutils_seconds_since_2000_to_struct_time(t, tm);
}
mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date,
mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
mp_uint_t t = timeutils_seconds_since_2000(year, month, date, hour, minute, second);
return t + TIMEUTILS_SECONDS_1970_TO_2000;
}
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { mp_int_t hours, mp_int_t minutes, mp_int_t seconds) {
// Normalize the tuple. This allows things like: // Normalize the tuple. This allows things like:
@ -222,5 +211,5 @@ mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
year++; year++;
} }
} }
return timeutils_seconds_since_epoch(year, month, mday, hours, minutes, seconds); return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds);
} }

View File

@ -4,7 +4,7 @@
* The MIT License (MIT) * The MIT License (MIT)
* *
* SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2015 Daniel Campora * SPDX-FileCopyrightText: Copyright (c) 2015 Daniel Campora
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -42,14 +42,6 @@ typedef struct _timeutils_struct_time_t {
uint16_t tm_yday; // 1..366 uint16_t tm_yday; // 1..366
} timeutils_struct_time_t; } timeutils_struct_time_t;
static inline uint64_t timeutils_seconds_since_2000_to_nanoseconds_since_1970(mp_uint_t s) {
return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL;
}
static inline mp_uint_t timeutils_seconds_since_2000_from_nanoseconds_since_1970(uint64_t ns) {
return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000;
}
bool timeutils_is_leap_year(mp_uint_t year); bool timeutils_is_leap_year(mp_uint_t year);
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
@ -60,18 +52,52 @@ void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t,
mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm); mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday,
mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date,
mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
mp_int_t hours, mp_int_t minutes, mp_int_t seconds); mp_int_t hours, mp_int_t minutes, mp_int_t seconds);
static inline uint64_t timeutils_nanoseconds_since_1970(mp_uint_t year, mp_uint_t month, // Select the Epoch used by the port.
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { #if MICROPY_EPOCH_IS_1970
return timeutils_seconds_since_2000_to_nanoseconds_since_1970(
timeutils_seconds_since_2000(year, month, date, hour, minute, second)); static inline void timeutils_seconds_since_epoch_to_struct_time(uint64_t t, timeutils_struct_time_t *tm) {
// TODO this will give incorrect results for dates before 2000/1/1
return timeutils_seconds_since_2000_to_struct_time(t - TIMEUTILS_SECONDS_1970_TO_2000, tm);
} }
static inline uint64_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) {
return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds) + TIMEUTILS_SECONDS_1970_TO_2000;
}
static inline uint64_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return timeutils_seconds_since_2000(year, month, date, hour, minute, second) + TIMEUTILS_SECONDS_1970_TO_2000;
}
static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) {
return ns / 1000000000ULL;
}
static inline uint64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(uint64_t ns) {
return ns;
}
#else // Epoch is 2000
#define timeutils_seconds_since_epoch_to_struct_time timeutils_seconds_since_2000_to_struct_time
#define timeutils_seconds_since_epoch timeutils_seconds_since_2000
#define timeutils_mktime timeutils_mktime_2000
static inline uint64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_uint_t s) {
return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL;
}
static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) {
return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000;
}
static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) {
return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000ULL;
}
#endif
#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H

View File

@ -53,12 +53,16 @@ const mp_arg_t mp_irq_init_args[] = {
mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) { mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) {
mp_irq_obj_t *self = m_new0(mp_irq_obj_t, 1); mp_irq_obj_t *self = m_new0(mp_irq_obj_t, 1);
mp_irq_init(self, methods, parent);
return self;
}
void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent) {
self->base.type = &mp_irq_type; self->base.type = &mp_irq_type;
self->methods = (mp_irq_methods_t *)methods; self->methods = (mp_irq_methods_t *)methods;
self->parent = parent; self->parent = parent;
self->handler = mp_const_none; self->handler = mp_const_none;
self->ishard = false; self->ishard = false;
return self;
} }
void mp_irq_handler(mp_irq_obj_t *self) { void mp_irq_handler(mp_irq_obj_t *self) {

View File

@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H #ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H #define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
#include "py/runtime.h"
/****************************************************************************** /******************************************************************************
DEFINE CONSTANTS DEFINE CONSTANTS
******************************************************************************/ ******************************************************************************/
@ -41,20 +43,17 @@ enum {
DEFINE TYPES DEFINE TYPES
******************************************************************************/ ******************************************************************************/
typedef mp_obj_t (*mp_irq_init_t)(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); typedef mp_uint_t (*mp_irq_trigger_fun_t)(mp_obj_t self, mp_uint_t trigger);
typedef mp_uint_t (*mp_irq_uint_method_one_uint_para_t)(mp_obj_t self, mp_uint_t trigger); typedef mp_uint_t (*mp_irq_info_fun_t)(mp_obj_t self, mp_uint_t info_type);
typedef mp_uint_t (*mp_irq_int_method_one_para_t)(mp_obj_t self, mp_uint_t info_type);
enum { enum {
MP_IRQ_INFO_FLAGS, MP_IRQ_INFO_FLAGS,
MP_IRQ_INFO_TRIGGERS, MP_IRQ_INFO_TRIGGERS,
MP_IRQ_INFO_CNT
}; };
typedef struct _mp_irq_methods_t { typedef struct _mp_irq_methods_t {
mp_irq_init_t init; mp_irq_trigger_fun_t trigger;
mp_irq_uint_method_one_uint_para_t trigger; mp_irq_info_fun_t info;
mp_irq_int_method_one_para_t info;
} mp_irq_methods_t; } mp_irq_methods_t;
typedef struct _mp_irq_obj_t { typedef struct _mp_irq_obj_t {
@ -77,6 +76,7 @@ extern const mp_obj_type_t mp_irq_type;
******************************************************************************/ ******************************************************************************/
mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent); mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent);
void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent);
void mp_irq_handler(mp_irq_obj_t *self); void mp_irq_handler(mp_irq_obj_t *self);
#endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H #endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H

View File

@ -57,6 +57,7 @@ STATIC bool repl_display_debugging_info = 0;
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8) #define EXEC_FLAG_SOURCE_IS_RAW_CODE (8)
#define EXEC_FLAG_SOURCE_IS_VSTR (16) #define EXEC_FLAG_SOURCE_IS_VSTR (16)
#define EXEC_FLAG_SOURCE_IS_FILENAME (32) #define EXEC_FLAG_SOURCE_IS_FILENAME (32)
#define EXEC_FLAG_SOURCE_IS_READER (64)
// parses, compiles and executes the code in the lexer // parses, compiles and executes the code in the lexer
// frees the lexer before returning // frees the lexer before returning
@ -69,10 +70,15 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
uint32_t start = 0; uint32_t start = 0;
#endif #endif
#ifdef MICROPY_BOARD_BEFORE_PYTHON_EXEC
MICROPY_BOARD_BEFORE_PYTHON_EXEC(input_kind, exec_flags);
#endif
// by default a SystemExit exception returns 0 // by default a SystemExit exception returns 0
pyexec_system_exit = 0; pyexec_system_exit = 0;
nlr_buf_t nlr; nlr_buf_t nlr;
nlr.ret_val = NULL;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_obj_t module_fun; mp_obj_t module_fun;
#if MICROPY_MODULE_FROZEN_MPY #if MICROPY_MODULE_FROZEN_MPY
@ -87,6 +93,8 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) {
const vstr_t *vstr = source; const vstr_t *vstr = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0);
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) {
lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source);
} else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) {
lex = mp_lexer_new_from_file(source); lex = mp_lexer_new_from_file(source);
} else { } else {
@ -130,6 +138,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
// uncaught exception // uncaught exception
mp_hal_set_interrupt_char(-1); // disable interrupt mp_hal_set_interrupt_char(-1); // disable interrupt
mp_handle_pending(false); // clear any pending exceptions (and run any callbacks) mp_handle_pending(false); // clear any pending exceptions (and run any callbacks)
if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) {
const mp_reader_t *reader = source;
reader->close(reader->data);
}
// print EOF after normal output // print EOF after normal output
if (exec_flags & EXEC_FLAG_PRINT_EOF) { if (exec_flags & EXEC_FLAG_PRINT_EOF) {
mp_hal_stdout_tx_strn("\x04", 1); mp_hal_stdout_tx_strn("\x04", 1);
@ -192,10 +206,107 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
mp_hal_stdout_tx_strn("\x04", 1); mp_hal_stdout_tx_strn("\x04", 1);
} }
#ifdef MICROPY_BOARD_AFTER_PYTHON_EXEC
MICROPY_BOARD_AFTER_PYTHON_EXEC(input_kind, exec_flags, nlr.ret_val, &ret);
#endif
return ret; return ret;
} }
#if MICROPY_ENABLE_COMPILER #if MICROPY_ENABLE_COMPILER
// This can be configured by a port (and even configured to a function to be
// computed dynamically) to indicate the maximum number of bytes that can be
// held in the stdin buffer.
#ifndef MICROPY_REPL_STDIN_BUFFER_MAX
#define MICROPY_REPL_STDIN_BUFFER_MAX (256)
#endif
typedef struct _mp_reader_stdin_t {
bool eof;
uint16_t window_max;
uint16_t window_remain;
} mp_reader_stdin_t;
STATIC mp_uint_t mp_reader_stdin_readbyte(void *data) {
mp_reader_stdin_t *reader = (mp_reader_stdin_t *)data;
if (reader->eof) {
return MP_READER_EOF;
}
int c = mp_hal_stdin_rx_chr();
if (c == CHAR_CTRL_C || c == CHAR_CTRL_D) {
reader->eof = true;
mp_hal_stdout_tx_strn("\x04", 1); // indicate end to host
if (c == CHAR_CTRL_C) {
#if MICROPY_KBD_EXCEPTION
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
#else
mp_raise_type(&mp_type_KeyboardInterrupt);
#endif
} else {
return MP_READER_EOF;
}
}
if (--reader->window_remain == 0) {
mp_hal_stdout_tx_strn("\x01", 1); // indicate window available to host
reader->window_remain = reader->window_max;
}
return c;
}
STATIC void mp_reader_stdin_close(void *data) {
mp_reader_stdin_t *reader = (mp_reader_stdin_t *)data;
if (!reader->eof) {
reader->eof = true;
mp_hal_stdout_tx_strn("\x04", 1); // indicate end to host
for (;;) {
int c = mp_hal_stdin_rx_chr();
if (c == CHAR_CTRL_C || c == CHAR_CTRL_D) {
break;
}
}
}
}
STATIC void mp_reader_new_stdin(mp_reader_t *reader, mp_reader_stdin_t *reader_stdin, uint16_t buf_max) {
// Make flow-control window half the buffer size, and indicate to the host that 2x windows are
// free (sending the window size implicitly indicates that a window is free, and then the 0x01
// indicates that another window is free).
size_t window = buf_max / 2;
char reply[3] = { window & 0xff, window >> 8, 0x01 };
mp_hal_stdout_tx_strn(reply, sizeof(reply));
reader_stdin->eof = false;
reader_stdin->window_max = window;
reader_stdin->window_remain = window;
reader->data = reader_stdin;
reader->readbyte = mp_reader_stdin_readbyte;
reader->close = mp_reader_stdin_close;
}
STATIC int do_reader_stdin(int c) {
if (c != 'A') {
// Unsupported command.
mp_hal_stdout_tx_strn("R\x00", 2);
return 0;
}
// Indicate reception of command.
mp_hal_stdout_tx_strn("R\x01", 2);
mp_reader_t reader;
mp_reader_stdin_t reader_stdin;
mp_reader_new_stdin(&reader, &reader_stdin, MICROPY_REPL_STDIN_BUFFER_MAX);
int exec_flags = EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_READER;
return parse_compile_execute(&reader, MP_PARSE_FILE_INPUT, exec_flags, NULL);
}
#if MICROPY_REPL_EVENT_DRIVEN #if MICROPY_REPL_EVENT_DRIVEN
typedef struct _repl_t { typedef struct _repl_t {
@ -229,6 +340,13 @@ void pyexec_event_repl_init(void) {
STATIC int pyexec_raw_repl_process_char(int c) { STATIC int pyexec_raw_repl_process_char(int c) {
if (c == CHAR_CTRL_A) { if (c == CHAR_CTRL_A) {
// reset raw REPL // reset raw REPL
if (vstr_len(MP_STATE_VM(repl_line)) == 2 && vstr_str(MP_STATE_VM(repl_line))[0] == CHAR_CTRL_E) {
int ret = do_reader_stdin(vstr_str(MP_STATE_VM(repl_line))[1]);
if (ret & PYEXEC_FORCED_EXIT) {
return ret;
}
goto reset;
}
mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
goto reset; goto reset;
} else if (c == CHAR_CTRL_B) { } else if (c == CHAR_CTRL_B) {
@ -413,6 +531,15 @@ raw_repl_reset:
int c = mp_hal_stdin_rx_chr(); int c = mp_hal_stdin_rx_chr();
if (c == CHAR_CTRL_A) { if (c == CHAR_CTRL_A) {
// reset raw REPL // reset raw REPL
if (vstr_len(&line) == 2 && vstr_str(&line)[0] == CHAR_CTRL_E) {
int ret = do_reader_stdin(vstr_str(&line)[1]);
if (ret & PYEXEC_FORCED_EXIT) {
return ret;
}
vstr_reset(&line);
mp_hal_stdout_tx_str(">");
continue;
}
goto raw_repl_reset; goto raw_repl_reset;
} else if (c == CHAR_CTRL_B) { } else if (c == CHAR_CTRL_B) {
// change to friendly REPL // change to friendly REPL
@ -453,12 +580,6 @@ int pyexec_friendly_repl(void) {
vstr_t line; vstr_t line;
vstr_init(&line, 32); 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: friendly_repl_reset:
mp_hal_stdout_tx_str("\r\n"); mp_hal_stdout_tx_str("\r\n");
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);

View File

@ -3477,6 +3477,10 @@ msgstr ""
msgid "name not defined" msgid "name not defined"
msgstr "" msgstr ""
#: py/asmthumb.c
msgid "native method too big"
msgstr ""
#: py/emitnative.c #: py/emitnative.c
msgid "native yield" msgid "native yield"
msgstr "" msgstr ""
@ -3518,6 +3522,10 @@ msgstr ""
msgid "no default packer" msgid "no default packer"
msgstr "" msgstr ""
#: extmod/modurandom.c
msgid "no default seed"
msgstr ""
#: py/builtinimport.c #: py/builtinimport.c
msgid "no module named '%q'" msgid "no module named '%q'"
msgstr "" msgstr ""
@ -4086,6 +4094,10 @@ msgstr ""
msgid "too many indices" msgid "too many indices"
msgstr "" msgstr ""
#: py/asmthumb.c
msgid "too many locals for native method"
msgstr ""
#: py/runtime.c #: py/runtime.c
#, c-format #, c-format
msgid "too many values to unpack (expected %d)" msgid "too many values to unpack (expected %d)"

View File

@ -9,6 +9,14 @@
#define MICROPY_PERSISTENT_CODE_LOAD (0) #define MICROPY_PERSISTENT_CODE_LOAD (0)
#define MICROPY_PERSISTENT_CODE_SAVE (1) #define MICROPY_PERSISTENT_CODE_SAVE (1)
#ifndef MICROPY_PERSISTENT_CODE_SAVE_FILE
#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || defined(__unix__) || defined(__APPLE__)
#define MICROPY_PERSISTENT_CODE_SAVE_FILE (1)
#else
#define MICROPY_PERSISTENT_CODE_SAVE_FILE (0)
#endif
#endif
#define MICROPY_EMIT_X64 (1) #define MICROPY_EMIT_X64 (1)
#define MICROPY_EMIT_X86 (1) #define MICROPY_EMIT_X86 (1)
#define MICROPY_EMIT_THUMB (1) #define MICROPY_EMIT_THUMB (1)

View File

@ -34,7 +34,7 @@ INC += -I$(BUILD)
# compiler settings # compiler settings
CWARN = -Wall -Werror CWARN = -Wall -Werror
CWARN += -Wpointer-arith -Wuninitialized -Wdouble-promotion -Wsign-compare -Wfloat-conversion CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
# Debugging/Optimization # Debugging/Optimization
@ -42,10 +42,12 @@ ifdef DEBUG
COPT ?= -O0 COPT ?= -O0
else else
COPT ?= -Os COPT ?= -Os
COPT += -fdata-sections -ffunction-sections
COPT += -DNDEBUG COPT += -DNDEBUG
endif endif
# Remove unused sections.
COPT += -fdata-sections -ffunction-sections
# Always enable symbols -- They're occasionally useful, and don't make it into the # Always enable symbols -- They're occasionally useful, and don't make it into the
# final .bin/.hex/.dfu so the extra size doesn't matter. # final .bin/.hex/.dfu so the extra size doesn't matter.
CFLAGS += -g CFLAGS += -g
@ -168,7 +170,6 @@ SRC_C += \
modtime.c \ modtime.c \
moduselect.c \ moduselect.c \
alloc.c \ alloc.c \
coverage.c \
fatfs_port.c \ fatfs_port.c \
supervisor/stub/filesystem.c \ supervisor/stub/filesystem.c \
supervisor/stub/safe_mode.c \ supervisor/stub/safe_mode.c \
@ -184,13 +185,17 @@ LIB_SRC_C += $(addprefix lib/,\
utils/gchelper_generic.c \ utils/gchelper_generic.c \
) )
SRC_CXX += \
$(SRC_MOD_CXX)
OBJ = $(PY_O) OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
# List of sources for qstr extraction # List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(LIB_SRC_C) $(EXTMOD_SRC_C) SRC_QSTR += $(SRC_C) $(SRC_CXX) $(LIB_SRC_C) $(EXTMOD_SRC_C)
# Append any auto-generated sources that are needed by sources listed in # Append any auto-generated sources that are needed by sources listed in
# SRC_QSTR # SRC_QSTR
SRC_QSTR_AUTO_DEPS += SRC_QSTR_AUTO_DEPS +=
@ -203,6 +208,14 @@ CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
MPY_CROSS_FLAGS += -mcache-lookup-bc MPY_CROSS_FLAGS += -mcache-lookup-bc
endif endif
HASCPP17 = $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 7)
ifeq ($(HASCPP17), 1)
CXXFLAGS += -std=c++17
else
CXXFLAGS += -std=c++11
endif
CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS) $(CXXFLAGS_MOD))
ifeq ($(MICROPY_FORCE_32BIT),1) ifeq ($(MICROPY_FORCE_32BIT),1)
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86' RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86'
else else

View File

@ -188,7 +188,7 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%ld\n", 123); // long mp_printf(&mp_plat_print, "%ld\n", 123); // long
mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex
mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex
mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision
mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision
mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools
#ifndef NDEBUG #ifndef NDEBUG

View File

@ -0,0 +1,23 @@
extern "C" {
#include "py/obj.h"
}
#if defined(MICROPY_UNIX_COVERAGE)
// Just to test building of C++ code.
STATIC mp_obj_t extra_cpp_coverage_impl() {
return mp_const_none;
}
extern "C" {
mp_obj_t extra_cpp_coverage(void);
mp_obj_t extra_cpp_coverage(void) {
return extra_cpp_coverage_impl();
}
// This is extern to avoid name mangling.
extern const mp_obj_fun_builtin_fixed_t extra_cpp_coverage_obj = {{&mp_type_fun_builtin_0}, {extra_cpp_coverage}};
}
#endif

View File

@ -132,7 +132,7 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
// allow to print the parse tree in the coverage build // allow to print the parse tree in the coverage build
if (mp_verbose_flag >= 3) { if (mp_verbose_flag >= 3) {
printf("----------------\n"); printf("----------------\n");
mp_parse_node_print(parse_tree.root, 0); mp_parse_node_print(&mp_plat_print, parse_tree.root, 0);
printf("----------------\n"); printf("----------------\n");
} }
#endif #endif
@ -534,7 +534,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
#if defined(MICROPY_UNIX_COVERAGE) #if defined(MICROPY_UNIX_COVERAGE)
{ {
MP_DECLARE_CONST_FUN_OBJ_0(extra_coverage_obj); MP_DECLARE_CONST_FUN_OBJ_0(extra_coverage_obj);
mp_store_global(QSTR_FROM_STR_STATIC("extra_coverage"), MP_OBJ_FROM_PTR(&extra_coverage_obj)); MP_DECLARE_CONST_FUN_OBJ_0(extra_cpp_coverage_obj);
mp_store_global(MP_QSTR_extra_coverage, MP_OBJ_FROM_PTR(&extra_coverage_obj));
mp_store_global(MP_QSTR_extra_cpp_coverage, MP_OBJ_FROM_PTR(&extra_cpp_coverage_obj));
} }
#endif #endif
@ -547,9 +549,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
// test_obj.attr = 42 // test_obj.attr = 42
// //
// mp_obj_t test_class_type, test_class_instance; // mp_obj_t test_class_type, test_class_instance;
// test_class_type = mp_obj_new_type(QSTR_FROM_STR_STATIC("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0)); // test_class_type = mp_obj_new_type(qstr_from_str("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0));
// mp_store_name(QSTR_FROM_STR_STATIC("test_obj"), test_class_instance = mp_call_function_0(test_class_type)); // mp_store_name(qstr_from_str("test_obj"), test_class_instance = mp_call_function_0(test_class_type));
// mp_store_attr(test_class_instance, QSTR_FROM_STR_STATIC("attr"), mp_obj_new_int(42)); // mp_store_attr(test_class_instance, qstr_from_str("attr"), mp_obj_new_int(42));
/* /*
printf("bytes:\n"); printf("bytes:\n");

View File

@ -49,7 +49,7 @@
#if MICROPY_PY_MACHINE #if MICROPY_PY_MACHINE
uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) {
uintptr_t addr = mp_obj_int_get_truncated(addr_o); uintptr_t addr = mp_obj_get_int_truncated(addr_o);
if ((addr & (align - 1)) != 0) { if ((addr & (align - 1)) != 0) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("address %08x is not aligned to %d bytes"), addr, align); mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("address %08x is not aligned to %d bytes"), addr, align);
} }

View File

@ -67,7 +67,7 @@ static inline int msec_sleep_tv(struct timeval *tv) {
#endif #endif
STATIC mp_obj_t mod_time_time(void) { STATIC mp_obj_t mod_time_time(void) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000; mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000;
@ -132,19 +132,19 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep);
STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, struct tm *(*time_func)(const time_t *timep)) {
time_t t; time_t t;
if (n_args == 0) { if (n_args == 0) {
t = time(NULL); t = time(NULL);
} else { } else {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
mp_float_t val = mp_obj_get_float(args[0]); mp_float_t val = mp_obj_get_float(args[0]);
t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val);
#else #else
t = mp_obj_get_int(args[0]); t = mp_obj_get_int(args[0]);
#endif #endif
} }
struct tm *tm = localtime(&t); struct tm *tm = time_func(&t);
mp_obj_t ret = mp_obj_new_tuple(9, NULL); mp_obj_t ret = mp_obj_new_tuple(9, NULL);
@ -165,6 +165,15 @@ STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) {
return ret; return ret;
} }
STATIC mp_obj_t mod_time_gmtime(size_t n_args, const mp_obj_t *args) {
return mod_time_gm_local_time(n_args, args, gmtime);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_gmtime_obj, 0, 1, mod_time_gmtime);
STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) {
return mod_time_gm_local_time(n_args, args, localtime);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime);
STATIC mp_obj_t mod_time_mktime(mp_obj_t tuple) { STATIC mp_obj_t mod_time_mktime(mp_obj_t tuple) {
@ -210,6 +219,8 @@ STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
{ MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
{ MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
{ MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) },
{ MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&mod_time_gmtime_obj) },
{ MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) }, { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) },
{ MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) }, { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) },
}; };

285
ports/unix/mpbthciport.c Normal file
View File

@ -0,0 +1,285 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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 "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && (MICROPY_BLUETOOTH_NIMBLE || (MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_H4))
#if !MICROPY_PY_THREAD
#error Unix HCI UART requires MICROPY_PY_THREAD
#endif
#include "extmod/modbluetooth.h"
#include "extmod/mpbthci.h"
#include <pthread.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG_printf(...) // printf(__VA_ARGS__)
#define DEBUG_HCI_DUMP (0)
uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
STATIC int uart_fd = -1;
// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
extern bool mp_bluetooth_hci_poll(void);
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
// For synchronous mode, we run all BLE stack code inside a scheduled task.
// This task is scheduled periodically (every 1ms) by a background thread.
// Allows the stack to tell us that we should stop trying to schedule.
extern bool mp_bluetooth_hci_active(void);
// Prevent double-enqueuing of the scheduled task.
STATIC volatile bool events_task_is_scheduled = false;
STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
(void)none_in;
MICROPY_PY_BLUETOOTH_ENTER
events_task_is_scheduled = false;
MICROPY_PY_BLUETOOTH_EXIT
mp_bluetooth_hci_poll();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task);
#endif // MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
STATIC const useconds_t UART_POLL_INTERVAL_US = 1000;
STATIC pthread_t hci_poll_thread_id;
STATIC void *hci_poll_thread(void *arg) {
(void)arg;
DEBUG_printf("hci_poll_thread: starting\n");
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
events_task_is_scheduled = false;
while (mp_bluetooth_hci_active()) {
MICROPY_PY_BLUETOOTH_ENTER
if (!events_task_is_scheduled) {
events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
}
MICROPY_PY_BLUETOOTH_EXIT
usleep(UART_POLL_INTERVAL_US);
}
#else
// In asynchronous (i.e. ringbuffer) mode, we run the BLE stack directly from the thread.
// This will return false when the stack is shutdown.
while (mp_bluetooth_hci_poll()) {
usleep(UART_POLL_INTERVAL_US);
}
#endif
DEBUG_printf("hci_poll_thread: stopped\n");
return NULL;
}
STATIC int configure_uart(void) {
struct termios toptions;
// Get existing config.
if (tcgetattr(uart_fd, &toptions) < 0) {
DEBUG_printf("Couldn't get term attributes");
return -1;
}
// Raw mode (disable all processing).
cfmakeraw(&toptions);
// 8N1, no parity.
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag |= CS8;
toptions.c_cflag &= ~PARENB;
// Enable receiver, ignore modem control lines
toptions.c_cflag |= CREAD | CLOCAL;
// Blocking, single-byte reads.
toptions.c_cc[VMIN] = 1;
toptions.c_cc[VTIME] = 0;
// Enable HW RTS/CTS flow control.
toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
toptions.c_cflag |= CRTSCTS;
// 1Mbit (TODO: make this configurable).
speed_t brate = B1000000;
cfsetospeed(&toptions, brate);
cfsetispeed(&toptions, brate);
// Apply immediately.
if (tcsetattr(uart_fd, TCSANOW, &toptions) < 0) {
DEBUG_printf("Couldn't set term attributes");
close(uart_fd);
uart_fd = -1;
return -1;
}
return 0;
}
// HCI UART bindings.
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
(void)port;
(void)baudrate;
DEBUG_printf("mp_bluetooth_hci_uart_init (unix)\n");
if (uart_fd != -1) {
DEBUG_printf("mp_bluetooth_hci_uart_init: already active\n");
return 0;
}
char uart_device_name[256] = "/dev/ttyUSB0";
char *path = getenv("MICROPYBTUART");
if (path != NULL) {
strcpy(uart_device_name, path);
}
DEBUG_printf("mp_bluetooth_hci_uart_init: Using HCI UART: %s\n", uart_device_name);
int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
uart_fd = open(uart_device_name, flags);
if (uart_fd == -1) {
printf("mp_bluetooth_hci_uart_init: Unable to open port %s\n", uart_device_name);
return -1;
}
if (configure_uart()) {
return -1;
}
// Create a thread to run the polling loop.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&hci_poll_thread_id, &attr, &hci_poll_thread, NULL);
return 0;
}
int mp_bluetooth_hci_uart_deinit(void) {
DEBUG_printf("mp_bluetooth_hci_uart_deinit\n");
if (uart_fd == -1) {
return 0;
}
// Wait for the poll loop to terminate when the state is set to OFF.
pthread_join(hci_poll_thread_id, NULL);
// Close the UART.
close(uart_fd);
uart_fd = -1;
return 0;
}
int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) {
(void)baudrate;
DEBUG_printf("mp_bluetooth_hci_uart_set_baudrate\n");
return 0;
}
int mp_bluetooth_hci_uart_readchar(void) {
// DEBUG_printf("mp_bluetooth_hci_uart_readchar\n");
if (uart_fd == -1) {
return -1;
}
uint8_t c;
ssize_t bytes_read = read(uart_fd, &c, 1);
if (bytes_read == 1) {
#if DEBUG_HCI_DUMP
printf("[% 8ld] RX: %02x\n", mp_hal_ticks_ms(), c);
#endif
return c;
} else {
return -1;
}
}
int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) {
// DEBUG_printf("mp_bluetooth_hci_uart_write\n");
if (uart_fd == -1) {
return 0;
}
#if DEBUG_HCI_DUMP
printf("[% 8ld] TX: %02x", mp_hal_ticks_ms(), buf[0]);
for (size_t i = 1; i < len; ++i) {
printf(":%02x", buf[i]);
}
printf("\n");
#endif
return write(uart_fd, buf, len);
}
// No-op implementations of HCI controller interface.
int mp_bluetooth_hci_controller_init(void) {
return 0;
}
int mp_bluetooth_hci_controller_deinit(void) {
return 0;
}
int mp_bluetooth_hci_controller_sleep_maybe(void) {
return 0;
}
bool mp_bluetooth_hci_controller_woken(void) {
return true;
}
int mp_bluetooth_hci_controller_wakeup(void) {
return 0;
}
#endif // MICROPY_PY_BLUETOOTH && (MICROPY_BLUETOOTH_NIMBLE || (MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_H4))

View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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.
*/
#ifndef MICROPY_INCLUDED_UNIX_BTSTACK_PORT_H
#define MICROPY_INCLUDED_UNIX_BTSTACK_PORT_H
#define MICROPY_HW_BLE_UART_ID (0)
#define MICROPY_HW_BLE_UART_BAUDRATE (1000000)
bool mp_bluetooth_hci_poll(void);
#if MICROPY_BLUETOOTH_BTSTACK_H4
void mp_bluetooth_hci_poll_h4(void);
void mp_bluetooth_btstack_port_init_h4(void);
#endif
#if MICROPY_BLUETOOTH_BTSTACK_USB
void mp_bluetooth_btstack_port_init_usb(void);
#endif
#endif // MICROPY_INCLUDED_UNIX_BTSTACK_PORT_H

View File

@ -0,0 +1,96 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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 "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
#include "lib/btstack/src/btstack.h"
#include "lib/btstack/platform/embedded/btstack_run_loop_embedded.h"
#include "lib/btstack/platform/embedded/hal_cpu.h"
#include "lib/btstack/platform/embedded/hal_time_ms.h"
#include "extmod/btstack/modbluetooth_btstack.h"
#include "mpbtstackport.h"
// Called by the UART polling thread in mpbthciport.c, or by the USB polling thread in mpbtstackport_usb.c.
bool mp_bluetooth_hci_poll(void) {
if (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_STARTING || mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE || mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_HALTING) {
// Pretend like we're running in IRQ context (i.e. other things can't be running at the same time).
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
#if MICROPY_BLUETOOTH_BTSTACK_H4
mp_bluetooth_hci_poll_h4();
#endif
btstack_run_loop_embedded_execute_once();
MICROPY_END_ATOMIC_SECTION(atomic_state);
return true;
}
return false;
}
// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
// following three functions are empty.
void hal_cpu_disable_irqs(void) {
}
void hal_cpu_enable_irqs(void) {
}
void hal_cpu_enable_irqs_and_sleep(void) {
}
uint32_t hal_time_ms(void) {
return mp_hal_ticks_ms();
}
void mp_bluetooth_btstack_port_init(void) {
static bool run_loop_init = false;
if (!run_loop_init) {
run_loop_init = true;
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
} else {
btstack_run_loop_embedded_get_instance()->init();
}
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
#if MICROPY_BLUETOOTH_BTSTACK_H4
mp_bluetooth_btstack_port_init_h4();
#endif
#if MICROPY_BLUETOOTH_BTSTACK_USB
mp_bluetooth_btstack_port_init_usb();
#endif
}
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK

View File

@ -0,0 +1,80 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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 <pthread.h>
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_H4
#include "lib/btstack/chipset/zephyr/btstack_chipset_zephyr.h"
#include "extmod/btstack/btstack_hci_uart.h"
#include "extmod/btstack/modbluetooth_btstack.h"
#include "mpbtstackport.h"
#define DEBUG_printf(...) // printf(__VA_ARGS__)
STATIC hci_transport_config_uart_t hci_transport_config_uart = {
HCI_TRANSPORT_CONFIG_UART,
1000000, // initial baudrate
0, // main baudrate
1, // flow control
NULL, // device name
};
void mp_bluetooth_hci_poll_h4(void) {
if (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_STARTING || mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE) {
mp_bluetooth_btstack_hci_uart_process();
}
}
void mp_bluetooth_btstack_port_init_h4(void) {
DEBUG_printf("mp_bluetooth_btstack_port_init_h4\n");
const hci_transport_t *transport = hci_transport_h4_instance(&mp_bluetooth_btstack_hci_uart_block);
hci_init(transport, &hci_transport_config_uart);
hci_set_chipset(btstack_chipset_zephyr_instance());
}
void mp_bluetooth_btstack_port_deinit(void) {
DEBUG_printf("mp_bluetooth_btstack_port_deinit\n");
hci_power_control(HCI_POWER_OFF);
hci_close();
}
void mp_bluetooth_btstack_port_start(void) {
DEBUG_printf("mp_bluetooth_btstack_port_start\n");
hci_power_control(HCI_POWER_ON);
}
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_H4

View File

@ -31,7 +31,7 @@
#include "py/mperrno.h" #include "py/mperrno.h"
#include "py/mphal.h" #include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_USB
#include "lib/btstack/src/btstack.h" #include "lib/btstack/src/btstack.h"
#include "lib/btstack/platform/embedded/btstack_run_loop_embedded.h" #include "lib/btstack/platform/embedded/btstack_run_loop_embedded.h"
@ -40,76 +40,15 @@
#include "extmod/btstack/modbluetooth_btstack.h" #include "extmod/btstack/modbluetooth_btstack.h"
#include "mpbtstackport.h"
#if !MICROPY_PY_THREAD #if !MICROPY_PY_THREAD
#error Unix btstack requires MICROPY_PY_THREAD #error Unix btstack requires MICROPY_PY_THREAD
#endif #endif
STATIC const useconds_t USB_POLL_INTERVAL_US = 1000; STATIC const useconds_t USB_POLL_INTERVAL_US = 1000;
STATIC const uint8_t read_static_address_command_complete_prefix[] = { 0x0e, 0x1b, 0x01, 0x09, 0xfc }; void mp_bluetooth_btstack_port_init_usb(void) {
STATIC uint8_t local_addr[6] = {0};
STATIC uint8_t static_address[6] = {0};
STATIC volatile bool have_addr = false;
STATIC bool using_static_address = false;
STATIC btstack_packet_callback_registration_t hci_event_callback_registration;
STATIC void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
if (packet_type != HCI_EVENT_PACKET) {
return;
}
switch (hci_event_packet_get_type(packet)) {
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) {
return;
}
gap_local_bd_addr(local_addr);
if (using_static_address) {
memcpy(local_addr, static_address, sizeof(local_addr));
}
have_addr = true;
break;
case HCI_EVENT_COMMAND_COMPLETE:
if (memcmp(packet, read_static_address_command_complete_prefix, sizeof(read_static_address_command_complete_prefix)) == 0) {
reverse_48(&packet[7], static_address);
gap_random_address_set(static_address);
using_static_address = true;
have_addr = true;
}
break;
default:
break;
}
}
// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
// following three functions are empty.
void hal_cpu_disable_irqs(void) {
}
void hal_cpu_enable_irqs(void) {
}
void hal_cpu_enable_irqs_and_sleep(void) {
}
uint32_t hal_time_ms(void) {
return mp_hal_ticks_ms();
}
void mp_bluetooth_btstack_port_init(void) {
static bool run_loop_init = false;
if (!run_loop_init) {
run_loop_init = true;
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
} else {
btstack_run_loop_embedded_get_instance()->init();
}
// MICROPYBTUSB can be a ':'' or '-' separated port list. // MICROPYBTUSB can be a ':'' or '-' separated port list.
char *path = getenv("MICROPYBTUSB"); char *path = getenv("MICROPYBTUSB");
if (path != NULL) { if (path != NULL) {
@ -128,11 +67,7 @@ void mp_bluetooth_btstack_port_init(void) {
hci_transport_usb_set_path(usb_path_len, usb_path); hci_transport_usb_set_path(usb_path_len, usb_path);
} }
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
hci_init(hci_transport_usb_instance(), NULL); hci_init(hci_transport_usb_instance(), NULL);
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
} }
STATIC pthread_t bstack_thread_id; STATIC pthread_t bstack_thread_id;
@ -142,9 +77,12 @@ void mp_bluetooth_btstack_port_deinit(void) {
// Wait for the poll loop to terminate when the state is set to OFF. // Wait for the poll loop to terminate when the state is set to OFF.
pthread_join(bstack_thread_id, NULL); pthread_join(bstack_thread_id, NULL);
have_addr = false;
} }
// Provided by mpbstackport_common.c.
extern bool mp_bluetooth_hci_poll(void);
STATIC void *btstack_thread(void *arg) { STATIC void *btstack_thread(void *arg) {
(void)arg; (void)arg;
hci_power_control(HCI_POWER_ON); hci_power_control(HCI_POWER_ON);
@ -155,19 +93,15 @@ STATIC void *btstack_thread(void *arg) {
// in modbluetooth_btstack.c setting the state back to OFF. // in modbluetooth_btstack.c setting the state back to OFF.
// Or, if a timeout results in it being set to TIMEOUT. // Or, if a timeout results in it being set to TIMEOUT.
while (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_STARTING || mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE) { while (true) {
// Pretend like we're running in IRQ context (i.e. other things can't be running at the same time). if (!mp_bluetooth_hci_poll()) {
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); break;
btstack_run_loop_embedded_execute_once(); }
MICROPY_END_ATOMIC_SECTION(atomic_state);
// The USB transport schedules events to the run loop at 1ms intervals, // The USB transport schedules events to the run loop at 1ms intervals,
// and the implementation currently polls rather than selects. // and the implementation currently polls rather than selects.
usleep(USB_POLL_INTERVAL_US); usleep(USB_POLL_INTERVAL_US);
} }
hci_close();
return NULL; return NULL;
} }
@ -179,13 +113,4 @@ void mp_bluetooth_btstack_port_start(void) {
pthread_create(&bstack_thread_id, &attr, &btstack_thread, NULL); pthread_create(&bstack_thread_id, &attr, &btstack_thread, NULL);
} }
void mp_hal_get_mac(int idx, uint8_t buf[6]) { #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_USB
if (idx == MP_HAL_MAC_BDADDR) {
if (!have_addr) {
mp_raise_OSError(MP_ENODEV);
}
memcpy(buf, local_addr, sizeof(local_addr));
}
}
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK

View File

@ -87,6 +87,7 @@
#define MICROPY_VFS_POSIX_FILE (1) #define MICROPY_VFS_POSIX_FILE (1)
#define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1) #define MICROPY_PY_BUILTINS_STR_PARTITION (1)
@ -347,11 +348,16 @@ void mp_unix_mark_exec(void);
#endif #endif
#if MICROPY_PY_THREAD #if MICROPY_PY_THREAD
#define MICROPY_BEGIN_ATOMIC_SECTION() (mp_thread_unix_begin_atomic_section(), 0) #define MICROPY_BEGIN_ATOMIC_SECTION() (mp_thread_unix_begin_atomic_section(), 0xffffffff)
#define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section() #define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section()
#endif #endif
#define MICROPY_EVENT_POLL_HOOK mp_hal_delay_us(500); #define MICROPY_EVENT_POLL_HOOK \
do { \
extern void mp_handle_pending(bool); \
mp_handle_pending(true); \
mp_hal_delay_us(500); \
} while (0);
#include <sched.h> #include <sched.h>
#define MICROPY_UNIX_MACHINE_IDLE sched_yield(); #define MICROPY_UNIX_MACHINE_IDLE sched_yield();

View File

@ -66,11 +66,6 @@ static inline int mp_hal_readline(vstr_t *vstr, const char *p) {
#endif #endif
// TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep:
// "The useconds argument shall be less than one million."
static inline void mp_hal_delay_ms(mp_uint_t ms) {
usleep((ms) * 1000);
}
static inline void mp_hal_delay_us(mp_uint_t us) { static inline void mp_hal_delay_us(mp_uint_t us) {
usleep(us); usleep(us);
} }

74
ports/unix/mpnimbleport.c Normal file
View File

@ -0,0 +1,74 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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 "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
#include "nimble/nimble_npl.h"
#include "extmod/nimble/modbluetooth_nimble.h"
#include "extmod/nimble/hal/hal_uart.h"
#define DEBUG_printf(...) // printf(__VA_ARGS__)
// Called by the UART polling thread in mpbthciport.c.
bool mp_bluetooth_hci_poll(void) {
// DEBUG_printf("mp_bluetooth_hci_poll (unix nimble) %d\n", mp_bluetooth_nimble_ble_state);
if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
DEBUG_printf("mp_bluetooth_hci_poll (unix nimble) -- shutdown\n");
return false;
}
if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) {
// Run any timers.
mp_bluetooth_nimble_os_callout_process();
// Process incoming UART data, and run events as they are generated.
mp_bluetooth_nimble_hci_uart_process(true);
// Run any remaining events (e.g. if there was no UART data).
mp_bluetooth_nimble_os_eventq_run_all();
}
return true;
}
bool mp_bluetooth_hci_active(void) {
return mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF;
}
// Extra port-specific helpers.
void mp_bluetooth_nimble_hci_uart_wfi(void) {
// This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK.
// Do not need to run events here, only processing incoming HCI data.
mp_bluetooth_nimble_hci_uart_process(false);
}
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE

33
ports/unix/mpnimbleport.h Normal file
View File

@ -0,0 +1,33 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jim Mussared
*
* 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.
*/
#ifndef MICROPY_INCLUDED_UNIX_NIMBLE_PORT_H
#define MICROPY_INCLUDED_UNIX_NIMBLE_PORT_H
#define MICROPY_HW_BLE_UART_ID (0)
#define MICROPY_HW_BLE_UART_BAUDRATE (1000000)
#endif // MICROPY_INCLUDED_UNIX_NIMBLE_PORT_H

View File

@ -167,6 +167,21 @@ mp_uint_t mp_hal_ticks_us(void) {
} }
uint64_t mp_hal_time_ns(void) { uint64_t mp_hal_time_ns(void) {
time_t now = time(NULL); struct timeval tv;
return (uint64_t)now * 1000000000ULL; gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000000000ULL + (uint64_t)tv.tv_usec * 1000ULL;
}
void mp_hal_delay_ms(mp_uint_t ms) {
#ifdef MICROPY_EVENT_POLL_HOOK
mp_uint_t start = mp_hal_ticks_ms();
while (mp_hal_ticks_ms() - start < ms) {
// MICROPY_EVENT_POLL_HOOK does mp_hal_delay_us(500) (i.e. usleep(500)).
MICROPY_EVENT_POLL_HOOK
}
#else
// TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep:
// "The useconds argument shall be less than one million."
usleep(ms * 1000);
#endif
} }

View File

@ -30,6 +30,7 @@
#define MICROPY_VFS (1) #define MICROPY_VFS (1)
#define MICROPY_PY_UOS_VFS (1) #define MICROPY_PY_UOS_VFS (1)
#define MICROPY_DEBUG_PARSE_RULE_NAME (1)
#define MICROPY_OPT_MATH_FACTORIAL (1) #define MICROPY_OPT_MATH_FACTORIAL (1)
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1)
#define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_ENABLE_SCHEDULER (1)
@ -39,6 +40,7 @@
#define MICROPY_WARNINGS_CATEGORY (1) #define MICROPY_WARNINGS_CATEGORY (1)
#define MICROPY_MODULE_GETATTR (1) #define MICROPY_MODULE_GETATTR (1)
#define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_DELATTR_SETATTR (1)
#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (1)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE (1)
#define MICROPY_PY_BUILTINS_NEXT2 (1) #define MICROPY_PY_BUILTINS_NEXT2 (1)

View File

@ -7,13 +7,19 @@ CFLAGS += \
-fprofile-arcs -ftest-coverage \ -fprofile-arcs -ftest-coverage \
-Wformat -Wmissing-declarations -Wmissing-prototypes \ -Wformat -Wmissing-declarations -Wmissing-prototypes \
-Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \
-DMICROPY_UNIX_COVERAGE -DMICROPY_UNIX_COVERAGE \
-DMODULE_CEXAMPLE_ENABLED=1 -DMODULE_CPPEXAMPLE_ENABLED=1
LDFLAGS += -fprofile-arcs -ftest-coverage LDFLAGS += -fprofile-arcs -ftest-coverage
USER_C_MODULES = $(TOP)/examples/usercmodule
MICROPY_VFS_FAT = 1 MICROPY_VFS_FAT = 1
MICROPY_VFS_LFS1 = 1 MICROPY_VFS_LFS1 = 1
MICROPY_VFS_LFS2 = 1 MICROPY_VFS_LFS2 = 1
FROZEN_DIR=variants/coverage/frzstr FROZEN_DIR=variants/coverage/frzstr
FROZEN_MPY_DIR=variants/coverage/frzmpy FROZEN_MPY_DIR=variants/coverage/frzmpy
SRC_C += coverage.c
SRC_CXX += coveragecpp.cpp

View File

@ -5,4 +5,5 @@ FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
MICROPY_VFS_FAT = 1 MICROPY_VFS_FAT = 1
MICROPY_VFS_LFS1 = 1 MICROPY_VFS_LFS1 = 1
MICROPY_VFS_LFS2 = 1 MICROPY_VFS_LFS2 = 1
MICROPY_PY_BLUETOOTH = 1
MICROPY_PY_BLUETOOTH ?= 1

View File

@ -100,7 +100,10 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
pos_found++; pos_found++;
given_arg = pos[i]; given_arg = pos[i];
} else { } else {
mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP); mp_map_elem_t *kw = NULL;
if (kws != NULL) {
kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP);
}
if (kw == NULL) { if (kw == NULL) {
if (allowed[i].flags & MP_ARG_REQUIRED) { if (allowed[i].flags & MP_ARG_REQUIRED) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
@ -134,7 +137,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
mp_raise_TypeError(MP_ERROR_TEXT("extra positional arguments given")); mp_raise_TypeError(MP_ERROR_TEXT("extra positional arguments given"));
#endif #endif
} }
if (kws_found < kws->used) { if (kws != NULL && kws_found < kws->used) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else

View File

@ -47,6 +47,7 @@
#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) #define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
#define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) #define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000)
#if MICROPY_EMIT_THUMB_ARMV7M
// Note: these actually take an imm12 but the high-bit is not encoded here // Note: these actually take an imm12 but the high-bit is not encoded here
#define OP_ADD_W_RRI_HI(reg_src) (0xf200 | (reg_src)) #define OP_ADD_W_RRI_HI(reg_src) (0xf200 | (reg_src))
#define OP_ADD_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff)) #define OP_ADD_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff))
@ -55,6 +56,7 @@
#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base)) #define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base))
#define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) #define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12))
#endif
static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
return mp_asm_base_get_cur_to_write_bytes(&as->base, n); return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
@ -122,7 +124,7 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
// If this Thumb machine code is run from ARM state then add a prelude // If this Thumb machine code is run from ARM state then add a prelude
// to switch to Thumb state for the duration of the function. // to switch to Thumb state for the duration of the function.
#if MICROPY_DYNAMIC_COMPILER || MICROPY_EMIT_ARM || (defined(__arm__) && !defined(__thumb2__)) #if MICROPY_DYNAMIC_COMPILER || MICROPY_EMIT_ARM || (defined(__arm__) && !defined(__thumb2__) && !defined(__thumb__))
#if MICROPY_DYNAMIC_COMPILER #if MICROPY_DYNAMIC_COMPILER
if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6) if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6)
#endif #endif
@ -171,11 +173,21 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
} }
asm_thumb_op16(as, OP_PUSH_RLIST_LR(reglist)); asm_thumb_op16(as, OP_PUSH_RLIST_LR(reglist));
if (stack_adjust > 0) { if (stack_adjust > 0) {
#if MICROPY_EMIT_THUMB_ARMV7M
if (UNSIGNED_FIT7(stack_adjust)) { if (UNSIGNED_FIT7(stack_adjust)) {
asm_thumb_op16(as, OP_SUB_SP(stack_adjust)); asm_thumb_op16(as, OP_SUB_SP(stack_adjust));
} else { } else {
asm_thumb_op32(as, OP_SUB_W_RRI_HI(ASM_THUMB_REG_SP), OP_SUB_W_RRI_LO(ASM_THUMB_REG_SP, stack_adjust * 4)); asm_thumb_op32(as, OP_SUB_W_RRI_HI(ASM_THUMB_REG_SP), OP_SUB_W_RRI_LO(ASM_THUMB_REG_SP, stack_adjust * 4));
} }
#else
int adj = stack_adjust;
// we don't expect the stack_adjust to be massive
while (!UNSIGNED_FIT7(adj)) {
asm_thumb_op16(as, OP_SUB_SP(127));
adj -= 127;
}
asm_thumb_op16(as, OP_SUB_SP(adj));
#endif
} }
as->push_reglist = reglist; as->push_reglist = reglist;
as->stack_adjust = stack_adjust; as->stack_adjust = stack_adjust;
@ -183,11 +195,21 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
void asm_thumb_exit(asm_thumb_t *as) { void asm_thumb_exit(asm_thumb_t *as) {
if (as->stack_adjust > 0) { if (as->stack_adjust > 0) {
#if MICROPY_EMIT_THUMB_ARMV7M
if (UNSIGNED_FIT7(as->stack_adjust)) { if (UNSIGNED_FIT7(as->stack_adjust)) {
asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust)); asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust));
} else { } else {
asm_thumb_op32(as, OP_ADD_W_RRI_HI(ASM_THUMB_REG_SP), OP_ADD_W_RRI_LO(ASM_THUMB_REG_SP, as->stack_adjust * 4)); asm_thumb_op32(as, OP_ADD_W_RRI_HI(ASM_THUMB_REG_SP), OP_ADD_W_RRI_LO(ASM_THUMB_REG_SP, as->stack_adjust * 4));
} }
#else
int adj = as->stack_adjust;
// we don't expect the stack_adjust to be massive
while (!UNSIGNED_FIT7(adj)) {
asm_thumb_op16(as, OP_ADD_SP(127));
adj -= 127;
}
asm_thumb_op16(as, OP_ADD_SP(adj));
#endif
} }
asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist)); asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist));
} }
@ -241,6 +263,8 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
asm_thumb_op16(as, 0x4600 | op_lo); asm_thumb_op16(as, 0x4600 | op_lo);
} }
#if MICROPY_EMIT_THUMB_ARMV7M
// if loading lo half with movw, the i16 value will be zero extended into the r32 register! // if loading lo half with movw, the i16 value will be zero extended into the r32 register!
size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) {
assert(reg_dest < ASM_THUMB_REG_R15); assert(reg_dest < ASM_THUMB_REG_R15);
@ -250,6 +274,16 @@ size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i1
return loc; return loc;
} }
#else
void asm_thumb_mov_rlo_i16(asm_thumb_t *as, uint rlo_dest, int i16_src) {
asm_thumb_mov_rlo_i8(as, rlo_dest, (i16_src >> 8) & 0xff);
asm_thumb_lsl_rlo_rlo_i5(as, rlo_dest, rlo_dest, 8);
asm_thumb_add_rlo_i8(as, rlo_dest, i16_src & 0xff);
}
#endif
#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff))
bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) {
@ -274,8 +308,13 @@ bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) {
asm_thumb_op16(as, OP_BCC_N(cond, rel)); asm_thumb_op16(as, OP_BCC_N(cond, rel));
return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel); return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel);
} else { } else {
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));
return true; return true;
#else
// this method should not be called for ARMV6M
return false;
#endif
} }
} }
@ -296,8 +335,30 @@ size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
size_t loc = mp_asm_base_get_code_pos(&as->base); size_t loc = mp_asm_base_get_code_pos(&as->base);
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32);
asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16); asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16);
#else
// should only be called with lo reg for ARMV6M
assert(reg_dest < ASM_THUMB_REG_R8);
// sanity check that generated code is aligned
assert(!as->base.code_base || !(3u & (uintptr_t)as->base.code_base));
// basically:
// (nop)
// ldr reg_dest, _data
// b 1f
// _data: .word i32
// 1:
if (as->base.code_offset & 2u) {
asm_thumb_op16(as, ASM_THUMB_OP_NOP);
}
asm_thumb_ldr_rlo_pcrel_i8(as, reg_dest, 0);
asm_thumb_op16(as, OP_B_N(2));
asm_thumb_op16(as, i32 & 0xffff);
asm_thumb_op16(as, i32 >> 16);
#endif
return loc; return loc;
} }
@ -305,27 +366,68 @@ size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) {
if (reg_dest < 8 && UNSIGNED_FIT8(i32)) { if (reg_dest < 8 && UNSIGNED_FIT8(i32)) {
asm_thumb_mov_rlo_i8(as, reg_dest, i32); asm_thumb_mov_rlo_i8(as, reg_dest, i32);
} else if (UNSIGNED_FIT16(i32)) {
asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32);
} else { } else {
asm_thumb_mov_reg_i32(as, reg_dest, i32); #if MICROPY_EMIT_THUMB_ARMV7M
if (UNSIGNED_FIT16(i32)) {
asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32);
} else {
asm_thumb_mov_reg_i32(as, reg_dest, i32);
}
#else
uint rlo_dest = reg_dest;
assert(rlo_dest < ASM_THUMB_REG_R8); // should never be called for ARMV6M
bool negate = i32 < 0 && ((i32 + i32) & 0xffffffffu); // don't negate 0x80000000
if (negate) {
i32 = -i32;
}
uint clz = __builtin_clz(i32);
uint ctz = i32 ? __builtin_ctz(i32) : 0;
assert(clz + ctz <= 32);
if (clz + ctz >= 24) {
asm_thumb_mov_rlo_i8(as, rlo_dest, (i32 >> ctz) & 0xff);
asm_thumb_lsl_rlo_rlo_i5(as, rlo_dest, rlo_dest, ctz);
} else if (UNSIGNED_FIT16(i32)) {
asm_thumb_mov_rlo_i16(as, rlo_dest, i32);
} else {
if (negate) {
// no point in negating if we're storing in 32 bit anyway
negate = false;
i32 = -i32;
}
asm_thumb_mov_reg_i32(as, rlo_dest, i32);
}
if (negate) {
asm_thumb_neg_rlo_rlo(as, rlo_dest, rlo_dest);
}
#endif
} }
} }
#define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) #define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
#define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) #define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
static void asm_thumb_mov_local_check(asm_thumb_t *as, int word_offset) {
if (as->base.pass >= MP_ASM_PASS_EMIT) {
assert(word_offset >= 0);
if (!UNSIGNED_FIT8(word_offset)) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("too many locals for native method"));
}
}
}
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) { void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) {
assert(rlo_src < ASM_THUMB_REG_R8); assert(rlo_src < ASM_THUMB_REG_R8);
int word_offset = local_num; int word_offset = local_num;
assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_mov_local_check(as, word_offset);
asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset)); asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset));
} }
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {
assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_dest < ASM_THUMB_REG_R8);
int word_offset = local_num; int word_offset = local_num;
assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_mov_local_check(as, word_offset);
asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset)); asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset));
} }
@ -341,21 +443,63 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) { void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) {
mp_uint_t dest = get_label_dest(as, label); mp_uint_t dest = get_label_dest(as, label);
mp_int_t rel = dest - as->base.code_offset; mp_int_t rel = dest - as->base.code_offset;
rel -= 4 + 4; // adjust for mov_reg_i16 and then PC+4 prefetch of add_reg_reg
rel |= 1; // to stay in Thumb state when jumping to this address rel |= 1; // to stay in Thumb state when jumping to this address
#if MICROPY_EMIT_THUMB_ARMV7M
rel -= 4 + 4; // adjust for mov_reg_i16 and then PC+4 prefetch of add_reg_reg
asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, rlo_dest, rel); // 4 bytes asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, rlo_dest, rel); // 4 bytes
#else
rel -= 8 + 4; // adjust for four instructions and then PC+4 prefetch of add_reg_reg
// 6 bytes
asm_thumb_mov_rlo_i16(as, rlo_dest, rel);
// 2 bytes - not always needed, but we want to keep the size the same
asm_thumb_sxth_rlo_rlo(as, rlo_dest, rlo_dest);
#endif
asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes
} }
#if MICROPY_EMIT_THUMB_ARMV7M
static inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { static inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) {
asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4)); asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4));
} }
#endif
void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) {
if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) { if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) {
asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset); asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset);
} else { } else {
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset); asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset);
#else
word_offset -= 31;
if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8) {
if (UNSIGNED_FIT8(word_offset) && (word_offset < 64 || reg_dest != reg_base)) {
if (word_offset < 64) {
if (reg_dest != reg_base) {
asm_thumb_mov_reg_reg(as, reg_dest, reg_base);
}
asm_thumb_add_rlo_i8(as, reg_dest, word_offset * 4);
} else {
asm_thumb_mov_rlo_i8(as, reg_dest, word_offset);
asm_thumb_lsl_rlo_rlo_i5(as, reg_dest, reg_dest, 2);
asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_base);
}
} else {
if (reg_dest != reg_base) {
asm_thumb_mov_rlo_i16(as, reg_dest, word_offset * 4);
asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_dest);
} else {
uint reg_other = reg_dest ^ 7;
asm_thumb_op16(as, OP_PUSH_RLIST((1 << reg_other)));
asm_thumb_mov_rlo_i16(as, reg_other, word_offset * 4);
asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_other);
asm_thumb_op16(as, OP_POP_RLIST((1 << reg_other)));
}
}
} else {
assert(0); // should never be called for ARMV6M
}
asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_dest, 31);
#endif
} }
} }
@ -378,7 +522,20 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) {
} else { } else {
// is a forwards jump, so need to assume it's large // is a forwards jump, so need to assume it's large
large_jump: large_jump:
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel)); asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel));
#else
if (SIGNED_FIT12(rel)) {
// this code path has to be the same number of instructions irrespective of rel
asm_thumb_op16(as, OP_B_N(rel));
} else {
asm_thumb_op16(as, ASM_THUMB_OP_NOP);
if (dest != (mp_uint_t)-1) {
// we have an actual branch > 12 bits; this is not handled yet
mp_raise_NotImplementedError(MP_ERROR_TEXT("native method too big"));
}
}
#endif
} }
} }
@ -397,10 +554,28 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
} else { } else {
// is a forwards jump, so need to assume it's large // is a forwards jump, so need to assume it's large
large_jump: large_jump:
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));
#else
// reverse the sense of the branch to jump over a longer branch
asm_thumb_op16(as, OP_BCC_N(cond ^ 1, 0));
asm_thumb_b_label(as, label);
#endif
} }
} }
void asm_thumb_bcc_rel9(asm_thumb_t *as, int cond, int rel) {
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
assert(SIGNED_FIT9(rel));
asm_thumb_op16(as, OP_BCC_N(cond, rel));
}
void asm_thumb_b_rel12(asm_thumb_t *as, int rel) {
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
assert(SIGNED_FIT12(rel));
asm_thumb_op16(as, OP_B_N(rel));
}
#define OP_BLX(reg) (0x4780 | ((reg) << 3)) #define OP_BLX(reg) (0x4780 | ((reg) << 3))
#define OP_SVC(arg) (0xdf00 | (arg)) #define OP_SVC(arg) (0xdf00 | (arg))

View File

@ -157,6 +157,7 @@ static inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint
#define ASM_THUMB_FORMAT_3_CMP (0x2800) #define ASM_THUMB_FORMAT_3_CMP (0x2800)
#define ASM_THUMB_FORMAT_3_ADD (0x3000) #define ASM_THUMB_FORMAT_3_ADD (0x3000)
#define ASM_THUMB_FORMAT_3_SUB (0x3800) #define ASM_THUMB_FORMAT_3_SUB (0x3800)
#define ASM_THUMB_FORMAT_3_LDR (0x4800)
#define ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8) ((op) | ((rlo) << 8) | (i8)) #define ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8) ((op) | ((rlo) << 8) | (i8))
@ -177,6 +178,9 @@ static inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8); asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8);
} }
static inline void asm_thumb_ldr_rlo_pcrel_i8(asm_thumb_t *as, uint rlo, uint i8) {
asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_LDR, rlo, i8);
}
// FORMAT 4: ALU operations // FORMAT 4: ALU operations
@ -202,6 +206,12 @@ void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src);
static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) { static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {
asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src); asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src);
} }
static inline void asm_thumb_mvn_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {
asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_MVN, rlo_dest, rlo_src);
}
static inline void asm_thumb_neg_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {
asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_NEG, rlo_dest, rlo_src);
}
// FORMAT 5: hi register operations (add, cmp, mov, bx) // FORMAT 5: hi register operations (add, cmp, mov, bx)
// For add/cmp/mov, at least one of the args must be a high register // For add/cmp/mov, at least one of the args must be a high register
@ -263,6 +273,32 @@ static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uin
static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) {
asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset); asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset);
} }
static inline void asm_thumb_lsl_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_src, uint shift) {
asm_thumb_format_1(as, ASM_THUMB_FORMAT_1_LSL, rlo_dest, rlo_src, shift);
}
static inline void asm_thumb_asr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_src, uint shift) {
asm_thumb_format_1(as, ASM_THUMB_FORMAT_1_ASR, rlo_dest, rlo_src, shift);
}
// FORMAT 11: sign/zero extend
#define ASM_THUMB_FORMAT_11_ENCODE(op, rlo_dest, rlo_src) \
((op) | ((rlo_src) << 3) | (rlo_dest))
#define ASM_THUMB_FORMAT_11_SXTH (0xb200)
#define ASM_THUMB_FORMAT_11_SXTB (0xb240)
#define ASM_THUMB_FORMAT_11_UXTH (0xb280)
#define ASM_THUMB_FORMAT_11_UXTB (0xb2c0)
static inline void asm_thumb_format_11(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src) {
assert(rlo_dest < ASM_THUMB_REG_R8);
assert(rlo_src < ASM_THUMB_REG_R8);
asm_thumb_op16(as, ASM_THUMB_FORMAT_11_ENCODE(op, rlo_dest, rlo_src));
}
static inline void asm_thumb_sxth_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {
asm_thumb_format_11(as, ASM_THUMB_FORMAT_11_SXTH, rlo_dest, rlo_src);
}
// TODO convert these to above format style // TODO convert these to above format style
@ -270,7 +306,12 @@ static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uin
#define ASM_THUMB_OP_MOVT (0xf2c0) #define ASM_THUMB_OP_MOVT (0xf2c0)
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);
#if MICROPY_EMIT_THUMB_ARMV7M
size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); size_t asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src);
#else
void asm_thumb_mov_rlo_i16(asm_thumb_t *as, uint rlo_dest, int i16_src);
#endif
// these return true if the destination is in range, false otherwise // these return true if the destination is in range, false otherwise
bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); bool asm_thumb_b_n_label(asm_thumb_t *as, uint label);
@ -289,6 +330,8 @@ void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint re
void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenience void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenience
void asm_thumb_bcc_rel9(asm_thumb_t *as, int cc, int rel);
void asm_thumb_b_rel12(asm_thumb_t *as, int rel);
// Holds a pointer to mp_fun_table // Holds a pointer to mp_fun_table
#define ASM_THUMB_REG_FUN_TABLE ASM_THUMB_REG_R7 #define ASM_THUMB_REG_FUN_TABLE ASM_THUMB_REG_R7
@ -344,7 +387,11 @@ void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenien
#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg)) #define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg))
#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm))
#if MICROPY_EMIT_THUMB_ARMV7M
#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_reg_i16((as), ASM_THUMB_OP_MOVW, (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_reg_i16((as), ASM_THUMB_OP_MOVW, (reg_dest), (imm))
#else
#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_thumb_mov_rlo_i16((as), (reg_dest), (imm))
#endif
#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_thumb_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_thumb_mov_reg_i32((as), (reg_dest), (imm))
#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src))

View File

@ -226,10 +226,10 @@ const byte *mp_decode_uint_skip(const byte *ptr);
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args);
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);
void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table);
void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);
const byte *mp_bytecode_print_str(const byte *ip); const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);
#define mp_bytecode_print_inst(code, const_table) mp_bytecode_print2(code, 1, const_table) #define mp_bytecode_print_inst(print, code, const_table) mp_bytecode_print2(print, code, 1, const_table)
// Helper macros to access pointer with least significant bits holding flags // Helper macros to access pointer with least significant bits holding flags
#define MP_TAGPTR_PTR(x) ((void *)((uintptr_t)(x) & ~((uintptr_t)3))) #define MP_TAGPTR_PTR(x) ((void *)((uintptr_t)(x) & ~((uintptr_t)3)))

View File

@ -204,6 +204,7 @@ typedef long mp_off_t;
#define MICROPY_PY_URE_MATCH_GROUPS (CIRCUITPY_RE) #define MICROPY_PY_URE_MATCH_GROUPS (CIRCUITPY_RE)
#define MICROPY_PY_URE_MATCH_SPAN_START_END (CIRCUITPY_RE) #define MICROPY_PY_URE_MATCH_SPAN_START_END (CIRCUITPY_RE)
#define MICROPY_PY_URE_SUB (CIRCUITPY_RE) #define MICROPY_PY_URE_SUB (CIRCUITPY_RE)
#define MICROPY_EPOCH_IS_1970 (0)
// LONGINT_IMPL_xxx are defined in the Makefile. // LONGINT_IMPL_xxx are defined in the Makefile.
// //

View File

@ -166,9 +166,15 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
/******************************************************************************/ /******************************************************************************/
// General runtime functions // General runtime functions
#define mp_load_name(qst) (mp_fun_table.load_name(qst)) #define mp_load_name(qst) (mp_fun_table.load_name((qst)))
#define mp_load_global(qst) (mp_fun_table.load_global(qst)) #define mp_load_global(qst) (mp_fun_table.load_global((qst)))
#define mp_store_global(qst, obj) (mp_fun_table.store_global((qst), (obj))) #define mp_load_attr(base, attr) (mp_fun_table.load_attr((base), (attr)))
#define mp_load_method(base, attr, dest) (mp_fun_table.load_method((base), (attr), (dest)))
#define mp_load_super_method(attr, dest) (mp_fun_table.load_super_method((attr), (dest)))
#define mp_store_name(qst, obj) (mp_fun_table.store_name((qst), (obj)))
#define mp_store_global(qst, obj) (mp_fun_table.store_global((qst), (obj)))
#define mp_store_attr(base, attr, val) (mp_fun_table.store_attr((base), (attr), (val)))
#define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj))) #define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj)))
#define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs))) #define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs)))
@ -199,6 +205,13 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \ #define MP_DYNRUNTIME_MAKE_FUNCTION(f) \
(mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL)) (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL))
#define mp_import_name(name, fromlist, level) \
(mp_fun_table.import_name((name), (fromlist), (level)))
#define mp_import_from(module, name) \
(mp_fun_table.import_from((module), (name)))
#define mp_import_all(module) \
(mp_fun_table.import_all((module))
/******************************************************************************/ /******************************************************************************/
// Exceptions // Exceptions

View File

@ -92,7 +92,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
#endif #endif
#if MICROPY_DEBUG_PRINTERS #if MICROPY_DEBUG_PRINTERS
if (mp_verbose_flag >= 2) { if (mp_verbose_flag >= 2) {
mp_bytecode_print(rc, code, len, const_table); mp_bytecode_print(&mp_plat_print, rc, code, len, const_table);
} }
#endif #endif
} }

View File

@ -108,7 +108,7 @@ STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint
return 0; return 0;
} }
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { if (!(strlen(p) == 2 && p[0] == 'r' && (mp_uint_t)p[1] == '0' + i)) {
emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence r0 to r3")); emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence r0 to r3"));
return 0; return 0;
} }
@ -573,7 +573,11 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
goto unknown_op; goto unknown_op;
} }
int label_num = get_arg_label(emit, op_str, pn_args[0]); int label_num = get_arg_label(emit, op_str, pn_args[0]);
if (!asm_thumb_bcc_nw_label(&emit->as, cc, label_num, op_len == 5 && op_str[4] == 'w')) { bool wide = op_len == 5 && op_str[4] == 'w';
if (wide && !ARMV7M) {
goto unknown_op;
}
if (!asm_thumb_bcc_nw_label(&emit->as, cc, label_num, wide)) {
goto branch_not_in_range; goto branch_not_in_range;
} }
} else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') { } else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') {
@ -701,23 +705,24 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
} else if (op == MP_QSTR_sub) { } else if (op == MP_QSTR_sub) {
op_code = ASM_THUMB_FORMAT_3_SUB; op_code = ASM_THUMB_FORMAT_3_SUB;
goto op_format_3; goto op_format_3;
} else if (ARMV7M && op == MP_QSTR_movw) { #if ARMV7M
} else if (op == MP_QSTR_movw) {
op_code = ASM_THUMB_OP_MOVW; op_code = ASM_THUMB_OP_MOVW;
mp_uint_t reg_dest; mp_uint_t reg_dest;
op_movw_movt: op_movw_movt:
reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff); int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src); asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src);
} else if (ARMV7M && op == MP_QSTR_movt) { } else if (op == MP_QSTR_movt) {
op_code = ASM_THUMB_OP_MOVT; op_code = ASM_THUMB_OP_MOVT;
goto op_movw_movt; goto op_movw_movt;
} else if (ARMV7M && op == MP_QSTR_movwt) { } else if (op == MP_QSTR_movwt) {
// this is a convenience instruction // this is a convenience instruction
mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff); uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff); asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff);
asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff); asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff);
} else if (ARMV7M && op == MP_QSTR_ldrex) { } else if (op == MP_QSTR_ldrex) {
mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15); mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
mp_parse_node_t pn_base, pn_offset; mp_parse_node_t pn_base, pn_offset;
if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
@ -725,6 +730,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2; mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2;
asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8); asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8);
} }
#endif
} else { } else {
// search table for ldr/str instructions // search table for ldr/str instructions
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_9_10_op_table); i++) { for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_9_10_op_table); i++) {

View File

@ -92,7 +92,7 @@ STATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uin
return 0; return 0;
} }
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'a' && p[1] == '2' + i)) { if (!(strlen(p) == 2 && p[0] == 'a' && (mp_uint_t)p[1] == '2' + i)) {
emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5")); emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5"));
return 0; return 0;
} }

View File

@ -239,6 +239,7 @@ struct _emit_t {
int pass; int pass;
bool do_viper_types; bool do_viper_types;
bool prelude_offset_uses_u16_encoding;
mp_uint_t local_vtype_alloc; mp_uint_t local_vtype_alloc;
vtype_kind_t *local_vtype; vtype_kind_t *local_vtype;
@ -367,6 +368,18 @@ STATIC void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) {
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \ emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
} while (false) } while (false)
#define emit_native_mov_state_imm_fix_u16_via(emit, local_num, imm, reg_temp) \
do { \
ASM_MOV_REG_IMM_FIX_U16((emit)->as, (reg_temp), (imm)); \
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
} while (false)
#define emit_native_mov_state_imm_fix_word_via(emit, local_num, imm, reg_temp) \
do { \
ASM_MOV_REG_IMM_FIX_WORD((emit)->as, (reg_temp), (imm)); \
emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
} while (false)
STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
@ -577,16 +590,27 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
// Set code_state.ip (offset from start of this function to prelude info) // Set code_state.ip (offset from start of this function to prelude info)
int code_state_ip_local = emit->code_state_start + OFFSETOF_CODE_STATE_IP;
#if N_PRELUDE_AS_BYTES_OBJ #if N_PRELUDE_AS_BYTES_OBJ
// Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode // Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1);
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t)); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t));
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE);
ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1); ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1);
emit_native_mov_state_reg(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, REG_LOCAL_3); emit_native_mov_state_reg(emit, code_state_ip_local, REG_LOCAL_3);
#else #else
// TODO this encoding may change size in the final pass, need to make it fixed if (emit->pass == MP_PASS_CODE_SIZE) {
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1); // Commit to the encoding size based on the value of prelude_offset in this pass.
// By using 32768 as the cut-off it is highly unlikely that prelude_offset will
// grow beyond 65535 by the end of thiss pass, and so require the larger encoding.
emit->prelude_offset_uses_u16_encoding = emit->prelude_offset < 32768;
}
if (emit->prelude_offset_uses_u16_encoding) {
assert(emit->prelude_offset <= 65535);
emit_native_mov_state_imm_fix_u16_via(emit, code_state_ip_local, emit->prelude_offset, REG_PARENT_ARG_1);
} else {
emit_native_mov_state_imm_fix_word_via(emit, code_state_ip_local, emit->prelude_offset, REG_PARENT_ARG_1);
}
#endif #endif
// Set code_state.n_state (only works on little endian targets due to n_state being uint16_t) // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)
@ -2458,6 +2482,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
asm_x86_setcc_r8(emit->as, ops[op_idx], REG_RET); asm_x86_setcc_r8(emit->as, ops[op_idx], REG_RET);
#elif N_THUMB #elif N_THUMB
asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs); asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);
#if MICROPY_EMIT_THUMB_ARMV7M
static uint16_t ops[6 + 6] = { static uint16_t ops[6 + 6] = {
// unsigned // unsigned
ASM_THUMB_OP_ITE_CC, ASM_THUMB_OP_ITE_CC,
@ -2477,6 +2502,28 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
asm_thumb_op16(emit->as, ops[op_idx]); asm_thumb_op16(emit->as, ops[op_idx]);
asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1); asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);
asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0); asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);
#else
static uint16_t ops[6 + 6] = {
// unsigned
ASM_THUMB_CC_CC,
ASM_THUMB_CC_HI,
ASM_THUMB_CC_EQ,
ASM_THUMB_CC_LS,
ASM_THUMB_CC_CS,
ASM_THUMB_CC_NE,
// signed
ASM_THUMB_CC_LT,
ASM_THUMB_CC_GT,
ASM_THUMB_CC_EQ,
ASM_THUMB_CC_LE,
ASM_THUMB_CC_GE,
ASM_THUMB_CC_NE,
};
asm_thumb_bcc_rel9(emit->as, ops[op_idx], 6);
asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);
asm_thumb_b_rel12(emit->as, 4);
asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);
#endif
#elif N_ARM #elif N_ARM
asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs); asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
static uint ccs[6 + 6] = { static uint ccs[6 + 6] = {

View File

@ -313,11 +313,7 @@ STATIC void gc_sweep(void) {
} }
#endif #endif
free_tail = 1; free_tail = 1;
ATB_ANY_TO_FREE(block); DEBUG_printf("gc_sweep(%p)\n", (void *)PTR_FROM_BLOCK(block));
#if CLEAR_ON_SWEEP
memset((void *)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);
#endif
DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block));
#ifdef LOG_HEAP_ACTIVITY #ifdef LOG_HEAP_ACTIVITY
gc_log_change(block, 0); gc_log_change(block, 0);
@ -325,7 +321,8 @@ STATIC void gc_sweep(void) {
#if MICROPY_PY_GC_COLLECT_RETVAL #if MICROPY_PY_GC_COLLECT_RETVAL
MP_STATE_MEM(gc_collected)++; MP_STATE_MEM(gc_collected)++;
#endif #endif
break; // fall through to free the head
MP_FALLTHROUGH
case AT_TAIL: case AT_TAIL:
if (free_tail) { if (free_tail) {

View File

@ -460,7 +460,8 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring)
vstr_add_char(&lex->vstr, '\\'); vstr_add_char(&lex->vstr, '\\');
break; break;
} }
// Otherwise fall through. // Otherwise fall through.
MP_FALLTHROUGH
case 'x': { case 'x': {
mp_uint_t num = 0; mp_uint_t num = 0;
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) { if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {

View File

@ -7,10 +7,12 @@ This script works with Python 2.6, 2.7, 3.3 and 3.4.
from __future__ import print_function from __future__ import print_function
import re
import sys
import io import io
import os import os
import re
import subprocess
import sys
import multiprocessing, multiprocessing.dummy
# Python 2/3 compatibility: # Python 2/3 compatibility:
# - iterating through bytes is different # - iterating through bytes is different
@ -65,6 +67,47 @@ del name2codepoint["and"]
del name2codepoint["or"] del name2codepoint["or"]
def preprocess():
if any(src in args.dependencies for src in args.changed_sources):
sources = args.sources
elif any(args.changed_sources):
sources = args.changed_sources
else:
sources = args.sources
csources = []
cxxsources = []
for source in sources:
if source.endswith(".cpp"):
cxxsources.append(source)
else:
csources.append(source)
try:
os.makedirs(os.path.dirname(args.output[0]))
except OSError:
pass
def pp(flags):
def run(files):
return subprocess.check_output(args.pp + flags + files)
return run
try:
cpus = multiprocessing.cpu_count()
except NotImplementedError:
cpus = 1
p = multiprocessing.dummy.Pool(cpus)
with open(args.output[0], "wb") as out_file:
for flags, sources in (
(args.cflags, csources),
(args.cxxflags, cxxsources),
):
batch_size = (len(sources) + cpus - 1) // cpus
chunks = [sources[i : i + batch_size] for i in range(0, len(sources), batch_size or 1)]
for output in p.imap(pp(flags), chunks):
out_file.write(output)
def write_out(fname, output): def write_out(fname, output):
if output: if output:
for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]: for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
@ -96,10 +139,9 @@ def process_file(f):
if line.startswith(("# ", "#line")): if line.startswith(("# ", "#line")):
m = re_line.match(line) m = re_line.match(line)
assert m is not None assert m is not None
# print(m.groups())
lineno = int(m.group(1)) lineno = int(m.group(1))
fname = m.group(2) fname = m.group(2)
if not fname.endswith(".c"): if os.path.splitext(fname)[1] not in [".c", ".cpp"]:
continue continue
if fname != last_fname: if fname != last_fname:
write_out(last_fname, output) write_out(last_fname, output)
@ -114,7 +156,8 @@ def process_file(f):
output.append('TRANSLATE("' + match[0] + '")') output.append('TRANSLATE("' + match[0] + '")')
lineno += 1 lineno += 1
write_out(last_fname, output) if last_fname:
write_out(last_fname, output)
return "" return ""

View File

@ -23,7 +23,7 @@ def get_version_info_from_git():
# Note: git describe doesn't work if no tag is available # Note: git describe doesn't work if no tag is available
try: try:
git_tag = subprocess.check_output( git_tag = subprocess.check_output(
["git", "describe", "--dirty", "--always", "--tags"], ["git", "describe", "--dirty", "--always", "--tags", "--match", "[1-9].*"],
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
universal_newlines=True, universal_newlines=True,
).strip() ).strip()
@ -91,6 +91,12 @@ def make_version_header(filename):
else: else:
version_string = ".".join(ver) version_string = ".".join(ver)
build_date = datetime.date.today()
if "SOURCE_DATE_EPOCH" in os.environ:
build_date = datetime.datetime.utcfromtimestamp(
int(os.environ["SOURCE_DATE_EPOCH"])
).date()
# Generate the file with the git and version info # Generate the file with the git and version info
file_data = """\ file_data = """\
// This file was generated by py/makeversionhdr.py // This file was generated by py/makeversionhdr.py

View File

@ -42,17 +42,6 @@
#define DEBUG_printf(...) (void)0 #define DEBUG_printf(...) (void)0
#endif #endif
// Fixed empty map. Useful when need to call kw-receiving functions
// without any keywords from C, etc.
const mp_map_t mp_const_empty_map = {
.all_keys_are_qstrs = 0,
.is_fixed = 1,
.is_ordered = 1,
.used = 0,
.alloc = 0,
.table = NULL,
};
// This table of sizes is used to control the growth of hash tables. // This table of sizes is used to control the growth of hash tables.
// The first set of sizes are chosen so the allocation fits exactly in a // The first set of sizes are chosen so the allocation fits exactly in a
// 4-word GC block, and it's not so important for these small values to be // 4-word GC block, and it's not so important for these small values to be

View File

@ -55,12 +55,8 @@ typedef unsigned int uint;
// Static assertion macro // Static assertion macro
#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
// Explicit fallthrough delcarations for case statements // Round-up integer division
#ifdef __GNUC__ #define MP_CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b))
#define FALLTHROUGH __attribute__((fallthrough))
#else
#define FALLTHROUGH ((void)0) /* FALLTHROUGH */
#endif
/** memory allocation ******************************************/ /** memory allocation ******************************************/

View File

@ -45,10 +45,26 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
$(RM) -f $(@:.o=.d) $(RM) -f $(@:.o=.d)
endef endef
define compile_cxx
$(ECHO) "CXX $<"
$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $<
@# The following fixes the dependency file.
@# See http://make.paulandlesley.org/autodep.html for details.
@# Regex adjusted from the above to play better with Windows paths, etc.
@$(CP) $(@:.o=.d) $(@:.o=.P); \
$(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
$(RM) -f $(@:.o=.d)
endef
vpath %.c . $(TOP) $(USER_C_MODULES) $(DEVICES_MODULES) vpath %.c . $(TOP) $(USER_C_MODULES) $(DEVICES_MODULES)
$(BUILD)/%.o: %.c $(BUILD)/%.o: %.c
$(call compile_c) $(call compile_c)
vpath %.cpp . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.o: %.cpp
$(call compile_cxx)
QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR
# frozen.c and frozen_mpy.c are created in $(BUILD), so use our rule # frozen.c and frozen_mpy.c are created in $(BUILD), so use our rule
@ -75,7 +91,7 @@ $(BUILD)/%.pp: %.c
# to get built before we try to compile any of them. # to get built before we try to compile any of them.
$(OBJ): | $(HEADER_BUILD)/qstrdefs.enum.h $(HEADER_BUILD)/mpversion.h $(OBJ): | $(HEADER_BUILD)/qstrdefs.enum.h $(HEADER_BUILD)/mpversion.h
# The logic for qstr regeneration is: # The logic for qstr regeneration (applied by makeqstrdefs.py) is:
# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^) # - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^)
# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?) # - else, if list of newer prerequisites ($?) is not empty, then process just these ($?)
# - else, process all source files ($^) [this covers "make -B" which can set $? to empty] # - else, process all source files ($^) [this covers "make -B" which can set $? to empty]
@ -172,7 +188,7 @@ LIBMICROPYTHON = libmicropython.a
# tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some # tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some
# other file to cause needed effect, e.g. relinking with new lib. # other file to cause needed effect, e.g. relinking with new lib.
lib $(LIBMICROPYTHON): $(OBJ) lib $(LIBMICROPYTHON): $(OBJ)
$(AR) rcs $(LIBMICROPYTHON) $^ $(Q)$(AR) rcs $(LIBMICROPYTHON) $^
$(LIBMICROPYTHON_EXTRA_CMD) $(LIBMICROPYTHON_EXTRA_CMD)
clean: clean:

View File

@ -100,7 +100,19 @@ mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
// sqrt(x): returns the square root of x // sqrt(x): returns the square root of x
MATH_FUN_1(sqrt, sqrt) MATH_FUN_1(sqrt, sqrt)
// pow(x, y): returns x to the power of y // pow(x, y): returns x to the power of y
#if MICROPY_PY_MATH_POW_FIX_NAN
mp_float_t pow_func(mp_float_t x, mp_float_t y) {
// pow(base, 0) returns 1 for any base, even when base is NaN
// pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN
if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) {
return MICROPY_FLOAT_CONST(1.0);
}
return MICROPY_FLOAT_C_FUN(pow)(x, y);
}
MATH_FUN_2(pow, pow_func)
#else
MATH_FUN_2(pow, pow) MATH_FUN_2(pow, pow)
#endif
// exp(x) // exp(x)
MATH_FUN_1(exp, exp) MATH_FUN_1(exp, exp)
#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
@ -194,17 +206,15 @@ MATH_FUN_1(lgamma, lgamma)
#if MICROPY_PY_MATH_ISCLOSE #if MICROPY_PY_MATH_ISCLOSE
STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol }; enum { ARG_rel_tol, ARG_abs_tol };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ},
{MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ},
{MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
{MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}}, {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}},
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mp_float_t a = mp_obj_get_float(args[ARG_a].u_obj); const mp_float_t a = mp_obj_get_float(pos_args[0]);
const mp_float_t b = mp_obj_get_float(args[ARG_b].u_obj); const mp_float_t b = mp_obj_get_float(pos_args[1]);
const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL
? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj); ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj);
const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj); const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj);

View File

@ -285,6 +285,11 @@
#define MICROPY_PERSISTENT_CODE_SAVE (0) #define MICROPY_PERSISTENT_CODE_SAVE (0)
#endif #endif
// Whether to support saving persistent code to a file via mp_raw_code_save_file
#ifndef MICROPY_PERSISTENT_CODE_SAVE_FILE
#define MICROPY_PERSISTENT_CODE_SAVE_FILE (0)
#endif
// Whether generated code can persist independently of the VM/runtime instance // Whether generated code can persist independently of the VM/runtime instance
// This is enabled automatically when needed by other features // This is enabled automatically when needed by other features
#ifndef MICROPY_PERSISTENT_CODE #ifndef MICROPY_PERSISTENT_CODE
@ -306,6 +311,11 @@
#define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_THUMB (0)
#endif #endif
// Whether to emit ARMv7-M instruction support in thumb native code
#ifndef MICROPY_EMIT_THUMB_ARMV7M
#define MICROPY_EMIT_THUMB_ARMV7M (1)
#endif
// Whether to enable the thumb inline assembler // Whether to enable the thumb inline assembler
#ifndef MICROPY_EMIT_INLINE_THUMB #ifndef MICROPY_EMIT_INLINE_THUMB
#define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0)
@ -461,6 +471,11 @@
#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0) #define MICROPY_DEBUG_MP_OBJ_SENTINELS (0)
#endif #endif
// Whether to print parse rule names (rather than integers) in mp_parse_node_print
#ifndef MICROPY_DEBUG_PARSE_RULE_NAME
#define MICROPY_DEBUG_PARSE_RULE_NAME (0)
#endif
// Whether to enable a simple VM stack overflow check // Whether to enable a simple VM stack overflow check
#ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW #ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW
#define MICROPY_DEBUG_VM_STACK_OVERFLOW (0) #define MICROPY_DEBUG_VM_STACK_OVERFLOW (0)
@ -1196,6 +1211,11 @@ typedef double mp_float_t;
#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0) #define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0)
#endif #endif
// Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN.
#ifndef MICROPY_PY_MATH_POW_FIX_NAN
#define MICROPY_PY_MATH_POW_FIX_NAN (0)
#endif
// Whether to provide "cmath" module // Whether to provide "cmath" module
#ifndef MICROPY_PY_CMATH #ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0) #define MICROPY_PY_CMATH (0)
@ -1649,6 +1669,13 @@ typedef double mp_float_t;
#endif #endif
#endif #endif
// Explicitly annotate switch case fall throughs
#if defined(__GNUC__) && __GNUC__ >= 7
#define MP_FALLTHROUGH __attribute__((fallthrough));
#else
#define MP_FALLTHROUGH
#endif
#ifndef MP_HTOBE16 #ifndef MP_HTOBE16
#if MP_ENDIANNESS_LITTLE #if MP_ENDIANNESS_LITTLE
#define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))) #define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)))

View File

@ -76,7 +76,7 @@ mp_uint_t mp_hal_ticks_cpu(void);
#endif #endif
#ifndef mp_hal_time_ns #ifndef mp_hal_time_ns
// Nanoseconds since 1970/1/1. // Nanoseconds since the Epoch.
uint64_t mp_hal_time_ns(void); uint64_t mp_hal_time_ns(void);
#endif #endif

View File

@ -484,10 +484,10 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
qstr qst = va_arg(args, qstr); qstr qst = va_arg(args, qstr);
size_t len; size_t len;
const char *str = (const char *)qstr_data(qst, &len); const char *str = (const char *)qstr_data(qst, &len);
if (prec < 0) { if (prec >= 0 && (size_t)prec < len) {
prec = len; len = prec;
} }
chrs += mp_print_strn(print, str, prec, flags, fill, width); chrs += mp_print_strn(print, str, len, flags, fill, width);
break; break;
} }
case 's': { case 's': {
@ -499,10 +499,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
break; break;
} }
#endif #endif
if (prec < 0) { size_t len = strlen(str);
prec = strlen(str); if (prec >= 0 && (size_t)prec < len) {
len = prec;
} }
chrs += mp_print_strn(print, str, prec, flags, fill, width); chrs += mp_print_strn(print, str, len, flags, fill, width);
break; break;
} }
case 'd': { case 'd': {
@ -557,11 +558,9 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
case 'l': { case 'l': {
unsigned long long int arg_value = va_arg(args, unsigned long long int); unsigned long long int arg_value = va_arg(args, unsigned long long int);
++fmt; ++fmt;
if (*fmt == 'u' || *fmt == 'd') { assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
break; break;
}
assert(!"unsupported fmt char");
} }
#endif #endif
default: default:

View File

@ -1613,7 +1613,6 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
return true; return true;
} }
// writes at most len bytes to buf (so buf should be zeroed before calling)
void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) {
byte *b = buf; byte *b = buf;
if (big_endian) { if (big_endian) {
@ -1645,6 +1644,15 @@ void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) {
} }
} }
} }
// fill remainder of buf with zero/sign extension of the integer
if (big_endian) {
len = b - buf;
} else {
len = buf + len - b;
buf = b;
}
memset(buf, z->neg ? 0xff : 0x00, len);
} }
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT

View File

@ -457,8 +457,6 @@ typedef enum _mp_map_lookup_kind_t {
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup
} mp_map_lookup_kind_t; } mp_map_lookup_kind_t;
extern const mp_map_t mp_const_empty_map;
static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) {
assert(pos < map->alloc); assert(pos < map->alloc);
return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL; return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL;
@ -732,17 +730,22 @@ extern const struct _mp_obj_bool_t mp_const_false_obj;
extern const struct _mp_obj_bool_t mp_const_true_obj; extern const struct _mp_obj_bool_t mp_const_true_obj;
#endif #endif
// Constant objects, globally accessible: b'', (), Ellipsis, NotImplemented, GeneratorExit() // Constant objects, globally accessible: b'', (), {}, Ellipsis, NotImplemented, GeneratorExit()
// The below macros are for convenience only. // The below macros are for convenience only.
#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj)) #define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj)) #define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj)) #define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
extern const struct _mp_obj_str_t mp_const_empty_bytes_obj; extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
extern const struct _mp_obj_dict_t mp_const_empty_dict_obj;
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj; extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj; extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
// Fixed empty map. Useful when calling keyword-receiving functions
// without any keywords from C, etc.
#define mp_const_empty_map (mp_const_empty_dict_obj.map)
// General API for objects // General API for objects
// These macros are derived from more primitive ones and are used to // These macros are derived from more primitive ones and are used to

View File

@ -49,4 +49,14 @@ typedef struct _mp_obj_array_t {
void *items; void *items;
} mp_obj_array_t; } mp_obj_array_t;
#if MICROPY_PY_BUILTINS_MEMORYVIEW
static inline void mp_obj_memoryview_init(mp_obj_array_t *self, size_t typecode, size_t offset, size_t len, void *items) {
self->base.type = &mp_type_memoryview;
self->typecode = typecode;
self->free = offset;
self->len = len;
self->items = items;
}
#endif
#endif // MICROPY_INCLUDED_PY_OBJARRAY_H #endif // MICROPY_INCLUDED_PY_OBJARRAY_H

View File

@ -36,6 +36,18 @@
#include "supervisor/linker.h" #include "supervisor/linker.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
const mp_obj_dict_t mp_const_empty_dict_obj = {
.base = { .type = &mp_type_dict },
.map = {
.all_keys_are_qstrs = 0,
.is_fixed = 1,
.is_ordered = 1,
.used = 0,
.alloc = 0,
.table = NULL,
}
};
STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
// This is a helper function to iterate through a dictionary. The state of // This is a helper function to iterate through a dictionary. The state of

View File

@ -171,7 +171,7 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, con
// reserved room (after the traceback data) for a tuple with 1 element. // reserved room (after the traceback data) for a tuple with 1 element.
// Otherwise we are free to use the whole buffer after the traceback data. // Otherwise we are free to use the whole buffer after the traceback data.
if (o_tuple == NULL && mp_emergency_exception_buf_size >= if (o_tuple == NULL && mp_emergency_exception_buf_size >=
EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args)) { (mp_int_t)(EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args))) {
o_tuple = (mp_obj_tuple_t *) o_tuple = (mp_obj_tuple_t *)
((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET); ((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET);
} }
@ -430,7 +430,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com
// that buffer to store the string object and its data (at least 16 bytes for // that buffer to store the string object and its data (at least 16 bytes for
// the string data), reserving room at the start for the traceback and 1-tuple. // the string data), reserving room at the start for the traceback and 1-tuple.
if ((o_str == NULL || o_str_buf == NULL) if ((o_str == NULL || o_str_buf == NULL)
&& mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16) { && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16)) {
used_emg_buf = true; used_emg_buf = true;
o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
+ EMG_BUF_STR_OFFSET); + EMG_BUF_STR_OFFSET);
@ -563,7 +563,7 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN); self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
if (self->traceback_data == NULL) { if (self->traceback_data == NULL) {
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
if (mp_emergency_exception_buf_size >= EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE) { if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) {
// There is room in the emergency buffer for traceback data // There is room in the emergency buffer for traceback data
size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
+ EMG_BUF_TRACEBACK_OFFSET); + EMG_BUF_TRACEBACK_OFFSET);

View File

@ -298,13 +298,19 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) { if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {
goto zero_division_error; goto zero_division_error;
} }
if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) { if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val) && !isnan(rhs_val)) {
#if MICROPY_PY_BUILTINS_COMPLEX #if MICROPY_PY_BUILTINS_COMPLEX
return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in); return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported")); mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
#endif #endif
} }
#if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.
if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {
lhs_val = MICROPY_FLOAT_CONST(1.0);
break;
}
#endif
lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);
break; break;
case MP_BINARY_OP_DIVMOD: { case MP_BINARY_OP_DIVMOD: {

View File

@ -353,6 +353,10 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (attr == MP_QSTR___name__) { if (attr == MP_QSTR___name__) {
dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in)); dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in));
} }
if (attr == MP_QSTR___globals__) {
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
dest[0] = MP_OBJ_FROM_PTR(self->globals);
}
} }
#endif #endif

View File

@ -515,8 +515,8 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_
STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_length, ARG_byteorder, ARG_signed }; enum { ARG_length, ARG_byteorder, ARG_signed };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];

View File

@ -124,7 +124,6 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) {
assert(mp_obj_is_type(self_in, &mp_type_int)); assert(mp_obj_is_type(self_in, &mp_type_int));
mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
memset(buf, 0, len);
mpz_as_bytes(&self->mpz, big_endian, len, buf); mpz_as_bytes(&self->mpz, big_endian, len, buf);
} }

View File

@ -447,6 +447,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
} }
return MP_OBJ_NEW_SMALL_INT(hash); return MP_OBJ_NEW_SMALL_INT(hash);
} }
MP_FALLTHROUGH
#endif #endif
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:

View File

@ -132,10 +132,10 @@ STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
bool is_bytes = true; bool is_bytes = true;
#endif #endif
if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) { if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {
mp_printf(print, "%.*s", str_len, str_data); print->print_strn(print->data, (const char *)str_data, str_len);
} else { } else {
if (is_bytes) { if (is_bytes) {
mp_print_str(print, "b"); print->print_strn(print->data, "b", 1);
} }
mp_str_print_quoted(print, str_data, str_len, is_bytes); mp_str_print_quoted(print, str_data, str_len, is_bytes);
} }
@ -214,6 +214,10 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, cons
return mp_const_empty_bytes; return mp_const_empty_bytes;
} }
if (mp_obj_is_type(args[0], &mp_type_bytes)) {
return args[0];
}
if (mp_obj_is_str(args[0])) { if (mp_obj_is_str(args[0])) {
if (n_args < 2 || n_args > 3) { if (n_args < 2 || n_args > 3) {
goto wrong_args; goto wrong_args;

View File

@ -94,7 +94,7 @@ STATIC void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
} }
#endif #endif
if (kind == PRINT_STR) { if (kind == PRINT_STR) {
mp_printf(print, "%.*s", str_len, str_data); print->print_strn(print->data, (const char *)str_data, str_len);
} else { } else {
uni_print_quoted(print, str_data, str_len); uni_print_quoted(print, str_data, str_len);
} }

View File

@ -1060,13 +1060,16 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (attr == MP_QSTR___dict__) { if (attr == MP_QSTR___dict__) {
// Returns a read-only dict of the class attributes. // Returns a read-only dict of the class attributes.
// If the internal locals is not fixed, a copy will be created. // If the internal locals is not fixed, a copy will be created.
mp_obj_dict_t *dict = self->locals_dict; const mp_obj_dict_t *dict = self->locals_dict;
if (!dict) {
dict = &mp_const_empty_dict_obj;
}
if (dict->map.is_fixed) { if (dict->map.is_fixed) {
dest[0] = MP_OBJ_FROM_PTR(dict); dest[0] = MP_OBJ_FROM_PTR(dict);
} else { } else {
dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict)); dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict));
dict = MP_OBJ_TO_PTR(dest[0]); mp_obj_dict_t *dict_copy = MP_OBJ_TO_PTR(dest[0]);
dict->map.is_fixed = 1; dict_copy->map.is_fixed = 1;
} }
return; return;
} }

View File

@ -57,9 +57,6 @@
#define RULE_ARG_RULE (0x2000) #define RULE_ARG_RULE (0x2000)
#define RULE_ARG_OPT_RULE (0x3000) #define RULE_ARG_OPT_RULE (0x3000)
// (un)comment to use rule names; for debugging
// #define USE_RULE_NAME (1)
// *FORMAT-OFF* // *FORMAT-OFF*
enum { enum {
@ -194,7 +191,7 @@ static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 =
#undef DEF_RULE_NC #undef DEF_RULE_NC
0; 0;
#if defined(USE_RULE_NAME) && USE_RULE_NAME #if MICROPY_DEBUG_PARSE_RULE_NAME
// Define an array of rule names corresponding to each rule // Define an array of rule names corresponding to each rule
STATIC const char *const rule_name_table[] = { STATIC const char *const rule_name_table[] = {
#define DEF_RULE(rule, comp, kind, ...) #rule, #define DEF_RULE(rule, comp, kind, ...) #rule,
@ -374,35 +371,35 @@ size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_
} }
#if MICROPY_DEBUG_PRINTERS #if MICROPY_DEBUG_PRINTERS
void mp_parse_node_print(mp_parse_node_t pn, size_t indent) { void mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t indent) {
if (MP_PARSE_NODE_IS_STRUCT(pn)) { if (MP_PARSE_NODE_IS_STRUCT(pn)) {
printf("[% 4d] ", (int)((mp_parse_node_struct_t *)pn)->source_line); mp_printf(print, "[% 4d] ", (int)((mp_parse_node_struct_t *)pn)->source_line);
} else { } else {
printf(" "); mp_printf(print, " ");
} }
for (size_t i = 0; i < indent; i++) { for (size_t i = 0; i < indent; i++) {
printf(" "); mp_printf(print, " ");
} }
if (MP_PARSE_NODE_IS_NULL(pn)) { if (MP_PARSE_NODE_IS_NULL(pn)) {
printf("NULL\n"); mp_printf(print, "NULL\n");
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn); mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
printf("int(" INT_FMT ")\n", arg); mp_printf(print, "int(" INT_FMT ")\n", arg);
} else if (MP_PARSE_NODE_IS_LEAF(pn)) { } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) { switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: case MP_PARSE_NODE_ID:
printf("id(%s)\n", qstr_str(arg)); mp_printf(print, "id(%s)\n", qstr_str(arg));
break; break;
case MP_PARSE_NODE_STRING: case MP_PARSE_NODE_STRING:
printf("str(%s)\n", qstr_str(arg)); mp_printf(print, "str(%s)\n", qstr_str(arg));
break; break;
case MP_PARSE_NODE_BYTES: case MP_PARSE_NODE_BYTES:
printf("bytes(%s)\n", qstr_str(arg)); mp_printf(print, "bytes(%s)\n", qstr_str(arg));
break; break;
default: default:
assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN); assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN);
printf("tok(%u)\n", (uint)arg); mp_printf(print, "tok(%u)\n", (uint)arg);
break; break;
} }
} else { } else {
@ -410,19 +407,19 @@ void mp_parse_node_print(mp_parse_node_t pn, size_t indent) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) { if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) {
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
printf("literal const(%016llx)\n", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32)); mp_printf(print, "literal const(%016llx)\n", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32));
#else #else
printf("literal const(%p)\n", (mp_obj_t)pns->nodes[0]); mp_printf(print, "literal const(%p)\n", (mp_obj_t)pns->nodes[0]);
#endif #endif
} else { } else {
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
#if defined(USE_RULE_NAME) && USE_RULE_NAME #if MICROPY_DEBUG_PARSE_RULE_NAME
printf("%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); mp_printf(print, "%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
#else #else
printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); mp_printf(print, "rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
#endif #endif
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
mp_parse_node_print(pns->nodes[i], indent + 2); mp_parse_node_print(print, pns->nodes[i], indent + 2);
} }
} }
} }
@ -430,10 +427,10 @@ void mp_parse_node_print(mp_parse_node_t pn, size_t indent) {
#endif // MICROPY_DEBUG_PRINTERS #endif // MICROPY_DEBUG_PRINTERS
/* /*
STATIC void result_stack_show(parser_t *parser) { STATIC void result_stack_show(const mp_print_t *print, parser_t *parser) {
printf("result stack, most recent first\n"); mp_printf(print, "result stack, most recent first\n");
for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) { for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) {
mp_parse_node_print(parser->result_stack[i], 0); mp_parse_node_print(print, parser->result_stack[i], 0);
} }
} }
*/ */

View File

@ -86,7 +86,7 @@ bool mp_parse_node_is_const_false(mp_parse_node_t pn);
bool mp_parse_node_is_const_true(mp_parse_node_t pn); bool mp_parse_node_is_const_true(mp_parse_node_t pn);
bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o); bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o);
size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes); size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes);
void mp_parse_node_print(mp_parse_node_t pn, size_t indent); void mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t indent);
typedef enum { typedef enum {
MP_PARSE_SINGLE_INPUT, MP_PARSE_SINGLE_INPUT,

View File

@ -853,10 +853,7 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) {
save_raw_code(print, rc, &qw); save_raw_code(print, rc, &qw);
} }
// here we define mp_raw_code_save_file depending on the port #if MICROPY_PERSISTENT_CODE_SAVE_FILE
// TODO abstract this away properly
#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || defined(__unix__)
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -881,8 +878,6 @@ void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) {
MP_THREAD_GIL_ENTER(); MP_THREAD_GIL_ENTER();
} }
#else #endif // MICROPY_PERSISTENT_CODE_SAVE_FILE
#error mp_raw_code_save_file not implemented for this platform
#endif
#endif // MICROPY_PERSISTENT_CODE_SAVE #endif // MICROPY_PERSISTENT_CODE_SAVE

View File

@ -35,7 +35,9 @@ ifneq ($(USER_C_MODULES),)
# pre-define USERMOD variables as expanded so that variables are immediate # pre-define USERMOD variables as expanded so that variables are immediate
# expanded as they're added to them # expanded as they're added to them
SRC_USERMOD := SRC_USERMOD :=
SRC_USERMOD_CXX :=
CFLAGS_USERMOD := CFLAGS_USERMOD :=
CXXFLAGS_USERMOD :=
LDFLAGS_USERMOD := LDFLAGS_USERMOD :=
$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ $(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \
$(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\ $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\
@ -44,7 +46,9 @@ $(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \
) )
SRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD)) SRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD))
SRC_MOD_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_CXX))
CFLAGS_MOD += $(CFLAGS_USERMOD) CFLAGS_MOD += $(CFLAGS_USERMOD)
CXXFLAGS_MOD += $(CXXFLAGS_USERMOD)
LDFLAGS_MOD += $(LDFLAGS_USERMOD) LDFLAGS_MOD += $(LDFLAGS_USERMOD)
endif endif

View File

@ -32,7 +32,7 @@
// See qstrdefs.h for a list of qstr's that are available as constants. // See qstrdefs.h for a list of qstr's that are available as constants.
// Reference them as MP_QSTR_xxxx. // Reference them as MP_QSTR_xxxx.
// //
// Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx") // Note: it would be possible to define MP_QSTR_xxx as qstr_from_str("xxx")
// for qstrs that are referenced this way, but you don't want to have them in ROM. // for qstrs that are referenced this way, but you don't want to have them in ROM.
// first entry in enum will be MP_QSTRnull=0, which indicates invalid/no qstr // first entry in enum will be MP_QSTRnull=0, which indicates invalid/no qstr
@ -73,7 +73,6 @@ typedef struct _qstr_pool_t {
const char *qstrs[]; const char *qstrs[];
} qstr_pool_t; } qstr_pool_t;
#define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s)))
#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len) #define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len)
void qstr_init(void); void qstr_init(void);

Some files were not shown because too many files have changed in this diff Show More