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)
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
of this software and associated documentation files (the "Software"), to deal

View File

@ -14,13 +14,11 @@ Functions
.. 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
:class: attention
If additional argument, *sep* is supplied, it is used as a separator
between hexadecimal values.
If the additional argument *sep* is supplied it is used as a separator
between hexadecimal values.
.. function:: unhexlify(data)

View File

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

View File

@ -1,5 +1,5 @@
:mod:`sys` -- system specific functions
=======================================
========================================
.. 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
CFLAGS_MOD += -DMICROPY_VFS_LFS2=0
$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-missing-field-initializers
endif
################################################################################

View File

@ -26,9 +26,9 @@ typedef struct _mp_obj_framebuf_t {
STATIC const mp_obj_type_t mp_type_framebuf;
#endif
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t);
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int);
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, 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 *, unsigned int, unsigned int);
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 {
setpixel_t setpixel;
@ -47,25 +47,25 @@ typedef struct _mp_framebuf_p_t {
// 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;
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);
}
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;
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;
}
STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
int reverse = fb->format == FRAMEBUF_MHMSB;
int advance = fb->stride >> 3;
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) {
unsigned int reverse = fb->format == FRAMEBUF_MHMSB;
unsigned int advance = fb->stride >> 3;
while (w--) {
uint8_t *b = &((uint8_t *)fb->buf)[(x >> 3) + y * advance];
int offset = reverse ? x & 7 : 7 - (x & 7);
for (int hh = h; hh; --hh) {
unsigned int offset = reverse ? x & 7 : 7 - (x & 7);
for (unsigned int hh = h; hh; --hh) {
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
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
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;
uint8_t offset = y & 0x07;
((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;
}
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--) {
uint8_t *b = &((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x];
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;
}
@ -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
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;
}
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];
}
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];
while (h--) {
for (int ww = w; ww; --ww) {
for (unsigned int ww = w; ww; --ww) {
*b++ = col;
}
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
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 shift = (x & 0x3) << 1;
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));
}
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 shift = (x & 0x3) << 1;
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) {
for (int xx = x; xx < x + w; xx++) {
for (int yy = y; yy < y + h; yy++) {
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 (unsigned int xx = x; xx < x + w; xx++) {
for (unsigned int yy = y; yy < y + h; yy++) {
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
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];
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) {
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;
}
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;
uint8_t *pixel_pair = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1];
uint8_t col_shifted_left = col << 4;
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);
while (h--) {
int ww = w;
unsigned int ww = w;
if (odd_x && ww > 0) {
*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
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)];
*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)];
}
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)];
while (h--) {
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},
};
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);
}
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);
}

View File

@ -23,10 +23,10 @@
#define TIMING_WRITE3 (10)
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);
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);
int status = !mp_hal_pin_read(pin);
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) {
mp_hal_pin_write(pin, 1);
mp_hal_pin_od_high(pin);
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_pin_write(pin, 1);
mp_hal_pin_od_high(pin);
mp_hal_delay_us_fast(TIMING_READ2);
int value = mp_hal_pin_read(pin);
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) {
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);
if (value) {
mp_hal_pin_write(pin, 1);
mp_hal_pin_od_high(pin);
}
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_quiet_timing_exit(i);
}

View File

@ -146,6 +146,9 @@ STATIC const mp_obj_type_t task_queue_type = {
/******************************************************************************/
// 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.
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);
}
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) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
// Check if task is already finished.
if (self->coro == mp_const_none) {
if (TASK_IS_DONE(self)) {
return mp_const_false;
}
// 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_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) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
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) {
dest[0] = self->data;
} 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;
}
} 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) {
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
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) {
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;
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
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;
}
STATIC mp_obj_t task_iternext(mp_obj_t 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.
nlr_raise(self->data);
} 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) {
// Second argument is for an extension to allow a separator to be used
// between values.
// First argument is the data to convert.
// Second argument is an optional separator to be used between values.
const char *sep = NULL;
mp_buffer_info_t bufinfo;
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;
} else {
// 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;
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);
}
// Fall thru to return uctypes struct object
MP_FALLTHROUGH
}
case PTR: {
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);
}
}
/* fallthru */
MP_FALLTHROUGH
default:
return MP_OBJ_NULL; // op not supported

View File

@ -10,15 +10,29 @@
#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
// by Ilya Levin
// http://www.literatecode.com/yasmarang
// Public Domain
#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 uint8_t yasmarang_dat = 0;
#endif
#endif
STATIC uint32_t yasmarang(void) {
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_obj_t mod_urandom_seed(mp_obj_t seed_in) {
mp_uint_t seed = mp_obj_get_int_truncated(seed_in);
STATIC mp_obj_t mod_urandom_seed(size_t n_args, const mp_obj_t *args) {
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_n = 69;
yasmarang_d = 233;
yasmarang_dat = 0;
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
@ -168,9 +191,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
#if SEED_ON_IMPORT
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;
}
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
STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
{ 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) },
#endif
{ 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];
vstr_add_strn(&vstr_return, start_match, end_match - start_match);
}
} else if (*repl == '\\') {
// Add the \ character
vstr_add_byte(&vstr_return, *repl++);
}
} else {
// 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:
if(*sp != *pc++)
return 0;
/* FALLTHROUGH */
MP_FALLTHROUGH
case Any:
sp++;
continue;

View File

@ -185,8 +185,6 @@ def run_until_complete(main_task=None):
if isinstance(er, StopIteration):
return er.value
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
waiting = False
if hasattr(t, "waiting"):
@ -194,13 +192,15 @@ def run_until_complete(main_task=None):
_task_queue.push_head(t.waiting.pop_head())
waiting = True
t.waiting = None # Free waiting queue head
# Print out exception for detached tasks
if not waiting and not isinstance(er, excs_stop):
_exc_context["exception"] = er
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# Indicate task is done
t.coro = None
# An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw).
_task_queue.push_head(t)
# 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

View File

@ -9,24 +9,44 @@ async def wait_for(aw, timeout, sleep=core.sleep):
if timeout is None:
return await aw
def cancel(aw, timeout, sleep):
await sleep(timeout)
aw.cancel()
def runner(waiter, aw):
nonlocal status, result
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:
ret = await aw
except core.CancelledError:
# Ignore CancelledError from aw, it's probably due to timeout
pass
finally:
# Cancel the "cancel" task if it's still active (optimisation instead of cancel_task.cancel())
if cancel_task.coro is not None:
core._task_queue.remove(cancel_task)
if cancel_task.coro is None:
# Cancel task ran to completion, ie there was a timeout
raise core.TimeoutError
return ret
# Wait for the timeout to elapse.
await sleep(timeout)
except core.CancelledError as er:
if status is True:
# aw completed successfully and cancelled the sleep, so return aw's result.
return result
elif status is None:
# This wait_for was cancelled externally, so cancel aw and re-raise.
status = True
runner_task.cancel()
raise er
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):

View File

@ -130,13 +130,16 @@ class Task:
self.ph_rightmost_parent = None # Paring heap
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.
self.waiting = TaskQueue()
return self
def __next__(self):
if not self.coro:
if self.coro is self:
# Task finished, raise return value to caller so it can continue.
raise self.data
else:
@ -145,9 +148,12 @@ class Task:
# Set calling task's data to this task that it waits on, to double-link it.
core.cur_task.data = self
def done(self):
return self.coro is self
def cancel(self):
# Check if task is already finished.
if self.coro is None:
if self.coro is self:
return False
# Can't cancel self (not supported yet).
if self is core.cur_task:
@ -166,3 +172,13 @@ class Task:
core._task_queue.push_head(self)
self.data = core.CancelledError
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);
// 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

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_2(mp_utime_ticks_diff_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

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 (is_abs) {
// path began with / and was not found
return MP_VFS_NONE;
}
// if we get here then there's nothing mounted on /, so the path doesn't exist
return MP_VFS_NONE;
}
// 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
nlr_buf_t nlr;
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_init(&blockdev, bdev_obj);
uint8_t buf[44];
mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf);
#if MICROPY_VFS_LFS1
if (memcmp(&buf[32], "littlefs", 8) == 0) {
// LFS1
vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL);
nlr_pop();
return vfs;
for (size_t block_num = 0; block_num <= 1; ++block_num) {
mp_vfs_blockdev_read_ext(&blockdev, block_num, 8, sizeof(buf), buf);
#if MICROPY_VFS_LFS1
if (memcmp(&buf[32], "littlefs", 8) == 0) {
// LFS1
mp_obj_t vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL);
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();
} else {
// 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);
#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) {

View File

@ -26,6 +26,7 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "lib/timeutils/timeutils.h"
#include "extmod/vfs.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 };
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_progsize, 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);
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).
for (size_t i = 0; i < 8; ++i) {
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) {
ns = ns << 8 | mtime_buf[i - 1];
}
mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns);
#if MICROPY_EPOCH_IS_1970
mtime += TIMEUTILS_SECONDS_1970_TO_2000;
#endif
// On-disk storage of timestamps uses 1970 as the Epoch, so convert to host's Epoch.
mtime = timeutils_seconds_since_epoch_from_nanoseconds_since_1970(ns);
}
#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_obj_t MP_VFS_LFSx(mount)(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
(void)self_in;
(void)readonly;
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
(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;
}
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
https://github.com/ARMmbed/littlefs
https://github.com/littlefs-project/littlefs
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
@ -13,7 +13,7 @@ version tags with the latest/desired ones, and set `$MPY_DIR`):
cp lfs1*.[ch] $MPY_DIR/lib/littlefs
git reset --hard HEAD
git checkout v2.1.3
git checkout v2.3.0
python2 ./scripts/prefix.py lfs2
cp lfs2*.[ch] $MPY_DIR/lib/littlefs
git reset --hard HEAD

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lfs2_util.h"
#ifdef __cplusplus
extern "C"
@ -21,7 +22,7 @@ extern "C"
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// 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_MINOR (0xffff & (LFS2_VERSION >> 0))
@ -123,20 +124,25 @@ enum lfs2_type {
enum lfs2_open_flags {
// open flags
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_RDWR = 3, // Open a file as read and write
LFS2_O_CREAT = 0x0100, // Create a file if it does not exist
LFS2_O_EXCL = 0x0200, // Fail if a file already exists
LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS2_O_APPEND = 0x0800, // Move to end of file on every write
#endif
// internally used flags
#ifndef LFS2_READONLY
LFS2_F_DIRTY = 0x010000, // File does not match storage
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_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_OPENED = 0x200000, // File has been opened
};
// File seek flags
@ -174,6 +180,16 @@ struct lfs2_config {
// are propogated to the user.
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
// multiple of this value.
lfs2_size_t read_size;
@ -399,6 +415,7 @@ typedef struct lfs2 {
/// Filesystem functions ///
#ifndef LFS2_READONLY
// Format a block device with 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.
int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config);
#endif
// Mounts a littlefs
//
@ -426,12 +444,15 @@ int lfs2_unmount(lfs2_t *lfs2);
/// General operations ///
#ifndef LFS2_READONLY
// Removes a file or directory
//
// If removing a directory, the directory must be empty.
// Returns a negative error code on failure.
int lfs2_remove(lfs2_t *lfs2, const char *path);
#endif
#ifndef LFS2_READONLY
// Rename or move a file or directory
//
// 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.
int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath);
#endif
// 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,
uint8_t type, void *buffer, lfs2_size_t size);
#ifndef LFS2_READONLY
// Set custom attributes
//
// 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.
int lfs2_setattr(lfs2_t *lfs2, const char *path,
uint8_t type, const void *buffer, lfs2_size_t size);
#endif
#ifndef LFS2_READONLY
// Removes a custom attribute
//
// If an attribute is not found, nothing happens.
//
// Returns a negative error code on failure.
int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type);
#endif
/// 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,
void *buffer, lfs2_size_t size);
#ifndef LFS2_READONLY
// Write data to file
//
// 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.
lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file,
const void *buffer, lfs2_size_t size);
#endif
// 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 off, int whence);
#ifndef LFS2_READONLY
// Truncates the size of the file to the specified size
//
// Returns a negative error code on failure.
int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size);
#endif
// 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 ///
#ifndef LFS2_READONLY
// Create a directory
//
// Returns a negative error code on failure.
int lfs2_mkdir(lfs2_t *lfs2, const char *path);
#endif
// Open a directory
//
@ -632,6 +664,7 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
// Returns a negative error code on failure.
int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
#ifndef LFS2_READONLY
#ifdef LFS2_MIGRATE
// 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.
int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg);
#endif
#endif
#ifdef __cplusplus

View File

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

View File

@ -4,7 +4,7 @@
* The MIT License (MIT)
*
* 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
* 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;
}
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
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_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday,
mp_int_t hours, mp_int_t minutes, mp_int_t seconds) {
// 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++;
}
}
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)
*
* 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
* 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
} 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);
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);
@ -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 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_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_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday,
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,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return timeutils_seconds_since_2000_to_nanoseconds_since_1970(
timeutils_seconds_since_2000(year, month, date, hour, minute, second));
// Select the Epoch used by the port.
#if MICROPY_EPOCH_IS_1970
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

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 *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->methods = (mp_irq_methods_t *)methods;
self->parent = parent;
self->handler = mp_const_none;
self->ishard = false;
return self;
}
void mp_irq_handler(mp_irq_obj_t *self) {

View File

@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H
#include "py/runtime.h"
/******************************************************************************
DEFINE CONSTANTS
******************************************************************************/
@ -41,20 +43,17 @@ enum {
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_uint_method_one_uint_para_t)(mp_obj_t self, mp_uint_t trigger);
typedef mp_uint_t (*mp_irq_int_method_one_para_t)(mp_obj_t self, mp_uint_t info_type);
typedef mp_uint_t (*mp_irq_trigger_fun_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);
enum {
MP_IRQ_INFO_FLAGS,
MP_IRQ_INFO_TRIGGERS,
MP_IRQ_INFO_CNT
};
typedef struct _mp_irq_methods_t {
mp_irq_init_t init;
mp_irq_uint_method_one_uint_para_t trigger;
mp_irq_int_method_one_para_t info;
mp_irq_trigger_fun_t trigger;
mp_irq_info_fun_t info;
} mp_irq_methods_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);
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);
#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_VSTR (16)
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
#define EXEC_FLAG_SOURCE_IS_READER (64)
// parses, compiles and executes the code in the lexer
// 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;
#endif
#ifdef MICROPY_BOARD_BEFORE_PYTHON_EXEC
MICROPY_BOARD_BEFORE_PYTHON_EXEC(input_kind, exec_flags);
#endif
// by default a SystemExit exception returns 0
pyexec_system_exit = 0;
nlr_buf_t nlr;
nlr.ret_val = NULL;
if (nlr_push(&nlr) == 0) {
mp_obj_t module_fun;
#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) {
const vstr_t *vstr = source;
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) {
lex = mp_lexer_new_from_file(source);
} else {
@ -130,6 +138,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
// uncaught exception
mp_hal_set_interrupt_char(-1); // disable interrupt
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
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
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);
}
#ifdef MICROPY_BOARD_AFTER_PYTHON_EXEC
MICROPY_BOARD_AFTER_PYTHON_EXEC(input_kind, exec_flags, nlr.ret_val, &ret);
#endif
return ret;
}
#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
typedef struct _repl_t {
@ -229,6 +340,13 @@ void pyexec_event_repl_init(void) {
STATIC int pyexec_raw_repl_process_char(int c) {
if (c == CHAR_CTRL_A) {
// 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");
goto reset;
} else if (c == CHAR_CTRL_B) {
@ -413,6 +531,15 @@ raw_repl_reset:
int c = mp_hal_stdin_rx_chr();
if (c == CHAR_CTRL_A) {
// 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;
} else if (c == CHAR_CTRL_B) {
// change to friendly REPL
@ -453,12 +580,6 @@ int pyexec_friendly_repl(void) {
vstr_t line;
vstr_init(&line, 32);
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
// in host mode, we enable the LCD for the repl
mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD")));
mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
#endif
friendly_repl_reset:
mp_hal_stdout_tx_str("\r\n");
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);

View File

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

View File

@ -9,6 +9,14 @@
#define MICROPY_PERSISTENT_CODE_LOAD (0)
#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_X86 (1)
#define MICROPY_EMIT_THUMB (1)

View File

@ -34,7 +34,7 @@ INC += -I$(BUILD)
# compiler settings
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)
# Debugging/Optimization
@ -42,10 +42,12 @@ ifdef DEBUG
COPT ?= -O0
else
COPT ?= -Os
COPT += -fdata-sections -ffunction-sections
COPT += -DNDEBUG
endif
# Remove unused sections.
COPT += -fdata-sections -ffunction-sections
# 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.
CFLAGS += -g
@ -168,7 +170,6 @@ SRC_C += \
modtime.c \
moduselect.c \
alloc.c \
coverage.c \
fatfs_port.c \
supervisor/stub/filesystem.c \
supervisor/stub/safe_mode.c \
@ -184,13 +185,17 @@ LIB_SRC_C += $(addprefix lib/,\
utils/gchelper_generic.c \
)
SRC_CXX += \
$(SRC_MOD_CXX)
OBJ = $(PY_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)/, $(EXTMOD_SRC_C:.c=.o))
# 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
# SRC_QSTR
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
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)
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86'
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, "%lx\n", 0x123); // long 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, "%b %b\n", 0, 1); // bools
#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
if (mp_verbose_flag >= 3) {
printf("----------------\n");
mp_parse_node_print(parse_tree.root, 0);
mp_parse_node_print(&mp_plat_print, parse_tree.root, 0);
printf("----------------\n");
}
#endif
@ -534,7 +534,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
#if defined(MICROPY_UNIX_COVERAGE)
{
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
@ -547,9 +549,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
// test_obj.attr = 42
//
// 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));
// mp_store_name(QSTR_FROM_STR_STATIC("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));
// 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("test_obj"), test_class_instance = mp_call_function_0(test_class_type));
// mp_store_attr(test_class_instance, qstr_from_str("attr"), mp_obj_new_int(42));
/*
printf("bytes:\n");

View File

@ -49,7 +49,7 @@
#if MICROPY_PY_MACHINE
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) {
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
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;
gettimeofday(&tv, NULL);
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_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;
if (n_args == 0) {
t = time(NULL);
} 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]);
t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val);
#else
t = mp_obj_get_int(args[0]);
#endif
}
struct tm *tm = localtime(&t);
struct tm *tm = time_func(&t);
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;
}
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_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_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_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_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/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/platform/embedded/btstack_run_loop_embedded.h"
@ -40,76 +40,15 @@
#include "extmod/btstack/modbluetooth_btstack.h"
#include "mpbtstackport.h"
#if !MICROPY_PY_THREAD
#error Unix btstack requires MICROPY_PY_THREAD
#endif
STATIC const useconds_t USB_POLL_INTERVAL_US = 1000;
STATIC const uint8_t read_static_address_command_complete_prefix[] = { 0x0e, 0x1b, 0x01, 0x09, 0xfc };
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();
}
void mp_bluetooth_btstack_port_init_usb(void) {
// MICROPYBTUSB can be a ':'' or '-' separated port list.
char *path = getenv("MICROPYBTUSB");
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_dump_open(NULL, HCI_DUMP_STDOUT);
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;
@ -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.
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) {
(void)arg;
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.
// 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) {
// 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();
btstack_run_loop_embedded_execute_once();
MICROPY_END_ATOMIC_SECTION(atomic_state);
while (true) {
if (!mp_bluetooth_hci_poll()) {
break;
}
// The USB transport schedules events to the run loop at 1ms intervals,
// and the implementation currently polls rather than selects.
usleep(USB_POLL_INTERVAL_US);
}
hci_close();
return NULL;
}
@ -179,13 +113,4 @@ void mp_bluetooth_btstack_port_start(void) {
pthread_create(&bstack_thread_id, &attr, &btstack_thread, NULL);
}
void mp_hal_get_mac(int idx, uint8_t buf[6]) {
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
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_USB

View File

@ -87,6 +87,7 @@
#define MICROPY_VFS_POSIX_FILE (1)
#define MICROPY_PY_FUNCTION_ATTRS (1)
#define MICROPY_PY_DESCRIPTORS (1)
#define MICROPY_PY_DELATTR_SETATTR (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
@ -347,11 +348,16 @@ void mp_unix_mark_exec(void);
#endif
#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()
#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>
#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
// 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) {
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) {
time_t now = time(NULL);
return (uint64_t)now * 1000000000ULL;
struct timeval tv;
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_PY_UOS_VFS (1)
#define MICROPY_DEBUG_PARSE_RULE_NAME (1)
#define MICROPY_OPT_MATH_FACTORIAL (1)
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1)
#define MICROPY_ENABLE_SCHEDULER (1)
@ -39,6 +40,7 @@
#define MICROPY_WARNINGS_CATEGORY (1)
#define MICROPY_MODULE_GETATTR (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_BUILTINS_MEMORYVIEW_ITEMSIZE (1)
#define MICROPY_PY_BUILTINS_NEXT2 (1)

View File

@ -7,13 +7,19 @@ CFLAGS += \
-fprofile-arcs -ftest-coverage \
-Wformat -Wmissing-declarations -Wmissing-prototypes \
-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
USER_C_MODULES = $(TOP)/examples/usercmodule
MICROPY_VFS_FAT = 1
MICROPY_VFS_LFS1 = 1
MICROPY_VFS_LFS2 = 1
FROZEN_DIR=variants/coverage/frzstr
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_LFS1 = 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++;
given_arg = pos[i];
} 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 (allowed[i].flags & MP_ARG_REQUIRED) {
#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"));
#endif
}
if (kws_found < kws->used) {
if (kws != NULL && kws_found < kws->used) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch();
#else

View File

@ -47,6 +47,7 @@
#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
#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
#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))
@ -55,6 +56,7 @@
#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base))
#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) {
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
// 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 (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_ARMV6)
#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));
if (stack_adjust > 0) {
#if MICROPY_EMIT_THUMB_ARMV7M
if (UNSIGNED_FIT7(stack_adjust)) {
asm_thumb_op16(as, OP_SUB_SP(stack_adjust));
} 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));
}
#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->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) {
if (as->stack_adjust > 0) {
#if MICROPY_EMIT_THUMB_ARMV7M
if (UNSIGNED_FIT7(as->stack_adjust)) {
asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust));
} 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));
}
#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));
}
@ -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);
}
#if MICROPY_EMIT_THUMB_ARMV7M
// 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) {
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;
}
#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))
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));
return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel);
} else {
#if MICROPY_EMIT_THUMB_ARMV7M
asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));
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);
#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_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;
}
@ -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) {
if (reg_dest < 8 && UNSIGNED_FIT8(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 {
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_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) {
assert(rlo_src < ASM_THUMB_REG_R8);
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));
}
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {
assert(rlo_dest < ASM_THUMB_REG_R8);
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));
}
@ -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) {
mp_uint_t dest = get_label_dest(as, label);
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
#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
#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
}
#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) {
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) {
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);
} else {
#if MICROPY_EMIT_THUMB_ARMV7M
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 {
// is a forwards jump, so need to assume it's large
large_jump:
#if MICROPY_EMIT_THUMB_ARMV7M
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 {
// is a forwards jump, so need to assume it's large
large_jump:
#if MICROPY_EMIT_THUMB_ARMV7M
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_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_ADD (0x3000)
#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))
@ -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) {
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
@ -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) {
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)
// 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) {
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
@ -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)
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);
#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
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_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_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
#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_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))
#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_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))

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_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_bytecode_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);
const byte *mp_bytecode_print_str(const byte *ip);
#define mp_bytecode_print_inst(code, const_table) mp_bytecode_print2(code, 1, 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 mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);
const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);
#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
#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_SPAN_START_END (CIRCUITPY_RE)
#define MICROPY_PY_URE_SUB (CIRCUITPY_RE)
#define MICROPY_EPOCH_IS_1970 (0)
// 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
#define mp_load_name(qst) (mp_fun_table.load_name(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_name(qst) (mp_fun_table.load_name((qst)))
#define mp_load_global(qst) (mp_fun_table.load_global((qst)))
#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_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) \
(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

View File

@ -92,7 +92,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
#endif
#if MICROPY_DEBUG_PRINTERS
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
}

View File

@ -108,7 +108,7 @@ STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint
return 0;
}
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"));
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;
}
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;
}
} 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) {
op_code = ASM_THUMB_FORMAT_3_SUB;
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;
mp_uint_t reg_dest;
op_movw_movt:
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);
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;
goto op_movw_movt;
} else if (ARMV7M && op == MP_QSTR_movwt) {
} else if (op == MP_QSTR_movwt) {
// this is a convenience instruction
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);
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);
} 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_parse_node_t 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;
asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8);
}
#endif
} else {
// search table for ldr/str instructions
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;
}
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"));
return 0;
}

View File

@ -239,6 +239,7 @@ struct _emit_t {
int pass;
bool do_viper_types;
bool prelude_offset_uses_u16_encoding;
mp_uint_t local_vtype_alloc;
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)); \
} 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) {
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);
// 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
// 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, 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_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
// TODO this encoding may change size in the final pass, need to make it fixed
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1);
if (emit->pass == MP_PASS_CODE_SIZE) {
// 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
// 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);
#elif N_THUMB
asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);
#if MICROPY_EMIT_THUMB_ARMV7M
static uint16_t ops[6 + 6] = {
// unsigned
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_mov_rlo_i8(emit->as, REG_RET, 1);
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
asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
static uint ccs[6 + 6] = {

View File

@ -313,11 +313,7 @@ STATIC void gc_sweep(void) {
}
#endif
free_tail = 1;
ATB_ANY_TO_FREE(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));
DEBUG_printf("gc_sweep(%p)\n", (void *)PTR_FROM_BLOCK(block));
#ifdef LOG_HEAP_ACTIVITY
gc_log_change(block, 0);
@ -325,7 +321,8 @@ STATIC void gc_sweep(void) {
#if MICROPY_PY_GC_COLLECT_RETVAL
MP_STATE_MEM(gc_collected)++;
#endif
break;
// fall through to free the head
MP_FALLTHROUGH
case AT_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, '\\');
break;
}
// Otherwise fall through.
// Otherwise fall through.
MP_FALLTHROUGH
case 'x': {
mp_uint_t num = 0;
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
import re
import sys
import io
import os
import re
import subprocess
import sys
import multiprocessing, multiprocessing.dummy
# Python 2/3 compatibility:
# - iterating through bytes is different
@ -65,6 +67,47 @@ del name2codepoint["and"]
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):
if output:
for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
@ -96,10 +139,9 @@ def process_file(f):
if line.startswith(("# ", "#line")):
m = re_line.match(line)
assert m is not None
# print(m.groups())
lineno = int(m.group(1))
fname = m.group(2)
if not fname.endswith(".c"):
if os.path.splitext(fname)[1] not in [".c", ".cpp"]:
continue
if fname != last_fname:
write_out(last_fname, output)
@ -114,7 +156,8 @@ def process_file(f):
output.append('TRANSLATE("' + match[0] + '")')
lineno += 1
write_out(last_fname, output)
if last_fname:
write_out(last_fname, output)
return ""

View File

@ -23,7 +23,7 @@ def get_version_info_from_git():
# Note: git describe doesn't work if no tag is available
try:
git_tag = subprocess.check_output(
["git", "describe", "--dirty", "--always", "--tags"],
["git", "describe", "--dirty", "--always", "--tags", "--match", "[1-9].*"],
stderr=subprocess.STDOUT,
universal_newlines=True,
).strip()
@ -91,6 +91,12 @@ def make_version_header(filename):
else:
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
file_data = """\
// This file was generated by py/makeversionhdr.py

View File

@ -42,17 +42,6 @@
#define DEBUG_printf(...) (void)0
#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.
// 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

View File

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

View File

@ -45,10 +45,26 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
$(RM) -f $(@:.o=.d)
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)
$(BUILD)/%.o: %.c
$(call compile_c)
vpath %.cpp . $(TOP) $(USER_C_MODULES)
$(BUILD)/%.o: %.cpp
$(call compile_cxx)
QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR
# 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.
$(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 ($^)
# - 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]
@ -172,7 +188,7 @@ LIBMICROPYTHON = libmicropython.a
# tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some
# other file to cause needed effect, e.g. relinking with new lib.
lib $(LIBMICROPYTHON): $(OBJ)
$(AR) rcs $(LIBMICROPYTHON) $^
$(Q)$(AR) rcs $(LIBMICROPYTHON) $^
$(LIBMICROPYTHON_EXTRA_CMD)
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
MATH_FUN_1(sqrt, sqrt)
// 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)
#endif
// exp(x)
MATH_FUN_1(exp, exp)
#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
@ -194,17 +206,15 @@ MATH_FUN_1(lgamma, lgamma)
#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) {
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[] = {
{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_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_parse_all(n_args, pos_args, 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 b = mp_obj_get_float(args[ARG_b].u_obj);
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(pos_args[0]);
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
? (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);

View File

@ -285,6 +285,11 @@
#define MICROPY_PERSISTENT_CODE_SAVE (0)
#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
// This is enabled automatically when needed by other features
#ifndef MICROPY_PERSISTENT_CODE
@ -306,6 +311,11 @@
#define MICROPY_EMIT_THUMB (0)
#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
#ifndef MICROPY_EMIT_INLINE_THUMB
#define MICROPY_EMIT_INLINE_THUMB (0)
@ -461,6 +471,11 @@
#define MICROPY_DEBUG_MP_OBJ_SENTINELS (0)
#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
#ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW
#define MICROPY_DEBUG_VM_STACK_OVERFLOW (0)
@ -1196,6 +1211,11 @@ typedef double mp_float_t;
#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0)
#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
#ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0)
@ -1649,6 +1669,13 @@ typedef double mp_float_t;
#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
#if MP_ENDIANNESS_LITTLE
#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
#ifndef mp_hal_time_ns
// Nanoseconds since 1970/1/1.
// Nanoseconds since the Epoch.
uint64_t mp_hal_time_ns(void);
#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);
size_t len;
const char *str = (const char *)qstr_data(qst, &len);
if (prec < 0) {
prec = len;
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;
}
case 's': {
@ -499,10 +499,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
break;
}
#endif
if (prec < 0) {
prec = strlen(str);
size_t len = 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;
}
case 'd': {
@ -557,11 +558,9 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
case 'l': {
unsigned long long int arg_value = va_arg(args, unsigned long long int);
++fmt;
if (*fmt == 'u' || *fmt == 'd') {
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
break;
}
assert(!"unsupported fmt char");
assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
break;
}
#endif
default:

View File

@ -1613,7 +1613,6 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
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) {
byte *b = buf;
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

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_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) {
assert(pos < map->alloc);
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;
#endif
// Constant objects, globally accessible: b'', (), Ellipsis, NotImplemented, GeneratorExit()
// Constant objects, globally accessible: b'', (), {}, Ellipsis, NotImplemented, GeneratorExit()
// 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_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_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_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_notimplemented_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
// 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;
} 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

View File

@ -36,6 +36,18 @@
#include "supervisor/linker.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);
// 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.
// Otherwise we are free to use the whole buffer after the traceback data.
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 *)
((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
// the string data), reserving room at the start for the traceback and 1-tuple.
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;
o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
+ 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);
if (self->traceback_data == NULL) {
#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
size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
+ 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)) {
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
return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);
#else
mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
#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);
break;
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__) {
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

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) {
enum { ARG_length, ARG_byteorder, ARG_signed };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ 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_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) {
assert(mp_obj_is_type(self_in, &mp_type_int));
mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
memset(buf, 0, len);
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);
}
MP_FALLTHROUGH
#endif
/* FALLTHROUGH */
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;
#endif
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 {
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);
}
@ -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;
}
if (mp_obj_is_type(args[0], &mp_type_bytes)) {
return args[0];
}
if (mp_obj_is_str(args[0])) {
if (n_args < 2 || n_args > 3) {
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
if (kind == PRINT_STR) {
mp_printf(print, "%.*s", str_len, str_data);
print->print_strn(print->data, (const char *)str_data, str_len);
} else {
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__) {
// Returns a read-only dict of the class attributes.
// 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) {
dest[0] = MP_OBJ_FROM_PTR(dict);
} else {
dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(dict));
dict = MP_OBJ_TO_PTR(dest[0]);
dict->map.is_fixed = 1;
mp_obj_dict_t *dict_copy = MP_OBJ_TO_PTR(dest[0]);
dict_copy->map.is_fixed = 1;
}
return;
}

View File

@ -57,9 +57,6 @@
#define RULE_ARG_RULE (0x2000)
#define RULE_ARG_OPT_RULE (0x3000)
// (un)comment to use rule names; for debugging
// #define USE_RULE_NAME (1)
// *FORMAT-OFF*
enum {
@ -194,7 +191,7 @@ static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 =
#undef DEF_RULE_NC
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
STATIC const char *const rule_name_table[] = {
#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
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)) {
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 {
printf(" ");
mp_printf(print, " ");
}
for (size_t i = 0; i < indent; i++) {
printf(" ");
mp_printf(print, " ");
}
if (MP_PARSE_NODE_IS_NULL(pn)) {
printf("NULL\n");
mp_printf(print, "NULL\n");
} else if (MP_PARSE_NODE_IS_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)) {
uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID:
printf("id(%s)\n", qstr_str(arg));
mp_printf(print, "id(%s)\n", qstr_str(arg));
break;
case MP_PARSE_NODE_STRING:
printf("str(%s)\n", qstr_str(arg));
mp_printf(print, "str(%s)\n", qstr_str(arg));
break;
case MP_PARSE_NODE_BYTES:
printf("bytes(%s)\n", qstr_str(arg));
mp_printf(print, "bytes(%s)\n", qstr_str(arg));
break;
default:
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;
}
} 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;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) {
#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
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
} else {
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
#if defined(USE_RULE_NAME) && USE_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);
#if MICROPY_DEBUG_PARSE_RULE_NAME
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
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
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
/*
STATIC void result_stack_show(parser_t *parser) {
printf("result stack, most recent first\n");
STATIC void result_stack_show(const mp_print_t *print, parser_t *parser) {
mp_printf(print, "result stack, most recent first\n");
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_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);
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 {
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);
}
// here we define mp_raw_code_save_file depending on the port
// TODO abstract this away properly
#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || defined(__unix__)
#if MICROPY_PERSISTENT_CODE_SAVE_FILE
#include <unistd.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();
}
#else
#error mp_raw_code_save_file not implemented for this platform
#endif
#endif // MICROPY_PERSISTENT_CODE_SAVE_FILE
#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
# expanded as they're added to them
SRC_USERMOD :=
SRC_USERMOD_CXX :=
CFLAGS_USERMOD :=
CXXFLAGS_USERMOD :=
LDFLAGS_USERMOD :=
$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \
$(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_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_CXX))
CFLAGS_MOD += $(CFLAGS_USERMOD)
CXXFLAGS_MOD += $(CXXFLAGS_USERMOD)
LDFLAGS_MOD += $(LDFLAGS_USERMOD)
endif

View File

@ -32,7 +32,7 @@
// See qstrdefs.h for a list of qstr's that are available as constants.
// 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.
// 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[];
} 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)
void qstr_init(void);

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