Merge remote-tracking branch 'origin/main' into main
This commit is contained in:
commit
70a325b077
2
LICENSE
2
LICENSE
@ -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
|
||||
|
@ -14,12 +14,10 @@ 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
|
||||
If the additional argument *sep* is supplied it is used as a separator
|
||||
between hexadecimal values.
|
||||
|
||||
.. function:: unhexlify(data)
|
||||
|
@ -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.
|
||||
|
@ -1,5 +1,5 @@
|
||||
:mod:`sys` -- system specific functions
|
||||
=======================================
|
||||
========================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
|
||||
|
34
examples/usercmodule/cexample/examplemodule.c
Normal file
34
examples/usercmodule/cexample/examplemodule.c
Normal 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);
|
9
examples/usercmodule/cexample/micropython.mk
Normal file
9
examples/usercmodule/cexample/micropython.mk
Normal 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)
|
17
examples/usercmodule/cppexample/example.cpp
Normal file
17
examples/usercmodule/cppexample/example.cpp
Normal 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);
|
||||
}
|
||||
}
|
25
examples/usercmodule/cppexample/examplemodule.c
Normal file
25
examples/usercmodule/cppexample/examplemodule.c
Normal 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);
|
5
examples/usercmodule/cppexample/examplemodule.h
Normal file
5
examples/usercmodule/cppexample/examplemodule.h
Normal 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);
|
12
examples/usercmodule/cppexample/micropython.mk
Normal file
12
examples/usercmodule/cppexample/micropython.mk
Normal 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++
|
@ -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
|
@ -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
@ -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
|
@ -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
|
||||
|
||||
################################################################################
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
@ -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) },
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
cancel_task = core.create_task(cancel(aw, timeout, sleep))
|
||||
def runner(waiter, aw):
|
||||
nonlocal status, result
|
||||
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
|
||||
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))
|
||||
|
||||
try:
|
||||
# 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
|
||||
return ret
|
||||
|
||||
|
||||
def wait_for_ms(aw, timeout):
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
20
extmod/vfs.c
20
extmod/vfs.c
@ -62,13 +62,9 @@ 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
|
||||
// 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
|
||||
*path_out = path;
|
||||
@ -144,15 +140,17 @@ 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);
|
||||
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
|
||||
vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL);
|
||||
mp_obj_t vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, &bdev_obj, NULL);
|
||||
nlr_pop();
|
||||
return vfs;
|
||||
}
|
||||
@ -160,11 +158,12 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
|
||||
#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);
|
||||
mp_obj_t 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) {
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
1172
lib/littlefs/lfs2.c
1172
lib/littlefs/lfs2.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
23
ports/unix/coveragecpp.cpp
Normal file
23
ports/unix/coveragecpp.cpp
Normal 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
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
285
ports/unix/mpbthciport.c
Normal 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))
|
44
ports/unix/mpbtstackport.h
Normal file
44
ports/unix/mpbtstackport.h
Normal 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
|
96
ports/unix/mpbtstackport_common.c
Normal file
96
ports/unix/mpbtstackport_common.c
Normal 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
|
80
ports/unix/mpbtstackport_h4.c
Normal file
80
ports/unix/mpbtstackport_h4.c
Normal 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
|
@ -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
|
@ -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();
|
||||
|
@ -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
74
ports/unix/mpnimbleport.c
Normal 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
33
ports/unix/mpnimbleport.h
Normal 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
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
185
py/asmthumb.c
185
py/asmthumb.c
@ -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)) {
|
||||
} else {
|
||||
#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))
|
||||
|
||||
|
@ -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))
|
||||
|
8
py/bc.h
8
py/bc.h
@ -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)))
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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_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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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] = {
|
||||
|
9
py/gc.c
9
py/gc.c
@ -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) {
|
||||
|
@ -461,6 +461,7 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring)
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through.
|
||||
MP_FALLTHROUGH
|
||||
case 'x': {
|
||||
mp_uint_t num = 0;
|
||||
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
|
||||
|
@ -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,6 +156,7 @@ def process_file(f):
|
||||
output.append('TRANSLATE("' + match[0] + '")')
|
||||
lineno += 1
|
||||
|
||||
if last_fname:
|
||||
write_out(last_fname, output)
|
||||
return ""
|
||||
|
||||
|
@ -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
|
||||
|
11
py/map.c
11
py/map.c
@ -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
|
||||
|
@ -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 ******************************************/
|
||||
|
||||
|
@ -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:
|
||||
|
22
py/modmath.c
22
py/modmath.c
@ -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);
|
||||
|
@ -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)))
|
||||
|
@ -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
|
||||
|
||||
|
17
py/mpprint.c
17
py/mpprint.c
@ -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,12 +558,10 @@ 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') {
|
||||
assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
|
||||
chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
|
||||
break;
|
||||
}
|
||||
assert(!"unsupported fmt char");
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
// if it's not %% then it's an unsupported format character
|
||||
|
10
py/mpz.c
10
py/mpz.c
@ -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
|
||||
|
9
py/obj.h
9
py/obj.h
@ -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
|
||||
|
@ -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
|
||||
|
12
py/objdict.c
12
py/objdict.c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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: {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)];
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
43
py/parse.c
43
py/parse.c
@ -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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
4
py/py.mk
4
py/py.mk
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user