Merge remote-tracking branch 'upstream/master' into nrf5_no_sdk
This commit is contained in:
commit
acce3a59d5
@ -155,6 +155,7 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chdir), (mp_obj_t)&mp_vfs_chdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getcwd), (mp_obj_t)&mp_vfs_getcwd_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ilistdir), (mp_obj_t)&mp_vfs_ilistdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listdir), (mp_obj_t)&mp_vfs_listdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&mp_vfs_mkdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename), (mp_obj_t)&mp_vfs_rename_obj},
|
||||
|
@ -1,6 +1,17 @@
|
||||
MicroPython libraries
|
||||
=====================
|
||||
|
||||
.. warning::
|
||||
|
||||
Important summary of this section
|
||||
|
||||
* MicroPython implements a subset of Python functionality for each module.
|
||||
* To ease extensibility, MicroPython versions of standard Python modules
|
||||
usually have ``u`` (micro) prefix.
|
||||
* Any particular MicroPython variant or port may miss any feature/function
|
||||
described in this general documentation, due to resource constraints.
|
||||
|
||||
|
||||
This chapter describes modules (function and class libraries) which are built
|
||||
into MicroPython. There are a few categories of modules:
|
||||
|
||||
|
@ -158,15 +158,6 @@ Methods
|
||||
and get the value of the pin. It is equivalent to Pin.value([x]).
|
||||
See :meth:`Pin.value` for more details.
|
||||
|
||||
.. method:: Pin.toggle()
|
||||
|
||||
Toggle the output value of the pin. Equivalent to ``pin.value(not pin.out_value())``.
|
||||
Returns ``None``.
|
||||
|
||||
Not all ports implement this method.
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
.. method:: Pin.id()
|
||||
|
||||
Get the pin identifier. This may return the ``id`` as specified in the
|
||||
|
96
docs/library/machine.Signal.rst
Normal file
96
docs/library/machine.Signal.rst
Normal file
@ -0,0 +1,96 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Signal:
|
||||
|
||||
class Signal -- control and sense external I/O devices
|
||||
======================================================
|
||||
|
||||
The Signal class is a simple extension of Pin class. Unlike Pin, which
|
||||
can be only in "absolute" 0 and 1 states, a Signal can be in "asserted"
|
||||
(on) or "deasserted" (off) states, while being inverted (active-low) or
|
||||
not. Summing up, it adds logical inversion support to Pin functionality.
|
||||
While this may seem a simple addition, it is exactly what is needed to
|
||||
support wide array of simple digital devices in a way portable across
|
||||
different boards, which is one of the major MicroPython goals. Regardless
|
||||
whether different users have an active-high or active-low LED, a normally
|
||||
open or normally closed relay - you can develop single, nicely looking
|
||||
application which works with each of them, and capture hardware
|
||||
configuration differences in few lines on the config file of your app.
|
||||
|
||||
Following is the guide when Signal vs Pin should be used:
|
||||
|
||||
* Use Signal: If you want to control a simple on/off (including software
|
||||
PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or
|
||||
read simple binary sensors, like normally open or normally closed buttons,
|
||||
pulled high or low, Reed switches, moisture/flame detectors, etc. etc.
|
||||
Summing up, if you have a real physical device/sensor requiring GPIO
|
||||
access, you likely should use a Signal.
|
||||
|
||||
* Use Pin: If you implement a higher-level protocol or bus to communicate
|
||||
with more complex devices.
|
||||
|
||||
The split between Pin and Signal come from the usecases above and the
|
||||
architecture of MicroPython: Pin offers the lowest overhead, which may
|
||||
be important when bit-banging protocols. But Signal adds additional
|
||||
flexibility on top of Pin, at the cost of minor overhead (much smaller
|
||||
than if you implemented active-high vs active-low device differences in
|
||||
Python manually!). Also, Pin is low-level object which needs to be
|
||||
implemented for each support board, while Signal is a high-level object
|
||||
which comes for free once Pin is implemented.
|
||||
|
||||
If in doubt, give the Signal a try! Once again, it is developed to save
|
||||
developers from the need to handle unexciting differences like active-low
|
||||
vs active-high signals, and allow other users to share and enjoy your
|
||||
application, instead of being frustrated by the fact that it doesn't
|
||||
work for them simply because their LEDs or relays are wired in a slightly
|
||||
different way.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: Signal(pin_obj, invert=False)
|
||||
Signal(pin_arguments..., \*, invert=False)
|
||||
|
||||
Create a Signal object. There're two ways to create it:
|
||||
|
||||
* By wrapping existing Pin object - universal method which works for
|
||||
any board.
|
||||
* By passing required Pin parameters directly to Signal constructor,
|
||||
skipping the need to create intermediate Pin object. Available on
|
||||
many, but not all boards.
|
||||
|
||||
The arguments are:
|
||||
|
||||
- ``pin_obj`` is existing Pin object.
|
||||
|
||||
- ``pin_arguments`` are the same arguments as can be passed to Pin constructor.
|
||||
|
||||
- ``invert`` - if True, the signal will be inverted (active low).
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Signal.value([x])
|
||||
|
||||
This method allows to set and get the value of the signal, depending on whether
|
||||
the argument ``x`` is supplied or not.
|
||||
|
||||
If the argument is omitted then this method gets the signal level, 1 meaning
|
||||
signal is asserted (active) and 0 - signal inactive.
|
||||
|
||||
If the argument is supplied then this method sets the signal level. The
|
||||
argument ``x`` can be anything that converts to a boolean. If it converts
|
||||
to ``True``, the signal is active, otherwise it is inactive.
|
||||
|
||||
Correspondence between signal being active and actual logic level on the
|
||||
underlying pin depends on whether signal is inverted (active-low) or not.
|
||||
For non-inverted signal, active status corresponds to logical 1, inactive -
|
||||
to logical 0. For inverted/active-low signal, active status corresponds
|
||||
to logical 0, while inactive - to logical 1.
|
||||
|
||||
.. method:: Signal.on()
|
||||
|
||||
Activate signal.
|
||||
|
||||
.. method:: Signal.off()
|
||||
|
||||
Deactivate signal.
|
@ -147,6 +147,7 @@ Classes
|
||||
|
||||
machine.I2C.rst
|
||||
machine.Pin.rst
|
||||
machine.Signal.rst
|
||||
machine.RTC.rst
|
||||
machine.SPI.rst
|
||||
machine.Timer.rst
|
||||
|
@ -37,6 +37,21 @@ Functions
|
||||
|
||||
Get the current directory.
|
||||
|
||||
.. function:: ilistdir([dir])
|
||||
|
||||
This function returns an iterator which then yields 3-tuples corresponding to
|
||||
the entries in the directory that it is listing. With no argument it lists the
|
||||
current directory, otherwise it lists the directory given by `dir`.
|
||||
|
||||
The 3-tuples have the form `(name, type, inode)`:
|
||||
|
||||
- `name` is a string (or bytes if `dir` is a bytes object) and is the name of
|
||||
the entry;
|
||||
- `type` is an integer that specifies the type of the entry, with 0x4000 for
|
||||
directories and 0x8000 for regular files;
|
||||
- `inode` is an integer corresponding to the inode of the file, and may be 0
|
||||
for filesystems that don't have such a notion.
|
||||
|
||||
.. function:: listdir([dir])
|
||||
|
||||
With no argument, list the current directory. Otherwise list the given directory.
|
||||
|
@ -5,7 +5,7 @@ MEMORY
|
||||
dport0_0_seg : org = 0x3ff00000, len = 0x10
|
||||
dram0_0_seg : org = 0x3ffe8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x8000
|
||||
irom0_0_seg : org = 0x40209000, len = 0x87000
|
||||
irom0_0_seg : org = 0x40209000, len = 0x8f000
|
||||
}
|
||||
|
||||
/* define common sections and symbols */
|
||||
|
@ -19,6 +19,8 @@ EXTERN(_KernelExceptionVector)
|
||||
EXTERN(_NMIExceptionVector)
|
||||
EXTERN(_UserExceptionVector)
|
||||
|
||||
_firmware_size = ORIGIN(irom0_0_seg) + LENGTH(irom0_0_seg) - 0x40200000;
|
||||
|
||||
PROVIDE(_memmap_vecbase_reset = 0x40000000);
|
||||
|
||||
/* Various memory-map dependent cache attribute settings: */
|
||||
|
@ -6,7 +6,7 @@ MEMORY
|
||||
dram0_0_seg : org = 0x3ffe8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x8000
|
||||
/* 0x3c000 is size of bootloader, 0x9000 is size of packed RAM segments */
|
||||
irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x87000
|
||||
irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000
|
||||
}
|
||||
|
||||
/* define common sections and symbols */
|
||||
|
@ -120,11 +120,13 @@ bool ets_loop_iter(void) {
|
||||
}
|
||||
|
||||
// handle overflow of system microsecond counter
|
||||
ets_intr_lock();
|
||||
uint32_t system_time_cur = system_get_time();
|
||||
if (system_time_cur < system_time_prev) {
|
||||
system_time_high_word += 1; // record overflow of low 32-bits
|
||||
}
|
||||
system_time_prev = system_time_cur;
|
||||
ets_intr_unlock();
|
||||
|
||||
//static unsigned cnt;
|
||||
bool progress = false;
|
||||
|
@ -159,12 +159,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
|
||||
// we assume there's a yaota8266 bootloader.
|
||||
#define IS_OTA_FIRMWARE() ((*(uint32_t*)0x40200000 & 0xff00) == 0x100)
|
||||
|
||||
extern byte _firmware_size[];
|
||||
|
||||
STATIC mp_obj_t esp_flash_user_start(void) {
|
||||
if (IS_OTA_FIRMWARE()) {
|
||||
return MP_OBJ_NEW_SMALL_INT(0x3c000 + 0x90000);
|
||||
} else {
|
||||
return MP_OBJ_NEW_SMALL_INT(0x90000);
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
|
||||
|
||||
|
@ -3,7 +3,7 @@ import esp
|
||||
class FlashBdev:
|
||||
|
||||
SEC_SIZE = 4096
|
||||
RESERVED_SECS = 0
|
||||
RESERVED_SECS = 1
|
||||
START_SEC = esp.flash_user_start() // SEC_SIZE + RESERVED_SECS
|
||||
NUM_BLK = 0x6b - RESERVED_SECS
|
||||
|
||||
|
@ -93,6 +93,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
#endif
|
||||
#if MICROPY_VFS_FAT
|
||||
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
|
||||
|
@ -2,4 +2,4 @@ from machine import Pin, Signal
|
||||
|
||||
# ESP12 module as used by many boards
|
||||
# Blue LED on pin 2, active low (inverted)
|
||||
LED = Signal(Pin(2, Pin.OUT), invert=True)
|
||||
LED = Signal(2, Pin.OUT, invert=True)
|
||||
|
@ -1,13 +1,13 @@
|
||||
from machine import Pin, Signal
|
||||
|
||||
# Red LED on pin LED_RED also kown as A13
|
||||
LED = Signal(Pin('LED_RED', Pin.OUT))
|
||||
LED = Signal('LED_RED', Pin.OUT)
|
||||
|
||||
# Green LED on pin LED_GREEN also known as A14
|
||||
LED2 = Signal(Pin('LED_GREEN', Pin.OUT))
|
||||
LED2 = Signal('LED_GREEN', Pin.OUT)
|
||||
|
||||
# Yellow LED on pin LED_YELLOW also known as A15
|
||||
LED3 = Signal(Pin('LED_YELLOW', Pin.OUT))
|
||||
LED3 = Signal('LED_YELLOW', Pin.OUT)
|
||||
|
||||
# Blue LED on pin LED_BLUE also known as B4
|
||||
LED4 = Signal(Pin('LED_BLUE', Pin.OUT))
|
||||
LED4 = Signal('LED_BLUE', Pin.OUT)
|
||||
|
@ -2,4 +2,4 @@ from machine import Pin, Signal
|
||||
|
||||
# Freescale/NXP FRDM-K64F board
|
||||
# Blue LED on port B, pin 21
|
||||
LED = Signal(Pin(("GPIO_1", 21), Pin.OUT))
|
||||
LED = Signal(("GPIO_1", 21), Pin.OUT)
|
||||
|
81
extmod/vfs.c
81
extmod/vfs.c
@ -286,7 +286,49 @@ mp_obj_t mp_vfs_getcwd(void) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj, mp_vfs_getcwd);
|
||||
|
||||
mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
|
||||
typedef struct _mp_vfs_ilistdir_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_fun_1_t iternext;
|
||||
union {
|
||||
mp_vfs_mount_t *vfs;
|
||||
mp_obj_t iter;
|
||||
} cur;
|
||||
bool is_str;
|
||||
bool is_iter;
|
||||
} mp_vfs_ilistdir_it_t;
|
||||
|
||||
STATIC mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) {
|
||||
mp_vfs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->is_iter) {
|
||||
// continue delegating to root dir
|
||||
return mp_iternext(self->cur.iter);
|
||||
} else if (self->cur.vfs == NULL) {
|
||||
// finished iterating mount points and no root dir is mounted
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
} else {
|
||||
// continue iterating mount points
|
||||
mp_vfs_mount_t *vfs = self->cur.vfs;
|
||||
self->cur.vfs = vfs->next;
|
||||
if (vfs->len == 1) {
|
||||
// vfs is mounted at root dir, delegate to it
|
||||
mp_obj_t root = mp_obj_new_str("/", 1, false);
|
||||
self->is_iter = true;
|
||||
self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root);
|
||||
return mp_iternext(self->cur.iter);
|
||||
} else {
|
||||
// a mounted directory
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
|
||||
t->items[0] = mp_obj_new_str_of_type(
|
||||
self->is_str ? &mp_type_str : &mp_type_bytes,
|
||||
(const byte*)vfs->str + 1, vfs->len - 1);
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t path_in;
|
||||
if (n_args == 1) {
|
||||
path_in = args[0];
|
||||
@ -299,22 +341,29 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
if (vfs == MP_VFS_ROOT) {
|
||||
// list the root directory
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
|
||||
if (vfs->len == 1) {
|
||||
// vfs is mounted at root dir, delegate to it
|
||||
mp_obj_t root = mp_obj_new_str("/", 1, false);
|
||||
mp_obj_t dir_list2 = mp_vfs_proxy_call(vfs, MP_QSTR_listdir, 1, &root);
|
||||
dir_list = mp_binary_op(MP_BINARY_OP_ADD, dir_list, dir_list2);
|
||||
} else {
|
||||
mp_obj_list_append(dir_list, mp_obj_new_str_of_type(mp_obj_get_type(path_in),
|
||||
(const byte*)vfs->str + 1, vfs->len - 1));
|
||||
}
|
||||
}
|
||||
return dir_list;
|
||||
mp_vfs_ilistdir_it_t *iter = m_new_obj(mp_vfs_ilistdir_it_t);
|
||||
iter->base.type = &mp_type_polymorph_iter;
|
||||
iter->iternext = mp_vfs_ilistdir_it_iternext;
|
||||
iter->cur.vfs = MP_STATE_VM(vfs_mount_table);
|
||||
iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;
|
||||
iter->is_iter = false;
|
||||
return MP_OBJ_FROM_PTR(iter);
|
||||
}
|
||||
|
||||
return mp_vfs_proxy_call(vfs, MP_QSTR_listdir, 1, &path_out);
|
||||
return mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &path_out);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj, 0, 1, mp_vfs_ilistdir);
|
||||
|
||||
mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t iter = mp_vfs_ilistdir(n_args, args);
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
mp_obj_t next;
|
||||
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_obj_t *items;
|
||||
mp_obj_get_array_fixed_n(next, 3, &items);
|
||||
mp_obj_list_append(dir_list, items[0]);
|
||||
}
|
||||
return dir_list;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj, 0, 1, mp_vfs_listdir);
|
||||
|
||||
@ -359,7 +408,7 @@ mp_obj_t mp_vfs_stat(mp_obj_t path_in) {
|
||||
mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);
|
||||
if (vfs == MP_VFS_ROOT) {
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(0x4000); // st_mode = stat.S_IFDIR
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); // st_mode
|
||||
for (int i = 1; i <= 9; ++i) {
|
||||
t->items[i] = MP_OBJ_NEW_SMALL_INT(0); // dev, nlink, uid, gid, size, atime, mtime, ctime
|
||||
}
|
||||
|
@ -35,6 +35,10 @@
|
||||
#define MP_VFS_NONE ((mp_vfs_mount_t*)1)
|
||||
#define MP_VFS_ROOT ((mp_vfs_mount_t*)0)
|
||||
|
||||
// MicroPython's port-standardized versions of stat constants
|
||||
#define MP_S_IFDIR (0x4000)
|
||||
#define MP_S_IFREG (0x8000)
|
||||
|
||||
// constants for block protocol ioctl
|
||||
#define BP_IOCTL_INIT (1)
|
||||
#define BP_IOCTL_DEINIT (2)
|
||||
@ -56,6 +60,7 @@ mp_obj_t mp_vfs_umount(mp_obj_t mnt_in);
|
||||
mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
mp_obj_t mp_vfs_chdir(mp_obj_t path_in);
|
||||
mp_obj_t mp_vfs_getcwd(void);
|
||||
mp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_vfs_mkdir(mp_obj_t path_in);
|
||||
mp_obj_t mp_vfs_remove(mp_obj_t path_in);
|
||||
@ -69,6 +74,7 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_umount_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_open_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_remove_obj);
|
||||
|
@ -91,7 +91,7 @@ STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mk
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
|
||||
|
||||
STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
bool is_str_type = true;
|
||||
const char *path;
|
||||
@ -104,9 +104,9 @@ STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) {
|
||||
path = "";
|
||||
}
|
||||
|
||||
return fat_vfs_listdir2(self, path, is_str_type);
|
||||
return fat_vfs_ilistdir2(self, path, is_str_type);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_listdir_obj, 1, 2, fat_vfs_listdir_func);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func);
|
||||
|
||||
STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_int_t attr) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
@ -225,9 +225,9 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||
mp_int_t mode = 0;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
mode |= 0x4000; // stat.S_IFDIR
|
||||
mode |= MP_S_IFDIR;
|
||||
} else {
|
||||
mode |= 0x8000; // stat.S_IFREG
|
||||
mode |= MP_S_IFREG;
|
||||
}
|
||||
mp_int_t seconds = timeutils_seconds_since_2000(
|
||||
1980 + ((fno.fdate >> 9) & 0x7f),
|
||||
@ -321,7 +321,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount);
|
||||
STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&fat_vfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&fat_vfs_rmdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) },
|
||||
|
@ -57,4 +57,4 @@ mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *p
|
||||
mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
|
||||
|
||||
mp_obj_t fat_vfs_listdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type);
|
||||
mp_obj_t fat_vfs_ilistdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type);
|
||||
|
@ -34,51 +34,62 @@
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "py/lexer.h"
|
||||
|
||||
// TODO: actually, the core function should be ilistdir()
|
||||
|
||||
mp_obj_t fat_vfs_listdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) {
|
||||
FRESULT res;
|
||||
FILINFO fno;
|
||||
typedef struct _mp_vfs_fat_ilistdir_it_t {
|
||||
mp_obj_base_t base;
|
||||
mp_fun_1_t iternext;
|
||||
bool is_str;
|
||||
FF_DIR dir;
|
||||
} mp_vfs_fat_ilistdir_it_t;
|
||||
|
||||
res = f_opendir(&vfs->fatfs, &dir, path);
|
||||
STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
|
||||
mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
for (;;) {
|
||||
FILINFO fno;
|
||||
FRESULT res = f_readdir(&self->dir, &fno);
|
||||
char *fn = fno.fname;
|
||||
if (res != FR_OK || fn[0] == 0) {
|
||||
// stop on error or end of dir
|
||||
break;
|
||||
}
|
||||
|
||||
// Note that FatFS already filters . and .., so we don't need to
|
||||
|
||||
// make 3-tuple with info about this entry
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
|
||||
if (self->is_str) {
|
||||
t->items[0] = mp_obj_new_str(fn, strlen(fn), false);
|
||||
} else {
|
||||
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
|
||||
}
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
// dir
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
|
||||
} else {
|
||||
// file
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
|
||||
}
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
|
||||
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
|
||||
// ignore error because we may be closing a second time
|
||||
f_closedir(&self->dir);
|
||||
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
|
||||
mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) {
|
||||
mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
|
||||
iter->base.type = &mp_type_polymorph_iter;
|
||||
iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
|
||||
iter->is_str = is_str_type;
|
||||
FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path);
|
||||
if (res != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
for (;;) {
|
||||
res = f_readdir(&dir, &fno); /* Read a directory item */
|
||||
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */
|
||||
if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */
|
||||
|
||||
char *fn = fno.fname;
|
||||
|
||||
/*
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
// dir
|
||||
} else {
|
||||
// file
|
||||
}
|
||||
*/
|
||||
|
||||
// make a string object for this entry
|
||||
mp_obj_t entry_o;
|
||||
if (is_str_type) {
|
||||
entry_o = mp_obj_new_str(fn, strlen(fn), false);
|
||||
} else {
|
||||
entry_o = mp_obj_new_bytes((const byte*)fn, strlen(fn));
|
||||
}
|
||||
|
||||
// add the entry to the list
|
||||
mp_obj_list_append(dir_list, entry_o);
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
return dir_list;
|
||||
return MP_OBJ_FROM_PTR(iter);
|
||||
}
|
||||
|
||||
mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) {
|
||||
|
@ -1,3 +1,14 @@
|
||||
# The following is a temporary hack to forefully undefine vars that might have
|
||||
# be defined by a calling Makefile (from recursive make).
|
||||
# TODO: Find a better way to be able to call this Makefile recursively.
|
||||
override undefine COPT
|
||||
override undefine CFLAGS_EXTRA
|
||||
override undefine LDFLAGS_EXTRA
|
||||
override undefine FROZEN_DIR
|
||||
override undefine FROZEN_MPY_DIR
|
||||
override undefine BUILD
|
||||
override undefine PROG
|
||||
|
||||
include ../py/mkenv.mk
|
||||
|
||||
# define main target
|
||||
|
@ -327,9 +327,10 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
|
||||
break;
|
||||
default:
|
||||
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||
if ((typecode | 0x20) == 'q' && MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
|
||||
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
|
||||
size_t size = mp_binary_get_size('@', typecode, NULL);
|
||||
mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
|
||||
sizeof(long long), (byte*)&((long long*)p)[index]);
|
||||
size, (uint8_t*)p + index * size);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -429,8 +429,13 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
// if args[3] (fromtuple) has magic value False, set up
|
||||
// this module for command-line "-m" option (set module's
|
||||
// name to __main__ instead of real name).
|
||||
if (i == mod_len && fromtuple == mp_const_false) {
|
||||
// name to __main__ instead of real name). Do this only
|
||||
// for *modules* however - packages never have their names
|
||||
// replaced, instead they're -m'ed using a special __main__
|
||||
// submodule in them. (This all apparently is done to not
|
||||
// touch package name itself, which is important for future
|
||||
// imports).
|
||||
if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) {
|
||||
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
|
||||
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
|
46
py/lexer.c
46
py/lexer.c
@ -137,24 +137,19 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
lex->chr1 = lex->chr2;
|
||||
lex->chr2 = lex->reader.readbyte(lex->reader.data);
|
||||
|
||||
if (lex->chr0 == '\r') {
|
||||
if (lex->chr1 == '\r') {
|
||||
// CR is a new line, converted to LF
|
||||
lex->chr0 = '\n';
|
||||
if (lex->chr1 == '\n') {
|
||||
// CR LF is a single new line
|
||||
lex->chr1 = lex->chr2;
|
||||
lex->chr1 = '\n';
|
||||
if (lex->chr2 == '\n') {
|
||||
// CR LF is a single new line, throw out the extra LF
|
||||
lex->chr2 = lex->reader.readbyte(lex->reader.data);
|
||||
}
|
||||
}
|
||||
|
||||
if (lex->chr2 == MP_LEXER_EOF) {
|
||||
// EOF, check if we need to insert a newline at end of file
|
||||
if (lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') {
|
||||
// if lex->chr1 == '\r' then this makes a CR LF which will be converted to LF above
|
||||
// otherwise it just inserts a LF
|
||||
// check if we need to insert a newline at end of file
|
||||
if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') {
|
||||
lex->chr2 = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void indent_push(mp_lexer_t *lex, size_t indent) {
|
||||
@ -677,7 +672,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {
|
||||
lex->source_name = src_name;
|
||||
lex->reader = reader;
|
||||
lex->line = 1;
|
||||
lex->column = 1;
|
||||
lex->column = -2; // account for 3 dummy bytes
|
||||
lex->emit_dent = 0;
|
||||
lex->nested_bracket_level = 0;
|
||||
lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;
|
||||
@ -688,27 +683,12 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {
|
||||
// store sentinel for first indentation level
|
||||
lex->indent_level[0] = 0;
|
||||
|
||||
// preload characters
|
||||
lex->chr0 = reader.readbyte(reader.data);
|
||||
lex->chr1 = reader.readbyte(reader.data);
|
||||
lex->chr2 = reader.readbyte(reader.data);
|
||||
|
||||
// if input stream is 0, 1 or 2 characters long and doesn't end in a newline, then insert a newline at the end
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
lex->chr0 = '\n';
|
||||
} else if (lex->chr1 == MP_LEXER_EOF) {
|
||||
if (lex->chr0 == '\r') {
|
||||
lex->chr0 = '\n';
|
||||
} else if (lex->chr0 != '\n') {
|
||||
lex->chr1 = '\n';
|
||||
}
|
||||
} else if (lex->chr2 == MP_LEXER_EOF) {
|
||||
if (lex->chr1 == '\r') {
|
||||
lex->chr1 = '\n';
|
||||
} else if (lex->chr1 != '\n') {
|
||||
lex->chr2 = '\n';
|
||||
}
|
||||
}
|
||||
// load lexer with start of file, advancing lex->column to 1
|
||||
// start with dummy bytes and use next_char() for proper EOL/EOF handling
|
||||
lex->chr0 = lex->chr1 = lex->chr2 = 0;
|
||||
next_char(lex);
|
||||
next_char(lex);
|
||||
next_char(lex);
|
||||
|
||||
// preload first token
|
||||
mp_lexer_to_next(lex);
|
||||
|
@ -102,15 +102,19 @@ $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DE
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIR),)
|
||||
# to build the MicroPython cross compiler
|
||||
$(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/windows/fmode.c
|
||||
$(Q)$(MAKE) -C $(TOP)/mpy-cross
|
||||
|
||||
# make a list of all the .py files that need compiling and freezing
|
||||
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==')
|
||||
FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
|
||||
|
||||
# to build .mpy files from .py files
|
||||
$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py
|
||||
$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross
|
||||
@$(ECHO) "MPY $<"
|
||||
$(Q)$(MKDIR) -p $(dir $@)
|
||||
$(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $^
|
||||
$(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $<
|
||||
|
||||
# to build frozen_mpy.c from all .mpy files
|
||||
$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h
|
||||
|
@ -406,7 +406,7 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *
|
||||
if (end_elem != NULL && end_elem->value != mp_const_none) {
|
||||
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
void *stream_obj = &mp_sys_stdout_obj;
|
||||
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
|
||||
if (file_elem != NULL && file_elem->value != mp_const_none) {
|
||||
@ -417,19 +417,19 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *
|
||||
#endif
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
mp_stream_write_adaptor(stream_obj, sep_data, sep_len);
|
||||
#else
|
||||
mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
mp_obj_print_helper(&print, args[i], PRINT_STR);
|
||||
#else
|
||||
mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
mp_stream_write_adaptor(stream_obj, end_data, end_len);
|
||||
#else
|
||||
mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0);
|
||||
|
@ -45,7 +45,7 @@ extern struct _mp_dummy_t mp_sys_stdin_obj;
|
||||
extern struct _mp_dummy_t mp_sys_stdout_obj;
|
||||
extern struct _mp_dummy_t mp_sys_stderr_obj;
|
||||
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
const mp_print_t mp_sys_stdout_print = {&mp_sys_stdout_obj, mp_stream_write_adaptor};
|
||||
#endif
|
||||
|
||||
@ -106,7 +106,7 @@ STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
|
||||
|
||||
STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) {
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
void *stream_obj = &mp_sys_stdout_obj;
|
||||
if (n_args > 1) {
|
||||
stream_obj = MP_OBJ_TO_PTR(args[1]); // XXX may fail
|
||||
|
@ -39,7 +39,7 @@
|
||||
#define PF_FLAG_ADD_PERCENT (0x100)
|
||||
#define PF_FLAG_SHOW_OCTAL_LETTER (0x200)
|
||||
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
# define MP_PYTHON_PRINTER &mp_sys_stdout_print
|
||||
#else
|
||||
# define MP_PYTHON_PRINTER &mp_plat_print
|
||||
@ -55,7 +55,7 @@ typedef struct _mp_print_t {
|
||||
// All (non-debug) prints go through one of the two interfaces below.
|
||||
// 1) Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN.
|
||||
extern const mp_print_t mp_plat_print;
|
||||
#if MICROPY_PY_IO
|
||||
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
|
||||
// 2) Wrapper for printing to sys.stdout.
|
||||
extern const mp_print_t mp_sys_stdout_print;
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
|
||||
|
@ -135,6 +135,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
|
||||
|
@ -1,4 +1,4 @@
|
||||
# test array('q') and array('Q')
|
||||
# test array types QqLl that require big-ints
|
||||
|
||||
try:
|
||||
from array import array
|
||||
@ -7,6 +7,9 @@ except ImportError:
|
||||
print("SKIP")
|
||||
sys.exit()
|
||||
|
||||
print(array('L', [0, 2**32-1]))
|
||||
print(array('l', [-2**31, 0, 2**31-1]))
|
||||
|
||||
print(array('q'))
|
||||
print(array('Q'))
|
||||
|
||||
|
@ -9,6 +9,14 @@ exec("\n")
|
||||
exec("\n\n")
|
||||
exec("\r")
|
||||
exec("\r\r")
|
||||
exec("\t")
|
||||
exec("\r\n")
|
||||
exec("\nprint(1)")
|
||||
exec("\rprint(2)")
|
||||
exec("\r\nprint(3)")
|
||||
exec("\n5")
|
||||
exec("\r6")
|
||||
exec("\r\n7")
|
||||
print(eval("1"))
|
||||
print(eval("12"))
|
||||
print(eval("123"))
|
||||
@ -19,6 +27,14 @@ print(eval("1\r"))
|
||||
print(eval("12\r"))
|
||||
print(eval("123\r"))
|
||||
|
||||
# line continuation
|
||||
print(eval("'123' \\\r '456'"))
|
||||
print(eval("'123' \\\n '456'"))
|
||||
print(eval("'123' \\\r\n '456'"))
|
||||
print(eval("'123'\\\r'456'"))
|
||||
print(eval("'123'\\\n'456'"))
|
||||
print(eval("'123'\\\r\n'456'"))
|
||||
|
||||
# backslash used to escape a line-break in a string
|
||||
print('a\
|
||||
b')
|
||||
|
@ -12,7 +12,3 @@ print(list(memoryview(array('b', [0x7f, -0x80]))))
|
||||
print(list(memoryview(array('B', [0x7f, 0x80, 0x81, 0xff]))))
|
||||
print(list(memoryview(array('h', [0x7f00, -0x8000]))))
|
||||
print(list(memoryview(array('H', [0x7f00, 0x8000, 0x8100, 0xffff]))))
|
||||
|
||||
# these constructors give an internal overflow in uPy
|
||||
#print(list(memoryview(array('i', [0x7f000000, -0x80000000]))))
|
||||
#print(list(memoryview(array('I', [0x7f000000, 0x80000000, 0x81000000, 0xffffffff]))))
|
||||
|
11
tests/basics/memoryview_intbig.py
Normal file
11
tests/basics/memoryview_intbig.py
Normal file
@ -0,0 +1,11 @@
|
||||
# test memoryview accessing maximum values for signed/unsigned elements
|
||||
try:
|
||||
from array import array
|
||||
memoryview
|
||||
except:
|
||||
import sys
|
||||
print("SKIP")
|
||||
sys.exit()
|
||||
|
||||
print(list(memoryview(array('i', [0x7f000000, -0x80000000]))))
|
||||
print(list(memoryview(array('I', [0x7f000000, 0x80000000, 0x81000000, 0xffffffff]))))
|
@ -20,9 +20,9 @@ class Filesystem:
|
||||
print(self.id, 'mount', readonly, mkfs)
|
||||
def umount(self):
|
||||
print(self.id, 'umount')
|
||||
def listdir(self, dir):
|
||||
print(self.id, 'listdir', dir)
|
||||
return ['a%d' % self.id]
|
||||
def ilistdir(self, dir):
|
||||
print(self.id, 'ilistdir', dir)
|
||||
return iter([('a%d' % self.id, 0, 0)])
|
||||
def chdir(self, dir):
|
||||
print(self.id, 'chdir', dir)
|
||||
def getcwd(self):
|
||||
@ -47,6 +47,10 @@ class Filesystem:
|
||||
|
||||
|
||||
# first we umount any existing mount points the target may have
|
||||
try:
|
||||
uos.umount('/')
|
||||
except OSError:
|
||||
pass
|
||||
for path in uos.listdir('/'):
|
||||
uos.umount('/' + path)
|
||||
|
||||
@ -60,6 +64,18 @@ print(uos.getcwd())
|
||||
uos.mount(Filesystem(1), '/test_mnt')
|
||||
print(uos.listdir())
|
||||
|
||||
# ilistdir
|
||||
i = uos.ilistdir()
|
||||
print(next(i))
|
||||
try:
|
||||
next(i)
|
||||
except StopIteration:
|
||||
print('StopIteration')
|
||||
try:
|
||||
next(i)
|
||||
except StopIteration:
|
||||
print('StopIteration')
|
||||
|
||||
# referencing the mount point in different ways
|
||||
print(uos.listdir('test_mnt'))
|
||||
print(uos.listdir('/test_mnt'))
|
||||
|
@ -2,20 +2,23 @@
|
||||
/
|
||||
1 mount False False
|
||||
['test_mnt']
|
||||
1 listdir /
|
||||
('test_mnt', 16384, 0)
|
||||
StopIteration
|
||||
StopIteration
|
||||
1 ilistdir /
|
||||
['a1']
|
||||
1 listdir /
|
||||
1 ilistdir /
|
||||
['a1']
|
||||
2 mount True False
|
||||
['test_mnt', 'test_mnt2']
|
||||
2 listdir /
|
||||
2 ilistdir /
|
||||
['a2']
|
||||
3 mount False False
|
||||
OSError
|
||||
OSError
|
||||
OSError
|
||||
1 chdir /
|
||||
1 listdir
|
||||
1 ilistdir
|
||||
['a1']
|
||||
1 getcwd
|
||||
/test_mntdir1
|
||||
@ -33,19 +36,19 @@ OSError
|
||||
2 umount
|
||||
OSError
|
||||
3 mount False False
|
||||
3 listdir /
|
||||
3 ilistdir /
|
||||
['a3']
|
||||
3 open test r
|
||||
4 mount False False
|
||||
3 listdir /
|
||||
3 ilistdir /
|
||||
['mnt', 'a3']
|
||||
4 listdir /
|
||||
4 ilistdir /
|
||||
['a4']
|
||||
4 chdir /
|
||||
4 listdir
|
||||
4 ilistdir
|
||||
['a4']
|
||||
3 chdir /subdir
|
||||
3 listdir
|
||||
3 ilistdir
|
||||
['a3']
|
||||
3 chdir /
|
||||
3 umount
|
||||
|
@ -115,4 +115,4 @@ except OSError as e:
|
||||
print(e.args[0] == 20) # uerrno.ENOTDIR
|
||||
|
||||
vfs.remove("foo_file.txt")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
@ -10,4 +10,4 @@ e
|
||||
True
|
||||
d
|
||||
True
|
||||
['foo_dir']
|
||||
[('foo_dir', 16384, 0)]
|
||||
|
@ -91,23 +91,23 @@ except OSError as e:
|
||||
|
||||
# trim full path
|
||||
vfs.rename("foo_dir/file-in-dir.txt", "foo_dir/file.txt")
|
||||
print(vfs.listdir("foo_dir"))
|
||||
print(list(vfs.ilistdir("foo_dir")))
|
||||
|
||||
vfs.rename("foo_dir/file.txt", "moved-to-root.txt")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
||||
# check that renaming to existing file will overwrite it
|
||||
with open("temp", "w") as f:
|
||||
f.write("new text")
|
||||
vfs.rename("temp", "moved-to-root.txt")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
with open("moved-to-root.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
# valid removes
|
||||
vfs.remove("foo_dir/sub_file.txt")
|
||||
vfs.rmdir("foo_dir")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
||||
# disk full
|
||||
try:
|
||||
|
@ -3,9 +3,9 @@ True
|
||||
True
|
||||
b'data in file'
|
||||
True
|
||||
['sub_file.txt', 'file.txt']
|
||||
['foo_dir', 'moved-to-root.txt']
|
||||
['foo_dir', 'moved-to-root.txt']
|
||||
[('sub_file.txt', 32768, 0), ('file.txt', 32768, 0)]
|
||||
[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)]
|
||||
[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)]
|
||||
new text
|
||||
['moved-to-root.txt']
|
||||
[('moved-to-root.txt', 32768, 0)]
|
||||
ENOSPC: True
|
||||
|
@ -1,10 +1,15 @@
|
||||
import sys
|
||||
import uerrno
|
||||
try:
|
||||
try:
|
||||
import uos_vfs as uos
|
||||
open = uos.vfs_open
|
||||
except ImportError:
|
||||
except ImportError:
|
||||
import uos
|
||||
except ImportError:
|
||||
print("SKIP")
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
uos.VfsFat
|
||||
except AttributeError:
|
||||
@ -44,6 +49,14 @@ except MemoryError:
|
||||
print("SKIP")
|
||||
sys.exit()
|
||||
|
||||
# first we umount any existing mount points the target may have
|
||||
try:
|
||||
uos.umount('/')
|
||||
except OSError:
|
||||
pass
|
||||
for path in uos.listdir('/'):
|
||||
uos.umount('/' + path)
|
||||
|
||||
uos.VfsFat.mkfs(bdev)
|
||||
uos.mount(bdev, '/')
|
||||
|
||||
|
@ -53,10 +53,10 @@ uos.mount(vfs, "/ramdisk")
|
||||
with vfs.open("file.txt", "w") as f:
|
||||
f.write("hello!")
|
||||
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
||||
with vfs.open("file.txt", "r") as f:
|
||||
print(f.read())
|
||||
|
||||
vfs.remove("file.txt")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
@ -1,3 +1,3 @@
|
||||
['file.txt']
|
||||
[('file.txt', 32768, 0)]
|
||||
hello!
|
||||
[]
|
||||
|
@ -65,7 +65,7 @@ except OSError as e:
|
||||
|
||||
with vfs.open("foo_file.txt", "w") as f:
|
||||
f.write("hello!")
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
||||
print("stat root:", vfs.stat("/"))
|
||||
print("stat file:", vfs.stat("foo_file.txt")[:-3]) # timestamps differ across runs
|
||||
@ -76,7 +76,7 @@ print(b"hello!" in bdev.data)
|
||||
vfs.mkdir("foo_dir")
|
||||
vfs.chdir("foo_dir")
|
||||
print("getcwd:", vfs.getcwd())
|
||||
print(vfs.listdir())
|
||||
print(list(vfs.ilistdir()))
|
||||
|
||||
with vfs.open("sub_file.txt", "w") as f:
|
||||
f.write("subdir file")
|
||||
@ -92,4 +92,10 @@ print("getcwd:", vfs.getcwd())
|
||||
uos.umount(vfs)
|
||||
|
||||
vfs = uos.VfsFat(bdev)
|
||||
print(vfs.listdir(b""))
|
||||
print(list(vfs.ilistdir(b"")))
|
||||
|
||||
# list a non-existent directory
|
||||
try:
|
||||
vfs.ilistdir(b"no_exist")
|
||||
except OSError as e:
|
||||
print('ENOENT:', e.args[0] == uerrno.ENOENT)
|
||||
|
@ -3,7 +3,7 @@ True
|
||||
statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255)
|
||||
getcwd: /
|
||||
True
|
||||
['foo_file.txt']
|
||||
[('foo_file.txt', 32768, 0)]
|
||||
stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
stat file: (32768, 0, 0, 0, 0, 0, 6)
|
||||
True
|
||||
@ -12,4 +12,5 @@ getcwd: /foo_dir
|
||||
[]
|
||||
True
|
||||
getcwd: /
|
||||
[b'foo_file.txt', b'foo_dir']
|
||||
[(b'foo_file.txt', 32768, 0), (b'foo_dir', 16384, 0)]
|
||||
ENOENT: True
|
||||
|
@ -332,25 +332,25 @@ class RawCode:
|
||||
raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,))
|
||||
|
||||
# generate constant table
|
||||
print('STATIC const mp_uint_t const_table_data_%s[%u] = {'
|
||||
print('STATIC const mp_rom_obj_t const_table_data_%s[%u] = {'
|
||||
% (self.escaped_name, len(self.qstrs) + len(self.objs) + len(self.raw_codes)))
|
||||
for qst in self.qstrs:
|
||||
print(' (mp_uint_t)MP_OBJ_NEW_QSTR(%s),' % global_qstrs[qst].qstr_id)
|
||||
print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id)
|
||||
for i in range(len(self.objs)):
|
||||
if type(self.objs[i]) is float:
|
||||
print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B')
|
||||
print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i))
|
||||
print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i))
|
||||
print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C')
|
||||
n = struct.unpack('<I', struct.pack('<f', self.objs[i]))[0]
|
||||
n = ((n & ~0x3) | 2) + 0x80800000
|
||||
print(' (mp_uint_t)0x%08x,' % (n,))
|
||||
print(' MP_ROM_INT(0x%08x),' % (n,))
|
||||
print('#else')
|
||||
print('#error "MICROPY_OBJ_REPR_D not supported with floats in frozen mpy files"')
|
||||
print('#endif')
|
||||
else:
|
||||
print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i))
|
||||
print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i))
|
||||
for rc in self.raw_codes:
|
||||
print(' (mp_uint_t)&raw_code_%s,' % rc.escaped_name)
|
||||
print(' MP_ROM_PTR(&raw_code_%s),' % rc.escaped_name)
|
||||
print('};')
|
||||
|
||||
# generate module
|
||||
@ -362,7 +362,7 @@ class RawCode:
|
||||
print(' .n_pos_args = %u,' % self.prelude[3])
|
||||
print(' .data.u_byte = {')
|
||||
print(' .bytecode = bytecode_data_%s,' % self.escaped_name)
|
||||
print(' .const_table = const_table_data_%s,' % self.escaped_name)
|
||||
print(' .const_table = (mp_uint_t*)const_table_data_%s,' % self.escaped_name)
|
||||
print(' #if MICROPY_PERSISTENT_CODE_SAVE')
|
||||
print(' .bc_len = %u,' % len(self.bytecode))
|
||||
print(' .n_obj = %u,' % len(self.objs))
|
||||
|
38
tools/mpy_cross_all.py
Executable file
38
tools/mpy_cross_all.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import os.path
|
||||
|
||||
argparser = argparse.ArgumentParser(description="Compile all .py files to .mpy recursively")
|
||||
argparser.add_argument("-o", "--out", help="output directory (default: input dir)")
|
||||
argparser.add_argument("--target", help="select MicroPython target config")
|
||||
argparser.add_argument("-mcache-lookup-bc", action="store_true", help="cache map lookups in the bytecode")
|
||||
argparser.add_argument("dir", help="input directory")
|
||||
args = argparser.parse_args()
|
||||
|
||||
TARGET_OPTS = {
|
||||
"unix": "-mcache-lookup-bc",
|
||||
"baremetal": "",
|
||||
}
|
||||
|
||||
args.dir = args.dir.rstrip("/")
|
||||
|
||||
if not args.out:
|
||||
args.out = args.dir
|
||||
|
||||
path_prefix_len = len(args.dir) + 1
|
||||
|
||||
for path, subdirs, files in os.walk(args.dir):
|
||||
for f in files:
|
||||
if f.endswith(".py"):
|
||||
fpath = path + "/" + f
|
||||
#print(fpath)
|
||||
out_fpath = args.out + "/" + fpath[path_prefix_len:-3] + ".mpy"
|
||||
out_dir = os.path.dirname(out_fpath)
|
||||
if not os.path.isdir(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
cmd = "mpy-cross -v -v %s -s %s %s -o %s" % (TARGET_OPTS.get(args.target, ""),
|
||||
fpath[path_prefix_len:], fpath, out_fpath)
|
||||
#print(cmd)
|
||||
res = os.system(cmd)
|
||||
assert res == 0
|
@ -2,6 +2,7 @@
|
||||
include ../py/mkenv.mk
|
||||
|
||||
FROZEN_DIR = scripts
|
||||
FROZEN_MPY_DIR = modules
|
||||
|
||||
# define main target
|
||||
PROG = micropython
|
||||
|
17
unix/main.c
17
unix/main.c
@ -553,6 +553,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
|
||||
mp_obj_t mod;
|
||||
nlr_buf_t nlr;
|
||||
bool subpkg_tried = false;
|
||||
|
||||
reimport:
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args);
|
||||
nlr_pop();
|
||||
@ -561,11 +564,17 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
return handle_uncaught_exception(nlr.ret_val) & 0xff;
|
||||
}
|
||||
|
||||
if (mp_obj_is_package(mod)) {
|
||||
// TODO
|
||||
mp_printf(&mp_stderr_print, "%s: -m for packages not yet implemented\n", argv[0]);
|
||||
exit(1);
|
||||
if (mp_obj_is_package(mod) && !subpkg_tried) {
|
||||
subpkg_tried = true;
|
||||
vstr_t vstr;
|
||||
int len = strlen(argv[a + 1]);
|
||||
vstr_init(&vstr, len + sizeof(".__main__"));
|
||||
vstr_add_strn(&vstr, argv[a + 1], len);
|
||||
vstr_add_strn(&vstr, ".__main__", sizeof(".__main__") - 1);
|
||||
import_args[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
||||
goto reimport;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
} else if (strcmp(argv[a], "-X") == 0) {
|
||||
|
@ -42,6 +42,7 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
|
||||
|
@ -1,20 +1,19 @@
|
||||
MicroPython port to Zephyr RTOS
|
||||
===============================
|
||||
|
||||
This is an initial port of MicroPython to Zephyr RTOS
|
||||
This is an work-in-progress port of MicroPython to Zephyr RTOS
|
||||
(http://zephyrproject.org).
|
||||
|
||||
The port integrates well with Zephyr build system, using the latest
|
||||
features which will be available in 1.6.0, and thus requires Zephyr
|
||||
master to build against. All boards supported by Zephyr (with standard
|
||||
level of feature support, like UART console) should work with
|
||||
MicroPython (but not all were tested).
|
||||
This port requires Zephyr version 1.8 or higher. All boards supported
|
||||
by Zephyr (with standard level of features support, like UART console)
|
||||
should work with MicroPython (but not all were tested).
|
||||
|
||||
Features supported at this time:
|
||||
|
||||
* REPL (interactive prompt) over Zephyr UART console.
|
||||
* `utime` module for time measurements and delays.
|
||||
* `machine.Pin` class for GPIO control.
|
||||
* `usocket` module for networking (IPv4/IPv6).
|
||||
* "Frozen modules" support to allow to bundle Python modules together
|
||||
with firmware. Including complete applications, including with
|
||||
run-on-boot capability.
|
||||
@ -97,10 +96,10 @@ MicroPython is committed to maintain minimal binary size for Zephyr port
|
||||
below 128KB, as long as Zephyr project is committed to maintain stable
|
||||
minimal size of their kernel (which they appear to be). Note that at such
|
||||
size, there is no support for any Zephyr features beyond REPL over UART,
|
||||
and only very minimal set of builtin Python modules. Thus, this build
|
||||
is more suitable for code size control and quick demonstrations on
|
||||
smaller systems. It's also suitable for careful enabling of features one
|
||||
by one to achieve needed functionality and code size. This is in a
|
||||
and only very minimal set of builtin Python modules is available. Thus,
|
||||
this build is more suitable for code size control and quick demonstrations
|
||||
on smaller systems. It's also suitable for careful enabling of features
|
||||
one by one to achieve needed functionality and code size. This is in the
|
||||
contrast to the "default" build, which may get more and more features
|
||||
enabled over time.
|
||||
|
||||
|
@ -35,7 +35,8 @@
|
||||
// Zephyr's generated version header
|
||||
#include <version.h>
|
||||
#include <net/net_context.h>
|
||||
#include <net/nbuf.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/dns_resolve.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG // print debugging info
|
||||
@ -51,7 +52,7 @@ typedef struct _socket_obj_t {
|
||||
struct k_fifo recv_q;
|
||||
struct k_fifo accept_q;
|
||||
};
|
||||
struct net_buf *cur_buf;
|
||||
struct net_pkt *cur_pkt;
|
||||
|
||||
#define STATE_NEW 0
|
||||
#define STATE_CONNECTING 1
|
||||
@ -114,13 +115,34 @@ STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct socka
|
||||
sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1]));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) {
|
||||
// We employ the fact that port and address offsets are the same for IPv4 & IPv6
|
||||
struct sockaddr_in6 *sockaddr_in6 = (struct sockaddr_in6*)addr;
|
||||
char buf[40];
|
||||
net_addr_ntop(addr->family, &sockaddr_in6->sin6_addr, buf, sizeof(buf));
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->family == AF_INET ? 2 : 4, NULL);
|
||||
|
||||
tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false);
|
||||
// We employ the fact that port offset is the same for IPv4 & IPv6
|
||||
// not filled in
|
||||
//tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port));
|
||||
tuple->items[1] = port;
|
||||
|
||||
if (addr->family == AF_INET6) {
|
||||
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); // flow_info
|
||||
tuple->items[3] = MP_OBJ_NEW_SMALL_INT(sockaddr_in6->sin6_scope_id);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
|
||||
// Copy data from Zephyr net_buf chain into linear buffer.
|
||||
// We don't use net_nbuf_read(), because it's weird (e.g., we'd like to
|
||||
// free processed data fragment ASAP, while net_nbuf_read() holds onto
|
||||
// We don't use net_pkt_read(), because it's weird (e.g., we'd like to
|
||||
// free processed data fragment ASAP, while net_pkt_read() holds onto
|
||||
// the whole fragment chain to do its deeds, and that's minor comparing
|
||||
// to the fact that it copies data byte by byte).
|
||||
static char *net_buf_gather(struct net_buf *buf, char *to, unsigned max_len) {
|
||||
struct net_buf *tmp = buf->frags;
|
||||
static char *net_pkt_gather(struct net_pkt *pkt, char *to, unsigned max_len) {
|
||||
struct net_buf *tmp = pkt->frags;
|
||||
|
||||
while (tmp && max_len) {
|
||||
unsigned len = tmp->len;
|
||||
@ -130,48 +152,47 @@ static char *net_buf_gather(struct net_buf *buf, char *to, unsigned max_len) {
|
||||
memcpy(to, tmp->data, len);
|
||||
to += len;
|
||||
max_len -= len;
|
||||
tmp = net_buf_frag_del(buf, tmp);
|
||||
tmp = net_pkt_frag_del(pkt, NULL, tmp);
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
// Callback for incoming packets.
|
||||
static void sock_received_cb(struct net_context *context, struct net_buf *net_buf, int status, void *user_data) {
|
||||
static void sock_received_cb(struct net_context *context, struct net_pkt *pkt, int status, void *user_data) {
|
||||
socket_obj_t *socket = (socket_obj_t*)user_data;
|
||||
DEBUG_printf("recv cb: context: %p, status: %d, buf: %p", context, status, net_buf);
|
||||
if (net_buf) {
|
||||
DEBUG_printf(" (sz=%d, l=%d), token: %p", net_buf->size, net_buf->len, net_nbuf_token(net_buf));
|
||||
DEBUG_printf("recv cb: context: %p, status: %d, pkt: %p", context, status, pkt);
|
||||
if (pkt) {
|
||||
DEBUG_printf(" (appdatalen=%d), token: %p", pkt->appdatalen, net_pkt_token(pkt));
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#if DEBUG > 1
|
||||
net_nbuf_print_frags(net_buf);
|
||||
net_pkt_print_frags(pkt);
|
||||
#endif
|
||||
|
||||
// if net_buf == NULL, EOF
|
||||
if (net_buf == NULL) {
|
||||
struct net_buf *last_buf = _k_fifo_peek_tail(&socket->recv_q);
|
||||
if (last_buf == NULL) {
|
||||
if (pkt == NULL) {
|
||||
struct net_pkt *last_pkt = _k_fifo_peek_tail(&socket->recv_q);
|
||||
if (last_pkt == NULL) {
|
||||
socket->state = STATE_PEER_CLOSED;
|
||||
k_fifo_cancel_wait(&socket->recv_q);
|
||||
DEBUG_printf("Marked socket %p as peer-closed\n", socket);
|
||||
} else {
|
||||
// We abuse "buf_sent" flag to store EOF flag
|
||||
net_nbuf_set_buf_sent(last_buf, true);
|
||||
DEBUG_printf("Set EOF flag on %p\n", last_buf);
|
||||
net_pkt_set_sent(last_pkt, true);
|
||||
DEBUG_printf("Set EOF flag on %p\n", last_pkt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that "EOF flag" is not set
|
||||
net_nbuf_set_buf_sent(net_buf, false);
|
||||
net_pkt_set_sent(pkt, false);
|
||||
|
||||
// We don't care about packet header, so get rid of it asap
|
||||
unsigned header_len = net_nbuf_appdata(net_buf) - net_buf->frags->data;
|
||||
net_buf_pull(net_buf->frags, header_len);
|
||||
unsigned header_len = net_pkt_appdata(pkt) - pkt->frags->data;
|
||||
net_buf_pull(pkt->frags, header_len);
|
||||
|
||||
// net_buf->frags will be overwritten by fifo, so save it
|
||||
net_nbuf_set_token(net_buf, net_buf->frags);
|
||||
k_fifo_put(&socket->recv_q, net_buf);
|
||||
k_fifo_put(&socket->recv_q, pkt);
|
||||
}
|
||||
|
||||
// Callback for incoming connections.
|
||||
@ -187,7 +208,7 @@ socket_obj_t *socket_new(void) {
|
||||
socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t);
|
||||
socket->base.type = (mp_obj_t)&socket_type;
|
||||
k_fifo_init(&socket->recv_q);
|
||||
socket->cur_buf = NULL;
|
||||
socket->cur_pkt = NULL;
|
||||
socket->state = STATE_NEW;
|
||||
return socket;
|
||||
}
|
||||
@ -309,7 +330,7 @@ STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, i
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
struct net_buf *send_buf = net_nbuf_get_tx(socket->ctx, K_FOREVER);
|
||||
struct net_pkt *send_pkt = net_pkt_get_tx(socket->ctx, K_FOREVER);
|
||||
|
||||
unsigned len = net_if_get_mtu(net_context_get_iface(socket->ctx));
|
||||
// Arbitrary value to account for protocol headers
|
||||
@ -318,11 +339,11 @@ STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, i
|
||||
len = size;
|
||||
}
|
||||
|
||||
if (!net_nbuf_append(send_buf, len, buf, K_FOREVER)) {
|
||||
len = net_buf_frags_len(send_buf);
|
||||
}
|
||||
// TODO: Return value of 0 is a hard case (as we wait forever, should
|
||||
// not happen).
|
||||
len = net_pkt_append(send_pkt, len, buf, K_FOREVER);
|
||||
|
||||
int err = net_context_send(send_buf, /*cb*/NULL, K_FOREVER, NULL, NULL);
|
||||
int err = net_context_send(send_pkt, /*cb*/NULL, K_FOREVER, NULL, NULL);
|
||||
if (err < 0) {
|
||||
*errcode = -err;
|
||||
return MP_STREAM_ERROR;
|
||||
@ -356,41 +377,42 @@ STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *
|
||||
|
||||
if (sock_type == SOCK_DGRAM) {
|
||||
|
||||
struct net_buf *net_buf = k_fifo_get(&socket->recv_q, K_FOREVER);
|
||||
// Restore ->frags overwritten by fifo
|
||||
net_buf->frags = net_nbuf_token(net_buf);
|
||||
struct net_pkt *pkt = k_fifo_get(&socket->recv_q, K_FOREVER);
|
||||
|
||||
recv_len = net_nbuf_appdatalen(net_buf);
|
||||
DEBUG_printf("recv: net_buf=%p, appdatalen: %d\n", net_buf, recv_len);
|
||||
recv_len = net_pkt_appdatalen(pkt);
|
||||
DEBUG_printf("recv: pkt=%p, appdatalen: %d\n", pkt, recv_len);
|
||||
|
||||
if (recv_len > max_len) {
|
||||
recv_len = max_len;
|
||||
}
|
||||
|
||||
net_buf_gather(net_buf, buf, recv_len);
|
||||
net_nbuf_unref(net_buf);
|
||||
net_pkt_gather(pkt, buf, recv_len);
|
||||
net_pkt_unref(pkt);
|
||||
|
||||
} else if (sock_type == SOCK_STREAM) {
|
||||
|
||||
do {
|
||||
|
||||
if (socket->cur_buf == NULL) {
|
||||
if (socket->cur_pkt == NULL) {
|
||||
if (socket->state == STATE_PEER_CLOSED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_printf("TCP recv: no cur_buf, getting\n");
|
||||
struct net_buf *net_buf = k_fifo_get(&socket->recv_q, K_FOREVER);
|
||||
// Restore ->frags overwritten by fifo
|
||||
net_buf->frags = net_nbuf_token(net_buf);
|
||||
DEBUG_printf("TCP recv: no cur_pkt, getting\n");
|
||||
struct net_pkt *pkt = k_fifo_get(&socket->recv_q, K_FOREVER);
|
||||
|
||||
DEBUG_printf("TCP recv: new cur_buf: %p\n", net_buf);
|
||||
socket->cur_buf = net_buf;
|
||||
if (pkt == NULL) {
|
||||
DEBUG_printf("TCP recv: NULL return from fifo\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct net_buf *frag = socket->cur_buf->frags;
|
||||
DEBUG_printf("TCP recv: new cur_pkt: %p\n", pkt);
|
||||
socket->cur_pkt = pkt;
|
||||
}
|
||||
|
||||
struct net_buf *frag = socket->cur_pkt->frags;
|
||||
if (frag == NULL) {
|
||||
printf("net_buf has empty fragments on start!\n");
|
||||
printf("net_pkt has empty fragments on start!\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@ -406,20 +428,20 @@ STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *
|
||||
if (recv_len != frag_len) {
|
||||
net_buf_pull(frag, recv_len);
|
||||
} else {
|
||||
frag = net_buf_frag_del(socket->cur_buf, frag);
|
||||
frag = net_pkt_frag_del(socket->cur_pkt, NULL, frag);
|
||||
if (frag == NULL) {
|
||||
DEBUG_printf("Finished processing net_buf %p\n", socket->cur_buf);
|
||||
// If "buf_sent" flag was set, it's last packet and we reached EOF
|
||||
if (net_nbuf_buf_sent(socket->cur_buf)) {
|
||||
DEBUG_printf("Finished processing pkt %p\n", socket->cur_pkt);
|
||||
// If "sent" flag was set, it's last packet and we reached EOF
|
||||
if (net_pkt_sent(socket->cur_pkt)) {
|
||||
socket->state = STATE_PEER_CLOSED;
|
||||
}
|
||||
net_nbuf_unref(socket->cur_buf);
|
||||
socket->cur_buf = NULL;
|
||||
net_pkt_unref(socket->cur_pkt);
|
||||
socket->cur_pkt = NULL;
|
||||
}
|
||||
}
|
||||
// Keep repeating while we're getting empty fragments
|
||||
// Zephyr IP stack appears to feed empty net_buf's with empty
|
||||
// frags for various TCP control packets.
|
||||
// Zephyr IP stack appears to have fed empty net_buf's with empty
|
||||
// frags for various TCP control packets - in previous versions.
|
||||
} while (recv_len == 0);
|
||||
}
|
||||
|
||||
@ -450,6 +472,13 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
|
||||
|
||||
STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args; // always 4
|
||||
mp_warning("setsockopt() not implemented");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
|
||||
|
||||
STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
return args[0];
|
||||
@ -475,6 +504,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
|
||||
@ -499,6 +529,82 @@ STATIC const mp_obj_type_t socket_type = {
|
||||
.locals_dict = (mp_obj_t)&socket_locals_dict,
|
||||
};
|
||||
|
||||
//
|
||||
// getaddrinfo() implementation
|
||||
//
|
||||
|
||||
typedef struct _getaddrinfo_state_t {
|
||||
mp_obj_t result;
|
||||
struct k_sem sem;
|
||||
mp_obj_t port;
|
||||
} getaddrinfo_state_t;
|
||||
|
||||
void dns_resolve_cb(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) {
|
||||
getaddrinfo_state_t *state = user_data;
|
||||
|
||||
if (info == NULL) {
|
||||
k_sem_give(&state->sem);
|
||||
return;
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(info->ai_family);
|
||||
// info->ai_socktype not filled
|
||||
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM);
|
||||
// info->ai_protocol not filled
|
||||
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP);
|
||||
tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
tuple->items[4] = format_inet_addr(&info->ai_addr, state->port);
|
||||
mp_obj_list_append(state->result, MP_OBJ_FROM_PTR(tuple));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_getaddrinfo(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t host_in = args[0], port_in = args[1];
|
||||
const char *host = mp_obj_str_get_str(host_in);
|
||||
mp_int_t family = 0;
|
||||
if (n_args > 2) {
|
||||
family = mp_obj_get_int(args[2]);
|
||||
}
|
||||
|
||||
getaddrinfo_state_t state;
|
||||
// Just validate that it's int
|
||||
(void)mp_obj_get_int(port_in);
|
||||
state.port = port_in;
|
||||
state.result = mp_obj_new_list(0, NULL);
|
||||
k_sem_init(&state.sem, 0, UINT_MAX);
|
||||
|
||||
int status;
|
||||
for (int i = 2; i--;) {
|
||||
int type = (family != AF_INET6 ? DNS_QUERY_TYPE_A : DNS_QUERY_TYPE_AAAA);
|
||||
status = dns_get_addr_info(host, type, NULL, dns_resolve_cb, &state, 3000);
|
||||
if (status < 0) {
|
||||
mp_raise_OSError(status);
|
||||
}
|
||||
k_sem_take(&state.sem, K_FOREVER);
|
||||
if (family != 0) {
|
||||
break;
|
||||
}
|
||||
family = AF_INET6;
|
||||
}
|
||||
|
||||
return state.result;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_getaddrinfo_obj, 2, 3, mod_getaddrinfo);
|
||||
|
||||
|
||||
STATIC mp_obj_t pkt_get_info(void) {
|
||||
struct k_mem_slab *rx, *tx;
|
||||
struct net_buf_pool *rx_data, *tx_data;
|
||||
net_pkt_get_info(&rx, &tx, &rx_data, &tx_data);
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(rx));
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(tx));
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(rx_data->avail_count);
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(tx_data->avail_count);
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pkt_get_info_obj, pkt_get_info);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) },
|
||||
// objects
|
||||
@ -509,6 +615,12 @@ STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOL_SOCKET), MP_OBJ_NEW_SMALL_INT(1) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SO_REUSEADDR), MP_OBJ_NEW_SMALL_INT(2) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_getaddrinfo_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pkt_get_info), (mp_obj_t)&pkt_get_info_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
|
||||
|
@ -17,6 +17,15 @@ CONFIG_NET_TCP=y
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_NET_NBUF_RX_COUNT=5
|
||||
|
||||
# DNS
|
||||
CONFIG_DNS_RESOLVER=y
|
||||
CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2
|
||||
CONFIG_DNS_SERVER_IP_ADDRESSES=y
|
||||
CONFIG_DNS_SERVER1="192.0.2.2"
|
||||
|
||||
# Required for usocket.pkt_get_info()
|
||||
CONFIG_NET_BUF_POOL_USAGE=y
|
||||
|
||||
# Uncomment to enable "INFO" level net_buf logging
|
||||
#CONFIG_NET_LOG=y
|
||||
#CONFIG_NET_DEBUG_NET_BUF=y
|
||||
|
@ -3,4 +3,4 @@
|
||||
CONFIG_NET_SLIP_TAP=y
|
||||
|
||||
# Default RAM easily overflows with uPy and networking
|
||||
CONFIG_RAM_SIZE=256
|
||||
CONFIG_RAM_SIZE=320
|
||||
|
Loading…
Reference in New Issue
Block a user