diff --git a/cc3200/mods/moduos.c b/cc3200/mods/moduos.c index add10ec6c8..ed8879bf3e 100644 --- a/cc3200/mods/moduos.c +++ b/cc3200/mods/moduos.c @@ -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}, diff --git a/docs/library/index.rst b/docs/library/index.rst index 1a61f6882c..770920a1ff 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -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: diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index 369c08f443..6d6ba7bfd9 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -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 diff --git a/docs/library/machine.Signal.rst b/docs/library/machine.Signal.rst new file mode 100644 index 0000000000..4869086274 --- /dev/null +++ b/docs/library/machine.Signal.rst @@ -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. diff --git a/docs/library/machine.rst b/docs/library/machine.rst index ea11a1ff45..c2c6b83fd6 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -147,6 +147,7 @@ Classes machine.I2C.rst machine.Pin.rst + machine.Signal.rst machine.RTC.rst machine.SPI.rst machine.Timer.rst diff --git a/docs/library/uos.rst b/docs/library/uos.rst index e1ea72967f..d1f83d2cc3 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.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. diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 960c751795..deeb82b456 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -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 */ diff --git a/esp8266/esp8266_common.ld b/esp8266/esp8266_common.ld index 1da835681a..bc983df700 100644 --- a/esp8266/esp8266_common.ld +++ b/esp8266/esp8266_common.ld @@ -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: */ diff --git a/esp8266/esp8266_ota.ld b/esp8266/esp8266_ota.ld index d9afaa8f26..604480a0a9 100644 --- a/esp8266/esp8266_ota.ld +++ b/esp8266/esp8266_ota.ld @@ -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 */ diff --git a/esp8266/ets_alt_task.c b/esp8266/ets_alt_task.c index 6434f23660..ff7dba1869 100644 --- a/esp8266/ets_alt_task.c +++ b/esp8266/ets_alt_task.c @@ -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; diff --git a/esp8266/modesp.c b/esp8266/modesp.c index 432fd5ac31..5eaae27d6a 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -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); diff --git a/esp8266/scripts/apa102.py b/esp8266/modules/apa102.py similarity index 100% rename from esp8266/scripts/apa102.py rename to esp8266/modules/apa102.py diff --git a/esp8266/scripts/dht.py b/esp8266/modules/dht.py similarity index 100% rename from esp8266/scripts/dht.py rename to esp8266/modules/dht.py diff --git a/esp8266/modules/flashbdev.py b/esp8266/modules/flashbdev.py index 8f8df0b640..40ba655c64 100644 --- a/esp8266/modules/flashbdev.py +++ b/esp8266/modules/flashbdev.py @@ -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 diff --git a/esp8266/scripts/inisetup.py b/esp8266/modules/inisetup.py similarity index 100% rename from esp8266/scripts/inisetup.py rename to esp8266/modules/inisetup.py diff --git a/esp8266/scripts/neopixel.py b/esp8266/modules/neopixel.py similarity index 100% rename from esp8266/scripts/neopixel.py rename to esp8266/modules/neopixel.py diff --git a/esp8266/scripts/ntptime.py b/esp8266/modules/ntptime.py similarity index 100% rename from esp8266/scripts/ntptime.py rename to esp8266/modules/ntptime.py diff --git a/esp8266/scripts/port_diag.py b/esp8266/modules/port_diag.py similarity index 100% rename from esp8266/scripts/port_diag.py rename to esp8266/modules/port_diag.py diff --git a/esp8266/moduos.c b/esp8266/moduos.c index a22fbd4df0..807d2e18a5 100644 --- a/esp8266/moduos.c +++ b/esp8266/moduos.c @@ -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) }, diff --git a/examples/hwapi/hwconfig_esp8266_esp12.py b/examples/hwapi/hwconfig_esp8266_esp12.py index 198a652d0a..2e855ee3d3 100644 --- a/examples/hwapi/hwconfig_esp8266_esp12.py +++ b/examples/hwapi/hwconfig_esp8266_esp12.py @@ -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) diff --git a/examples/hwapi/hwconfig_pyboard.py b/examples/hwapi/hwconfig_pyboard.py index 4db4324919..fb260033e5 100644 --- a/examples/hwapi/hwconfig_pyboard.py +++ b/examples/hwapi/hwconfig_pyboard.py @@ -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) diff --git a/examples/hwapi/hwconfig_z_frdm_k64f.py b/examples/hwapi/hwconfig_z_frdm_k64f.py index 6313e2ddb5..377c638787 100644 --- a/examples/hwapi/hwconfig_z_frdm_k64f.py +++ b/examples/hwapi/hwconfig_z_frdm_k64f.py @@ -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) diff --git a/extmod/vfs.c b/extmod/vfs.c index 84e9fe82d7..f158bd3877 100644 --- a/extmod/vfs.c +++ b/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 } diff --git a/extmod/vfs.h b/extmod/vfs.h index 4a1c225a03..edaeb53496 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -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); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index dee4f92988..0ec3fe6d2e 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -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) }, diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 7eb865254f..6c7c05a9ac 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -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); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 19db99c7f7..7c16db7e5b 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -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) { diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index 6ed4e653f8..de07d2f6d4 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -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 diff --git a/py/binary.c b/py/binary.c index 6450478cc1..34feb384ea 100644 --- a/py/binary.c +++ b/py/binary.c @@ -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 diff --git a/py/builtinimport.c b/py/builtinimport.c index cf17d53053..d01ebbe73f 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -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 diff --git a/py/lexer.c b/py/lexer.c index 05651abecf..abc1f3ebbb 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -137,23 +137,18 @@ 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 - lex->chr2 = '\n'; - } + // 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'; } } @@ -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); diff --git a/py/mkrules.mk b/py/mkrules.mk index 2ba57e0eec..b37415e050 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -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 diff --git a/py/modbuiltins.c b/py/modbuiltins.c index e8119456db..17bd30c521 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -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); diff --git a/py/modsys.c b/py/modsys.c index b208c88bd6..5fbcb944c4 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -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 diff --git a/py/mpprint.h b/py/mpprint.h index f9204e322d..4fc904a20a 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -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 diff --git a/qemu-arm/moduos.c b/qemu-arm/moduos.c index dcb67396b5..a48b51db01 100644 --- a/qemu-arm/moduos.c +++ b/qemu-arm/moduos.c @@ -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) }, diff --git a/stmhal/moduos.c b/stmhal/moduos.c index 2d648cb919..ece6019fbf 100644 --- a/stmhal/moduos.c +++ b/stmhal/moduos.c @@ -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) }, diff --git a/tests/basics/array_intbig.py b/tests/basics/array_intbig.py index 2975cd3851..4a3b2a0d42 100644 --- a/tests/basics/array_intbig.py +++ b/tests/basics/array_intbig.py @@ -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')) diff --git a/tests/basics/lexer.py b/tests/basics/lexer.py index 5f12afa70f..244de8cb98 100644 --- a/tests/basics/lexer.py +++ b/tests/basics/lexer.py @@ -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') diff --git a/tests/basics/memoryview2.py b/tests/basics/memoryview2.py index edb7c9e640..4b5af852b2 100644 --- a/tests/basics/memoryview2.py +++ b/tests/basics/memoryview2.py @@ -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])))) diff --git a/tests/basics/memoryview_intbig.py b/tests/basics/memoryview_intbig.py new file mode 100644 index 0000000000..180f15d186 --- /dev/null +++ b/tests/basics/memoryview_intbig.py @@ -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])))) diff --git a/tests/extmod/vfs_basic.py b/tests/extmod/vfs_basic.py index 1821a277dc..a3b2f3c29b 100644 --- a/tests/extmod/vfs_basic.py +++ b/tests/extmod/vfs_basic.py @@ -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')) diff --git a/tests/extmod/vfs_basic.py.exp b/tests/extmod/vfs_basic.py.exp index 416d45961a..8a23aa8ae7 100644 --- a/tests/extmod/vfs_basic.py.exp +++ b/tests/extmod/vfs_basic.py.exp @@ -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 diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index 526b3f5c1b..9036df7a5c 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -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())) diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index 7959a70eed..d777585cf7 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -10,4 +10,4 @@ e True d True -['foo_dir'] +[('foo_dir', 16384, 0)] diff --git a/tests/extmod/vfs_fat_fileio2.py b/tests/extmod/vfs_fat_fileio2.py index 111abfa7ea..b2a0ba70f4 100644 --- a/tests/extmod/vfs_fat_fileio2.py +++ b/tests/extmod/vfs_fat_fileio2.py @@ -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: diff --git a/tests/extmod/vfs_fat_fileio2.py.exp b/tests/extmod/vfs_fat_fileio2.py.exp index 38ec5c9b9d..118dee26b5 100644 --- a/tests/extmod/vfs_fat_fileio2.py.exp +++ b/tests/extmod/vfs_fat_fileio2.py.exp @@ -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 diff --git a/tests/extmod/vfs_fat_more.py b/tests/extmod/vfs_fat_more.py index 217d639956..dacb215535 100644 --- a/tests/extmod/vfs_fat_more.py +++ b/tests/extmod/vfs_fat_more.py @@ -1,10 +1,15 @@ import sys import uerrno try: - import uos_vfs as uos - open = uos.vfs_open + try: + import uos_vfs as uos + open = uos.vfs_open + except ImportError: + import uos except ImportError: - import uos + 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, '/') diff --git a/tests/extmod/vfs_fat_oldproto.py b/tests/extmod/vfs_fat_oldproto.py index 77d3492125..3e66758c36 100644 --- a/tests/extmod/vfs_fat_oldproto.py +++ b/tests/extmod/vfs_fat_oldproto.py @@ -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())) diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp index a389a52170..ab8338cbba 100644 --- a/tests/extmod/vfs_fat_oldproto.py.exp +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -1,3 +1,3 @@ -['file.txt'] +[('file.txt', 32768, 0)] hello! [] diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 81f9418b28..fe72a8beff 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -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) diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index 137db58419..ccd0f7134c 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -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 diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index aff4fd2108..483a992db1 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -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(' #include -#include +#include +#include #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; + } + + DEBUG_printf("TCP recv: new cur_pkt: %p\n", pkt); + socket->cur_pkt = pkt; } - struct net_buf *frag = socket->cur_buf->frags; + 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); diff --git a/zephyr/prj_base.conf b/zephyr/prj_base.conf index 1a0b407116..4346f20bf9 100644 --- a/zephyr/prj_base.conf +++ b/zephyr/prj_base.conf @@ -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 diff --git a/zephyr/prj_qemu_x86.conf b/zephyr/prj_qemu_x86.conf index cb90834ac0..ef60cfec91 100644 --- a/zephyr/prj_qemu_x86.conf +++ b/zephyr/prj_qemu_x86.conf @@ -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