Merge tag 'v1.9.1'
Fixes for stmhal USB mass storage, lwIP bindings and VFS regressions This release provides an important fix for the USB mass storage device in the stmhal port by implementing the SCSI SYNCHRONIZE_CACHE command, which is now require by some Operating Systems. There are also fixes for the lwIP bindings to improve non-blocking sockets and error codes. The VFS has some regressions fixed including the ability to statvfs the root. All changes are listed below. py core: - modbuiltins: add core-provided version of input() function - objstr: catch case of negative "maxsplit" arg to str.rsplit() - persistentcode: allow to compile with complex numbers disabled - objstr: allow to compile with obj-repr D, and unicode disabled - modsys: allow to compile with obj-repr D and PY_ATTRTUPLE disabled - provide mp_decode_uint_skip() to help reduce stack usage - makeqstrdefs.py: make script run correctly with Python 2.6 - objstringio: if created from immutable object, follow copy on write policy extmod: - modlwip: connect: for non-blocking mode, return EINPROGRESS - modlwip: fix error codes for duplicate calls to connect() - modlwip: accept: fix error code for non-blocking mode - vfs: allow to statvfs the root directory - vfs: allow "buffering" and "encoding" args to VFS's open() - modframebuf: fix signed/unsigned comparison pendantic warning lib: - libm: use isfinite instead of finitef, for C99 compatibility - utils/interrupt_char: remove support for KBD_EXCEPTION disabled tests: - basics/string_rsplit: add tests for negative "maxsplit" argument - float: convert "sys.exit()" to "raise SystemExit" - float/builtin_float_minmax: PEP8 fixes - basics: convert "sys.exit()" to "raise SystemExit" - convert remaining "sys.exit()" to "raise SystemExit" unix port: - convert to use core-provided version of built-in import() - Makefile: replace references to make with $(MAKE) windows port: - convert to use core-provided version of built-in import() qemu-arm port: - Makefile: adjust object-file lists to get correct dependencies - enable micropython.mem_*() functions to allow more tests stmhal port: - boards: enable DAC for NUCLEO_F767ZI board - add support for NUCLEO_F446RE board - pass USB handler as parameter to allow more than one USB handler - usb: use local USB handler variable in Start-of-Frame handler - usb: make state for USB device private to top-level USB driver - usbdev: for MSC implement SCSI SYNCHRONIZE_CACHE command - convert from using stmhal's input() to core provided version cc3200 port: - convert from using stmhal's input() to core provided version teensy port: - convert from using stmhal's input() to core provided version esp8266 port: - Makefile: replace references to make with $(MAKE) - Makefile: add clean-modules target - convert from using stmhal's input() to core provided version zephyr port: - modusocket: getaddrinfo: Fix mp_obj_len() usage - define MICROPY_PY_SYS_PLATFORM (to "zephyr") - machine_pin: use native Zephyr types for Zephyr API calls docs: - machine.Pin: remove out_value() method - machine.Pin: add on() and off() methods - esp8266: consistently replace Pin.high/low methods with .on/off - esp8266/quickref: polish Pin.on()/off() examples - network: move confusingly-named cc3200 Server class to its reference - uos: deconditionalize, remove minor port-specific details - uos: move cc3200 port legacy VFS mounting functions to its ref doc - machine: sort machine classes in logical order, not alphabetically - network: first step to describe standard network class interface examples: - embedding: use core-provided KeyboardInterrupt object
This commit is contained in:
commit
30ee7019ca
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -10,11 +10,11 @@
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.dxf binary
|
||||
*.mpy binary
|
||||
|
||||
# These should also not be modified by git.
|
||||
tests/basics/string_cr_conversion.py -text
|
||||
tests/basics/string_crlf_conversion.py -text
|
||||
stmhal/startup_stm32f40xx.s -text
|
||||
stmhal/pybcdc.inf_template -text
|
||||
stmhal/usbd_* -text
|
||||
stmhal/boards/*/stm32f4xx_hal_conf.h -text
|
||||
@ -28,4 +28,3 @@ cc3200/hal/des.c -text
|
||||
cc3200/hal/i2s.c -text
|
||||
cc3200/hal/i2s.h -text
|
||||
cc3200/version.h -text
|
||||
lib/fatfs/** -text
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -44,3 +44,7 @@ user.props
|
||||
# Sphinx output
|
||||
###############
|
||||
_build
|
||||
|
||||
# Generated rst files
|
||||
######################
|
||||
genrst/
|
||||
|
@ -60,7 +60,7 @@ script:
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --emit native)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --via-mpy -d basics float)
|
||||
|
||||
after_success:
|
||||
# run coveralls coverage analysis (try to, even if some builds/tests failed)
|
||||
- (cd unix && coveralls --root .. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
after_failure:
|
||||
|
@ -125,7 +125,7 @@ CFLAGS_CORTEX_M0 = \
|
||||
-DCIRCUITPY_CANARY_WORD=0xADAF00 \
|
||||
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
|
||||
--param max-inline-insns-single=500
|
||||
CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(COPT)
|
||||
CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(CFLAGS_MOD) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
# TODO(tannewt): Figure out what NDEBUG does. Adding it to the debug build
|
||||
@ -184,7 +184,6 @@ SRC_C = \
|
||||
access_vfs.c \
|
||||
autoreload.c \
|
||||
background.c \
|
||||
builtin_open.c \
|
||||
fatfs_port.c \
|
||||
flash_api.c \
|
||||
main.c \
|
||||
@ -213,17 +212,15 @@ SRC_C = \
|
||||
boards/$(BOARD)/board.c \
|
||||
boards/$(BOARD)/pins.c \
|
||||
freetouch/adafruit_ptc.c \
|
||||
lib/fatfs/ff.c \
|
||||
lib/fatfs/option/ccsbcs.c \
|
||||
lib/oofatfs/ff.c \
|
||||
lib/oofatfs/option/ccsbcs.c \
|
||||
lib/timeutils/timeutils.c \
|
||||
lib/utils/buffer_helper.c \
|
||||
lib/utils/context_manager_helpers.c \
|
||||
lib/utils/interrupt_char.c \
|
||||
lib/utils/pyexec.c \
|
||||
lib/utils/pyhelp.c \
|
||||
lib/utils/stdout_helpers.c \
|
||||
lib/libc/string0.c \
|
||||
lib/mp-readline/builtin_input.c \
|
||||
lib/mp-readline/readline.c
|
||||
|
||||
STM_SRC_C = $(addprefix stmhal/,\
|
||||
@ -261,14 +258,14 @@ SRC_COMMON_HAL = \
|
||||
SRC_BINDINGS_ENUMS = \
|
||||
digitalio/Direction.c \
|
||||
digitalio/DriveMode.c \
|
||||
digitalio/Pull.c
|
||||
digitalio/Pull.c \
|
||||
help.c
|
||||
|
||||
SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \
|
||||
$(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \
|
||||
$(addprefix common-hal/, $(SRC_COMMON_HAL))
|
||||
|
||||
SRC_SHARED_MODULE = \
|
||||
help.c \
|
||||
bitbangio/__init__.c \
|
||||
bitbangio/I2C.c \
|
||||
bitbangio/OneWire.c \
|
||||
|
@ -30,8 +30,11 @@
|
||||
#include "autoreload.h"
|
||||
|
||||
#include "asf/common/services/usb/class/msc/device/udi_msc.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "lib/oofatfs/ffconf.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mpstate.h"
|
||||
@ -47,15 +50,14 @@
|
||||
//! An error occurred -> CTRL_FAIL
|
||||
Ctrl_status vfs_test_unit_ready(void)
|
||||
{
|
||||
if (VFS_INDEX >= MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
|
||||
return CTRL_FAIL;
|
||||
}
|
||||
DSTATUS status = disk_status(VFS_INDEX);
|
||||
if (status == STA_NOINIT) {
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
|
||||
mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
|
||||
for (uint8_t i = 0; current_mount != NULL; i++) {
|
||||
if (i == VFS_INDEX) {
|
||||
return CTRL_GOOD;
|
||||
}
|
||||
current_mount = current_mount->next;
|
||||
}
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
|
||||
//! This function returns the address of the last valid sector
|
||||
@ -81,13 +83,17 @@ Ctrl_status vfs_read_capacity(uint32_t *last_valid_sector)
|
||||
//!
|
||||
bool vfs_wr_protect(void)
|
||||
{
|
||||
if (VFS_INDEX >= MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
|
||||
return true;
|
||||
}
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[VFS_INDEX];
|
||||
if (vfs == NULL) {
|
||||
mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
|
||||
for (uint8_t i = 0; current_mount != NULL; i++) {
|
||||
if (i == VFS_INDEX) {
|
||||
break;
|
||||
}
|
||||
current_mount = current_mount->next;
|
||||
}
|
||||
if (current_mount == NULL) {
|
||||
return true;
|
||||
}
|
||||
fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj;
|
||||
|
||||
// This is used to determine the writeability of the disk from USB.
|
||||
if (vfs->writeblocks[0] == MP_OBJ_NULL ||
|
||||
@ -170,9 +176,18 @@ Ctrl_status vfs_usb_write_10(uint32_t addr, volatile uint16_t nb_sector)
|
||||
}
|
||||
// Since by getting here we assume the mount is read-only to MicroPython
|
||||
// lets update the cached FatFs sector if its the one we just wrote.
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[VFS_INDEX];
|
||||
volatile uint16_t x = addr;
|
||||
(void) x;
|
||||
mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
|
||||
for (uint8_t i = 0; current_mount != NULL; i++) {
|
||||
if (i == VFS_INDEX) {
|
||||
break;
|
||||
}
|
||||
current_mount = current_mount->next;
|
||||
}
|
||||
if (current_mount == NULL) {
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj;
|
||||
|
||||
#if _MAX_SS != _MIN_SS
|
||||
if (vfs->ssize == FILESYSTEM_BLOCK_SIZE) {
|
||||
#else
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/runtime.h"
|
||||
|
@ -26,19 +26,8 @@
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h" /* FatFs lower layer API */
|
||||
#include "lib/fatfs/diskio.h" /* FatFs lower layer API */
|
||||
|
||||
const PARTITION VolToPart[MICROPY_FATFS_VOLUMES] = {
|
||||
{0, 1}, // Logical drive 0 ==> Physical drive 0, 1st partition
|
||||
{1, 0}, // Logical drive 1 ==> Physical drive 1 (auto detection)
|
||||
{2, 0}, // Logical drive 2 ==> Physical drive 2 (auto detection)
|
||||
{3, 0}, // Logical drive 3 ==> Physical drive 3 (auto detection)
|
||||
/*
|
||||
{0, 2}, // Logical drive 2 ==> Physical drive 0, 2nd partition
|
||||
{0, 3}, // Logical drive 3 ==> Physical drive 0, 3rd partition
|
||||
*/
|
||||
};
|
||||
#include "lib/oofatfs/ff.h" /* FatFs lower layer API */
|
||||
#include "lib/oofatfs/diskio.h" /* FatFs lower layer API */
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
// TODO(tannewt): Support the RTC.
|
||||
|
@ -31,13 +31,17 @@
|
||||
#define VFS_INDEX 0
|
||||
|
||||
void flash_set_usb_writeable(bool usb_writeable) {
|
||||
if (VFS_INDEX >= MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
|
||||
return;
|
||||
}
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[VFS_INDEX];
|
||||
if (vfs == NULL) {
|
||||
mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
|
||||
for (uint8_t i = 0; current_mount != NULL; i++) {
|
||||
if (i == VFS_INDEX) {
|
||||
break;
|
||||
}
|
||||
current_mount = current_mount->next;
|
||||
}
|
||||
if (current_mount == NULL) {
|
||||
return;
|
||||
}
|
||||
fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj;
|
||||
|
||||
if (usb_writeable) {
|
||||
vfs->flags |= FSUSER_USB_WRITEABLE;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_FLASH_API_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_FLASH_API_H__
|
||||
|
||||
#include "extmod/fsusermount.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
|
||||
extern void flash_init_vfs(fs_user_mount_t *vfs);
|
||||
extern void flash_flush(void);
|
||||
|
@ -28,11 +28,12 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include "py/gc.h"
|
||||
#include "py/stackctrl.h"
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "asf/common/services/sleepmgr/sleepmgr.h"
|
||||
#include "asf/common/services/usb/udc/udc.h"
|
||||
@ -48,6 +48,7 @@
|
||||
#include "tick.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
mp_vfs_mount_t mp_vfs_mount_flash;
|
||||
|
||||
typedef enum {
|
||||
NO_SAFE_MODE = 0,
|
||||
@ -80,39 +81,42 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
// want it to be executed without using stack within main() function
|
||||
void init_flash_fs(void) {
|
||||
// init the vfs object
|
||||
fs_user_mount_t *vfs = &fs_user_mount_flash;
|
||||
vfs->str = "/flash";
|
||||
vfs->len = 6;
|
||||
vfs->flags = 0;
|
||||
flash_init_vfs(vfs);
|
||||
|
||||
// put the flash device in slot 0 (it will be unused at this point)
|
||||
MP_STATE_PORT(fs_user_mount)[0] = vfs;
|
||||
fs_user_mount_t *vfs_fat = &fs_user_mount_flash;
|
||||
vfs_fat->flags = 0;
|
||||
flash_init_vfs(vfs_fat);
|
||||
|
||||
// try to mount the flash
|
||||
FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1);
|
||||
FRESULT res = f_mount(&vfs_fat->fatfs);
|
||||
|
||||
if (res == FR_NO_FILESYSTEM) {
|
||||
// no filesystem so create a fresh one
|
||||
|
||||
res = f_mkfs("/flash", 0, 0);
|
||||
uint8_t working_buf[_MAX_SS];
|
||||
res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf));
|
||||
// Flush the new file system to make sure its repaired immediately.
|
||||
flash_flush();
|
||||
if (res != FR_OK) {
|
||||
MP_STATE_PORT(fs_user_mount)[0] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// set label
|
||||
f_setlabel("CIRCUITPY");
|
||||
f_setlabel(&vfs_fat->fatfs, "CIRCUITPY");
|
||||
} else if (res != FR_OK) {
|
||||
MP_STATE_PORT(fs_user_mount)[0] = NULL;
|
||||
return;
|
||||
}
|
||||
mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t);
|
||||
if (vfs == NULL) {
|
||||
return;
|
||||
}
|
||||
vfs->str = "/";
|
||||
vfs->len = 1;
|
||||
vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
|
||||
vfs->next = NULL;
|
||||
MP_STATE_VM(vfs_mount_table) = vfs;
|
||||
|
||||
// The current directory is used as the boot up directory.
|
||||
// It is set to the internal flash filesystem by default.
|
||||
f_chdrive("/flash");
|
||||
MP_STATE_PORT(vfs_cur) = vfs;
|
||||
}
|
||||
|
||||
static char heap[16384];
|
||||
@ -124,9 +128,7 @@ void reset_mp(void) {
|
||||
|
||||
// Sync the file systems in case any used RAM from the GC to cache. As soon
|
||||
// as we re-init the GC all bets are off on the cache.
|
||||
disk_ioctl(0, CTRL_SYNC, NULL);
|
||||
disk_ioctl(1, CTRL_SYNC, NULL);
|
||||
disk_ioctl(2, CTRL_SYNC, NULL);
|
||||
flash_flush();
|
||||
|
||||
// Clear the readline history. It references the heap we're about to destroy.
|
||||
readline_init0();
|
||||
@ -230,13 +232,8 @@ void reset_samd21(void) {
|
||||
}
|
||||
|
||||
bool maybe_run(const char* filename, pyexec_result_t* exec_result) {
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
FRESULT res = f_stat(filename, &fno);
|
||||
if (res != FR_OK || fno.fattrib & AM_DIR) {
|
||||
mp_import_stat_t stat = mp_import_stat(filename);
|
||||
if (stat != MP_IMPORT_STAT_FILE) {
|
||||
return false;
|
||||
}
|
||||
mp_hal_stdout_tx_str(filename);
|
||||
@ -607,7 +604,8 @@ int main(void) {
|
||||
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
|
||||
FIL file_pointer;
|
||||
boot_output_file = &file_pointer;
|
||||
f_open(boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_open(&((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs,
|
||||
boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
|
||||
#endif
|
||||
|
||||
// TODO(tannewt): Re-add support for flashing boot error output.
|
||||
@ -688,17 +686,8 @@ void gc_collect(void) {
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
mp_import_stat_t fat_vfs_import_stat(const char *path);
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
#if MICROPY_VFS_FAT
|
||||
return fat_vfs_import_stat(path);
|
||||
#else
|
||||
(void)path;
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
#endif
|
||||
}
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
void NORETURN nlr_jump_fail(void *val) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
void NORETURN __fatal_error(const char *msg) {
|
||||
|
@ -32,11 +32,11 @@
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "timeutils.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
/// \module os - basic "operating system" services
|
||||
///
|
||||
@ -76,285 +76,42 @@ STATIC mp_obj_t os_uname(void) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
|
||||
/// \function chdir(path)
|
||||
/// Change current directory.
|
||||
STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
|
||||
const char *path;
|
||||
path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FRESULT res = f_chdrive(path);
|
||||
|
||||
if (res == FR_OK) {
|
||||
res = f_chdir(path);
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
// TODO should be mp_type_FileNotFoundError
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
|
||||
|
||||
/// \function getcwd()
|
||||
/// Get the current directory.
|
||||
STATIC mp_obj_t os_getcwd(void) {
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
FRESULT res = f_getcwd(buf, sizeof buf);
|
||||
|
||||
if (res != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
return mp_obj_new_str(buf, strlen(buf), false);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
|
||||
|
||||
/// \function listdir([dir])
|
||||
/// With no argument, list the current directory. Otherwise list the given directory.
|
||||
STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
bool is_str_type = true;
|
||||
const char *path;
|
||||
if (n_args == 1) {
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_bytes) {
|
||||
is_str_type = false;
|
||||
}
|
||||
path = mp_obj_str_get_str(args[0]);
|
||||
} else {
|
||||
path = "";
|
||||
}
|
||||
|
||||
// "hack" to list root directory
|
||||
if (path[0] == '/' && path[1] == '\0') {
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
|
||||
if (vfs != NULL) {
|
||||
mp_obj_list_append(dir_list, mp_obj_new_str(vfs->str + 1, vfs->len - 1, false));
|
||||
}
|
||||
}
|
||||
return dir_list;
|
||||
}
|
||||
|
||||
return fat_vfs_listdir(path, is_str_type);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
|
||||
|
||||
/// \function mkdir(path)
|
||||
/// Create a new directory.
|
||||
STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_mkdir(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
case FR_EXIST:
|
||||
// TODO should be FileExistsError
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path));
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
|
||||
|
||||
/// \function remove(path)
|
||||
/// Remove a file.
|
||||
STATIC mp_obj_t os_remove(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
// TODO check that path is actually a file before trying to unlink it
|
||||
FRESULT res = f_unlink(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
|
||||
|
||||
/// \function rename(old_path, new_path)
|
||||
/// Rename a file
|
||||
STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) {
|
||||
const char *old_path = mp_obj_str_get_str(path_in);
|
||||
const char *new_path = mp_obj_str_get_str(path_out);
|
||||
FRESULT res = f_rename(old_path, new_path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error renaming file '%s' to '%s'", old_path, new_path));
|
||||
}
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
|
||||
|
||||
/// \function rmdir(path)
|
||||
/// Remove a directory.
|
||||
STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
// TODO check that path is actually a directory before trying to unlink it
|
||||
FRESULT res = f_unlink(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir);
|
||||
|
||||
// Checks for path equality, ignoring trailing slashes:
|
||||
// path_equal(/, /) -> true
|
||||
// path_equal(/flash//, /flash) -> true
|
||||
// second argument must be in canonical form (meaning no trailing slash, unless it's just /)
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical) {
|
||||
for (; *path_canonical != '\0' && *path == *path_canonical; ++path, ++path_canonical) {
|
||||
}
|
||||
if (*path_canonical != '\0') {
|
||||
return false;
|
||||
}
|
||||
for (; *path == '/'; ++path) {
|
||||
}
|
||||
return *path == '\0';
|
||||
}
|
||||
|
||||
/// \function stat(path)
|
||||
/// Get the status of a file or directory.
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
FRESULT res;
|
||||
if (path_equal(path, "/")) {
|
||||
// stat root directory
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
} else {
|
||||
res = FR_NO_PATH;
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
|
||||
if (vfs != NULL && path_equal(path, vfs->str)) {
|
||||
// stat mounted device directory
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
res = FR_OK;
|
||||
}
|
||||
}
|
||||
if (res == FR_NO_PATH) {
|
||||
// stat normal file
|
||||
res = f_stat(path, &fno);
|
||||
}
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
mp_int_t mode = 0;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
mode |= 0x4000; // stat.S_IFDIR
|
||||
} else {
|
||||
mode |= 0x8000; // stat.S_IFREG
|
||||
}
|
||||
mp_int_t seconds = timeutils_seconds_since_2000(
|
||||
1980 + ((fno.fdate >> 9) & 0x7f),
|
||||
(fno.fdate >> 5) & 0x0f,
|
||||
fno.fdate & 0x1f,
|
||||
(fno.ftime >> 11) & 0x1f,
|
||||
(fno.ftime >> 5) & 0x3f,
|
||||
2 * (fno.ftime & 0x1f)
|
||||
);
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime
|
||||
|
||||
return t;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
STATIC mp_obj_t os_statvfs(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
DWORD nclst;
|
||||
FATFS *fatfs;
|
||||
FRESULT res = f_getfree(path, &nclst, &fatfs);
|
||||
if (res != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * 512); // f_bsize - block size
|
||||
t->items[1] = t->items[0]; // f_frsize - fragment size
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // f_blocks - total number of blocks
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree - number of free blocks
|
||||
t->items[4] = t->items[3]; // f_bavail - free blocks avail to unpriviledged users
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files - # inodes
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree - # free inodes
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail - # free inodes avail to unpriviledges users
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax
|
||||
|
||||
return t;
|
||||
|
||||
error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_statvfs_obj, os_statvfs);
|
||||
|
||||
/// \function sync()
|
||||
/// Sync all filesystems.
|
||||
STATIC mp_obj_t os_sync(void) {
|
||||
disk_ioctl(0, CTRL_SYNC, NULL);
|
||||
disk_ioctl(1, CTRL_SYNC, NULL);
|
||||
disk_ioctl(2, CTRL_SYNC, NULL);
|
||||
for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
|
||||
// this assumes that vfs->obj is fs_user_mount_t with block device functions
|
||||
disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
|
||||
|
||||
STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uname), (mp_obj_t)&os_uname_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chdir), (mp_obj_t)&os_chdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getcwd), (mp_obj_t)&os_getcwd_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listdir), (mp_obj_t)&os_listdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename),(mp_obj_t)&os_rename_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_rmdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_statvfs), (mp_obj_t)&os_statvfs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&mod_os_sync_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) },
|
||||
|
||||
/// \constant sep - separation character used in paths
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },
|
||||
|
||||
// these are MicroPython extensions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&fsuser_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umount), (mp_obj_t)&fsuser_umount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&fsuser_mkfs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
@ -38,6 +38,10 @@
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP_TEXT circuitpython_help_text
|
||||
#define MICROPY_PY_BUILTINS_INPUT (1)
|
||||
#define MICROPY_PY_BUILTINS_FILTER (1)
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (1)
|
||||
@ -69,13 +73,13 @@
|
||||
#define MICROPY_FATFS_VOLUMES (4)
|
||||
#define MICROPY_FATFS_MULTI_PARTITION (1)
|
||||
#define MICROPY_FATFS_NUM_PERSISTENT (1)
|
||||
#define MICROPY_FSUSERMOUNT (1)
|
||||
// Only enable this if you really need it. It allocates a byte cache of this
|
||||
// size.
|
||||
// #define MICROPY_FATFS_MAX_SS (4096)
|
||||
|
||||
#define FILESYSTEM_BLOCK_SIZE (512)
|
||||
|
||||
#define MICROPY_VFS (1)
|
||||
#define MICROPY_VFS_FAT (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (0)
|
||||
@ -85,7 +89,7 @@
|
||||
#define MICROPY_USE_INTERNAL_PRINTF (1)
|
||||
#define MICROPY_PY_SYS_STDFILES (1)
|
||||
#define MICROPY_PY_IO_FILEIO (1)
|
||||
#define MICROPY_READER_FATFS (1)
|
||||
#define MICROPY_READER_VFS (1)
|
||||
#define MICROPY_PERSISTENT_CODE_LOAD (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
|
||||
@ -112,6 +116,9 @@ typedef long mp_off_t;
|
||||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
#define mp_import_stat mp_vfs_import_stat
|
||||
#define mp_builtin_open_obj mp_vfs_open_obj
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
|
||||
#define USB_RX_BUF_SIZE 128
|
||||
|
||||
|
@ -30,11 +30,12 @@
|
||||
|
||||
#include "asf/sam0/drivers/sercom/spi/spi.h"
|
||||
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
|
||||
#include "rgb_led_status.h"
|
||||
#include "shared_dma.h"
|
||||
|
@ -13,7 +13,7 @@ INC += -I..
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
|
@ -6,15 +6,12 @@
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/repl.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
if (lex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
@ -35,7 +32,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
return NULL;
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
@ -48,6 +45,7 @@ mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs)
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
void NORETURN __fatal_error(const char *msg) {
|
||||
|
@ -46,8 +46,6 @@
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
|
||||
#define UINT_FMT "%lu"
|
||||
|
@ -20,9 +20,10 @@ include ../py/mkenv.mk
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -march=armv7e-m -mabi=aapcs -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) -Os
|
||||
CFLAGS = -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) -Os
|
||||
CFLAGS += -g -ffunction-sections -fdata-sections -fno-common -fsigned-char -mno-unaligned-access
|
||||
CFLAGS += -Iboards/$(BOARD)
|
||||
CFLAGS += $(CFLAGS_MOD)
|
||||
|
||||
LDFLAGS = -Wl,-nostdlib -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
|
@ -138,7 +138,7 @@ If `WIPY_IP`, `WIPY_USER` or `WIPY_PWD` are omitted the default values (the ones
|
||||
## Regarding old revisions of the CC3200-LAUNCHXL
|
||||
|
||||
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and MicroPython cannot run
|
||||
there. Make sure to use a **v4.1 (or higer) LAUNCHXL board** when trying this port, otherwise it won't work.
|
||||
there. Make sure to use a **v4.1 (or higher) LAUNCHXL board** when trying this port, otherwise it won't work.
|
||||
|
||||
### Note regarding FileZilla
|
||||
|
||||
|
@ -18,10 +18,6 @@ APP_INC += -Iutil
|
||||
APP_INC += -Ibootmgr
|
||||
APP_INC += -I$(BUILD)
|
||||
APP_INC += -I$(BUILD)/genhdr
|
||||
APP_INC += -I../lib/fatfs
|
||||
APP_INC += -I../lib/mp-readline
|
||||
APP_INC += -I../lib/netutils
|
||||
APP_INC += -I../lib/timeutils
|
||||
APP_INC += -I../stmhal
|
||||
|
||||
APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS
|
||||
@ -29,9 +25,6 @@ APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS
|
||||
APP_FATFS_SRC_C = $(addprefix fatfs/src/,\
|
||||
drivers/sflash_diskio.c \
|
||||
drivers/sd_diskio.c \
|
||||
option/syscall.c \
|
||||
diskio.c \
|
||||
ffconf.c \
|
||||
)
|
||||
|
||||
APP_RTOS_SRC_C = $(addprefix FreeRTOS/Source/,\
|
||||
@ -81,7 +74,6 @@ APP_MISC_SRC_C = $(addprefix misc/,\
|
||||
mpirq.c \
|
||||
mperror.c \
|
||||
mpexception.c \
|
||||
mpsystick.c \
|
||||
)
|
||||
|
||||
APP_MODS_SRC_C = $(addprefix mods/,\
|
||||
@ -98,6 +90,7 @@ APP_MODS_SRC_C = $(addprefix mods/,\
|
||||
pybpin.c \
|
||||
pybi2c.c \
|
||||
pybrtc.c \
|
||||
pybflash.c \
|
||||
pybsd.c \
|
||||
pybsleep.c \
|
||||
pybspi.c \
|
||||
@ -143,24 +136,21 @@ APP_MAIN_SRC_C = \
|
||||
main.c \
|
||||
mptask.c \
|
||||
mpthreadport.c \
|
||||
serverstask.c
|
||||
serverstask.c \
|
||||
fatfs_port.c \
|
||||
|
||||
APP_LIB_SRC_C = $(addprefix lib/,\
|
||||
fatfs/ff.c \
|
||||
fatfs/option/ccsbcs.c \
|
||||
oofatfs/ff.c \
|
||||
oofatfs/option/unicode.c \
|
||||
libc/string0.c \
|
||||
mp-readline/readline.c \
|
||||
netutils/netutils.c \
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/pyhelp.c \
|
||||
)
|
||||
|
||||
APP_STM_SRC_C = $(addprefix stmhal/,\
|
||||
bufhelper.c \
|
||||
builtin_open.c \
|
||||
import.c \
|
||||
input.c \
|
||||
irq.c \
|
||||
pybstdio.c \
|
||||
)
|
||||
|
@ -26,8 +26,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "std.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "hw_ints.h"
|
||||
|
@ -1,209 +0,0 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various exsisting */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/obj.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h" /* FatFs lower layer API */
|
||||
#include "sflash_diskio.h" /* Serial flash disk IO API */
|
||||
#include "sd_diskio.h" /* SDCARD disk IO API */
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "timeutils.h"
|
||||
#include "pybsd.h"
|
||||
#include "moduos.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_status();
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
if (mount_obj->writeblocks[0] == MP_OBJ_NULL) {
|
||||
return STA_PROTECT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return STA_NODISK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
if (pdrv == PD_FLASH) {
|
||||
if (RES_OK != sflash_disk_init()) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
if (mount_obj->writeblocks[0] == MP_OBJ_NULL) {
|
||||
return STA_PROTECT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return STA_NODISK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_read(buff, sector, count);
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
return sd_disk_read(buff, sector, count);
|
||||
}
|
||||
mount_obj->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
|
||||
mount_obj->readblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, buff);
|
||||
return mp_obj_get_int(mp_call_method_n_kw(2, 0, mount_obj->readblocks));
|
||||
}
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if _USE_WRITE
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (pdrv == PD_FLASH) {
|
||||
return sflash_disk_write(buff, sector, count);
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
return sd_disk_write(buff, sector, count);
|
||||
}
|
||||
mount_obj->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
|
||||
mount_obj->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, (void *)buff);
|
||||
return mp_obj_get_int(mp_call_method_n_kw(2, 0, mount_obj->writeblocks));
|
||||
}
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if _USE_IOCTL
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
if (pdrv == PD_FLASH) {
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
return sflash_disk_flush();
|
||||
case GET_SECTOR_COUNT:
|
||||
*((DWORD*)buff) = SFLASH_SECTOR_COUNT;
|
||||
return RES_OK;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((DWORD*)buff) = SFLASH_SECTOR_SIZE;
|
||||
return RES_OK;
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = 1; // high-level sector erase size in units of the block size
|
||||
return RES_OK;
|
||||
}
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(pdrv))) {
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
if (mount_obj->sync[0] != MP_OBJ_NULL) {
|
||||
mp_call_method_n_kw(0, 0, mount_obj->sync);
|
||||
}
|
||||
return RES_OK;
|
||||
case GET_SECTOR_COUNT:
|
||||
// optimization for the built-in sd card device
|
||||
if (mount_obj->device == (mp_obj_t)&pybsd_obj) {
|
||||
*((DWORD*)buff) = sd_disk_info.ulNofBlock * (sd_disk_info.ulBlockSize / 512);
|
||||
} else {
|
||||
*((DWORD*)buff) = mp_obj_get_int(mp_call_method_n_kw(0, 0, mount_obj->count));
|
||||
}
|
||||
return RES_OK;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((DWORD*)buff) = SD_SECTOR_SIZE; // Sector size is fixed to 512 bytes, as with SD cards
|
||||
return RES_OK;
|
||||
case GET_BLOCK_SIZE:
|
||||
*((DWORD*)buff) = 1; // high-level sector erase size in units of the block size
|
||||
return RES_OK;
|
||||
}
|
||||
}
|
||||
// nothing mounted
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !_FS_READONLY && !_FS_NORTC
|
||||
DWORD get_fattime (
|
||||
void
|
||||
)
|
||||
{
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
|
||||
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) |
|
||||
((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) |
|
||||
((tm.tm_min) << 5) | (tm.tm_sec >> 1);
|
||||
}
|
||||
#endif
|
||||
|
@ -39,11 +39,12 @@
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "hw_types.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "hw_ints.h"
|
||||
#include "rom_map.h"
|
||||
#include "diskio.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "sdhost.h"
|
||||
#include "pin.h"
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "std.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "simplelink.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "debug.h"
|
||||
#include "modnetwork.h"
|
||||
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/ffconf.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "moduos.h"
|
||||
|
||||
#if _FS_RPATH
|
||||
extern BYTE ff_CurrVol;
|
||||
#endif
|
||||
|
||||
STATIC bool check_path(const TCHAR **path, const char *mount_point_str, mp_uint_t mount_point_len) {
|
||||
if (strncmp(*path, mount_point_str, mount_point_len) == 0) {
|
||||
if ((*path)[mount_point_len] == '/') {
|
||||
*path += mount_point_len;
|
||||
return true;
|
||||
} else if ((*path)[mount_point_len] == '\0') {
|
||||
*path = "/";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// "path" is the path to lookup; will advance this pointer beyond the volume name.
|
||||
// Returns logical drive number (-1 means invalid path).
|
||||
int ff_get_ldnumber (const TCHAR **path) {
|
||||
if (!(*path)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (**path != '/') {
|
||||
#if _FS_RPATH
|
||||
return ff_CurrVol;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (check_path(path, "/flash", 6)) {
|
||||
return PD_FLASH;
|
||||
}
|
||||
else {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (check_path(path, mount_obj->path, mount_obj->pathlen)) {
|
||||
return mount_obj->vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ff_get_volname(BYTE vol, TCHAR **dest) {
|
||||
if (vol == PD_FLASH) {
|
||||
memcpy(*dest, "/flash", 6);
|
||||
*dest += 6;
|
||||
} else {
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_volume(vol))) {
|
||||
memcpy(*dest, mount_obj->path, mount_obj->pathlen);
|
||||
*dest += mount_obj->pathlen;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample code of OS dependent controls for FatFs */
|
||||
/* (C)ChaN, 2014 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
|
||||
#if _FS_REENTRANT
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
|
||||
BYTE vol, /* Corresponding logical drive being processed */
|
||||
_SYNC_t *sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
//
|
||||
// *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
|
||||
// ret = (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
|
||||
// ret = 1; /* The initial value of the semaphore must be 1. */
|
||||
|
||||
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
vSemaphoreCreateBinary( (*sobj) ); /* FreeRTOS */
|
||||
ret = (int)(*sobj != NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
|
||||
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
// ret = CloseHandle(sobj); /* Win32 */
|
||||
|
||||
// ret = 1; /* uITRON (nothing to do) */
|
||||
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
vSemaphoreDelete(sobj); /* FreeRTOS */
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
|
||||
|
||||
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
|
||||
|
||||
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
// ReleaseMutex(sobj); /* Win32 */
|
||||
|
||||
// sig_sem(sobj); /* uITRON */
|
||||
|
||||
// OSMutexPost(sobj); /* uC/OS-II */
|
||||
|
||||
xSemaphoreGive(sobj); /* FreeRTOS */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
|
||||
*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return pvPortMalloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free */
|
||||
)
|
||||
{
|
||||
vPortFree(mblock); /* Discard the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
74
cc3200/fatfs_port.c
Normal file
74
cc3200/fatfs_port.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2017 Damien P. George
|
||||
* Parts of this file are (C)ChaN, 2014, from FatFs option/syscall.c
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "mods/pybrtc.h"
|
||||
|
||||
#if _FS_REENTRANT
|
||||
// Create a Synchronization Object
|
||||
// This function is called in f_mount() function to create a new
|
||||
// synchronization object, such as semaphore and mutex.
|
||||
// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR.
|
||||
int ff_cre_syncobj(FATFS *fatfs, _SYNC_t *sobj) {
|
||||
vSemaphoreCreateBinary((*sobj));
|
||||
return (int)(*sobj != NULL);
|
||||
}
|
||||
|
||||
// Delete a Synchronization Object
|
||||
// This function is called in f_mount() function to delete a synchronization
|
||||
// object that created with ff_cre_syncobj function.
|
||||
// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR.
|
||||
int ff_del_syncobj(_SYNC_t sobj) {
|
||||
vSemaphoreDelete(sobj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Request Grant to Access the Volume
|
||||
// This function is called on entering file functions to lock the volume.
|
||||
// When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
int ff_req_grant(_SYNC_t sobj) {
|
||||
return (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE);
|
||||
}
|
||||
|
||||
// Release Grant to Access the Volume
|
||||
// This function is called on leaving file functions to unlock the volume.
|
||||
void ff_rel_grant(_SYNC_t sobj) {
|
||||
xSemaphoreGive(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
|
||||
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) |
|
||||
((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) |
|
||||
((tm.tm_min) << 5) | (tm.tm_sec >> 1);
|
||||
}
|
161
cc3200/ftp/ftp.c
161
cc3200/ftp/ftp.c
@ -25,11 +25,14 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include "std.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/obj.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
@ -43,11 +46,9 @@
|
||||
#include "modusocket.h"
|
||||
#include "debug.h"
|
||||
#include "serverstask.h"
|
||||
#include "ff.h"
|
||||
#include "fifo.h"
|
||||
#include "socketfifo.h"
|
||||
#include "updater.h"
|
||||
#include "timeutils.h"
|
||||
#include "moduos.h"
|
||||
|
||||
/******************************************************************************
|
||||
@ -115,7 +116,7 @@ typedef struct {
|
||||
uint8_t *dBuffer;
|
||||
uint32_t ctimeout;
|
||||
union {
|
||||
DIR dp;
|
||||
FF_DIR dp;
|
||||
FIL fp;
|
||||
};
|
||||
int16_t lc_sd;
|
||||
@ -192,6 +193,80 @@ static const ftp_month_t ftp_month[] = { { "Jan" }, { "Feb" }, { "Mar" }, { "Apr
|
||||
static SocketFifoElement_t ftp_fifoelements[FTP_SOCKETFIFO_ELEMENTS_MAX];
|
||||
static FIFO_t ftp_socketfifo;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE VFS WRAPPER FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
// These wrapper functions are used so that the FTP server can access the
|
||||
// mounted FATFS devices directly without going through the costly mp_vfs_XXX
|
||||
// functions. The latter may raise exceptions and we would then need to wrap
|
||||
// all calls in an nlr handler. The wrapper functions below assume that there
|
||||
// are only FATFS filesystems mounted.
|
||||
|
||||
STATIC FATFS *lookup_path(const TCHAR **path) {
|
||||
mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path);
|
||||
if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) {
|
||||
return NULL;
|
||||
}
|
||||
// here we assume that the mounted device is FATFS
|
||||
return &((fs_user_mount_t*)MP_OBJ_TO_PTR(fs->obj))->fatfs;
|
||||
}
|
||||
|
||||
STATIC FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_open(fs, fp, path, mode);
|
||||
}
|
||||
|
||||
STATIC FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_opendir(fs, dp, path);
|
||||
}
|
||||
|
||||
STATIC FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_stat(fs, path, fno);
|
||||
}
|
||||
|
||||
STATIC FRESULT f_mkdir_helper(const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_mkdir(fs, path);
|
||||
}
|
||||
|
||||
STATIC FRESULT f_unlink_helper(const TCHAR *path) {
|
||||
FATFS *fs = lookup_path(&path);
|
||||
if (fs == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_unlink(fs, path);
|
||||
}
|
||||
|
||||
STATIC FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new) {
|
||||
FATFS *fs_old = lookup_path(&path_old);
|
||||
if (fs_old == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
FATFS *fs_new = lookup_path(&path_new);
|
||||
if (fs_new == NULL) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
if (fs_old != fs_new) {
|
||||
return FR_NO_PATH;
|
||||
}
|
||||
return f_rename(fs_new, path_old, path_new);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@ -210,7 +285,7 @@ static void ftp_close_cmd_data (void);
|
||||
static ftp_cmd_index_t ftp_pop_command (char **str);
|
||||
static void ftp_pop_param (char **str, char *param);
|
||||
static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno);
|
||||
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name);
|
||||
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, const char *name);
|
||||
static bool ftp_open_file (const char *path, int mode);
|
||||
static ftp_result_t ftp_read_file (char *filebuf, uint32_t desiredsize, uint32_t *actualsize);
|
||||
static ftp_result_t ftp_write_file (char *filebuf, uint32_t size);
|
||||
@ -424,12 +499,12 @@ static void ftp_wait_for_enabled (void) {
|
||||
|
||||
static bool ftp_create_listening_socket (_i16 *sd, _u16 port, _u8 backlog) {
|
||||
SlSockNonblocking_t nonBlockingOption;
|
||||
sockaddr_in sServerAddress;
|
||||
SlSockAddrIn_t sServerAddress;
|
||||
_i16 _sd;
|
||||
_i16 result;
|
||||
|
||||
// Open a socket for ftp data listen
|
||||
ASSERT ((*sd = sl_Socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) > 0);
|
||||
ASSERT ((*sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_IPPROTO_IP)) > 0);
|
||||
_sd = *sd;
|
||||
|
||||
if (_sd > 0) {
|
||||
@ -438,12 +513,12 @@ static bool ftp_create_listening_socket (_i16 *sd, _u16 port, _u8 backlog) {
|
||||
|
||||
// Enable non-blocking mode
|
||||
nonBlockingOption.NonblockingEnabled = 1;
|
||||
ASSERT ((result = sl_SetSockOpt(_sd, SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
|
||||
ASSERT ((result = sl_SetSockOpt(_sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
|
||||
|
||||
// Bind the socket to a port number
|
||||
sServerAddress.sin_family = AF_INET;
|
||||
sServerAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
sServerAddress.sin_port = htons(port);
|
||||
sServerAddress.sin_family = SL_AF_INET;
|
||||
sServerAddress.sin_addr.s_addr = SL_INADDR_ANY;
|
||||
sServerAddress.sin_port = sl_Htons(port);
|
||||
|
||||
ASSERT ((result |= sl_Bind(_sd, (const SlSockAddr_t *)&sServerAddress, sizeof(sServerAddress))) == SL_SOC_OK);
|
||||
|
||||
@ -459,7 +534,7 @@ static bool ftp_create_listening_socket (_i16 *sd, _u16 port, _u8 backlog) {
|
||||
}
|
||||
|
||||
static ftp_result_t ftp_wait_for_connection (_i16 l_sd, _i16 *n_sd) {
|
||||
sockaddr_in sClientAddress;
|
||||
SlSockAddrIn_t sClientAddress;
|
||||
SlSocklen_t in_addrSize;
|
||||
|
||||
// accepts a connection from a TCP client, if there is any, otherwise returns SL_EAGAIN
|
||||
@ -604,10 +679,6 @@ static void ftp_process_cmd (void) {
|
||||
ftp_result_t result;
|
||||
FRESULT fres;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
ftp_data.closechild = false;
|
||||
// also use the reply buffer to receive new commands
|
||||
@ -634,7 +705,7 @@ static void ftp_process_cmd (void) {
|
||||
fres = FR_NO_PATH;
|
||||
ftp_pop_param (&bufptr, ftp_scratch_buffer);
|
||||
ftp_open_child (ftp_path, ftp_scratch_buffer);
|
||||
if ((ftp_path[0] == '/' && ftp_path[1] == '\0') || ((fres = f_opendir (&ftp_data.dp, ftp_path)) == FR_OK)) {
|
||||
if ((ftp_path[0] == '/' && ftp_path[1] == '\0') || ((fres = f_opendir_helper (&ftp_data.dp, ftp_path)) == FR_OK)) {
|
||||
if (fres == FR_OK) {
|
||||
f_closedir(&ftp_data.dp);
|
||||
}
|
||||
@ -653,7 +724,7 @@ static void ftp_process_cmd (void) {
|
||||
case E_FTP_CMD_SIZE:
|
||||
{
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
if (FR_OK == f_stat (ftp_path, &fno)) {
|
||||
if (FR_OK == f_stat_helper(ftp_path, &fno)) {
|
||||
// send the size
|
||||
snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "%u", (_u32)fno.fsize);
|
||||
ftp_send_reply(213, (char *)ftp_data.dBuffer);
|
||||
@ -665,7 +736,7 @@ static void ftp_process_cmd (void) {
|
||||
break;
|
||||
case E_FTP_CMD_MDTM:
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
if (FR_OK == f_stat (ftp_path, &fno)) {
|
||||
if (FR_OK == f_stat_helper(ftp_path, &fno)) {
|
||||
// send the last modified time
|
||||
snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "%u%02u%02u%02u%02u%02u",
|
||||
1980 + ((fno.fdate >> 9) & 0x7f), (fno.fdate >> 5) & 0x0f,
|
||||
@ -773,7 +844,7 @@ static void ftp_process_cmd (void) {
|
||||
case E_FTP_CMD_DELE:
|
||||
case E_FTP_CMD_RMD:
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
if (FR_OK == f_unlink(ftp_path)) {
|
||||
if (FR_OK == f_unlink_helper(ftp_path)) {
|
||||
ftp_send_reply(250, NULL);
|
||||
}
|
||||
else {
|
||||
@ -782,7 +853,7 @@ static void ftp_process_cmd (void) {
|
||||
break;
|
||||
case E_FTP_CMD_MKD:
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
if (FR_OK == f_mkdir(ftp_path)) {
|
||||
if (FR_OK == f_mkdir_helper(ftp_path)) {
|
||||
ftp_send_reply(250, NULL);
|
||||
}
|
||||
else {
|
||||
@ -791,7 +862,7 @@ static void ftp_process_cmd (void) {
|
||||
break;
|
||||
case E_FTP_CMD_RNFR:
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
if (FR_OK == f_stat (ftp_path, &fno)) {
|
||||
if (FR_OK == f_stat_helper(ftp_path, &fno)) {
|
||||
ftp_send_reply(350, NULL);
|
||||
// save the current path
|
||||
strcpy ((char *)ftp_data.dBuffer, ftp_path);
|
||||
@ -803,7 +874,7 @@ static void ftp_process_cmd (void) {
|
||||
case E_FTP_CMD_RNTO:
|
||||
ftp_get_param_and_open_child (&bufptr);
|
||||
// old path was saved in the data buffer
|
||||
if (FR_OK == (fres = f_rename ((char *)ftp_data.dBuffer, ftp_path))) {
|
||||
if (FR_OK == (fres = f_rename_helper((char *)ftp_data.dBuffer, ftp_path))) {
|
||||
ftp_send_reply(250, NULL);
|
||||
}
|
||||
else {
|
||||
@ -860,6 +931,13 @@ static void ftp_close_cmd_data (void) {
|
||||
ftp_close_filesystem_on_error ();
|
||||
}
|
||||
|
||||
static void stoupper (char *str) {
|
||||
while (str && *str != '\0') {
|
||||
*str = (char)unichar_toupper((int)(*str));
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
static ftp_cmd_index_t ftp_pop_command (char **str) {
|
||||
char _cmd[FTP_CMD_SIZE_MAX];
|
||||
ftp_pop_param (str, _cmd);
|
||||
@ -898,24 +976,16 @@ static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) {
|
||||
if (FTP_UNIX_SECONDS_180_DAYS < tseconds - fseconds) {
|
||||
return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %5u %s\r\n",
|
||||
type, (_u32)fno->fsize, ftp_month[mindex].month, day,
|
||||
#if _USE_LFN
|
||||
1980 + ((fno->fdate >> 9) & 0x7f), *fno->lfname ? fno->lfname : fno->fname);
|
||||
#else
|
||||
1980 + ((fno->fdate >> 9) & 0x7f), fno->fname);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %02u:%02u %s\r\n",
|
||||
type, (_u32)fno->fsize, ftp_month[mindex].month, day,
|
||||
#if _USE_LFN
|
||||
(fno->ftime >> 11) & 0x1f, (fno->ftime >> 5) & 0x3f, *fno->lfname ? fno->lfname : fno->fname);
|
||||
#else
|
||||
(fno->ftime >> 11) & 0x1f, (fno->ftime >> 5) & 0x3f, fno->fname);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name) {
|
||||
static int ftp_print_eplf_drive (char *dest, uint32_t destsize, const char *name) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t tseconds;
|
||||
char *type = "d";
|
||||
@ -934,7 +1004,7 @@ static int ftp_print_eplf_drive (char *dest, uint32_t destsize, char *name) {
|
||||
}
|
||||
|
||||
static bool ftp_open_file (const char *path, int mode) {
|
||||
FRESULT res = f_open(&ftp_data.fp, path, mode);
|
||||
FRESULT res = f_open_helper(&ftp_data.fp, path, mode);
|
||||
if (res != FR_OK) {
|
||||
return false;
|
||||
}
|
||||
@ -976,7 +1046,7 @@ static ftp_result_t ftp_open_dir_for_listing (const char *path) {
|
||||
ftp_data.listroot = true;
|
||||
} else {
|
||||
FRESULT res;
|
||||
res = f_opendir(&ftp_data.dp, path); /* Open the directory */
|
||||
res = f_opendir_helper(&ftp_data.dp, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
return E_FTP_RESULT_FAILED;
|
||||
}
|
||||
@ -993,9 +1063,6 @@ static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *li
|
||||
ftp_result_t result = E_FTP_RESULT_CONTINUE;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = mem_Malloc(_MAX_LFN);
|
||||
fno.lfsize = _MAX_LFN;
|
||||
|
||||
// read up to 2 directory items
|
||||
while (listcount < 2) {
|
||||
#else
|
||||
@ -1004,17 +1071,20 @@ static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *li
|
||||
#endif
|
||||
if (ftp_data.listroot) {
|
||||
// root directory "hack"
|
||||
if (0 == ftp_data.volcount) {
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), "flash");
|
||||
} else if (ftp_data.volcount <= MP_STATE_PORT(mount_obj_list).len) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[(ftp_data.volcount - 1)]));
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), (char *)&mount_obj->path[1]);
|
||||
} else {
|
||||
mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table);
|
||||
int i = ftp_data.volcount;
|
||||
while (vfs != NULL && i != 0) {
|
||||
vfs = vfs->next;
|
||||
i -= 1;
|
||||
}
|
||||
if (vfs == NULL) {
|
||||
if (!next) {
|
||||
// no volume found this time, we are done
|
||||
ftp_data.volcount = 0;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
next += ftp_print_eplf_drive((list + next), (maxlistsize - next), vfs->str + 1);
|
||||
}
|
||||
ftp_data.volcount++;
|
||||
} else {
|
||||
@ -1036,9 +1106,6 @@ static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *li
|
||||
ftp_close_files();
|
||||
}
|
||||
*listsize = next;
|
||||
#if _USE_LFN
|
||||
mem_Free(fno.lfname);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,19 @@ mp_uint_t mp_hal_ticks_ms(void) {
|
||||
return HAL_tickCount;
|
||||
}
|
||||
|
||||
// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge
|
||||
// to grab a microsecond counter.
|
||||
mp_uint_t mp_hal_ticks_us(void) {
|
||||
mp_uint_t irq_state = disable_irq();
|
||||
uint32_t counter = SysTickValueGet();
|
||||
uint32_t milliseconds = mp_hal_ticks_ms();
|
||||
enable_irq(irq_state);
|
||||
|
||||
uint32_t load = SysTickPeriodGet();
|
||||
counter = load - counter; // Convert from decrementing to incrementing
|
||||
return (milliseconds * 1000) + ((counter * 1000) / load);
|
||||
}
|
||||
|
||||
void mp_hal_delay_ms(mp_uint_t delay) {
|
||||
// only if we are not within interrupt context and interrupts are enabled
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
|
||||
@ -211,4 +224,3 @@ static void hal_TickInit (void) {
|
||||
MAP_SysTickEnable();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hal/utils.h"
|
||||
#include "hal/systick.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
@ -64,4 +67,7 @@ extern void HAL_SystemDeInit (void);
|
||||
extern void HAL_IncrementTick(void);
|
||||
extern void mp_hal_set_interrupt_char (int c);
|
||||
|
||||
#define mp_hal_delay_us(usec) UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec))
|
||||
#define mp_hal_ticks_cpu() (SysTickPeriodGet() - SysTickValueGet())
|
||||
|
||||
#endif /* CC3200_LAUNCHXL_HAL_CC3200_HAL_H_ */
|
||||
|
@ -98,13 +98,6 @@ int main (void) {
|
||||
for ( ; ; );
|
||||
}
|
||||
|
||||
void stoupper (char *str) {
|
||||
while (str && *str != '\0') {
|
||||
*str = (char)toupper((int)(*str));
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
// We need this when configSUPPORT_STATIC_ALLOCATION is enabled
|
||||
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
|
||||
StackType_t **ppxIdleTaskStackBuffer,
|
||||
|
@ -25,23 +25,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "py/builtin.h"
|
||||
|
||||
#include "lib/utils/pyhelp.h"
|
||||
|
||||
STATIC const char help_text[] = "Welcome to MicroPython!\n"
|
||||
const char *cc3200_help_text = "Welcome to MicroPython!\n"
|
||||
"For online help please visit http://micropython.org/help/.\n"
|
||||
"For further help on a specific object, type help(obj)\n";
|
||||
|
||||
STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
// print a general help message
|
||||
printf("%s", help_text);
|
||||
}
|
||||
else {
|
||||
// try to print something sensible about the given object
|
||||
pyhelp_print_obj(args[0]);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, pyb_help);
|
||||
|
@ -40,9 +40,6 @@ STATIC void mpexception_set_user_interrupt (int chr, void *data);
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
const char mpexception_os_resource_not_avaliable[] = "resource not available";
|
||||
const char mpexception_os_operation_failed[] = "the requested operation failed";
|
||||
const char mpexception_os_request_not_possible[] = "the requested operation is not possible";
|
||||
const char mpexception_value_invalid_arguments[] = "invalid argument(s) value";
|
||||
const char mpexception_num_type_invalid_arguments[] = "invalid argument(s) num/type";
|
||||
const char mpexception_uncaught[] = "uncaught exception";
|
||||
|
@ -28,9 +28,6 @@
|
||||
#ifndef MPEXCEPTION_H_
|
||||
#define MPEXCEPTION_H_
|
||||
|
||||
extern const char mpexception_os_resource_not_avaliable[];
|
||||
extern const char mpexception_os_operation_failed[];
|
||||
extern const char mpexception_os_request_not_possible[];
|
||||
extern const char mpexception_value_invalid_arguments[];
|
||||
extern const char mpexception_num_type_invalid_arguments[];
|
||||
extern const char mpexception_uncaught[];
|
||||
|
@ -24,7 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "std.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "mpsystick.h"
|
||||
#include "systick.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#endif
|
||||
|
||||
|
||||
bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
|
||||
return mp_hal_ticks_ms() - start_tick >= delay_ms;
|
||||
}
|
||||
|
||||
// waits until at least delay_ms milliseconds have passed from the sampling of
|
||||
// startTick. Handles overflow properly. Assumes stc was taken from
|
||||
// mp_hal_ticks_ms() some time before calling this function.
|
||||
void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
|
||||
#ifdef USE_FREERTOS
|
||||
vTaskDelay (delay_ms / portTICK_PERIOD_MS);
|
||||
#else
|
||||
while (!sys_tick_has_passed(start_tick, delay_ms)) {
|
||||
__WFI(); // enter sleep mode, waiting for interrupt
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge
|
||||
// to grab a microsecond counter.
|
||||
// We assume that mp_hal_ticks_ms returns milliseconds.
|
||||
uint32_t sys_tick_get_microseconds(void) {
|
||||
mp_uint_t irq_state = disable_irq();
|
||||
uint32_t counter = SysTickValueGet();
|
||||
uint32_t milliseconds = mp_hal_ticks_ms();
|
||||
enable_irq(irq_state);
|
||||
|
||||
uint32_t load = SysTickPeriodGet();
|
||||
counter = load - counter; // Convert from decrementing to incrementing
|
||||
return (milliseconds * 1000) + ((counter * 1000) / load);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Daniel Campora
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MPSYSTICK_H
|
||||
#define MPSYSTICK_H
|
||||
|
||||
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
|
||||
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
|
||||
uint32_t sys_tick_get_microseconds(void);
|
||||
|
||||
#endif // MPSYSTICK_H
|
@ -26,7 +26,6 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "std.h"
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
@ -112,10 +111,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info)
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t machine_freq(void) {
|
||||
mp_obj_t tuple[1] = {
|
||||
mp_obj_new_int(HAL_FCPU_HZ),
|
||||
};
|
||||
return mp_obj_new_tuple(1, tuple);
|
||||
return mp_obj_new_int(HAL_FCPU_HZ);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
|
||||
|
||||
|
@ -25,12 +25,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <std.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "modnetwork.h"
|
||||
#include "mpexception.h"
|
||||
@ -101,7 +100,7 @@ STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, size_t n_args
|
||||
// check the server id
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
if (mp_obj_get_int(args[0].u_obj) != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) {
|
||||
self->digested = false;
|
||||
}
|
||||
} else {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ STATIC mp_obj_t hash_read (mp_obj_t self_in) {
|
||||
}
|
||||
} else if (self->c_size < self->b_size) {
|
||||
// it's a fixed len block which is still incomplete
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
if (!self->digested) {
|
||||
|
@ -33,15 +33,17 @@
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "moduos.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "random.h"
|
||||
#include "mpexception.h"
|
||||
#include "version.h"
|
||||
#include "timeutils.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybuart.h"
|
||||
|
||||
@ -59,155 +61,20 @@
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint32_t os_num_mounted_devices;
|
||||
STATIC os_term_dup_obj_t os_term_dup_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void unmount (os_fs_mount_t *mount_obj);
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical);
|
||||
STATIC void append_dir_item (mp_obj_t dirlist, const char *item, bool string);
|
||||
STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonly);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void moduos_init0 (void) {
|
||||
// initialize the mount objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mount_obj_list), 0);
|
||||
os_num_mounted_devices = 0;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_path (const char *path) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (!strcmp(path, mount_obj->path)) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_volume (uint8_t vol) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (vol == mount_obj->vol) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_fs_mount_t *osmount_find_by_device (mp_obj_t device) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (device == mount_obj->device) {
|
||||
return mount_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void osmount_unmount_all (void) {
|
||||
//TODO
|
||||
/*
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
unmount(mount_obj);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
// Checks for path equality, ignoring trailing slashes:
|
||||
// path_equal(/, /) -> true
|
||||
// path_equal(/flash//, /flash) -> true
|
||||
// second argument must be in canonical form (meaning no trailing slash, unless it's just /)
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical) {
|
||||
for (; *path_canonical != '\0' && *path == *path_canonical; ++path, ++path_canonical) {
|
||||
}
|
||||
if (*path_canonical != '\0') {
|
||||
return false;
|
||||
}
|
||||
for (; *path == '/'; ++path) {
|
||||
}
|
||||
return *path == '\0';
|
||||
}
|
||||
|
||||
STATIC void append_dir_item (mp_obj_t dirlist, const char *item, bool string) {
|
||||
// make a string object for this entry
|
||||
mp_obj_t entry_o;
|
||||
if (string) {
|
||||
entry_o = mp_obj_new_str(item, strlen(item), false);
|
||||
} else {
|
||||
entry_o = mp_obj_new_bytes((const byte*)item, strlen(item));
|
||||
}
|
||||
|
||||
// add the entry to the list
|
||||
mp_obj_list_append(dirlist, entry_o);
|
||||
}
|
||||
|
||||
STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonly) {
|
||||
// is the mount point already in use?
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
// cannot mount twice or on existing paths
|
||||
if (f_stat(path, &fno) == FR_OK || osmount_find_by_device(device)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
}
|
||||
|
||||
// create a new object
|
||||
os_fs_mount_t *self = m_new_obj(os_fs_mount_t);
|
||||
self->device = device;
|
||||
self->path = path;
|
||||
self->pathlen = pathlen;
|
||||
self->vol = os_num_mounted_devices + 1; // '/flash' is volume 0
|
||||
|
||||
if (device == (mp_obj_t)&pybsd_obj) {
|
||||
// need to make it different to NULL, otherwise it's read only by default
|
||||
self->writeblocks[0] = mp_const_none;
|
||||
self->sync[0] = MP_OBJ_NULL; // no need to sync the SD card
|
||||
self->count[0] = MP_OBJ_NULL;
|
||||
} else {
|
||||
// load block protocol methods
|
||||
mp_load_method(device, MP_QSTR_readblocks, self->readblocks);
|
||||
mp_load_method_maybe(device, MP_QSTR_writeblocks, self->writeblocks);
|
||||
mp_load_method_maybe(device, MP_QSTR_sync, self->sync);
|
||||
mp_load_method(device, MP_QSTR_count, self->count);
|
||||
}
|
||||
|
||||
// Read-only device indicated by writeblocks[0] == MP_OBJ_NULL.
|
||||
// User can specify read-only device by:
|
||||
// 1. readonly=True keyword argument
|
||||
// 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)
|
||||
if (readonly) {
|
||||
self->writeblocks[0] = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
// we need to add it before doing the actual mount, so that the volume can be found
|
||||
mp_obj_list_append(&MP_STATE_PORT(mount_obj_list), self);
|
||||
|
||||
// actually mount it
|
||||
if (f_mount(&self->fatfs, self->path, 1) != FR_OK) {
|
||||
// remove it and raise
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), self);
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
|
||||
// mount succeeded, increment the count
|
||||
os_num_mounted_devices++;
|
||||
}
|
||||
|
||||
STATIC void unmount (os_fs_mount_t *mount_obj) {
|
||||
// remove it from the list and then call FatFs
|
||||
f_mount (NULL, mount_obj->path, 1);
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), mount_obj);
|
||||
os_num_mounted_devices--;
|
||||
*/
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -239,193 +106,6 @@ STATIC mp_obj_t os_uname(void) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
|
||||
/// \function chdir(path)
|
||||
/// Change current directory.
|
||||
STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
|
||||
const char *path;
|
||||
path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FRESULT res = f_chdrive(path);
|
||||
|
||||
if (res == FR_OK) {
|
||||
res = f_chdir(path);
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
|
||||
|
||||
STATIC mp_obj_t os_getcwd(void) {
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
FRESULT res = f_getcwd(buf, sizeof buf);
|
||||
if (res != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
return mp_obj_new_str(buf, strlen(buf), false);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
|
||||
|
||||
STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
bool is_str_type = true;
|
||||
const char *path;
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
if (n_args == 1) {
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_bytes) {
|
||||
is_str_type = false;
|
||||
}
|
||||
path = mp_obj_str_get_str(args[0]);
|
||||
} else {
|
||||
path = "";
|
||||
}
|
||||
|
||||
// "hack" to list the root directory
|
||||
if (path[0] == '/' && path[1] == '\0') {
|
||||
// add 'flash' to the list
|
||||
append_dir_item (dir_list, "flash", is_str_type);
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
append_dir_item (dir_list, &mount_obj->path[1], is_str_type);
|
||||
}
|
||||
} else {
|
||||
FRESULT res;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
char lfn_buf[_MAX_LFN + 1];
|
||||
fno.lfname = lfn_buf;
|
||||
fno.lfsize = sizeof(lfn_buf);
|
||||
#endif
|
||||
|
||||
res = f_opendir(&dir, path); /* Open the directory */
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
#if _USE_LFN
|
||||
char *fn = *fno.lfname ? fno.lfname : fno.fname;
|
||||
#else
|
||||
char *fn = fno.fname;
|
||||
#endif
|
||||
|
||||
// add the entry to the list
|
||||
append_dir_item (dir_list, fn, is_str_type);
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
return dir_list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
|
||||
|
||||
STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_mkdir(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
case FR_EXIST:
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
break;
|
||||
default:
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
|
||||
|
||||
STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) {
|
||||
const char *old_path = mp_obj_str_get_str(path_in);
|
||||
const char *new_path = mp_obj_str_get_str(path_out);
|
||||
FRESULT res = f_rename(old_path, new_path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
|
||||
|
||||
STATIC mp_obj_t os_remove(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_unlink(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
|
||||
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
bool isbuilt_in = false;
|
||||
FILINFO fno;
|
||||
FRESULT res;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
// check on the user mounted devices
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
|
||||
os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
|
||||
if (path_equal(path, mount_obj->path)) {
|
||||
isbuilt_in = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (path_equal(path, "/") || path_equal(path, "/flash") || isbuilt_in) {
|
||||
// stat built-in directory
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
} else if ((res = f_stat(path, &fno)) != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
mp_int_t mode = 0;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
mode |= 0x4000; // stat.S_IFDIR
|
||||
} else {
|
||||
mode |= 0x8000; // stat.S_IFREG
|
||||
}
|
||||
mp_int_t seconds = timeutils_seconds_since_2000(
|
||||
1980 + ((fno.fdate >> 9) & 0x7f),
|
||||
(fno.fdate >> 5) & 0x0f,
|
||||
fno.fdate & 0x1f,
|
||||
(fno.ftime >> 11) & 0x1f,
|
||||
(fno.ftime >> 5) & 0x3f,
|
||||
2 * (fno.ftime & 0x1f)
|
||||
);
|
||||
t->items[0] = mp_obj_new_int(mode); // st_mode
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = mp_obj_new_int(fno.fsize); // st_size
|
||||
t->items[7] = mp_obj_new_int(seconds); // st_atime
|
||||
t->items[8] = t->items[7]; // st_mtime
|
||||
t->items[9] = t->items[7]; // st_ctime
|
||||
return t;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
STATIC mp_obj_t os_sync(void) {
|
||||
sflash_disk_flush();
|
||||
return mp_const_none;
|
||||
@ -443,110 +123,6 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
|
||||
|
||||
STATIC mp_obj_t os_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t mount_args[] = {
|
||||
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_obj_t device = pos_args[0];
|
||||
mp_obj_t mount_point = pos_args[1];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(mount_args)];
|
||||
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(mount_args), mount_args, args);
|
||||
|
||||
// get the mount point
|
||||
mp_uint_t pathlen;
|
||||
const char *path_in = mp_obj_str_get_data(mount_point, &pathlen);
|
||||
if (pathlen == 0) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
char *path = m_new(char, pathlen + 1);
|
||||
memcpy(path, path_in, pathlen);
|
||||
path[pathlen] = '\0';
|
||||
|
||||
// "remove" any extra slahes at the end
|
||||
while (path[(pathlen - 1)] == '/') {
|
||||
path[--pathlen] = '\0';
|
||||
}
|
||||
|
||||
// is the mount point valid?
|
||||
if (pathlen < 2 || path[0] !='/' || strchr(&path[1], '/')) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// now mount it
|
||||
mount(device, path, pathlen, args[0].u_bool);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(os_mount_obj, 2, os_mount);
|
||||
|
||||
STATIC mp_obj_t os_unmount(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
|
||||
// '/flash' cannot be unmounted, also not the current working directory
|
||||
if (path_equal(path, "/flash")) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
}
|
||||
|
||||
// now unmount it
|
||||
os_fs_mount_t *mount_obj;
|
||||
if ((mount_obj = osmount_find_by_path(path))) {
|
||||
unmount (mount_obj);
|
||||
} else {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_unmount_obj, os_unmount);
|
||||
|
||||
STATIC mp_obj_t os_mkfs(mp_obj_t device) {
|
||||
const char *path = "/__mkfs__mnt__";
|
||||
os_fs_mount_t *mount_obj = NULL;
|
||||
bool unmt = false;
|
||||
FRESULT res;
|
||||
|
||||
if (MP_OBJ_IS_STR_OR_BYTES(device)) {
|
||||
path = mp_obj_str_get_str(device);
|
||||
// otherwise the relative path check will pass...
|
||||
if (path[0] != '/') {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments);
|
||||
}
|
||||
} else {
|
||||
// mount it briefly
|
||||
mount(device, path, strlen(path), false);
|
||||
unmt = true;
|
||||
}
|
||||
|
||||
byte sfd = 0;
|
||||
if (!memcmp(path, "/flash", strlen("/flash"))) {
|
||||
sfd = 1;
|
||||
} else if ((mount_obj = osmount_find_by_path(path))) {
|
||||
if (mount_obj->device != (mp_obj_t)&pybsd_obj &&
|
||||
mp_obj_get_int(mp_call_method_n_kw(0, 0, mount_obj->count)) < 2048) {
|
||||
sfd = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// now format the device
|
||||
res = f_mkfs(path, sfd, 0);
|
||||
|
||||
if (unmt && mount_obj) {
|
||||
unmount (mount_obj);
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs);
|
||||
|
||||
STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
|
||||
@ -576,26 +152,28 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uname), (mp_obj_t)&os_uname_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chdir), (mp_obj_t)&os_chdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getcwd), (mp_obj_t)&os_getcwd_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listdir), (mp_obj_t)&os_listdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename), (mp_obj_t)&os_rename_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_remove_obj }, // rmdir aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
|
||||
{ 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},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&mp_vfs_remove_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&mp_vfs_rmdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&mp_vfs_stat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&mp_vfs_remove_obj }, // unlink aliases to remove
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_urandom), (mp_obj_t)&os_urandom_obj },
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj },
|
||||
// removed: mkfs
|
||||
// renamed: unmount -> umount
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&mp_vfs_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umount), (mp_obj_t)&mp_vfs_umount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_VfsFat), (mp_obj_t)&mp_fat_vfs_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dupterm), (mp_obj_t)&os_dupterm_obj },
|
||||
|
||||
/// \constant sep - separation character used in paths
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
@ -28,22 +28,11 @@
|
||||
#ifndef MODUOS_H_
|
||||
#define MODUOS_H_
|
||||
|
||||
#include "ff.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _os_fs_mount_t {
|
||||
mp_obj_t device;
|
||||
const char *path;
|
||||
mp_uint_t pathlen;
|
||||
mp_obj_t readblocks[4];
|
||||
mp_obj_t writeblocks[4];
|
||||
mp_obj_t sync[2];
|
||||
mp_obj_t count[2];
|
||||
FATFS fatfs;
|
||||
uint8_t vol;
|
||||
} os_fs_mount_t;
|
||||
|
||||
typedef struct _os_term_dup_obj_t {
|
||||
mp_obj_t stream_o;
|
||||
@ -54,9 +43,6 @@ typedef struct _os_term_dup_obj_t {
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void moduos_init0 (void);
|
||||
os_fs_mount_t *osmount_find_by_path (const char *path);
|
||||
os_fs_mount_t *osmount_find_by_volume (uint8_t vol);
|
||||
void osmount_unmount_all (void);
|
||||
|
||||
#endif // MODUOS_H_
|
||||
|
@ -34,12 +34,254 @@
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "netutils.h"
|
||||
#include "lib/netutils/netutils.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "modusocket.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
/******************************************************************************/
|
||||
// The following set of macros and functions provide a glue between the CC3100
|
||||
// simplelink layer and the functions/methods provided by the usocket module.
|
||||
// They were historically in a separate file because usocket was designed to
|
||||
// work with multiple NICs, and the wlan_XXX functions just provided one
|
||||
// particular NIC implementation (that of the CC3100). But the CC3200 port only
|
||||
// supports a single NIC (being the CC3100) so it's unnecessary and inefficient
|
||||
// to provide an intermediate wrapper layer. Hence the wlan_XXX functions
|
||||
// are provided below as static functions so they can be inlined directly by
|
||||
// the corresponding usocket calls.
|
||||
|
||||
#define WLAN_MAX_RX_SIZE 16000
|
||||
#define WLAN_MAX_TX_SIZE 1476
|
||||
|
||||
#define MAKE_SOCKADDR(addr, ip, port) SlSockAddr_t addr; \
|
||||
addr.sa_family = SL_AF_INET; \
|
||||
addr.sa_data[0] = port >> 8; \
|
||||
addr.sa_data[1] = port; \
|
||||
addr.sa_data[2] = ip[3]; \
|
||||
addr.sa_data[3] = ip[2]; \
|
||||
addr.sa_data[4] = ip[1]; \
|
||||
addr.sa_data[5] = ip[0];
|
||||
|
||||
#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
|
||||
ip[0] = addr.sa_data[5]; \
|
||||
ip[1] = addr.sa_data[4]; \
|
||||
ip[2] = addr.sa_data[3]; \
|
||||
ip[3] = addr.sa_data[2];
|
||||
|
||||
STATIC int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) {
|
||||
uint32_t ip;
|
||||
int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family);
|
||||
out_ip[0] = ip;
|
||||
out_ip[1] = ip >> 8;
|
||||
out_ip[2] = ip >> 16;
|
||||
out_ip[3] = ip >> 24;
|
||||
return result;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) {
|
||||
int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto);
|
||||
if (sd < 0) {
|
||||
*_errno = sd;
|
||||
return -1;
|
||||
}
|
||||
s->sock_base.sd = sd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC void wlan_socket_close(mod_network_socket_obj_t *s) {
|
||||
// this is to prevent the finalizer to close a socket that failed when being created
|
||||
if (s->sock_base.sd >= 0) {
|
||||
modusocket_socket_delete(s->sock_base.sd);
|
||||
sl_Close(s->sock_base.sd);
|
||||
s->sock_base.sd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr));
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) {
|
||||
int ret = sl_Listen(s->sock_base.sd, backlog);
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) {
|
||||
// accept incoming connection
|
||||
int16_t sd;
|
||||
SlSockAddr_t addr;
|
||||
SlSocklen_t addr_len = sizeof(addr);
|
||||
|
||||
sd = sl_Accept(s->sock_base.sd, &addr, &addr_len);
|
||||
// save the socket descriptor
|
||||
s2->sock_base.sd = sd;
|
||||
if (sd < 0) {
|
||||
*_errno = sd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return ip and port
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr));
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
|
||||
mp_int_t bytes = 0;
|
||||
if (len > 0) {
|
||||
bytes = sl_Send(s->sock_base.sd, (const void *)buf, len, 0);
|
||||
}
|
||||
if (bytes <= 0) {
|
||||
*_errno = bytes;
|
||||
return -1;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
|
||||
int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
|
||||
SlSockAddr_t addr;
|
||||
SlSocklen_t addr_len = sizeof(addr);
|
||||
mp_int_t ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
|
||||
int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) {
|
||||
int ret;
|
||||
bool has_timeout;
|
||||
if (timeout_s == 0 || timeout_s == -1) {
|
||||
SlSockNonblocking_t option;
|
||||
if (timeout_s == 0) {
|
||||
// set non-blocking mode
|
||||
option.NonblockingEnabled = 1;
|
||||
} else {
|
||||
// set blocking mode
|
||||
option.NonblockingEnabled = 0;
|
||||
}
|
||||
ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option));
|
||||
has_timeout = false;
|
||||
} else {
|
||||
// set timeout
|
||||
struct SlTimeval_t timeVal;
|
||||
timeVal.tv_sec = timeout_s; // seconds
|
||||
timeVal.tv_usec = 0; // microseconds. 10000 microseconds resolution
|
||||
ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_RCVTIMEO, &timeVal, sizeof(timeVal));
|
||||
has_timeout = true;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->sock_base.has_timeout = has_timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) {
|
||||
mp_int_t ret;
|
||||
if (request == MP_STREAM_POLL) {
|
||||
mp_uint_t flags = arg;
|
||||
ret = 0;
|
||||
int32_t sd = s->sock_base.sd;
|
||||
|
||||
// init fds
|
||||
SlFdSet_t rfds, wfds, xfds;
|
||||
SL_FD_ZERO(&rfds);
|
||||
SL_FD_ZERO(&wfds);
|
||||
SL_FD_ZERO(&xfds);
|
||||
|
||||
// set fds if needed
|
||||
if (flags & MP_STREAM_POLL_RD) {
|
||||
SL_FD_SET(sd, &rfds);
|
||||
}
|
||||
if (flags & MP_STREAM_POLL_WR) {
|
||||
SL_FD_SET(sd, &wfds);
|
||||
}
|
||||
if (flags & MP_STREAM_POLL_HUP) {
|
||||
SL_FD_SET(sd, &xfds);
|
||||
}
|
||||
|
||||
// call simplelink's select with minimum timeout
|
||||
SlTimeval_t tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
|
||||
|
||||
// check for errors
|
||||
if (nfds == -1) {
|
||||
*_errno = nfds;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check return of select
|
||||
if (SL_FD_ISSET(sd, &rfds)) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
if (SL_FD_ISSET(sd, &wfds)) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
if (SL_FD_ISSET(sd, &xfds)) {
|
||||
ret |= MP_STREAM_POLL_HUP;
|
||||
}
|
||||
} else {
|
||||
*_errno = MP_EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
@ -95,13 +337,13 @@ void modusocket_socket_delete (int16_t sd) {
|
||||
}
|
||||
|
||||
void modusocket_enter_sleep (void) {
|
||||
fd_set socketset;
|
||||
SlFdSet_t socketset;
|
||||
int16_t maxfd = 0;
|
||||
|
||||
for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
|
||||
int16_t sd;
|
||||
if ((sd = modusocket_sockets[i].sd) >= 0) {
|
||||
FD_SET(sd, &socketset);
|
||||
SL_FD_SET(sd, &socketset);
|
||||
maxfd = (maxfd > sd) ? maxfd : sd;
|
||||
}
|
||||
}
|
||||
@ -133,9 +375,9 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
||||
// create socket object
|
||||
mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
|
||||
s->base.type = (mp_obj_t)&socket_type;
|
||||
s->sock_base.u_param.domain = AF_INET;
|
||||
s->sock_base.u_param.type = SOCK_STREAM;
|
||||
s->sock_base.u_param.proto = IPPROTO_TCP;
|
||||
s->sock_base.u_param.domain = SL_AF_INET;
|
||||
s->sock_base.u_param.type = SL_SOCK_STREAM;
|
||||
s->sock_base.u_param.proto = SL_IPPROTO_TCP;
|
||||
s->sock_base.u_param.fileno = -1;
|
||||
s->sock_base.has_timeout = false;
|
||||
s->sock_base.cert_req = false;
|
||||
@ -180,7 +422,7 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// call the NIC to bind the socket
|
||||
int _errno;
|
||||
int _errno = 0;
|
||||
if (wlan_socket_bind(self, ip, port, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
@ -217,8 +459,8 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
||||
|
||||
// accept the incoming connection
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port;
|
||||
int _errno;
|
||||
mp_uint_t port = 0;
|
||||
int _errno = 0;
|
||||
if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
@ -277,8 +519,8 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
int _errno;
|
||||
mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
|
||||
if (ret < 0) {
|
||||
if (_errno == EAGAIN && self->sock_base.has_timeout) {
|
||||
mp_raise_msg(&mp_type_TimeoutError, "timed out");
|
||||
if (_errno == MP_EAGAIN && self->sock_base.has_timeout) {
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
@ -304,7 +546,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// call the nic to sendto
|
||||
int _errno;
|
||||
int _errno = 0;
|
||||
mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
|
||||
if (ret < 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
@ -319,12 +561,12 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, mp_obj_get_int(len_in));
|
||||
byte ip[4];
|
||||
mp_uint_t port;
|
||||
int _errno;
|
||||
mp_uint_t port = 0;
|
||||
int _errno = 0;
|
||||
mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno);
|
||||
if (ret < 0) {
|
||||
if (_errno == EAGAIN && self->sock_base.has_timeout) {
|
||||
mp_raise_msg(&mp_type_TimeoutError, "timed out");
|
||||
if (_errno == MP_EAGAIN && self->sock_base.has_timeout) {
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
@ -495,19 +737,19 @@ STATIC const mp_obj_type_t socket_type = {
|
||||
// function usocket.getaddrinfo(host, port)
|
||||
/// \function getaddrinfo(host, port)
|
||||
STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
|
||||
mp_uint_t hlen;
|
||||
size_t hlen;
|
||||
const char *host = mp_obj_str_get_data(host_in, &hlen);
|
||||
mp_int_t port = mp_obj_get_int(port_in);
|
||||
|
||||
// ipv4 only
|
||||
uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
int32_t result = wlan_gethostbyname(host, hlen, out_ip, AF_INET);
|
||||
int32_t result = wlan_gethostbyname(host, hlen, out_ip, SL_AF_INET);
|
||||
if (result < 0) {
|
||||
mp_raise_OSError(-result);
|
||||
}
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET);
|
||||
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM);
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SL_AF_INET);
|
||||
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SL_SOCK_STREAM);
|
||||
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
|
||||
tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
|
||||
tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_LITTLE);
|
||||
@ -521,19 +763,15 @@ STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&socket_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_usocket_getaddrinfo_obj },
|
||||
|
||||
// class exceptions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_error), (mp_obj_t)&mp_type_OSError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&mp_type_TimeoutError },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(SL_AF_INET) },
|
||||
|
||||
{ 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_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SL_SOCK_STREAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SL_SOCK_DGRAM) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_SEC), MP_OBJ_NEW_SMALL_INT(SL_SEC_SOCKET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(SL_IPPROTO_TCP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(SL_IPPROTO_UDP) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
|
||||
|
@ -25,7 +25,6 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <std.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
@ -33,7 +33,8 @@
|
||||
#include "py/obj.h"
|
||||
#include "py/smallint.h"
|
||||
#include "py/mphal.h"
|
||||
#include "timeutils.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "extmod/utime_mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
@ -41,7 +42,6 @@
|
||||
#include "prcm.h"
|
||||
#include "systick.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpsystick.h"
|
||||
#include "mpexception.h"
|
||||
#include "utils.h"
|
||||
|
||||
@ -102,7 +102,7 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
|
||||
|
||||
STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
mp_uint_t len;
|
||||
size_t len;
|
||||
mp_obj_t *elem;
|
||||
|
||||
mp_obj_get_array(tuple, &len, &elem);
|
||||
@ -131,50 +131,6 @@ STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
|
||||
|
||||
STATIC mp_obj_t time_sleep_ms (mp_obj_t ms_in) {
|
||||
mp_int_t ms = mp_obj_get_int(ms_in);
|
||||
if (ms > 0) {
|
||||
mp_hal_delay_ms(ms);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms);
|
||||
|
||||
STATIC mp_obj_t time_sleep_us (mp_obj_t usec_in) {
|
||||
mp_int_t usec = mp_obj_get_int(usec_in);
|
||||
if (usec > 0) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_ms(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
|
||||
|
||||
STATIC mp_obj_t time_ticks_us(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_cpu(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT((SysTickPeriodGet() - SysTickValueGet()) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
|
||||
|
||||
STATIC mp_obj_t time_ticks_diff(mp_obj_t t0, mp_obj_t t1) {
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
uint32_t start = mp_obj_get_int(t0);
|
||||
uint32_t end = mp_obj_get_int(t1);
|
||||
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff);
|
||||
|
||||
STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) },
|
||||
|
||||
@ -184,12 +140,13 @@ STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&mp_utime_ticks_cpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_add), (mp_obj_t)&mp_utime_ticks_add_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "std.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/ioctl.h"
|
||||
@ -36,13 +36,8 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "timeutils.h"
|
||||
#include "netutils.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "lib/netutils/netutils.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modusocket.h"
|
||||
#include "modwlan.h"
|
||||
@ -118,26 +113,6 @@ typedef enum{
|
||||
|
||||
#define ASSERT_ON_ERROR(x) ASSERT((x) >= 0)
|
||||
|
||||
#define IPV4_ADDR_STR_LEN_MAX (16)
|
||||
|
||||
#define WLAN_MAX_RX_SIZE 16000
|
||||
#define WLAN_MAX_TX_SIZE 1476
|
||||
|
||||
#define MAKE_SOCKADDR(addr, ip, port) sockaddr addr; \
|
||||
addr.sa_family = AF_INET; \
|
||||
addr.sa_data[0] = port >> 8; \
|
||||
addr.sa_data[1] = port; \
|
||||
addr.sa_data[2] = ip[3]; \
|
||||
addr.sa_data[3] = ip[2]; \
|
||||
addr.sa_data[4] = ip[1]; \
|
||||
addr.sa_data[5] = ip[0];
|
||||
|
||||
#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
|
||||
ip[0] = addr.sa_data[5]; \
|
||||
ip[1] = addr.sa_data[4]; \
|
||||
ip[2] = addr.sa_data[3]; \
|
||||
ip[3] = addr.sa_data[2];
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
@ -162,7 +137,9 @@ STATIC const mp_irq_methods_t wlan_irq_methods;
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
OsiLockObj_t wlan_LockObj;
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
@ -397,14 +374,18 @@ void SimpleLinkSockEventHandler(SlSockEvent_t *pSock) {
|
||||
__attribute__ ((section (".boot")))
|
||||
void wlan_pre_init (void) {
|
||||
// create the wlan lock
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
ASSERT(OSI_OK == sl_LockObjCreate(&wlan_LockObj, "WlanLock"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void wlan_first_start (void) {
|
||||
if (wlan_obj.mode < 0) {
|
||||
CLR_STATUS_BIT_ALL(wlan_obj.status);
|
||||
wlan_obj.mode = sl_Start(0, 0, 0);
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
#endif
|
||||
}
|
||||
|
||||
// get the mac address
|
||||
@ -513,7 +494,9 @@ void wlan_update(void) {
|
||||
|
||||
void wlan_stop (uint32_t timeout) {
|
||||
wlan_servers_stop();
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
#endif
|
||||
sl_Stop(timeout);
|
||||
wlan_clear_data();
|
||||
wlan_obj.mode = -1;
|
||||
@ -569,11 +552,15 @@ STATIC void wlan_clear_data (void) {
|
||||
|
||||
STATIC void wlan_reenable (SlWlanMode_t mode) {
|
||||
// stop and start again
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER);
|
||||
#endif
|
||||
sl_Stop(SL_STOP_TIMEOUT);
|
||||
wlan_clear_data();
|
||||
wlan_obj.mode = sl_Start(0, 0, 0);
|
||||
#ifdef SL_PLATFORM_MULTI_THREADED
|
||||
sl_LockObjUnlock (&wlan_LockObj);
|
||||
#endif
|
||||
ASSERT (wlan_obj.mode == mode);
|
||||
}
|
||||
|
||||
@ -787,7 +774,7 @@ STATIC mp_obj_t wlan_init_helper(wlan_obj_t *self, const mp_arg_val_t *args) {
|
||||
wlan_validate_mode(mode);
|
||||
|
||||
// get the ssid
|
||||
mp_uint_t ssid_len = 0;
|
||||
size_t ssid_len = 0;
|
||||
const char *ssid = NULL;
|
||||
if (args[1].u_obj != NULL) {
|
||||
ssid = mp_obj_str_get_data(args[1].u_obj, &ssid_len);
|
||||
@ -796,7 +783,7 @@ STATIC mp_obj_t wlan_init_helper(wlan_obj_t *self, const mp_arg_val_t *args) {
|
||||
|
||||
// get the auth config
|
||||
uint8_t auth = SL_SEC_TYPE_OPEN;
|
||||
mp_uint_t key_len = 0;
|
||||
size_t key_len = 0;
|
||||
const char *key = NULL;
|
||||
if (args[2].u_obj != mp_const_none) {
|
||||
mp_obj_t *sec;
|
||||
@ -811,8 +798,9 @@ STATIC mp_obj_t wlan_init_helper(wlan_obj_t *self, const mp_arg_val_t *args) {
|
||||
wlan_validate_channel(channel);
|
||||
|
||||
// get the antenna type
|
||||
uint8_t antenna = args[4].u_int;
|
||||
uint8_t antenna = 0;
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
antenna = args[4].u_int;
|
||||
wlan_validate_antenna(antenna);
|
||||
#endif
|
||||
|
||||
@ -828,7 +816,9 @@ STATIC const mp_arg_t wlan_init_args[] = {
|
||||
{ MP_QSTR_ssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
{ MP_QSTR_antenna, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ANTENNA_TYPE_INTERNAL} },
|
||||
#endif
|
||||
};
|
||||
STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
@ -847,7 +837,7 @@ STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
// start the peripheral
|
||||
wlan_init_helper(self, &args[1]);
|
||||
@ -871,7 +861,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) {
|
||||
|
||||
// check for correct wlan mode
|
||||
if (wlan_obj.mode == ROLE_AP) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
Sl_WlanNetworkEntry_t wlanEntry;
|
||||
@ -925,7 +915,7 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
|
||||
// check for the correct wlan mode
|
||||
if (wlan_obj.mode == ROLE_AP) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// parse args
|
||||
@ -933,13 +923,13 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// get the ssid
|
||||
mp_uint_t ssid_len;
|
||||
size_t ssid_len;
|
||||
const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len);
|
||||
wlan_validate_ssid_len(ssid_len);
|
||||
|
||||
// get the auth config
|
||||
uint8_t auth = SL_SEC_TYPE_OPEN;
|
||||
mp_uint_t key_len = 0;
|
||||
size_t key_len = 0;
|
||||
const char *key = NULL;
|
||||
if (args[1].u_obj != mp_const_none) {
|
||||
mp_obj_t *sec;
|
||||
@ -973,7 +963,7 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||
modwlan_Status_t status;
|
||||
status = wlan_do_connect (ssid, ssid_len, bssid, auth, key, key_len, timeout);
|
||||
if (status == MODWLAN_ERROR_TIMEOUT) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
} else if (status == MODWLAN_ERROR_INVALID_PARAMS) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
@ -1004,7 +994,7 @@ STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
|
||||
// check the interface id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// get the configuration
|
||||
@ -1088,7 +1078,7 @@ STATIC mp_obj_t wlan_ssid (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false);
|
||||
} else {
|
||||
mp_uint_t len;
|
||||
size_t len;
|
||||
const char *ssid = mp_obj_str_get_data(args[1], &len);
|
||||
wlan_validate_ssid_len(len);
|
||||
wlan_set_ssid(ssid, len, false);
|
||||
@ -1112,7 +1102,7 @@ STATIC mp_obj_t wlan_auth (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
} else {
|
||||
// get the auth config
|
||||
uint8_t auth = SL_SEC_TYPE_OPEN;
|
||||
mp_uint_t key_len = 0;
|
||||
size_t key_len = 0;
|
||||
const char *key = NULL;
|
||||
if (args[1] != mp_const_none) {
|
||||
mp_obj_t *sec;
|
||||
@ -1235,13 +1225,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
|
||||
// strcpy(urn, p);
|
||||
//
|
||||
// if (sl_NetAppSet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, len, (unsigned char *)urn) < 0) {
|
||||
// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
// mp_raise_OSError(MP_EIO);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// // get the URN
|
||||
// if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) {
|
||||
// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
// mp_raise_OSError(MP_EIO);
|
||||
// }
|
||||
// return mp_obj_new_str(urn, (len - 1), false);
|
||||
// }
|
||||
@ -1255,9 +1245,9 @@ STATIC mp_obj_t wlan_print_ver(void) {
|
||||
byte config_opt = SL_DEVICE_GENERAL_VERSION;
|
||||
byte config_len = sizeof(ver);
|
||||
sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION, &config_opt, &config_len, (byte*)&ver);
|
||||
printf("NWP: %d.%d.%d.%d\n", ver.NwpVersion[0], ver.NwpVersion[1], ver.NwpVersion[2], ver.NwpVersion[3]);
|
||||
printf("MAC: %d.%d.%d.%d\n", ver.ChipFwAndPhyVersion.FwVersion[0], ver.ChipFwAndPhyVersion.FwVersion[1],
|
||||
ver.ChipFwAndPhyVersion.FwVersion[2], ver.ChipFwAndPhyVersion.FwVersion[3]);
|
||||
printf("NWP: %d.%d.%d.%d\n", (int)ver.NwpVersion[0], (int)ver.NwpVersion[1], (int)ver.NwpVersion[2], (int)ver.NwpVersion[3]);
|
||||
printf("MAC: %d.%d.%d.%d\n", (int)ver.ChipFwAndPhyVersion.FwVersion[0], (int)ver.ChipFwAndPhyVersion.FwVersion[1],
|
||||
(int)ver.ChipFwAndPhyVersion.FwVersion[2], (int)ver.ChipFwAndPhyVersion.FwVersion[3]);
|
||||
printf("PHY: %d.%d.%d.%d\n", ver.ChipFwAndPhyVersion.PhyVersion[0], ver.ChipFwAndPhyVersion.PhyVersion[1],
|
||||
ver.ChipFwAndPhyVersion.PhyVersion[2], ver.ChipFwAndPhyVersion.PhyVersion[3]);
|
||||
return mp_const_none;
|
||||
@ -1289,8 +1279,10 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WEP), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WEP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WPA), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) },
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EXT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ANY_EVENT), MP_OBJ_NEW_SMALL_INT(MODWLAN_WIFI_EVENT_ANY) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table);
|
||||
@ -1310,220 +1302,3 @@ STATIC const mp_irq_methods_t wlan_irq_methods = {
|
||||
.disable = wlan_lpds_irq_disable,
|
||||
.flags = wlan_irq_flags,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings; WLAN socket
|
||||
|
||||
int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) {
|
||||
uint32_t ip;
|
||||
int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family);
|
||||
out_ip[0] = ip;
|
||||
out_ip[1] = ip >> 8;
|
||||
out_ip[2] = ip >> 16;
|
||||
out_ip[3] = ip >> 24;
|
||||
return result;
|
||||
}
|
||||
|
||||
int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) {
|
||||
int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto);
|
||||
if (sd < 0) {
|
||||
*_errno = sd;
|
||||
return -1;
|
||||
}
|
||||
s->sock_base.sd = sd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wlan_socket_close(mod_network_socket_obj_t *s) {
|
||||
// this is to prevent the finalizer to close a socket that failed when being created
|
||||
if (s->sock_base.sd >= 0) {
|
||||
modusocket_socket_delete(s->sock_base.sd);
|
||||
sl_Close(s->sock_base.sd);
|
||||
s->sock_base.sd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr));
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) {
|
||||
int ret = sl_Listen(s->sock_base.sd, backlog);
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) {
|
||||
// accept incoming connection
|
||||
int16_t sd;
|
||||
sockaddr addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
sd = sl_Accept(s->sock_base.sd, &addr, &addr_len);
|
||||
// save the socket descriptor
|
||||
s2->sock_base.sd = sd;
|
||||
if (sd < 0) {
|
||||
*_errno = sd;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return ip and port
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr));
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
|
||||
mp_int_t bytes = 0;
|
||||
if (len > 0) {
|
||||
bytes = sl_Send(s->sock_base.sd, (const void *)buf, len, 0);
|
||||
}
|
||||
if (bytes <= 0) {
|
||||
*_errno = bytes;
|
||||
return -1;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
|
||||
int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
|
||||
sockaddr addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
mp_int_t ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
|
||||
int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen);
|
||||
if (ret < 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) {
|
||||
int ret;
|
||||
bool has_timeout;
|
||||
if (timeout_s == 0 || timeout_s == -1) {
|
||||
SlSockNonblocking_t option;
|
||||
if (timeout_s == 0) {
|
||||
// set non-blocking mode
|
||||
option.NonblockingEnabled = 1;
|
||||
} else {
|
||||
// set blocking mode
|
||||
option.NonblockingEnabled = 0;
|
||||
}
|
||||
ret = sl_SetSockOpt(s->sock_base.sd, SOL_SOCKET, SO_NONBLOCKING, &option, sizeof(option));
|
||||
has_timeout = false;
|
||||
} else {
|
||||
// set timeout
|
||||
struct SlTimeval_t timeVal;
|
||||
timeVal.tv_sec = timeout_s; // seconds
|
||||
timeVal.tv_usec = 0; // microseconds. 10000 microseconds resolution
|
||||
ret = sl_SetSockOpt(s->sock_base.sd, SOL_SOCKET, SO_RCVTIMEO, &timeVal, sizeof(timeVal));
|
||||
has_timeout = true;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
*_errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->sock_base.has_timeout = has_timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) {
|
||||
mp_int_t ret;
|
||||
if (request == MP_STREAM_POLL) {
|
||||
mp_uint_t flags = arg;
|
||||
ret = 0;
|
||||
int32_t sd = s->sock_base.sd;
|
||||
|
||||
// init fds
|
||||
fd_set rfds, wfds, xfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&xfds);
|
||||
|
||||
// set fds if needed
|
||||
if (flags & MP_STREAM_POLL_RD) {
|
||||
FD_SET(sd, &rfds);
|
||||
}
|
||||
if (flags & MP_STREAM_POLL_WR) {
|
||||
FD_SET(sd, &wfds);
|
||||
}
|
||||
if (flags & MP_STREAM_POLL_HUP) {
|
||||
FD_SET(sd, &xfds);
|
||||
}
|
||||
|
||||
// call simplelink's select with minimum timeout
|
||||
SlTimeval_t tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1;
|
||||
int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
|
||||
|
||||
// check for errors
|
||||
if (nfds == -1) {
|
||||
*_errno = nfds;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check return of select
|
||||
if (FD_ISSET(sd, &rfds)) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
if (FD_ISSET(sd, &wfds)) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
if (FD_ISSET(sd, &xfds)) {
|
||||
ret |= MP_STREAM_POLL_HUP;
|
||||
}
|
||||
} else {
|
||||
*_errno = EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -97,19 +97,4 @@ extern bool wlan_is_connected (void);
|
||||
extern void wlan_set_current_time (uint32_t seconds_since_2000);
|
||||
extern void wlan_off_on (void);
|
||||
|
||||
extern int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family);
|
||||
extern int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno);
|
||||
extern void wlan_socket_close(mod_network_socket_obj_t *s);
|
||||
extern int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno);
|
||||
extern int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno);
|
||||
extern int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno);
|
||||
extern int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno);
|
||||
extern int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno);
|
||||
extern int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno);
|
||||
extern int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno);
|
||||
extern int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno);
|
||||
extern int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
|
||||
extern int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno);
|
||||
extern int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno);
|
||||
|
||||
#endif /* MODWLAN_H_ */
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_adc.h"
|
||||
@ -104,7 +105,7 @@ STATIC void pyb_adc_init (pyb_adc_obj_t *self) {
|
||||
STATIC void pyb_adc_check_init(void) {
|
||||
// not initialized
|
||||
if (!pyb_adc_obj.enabled) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +150,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// check the number of bits
|
||||
@ -206,7 +207,7 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
ch_id = mp_obj_get_int(args[0].u_obj);
|
||||
if (ch_id >= PYB_ADC_NUM_CHANNELS) {
|
||||
mp_raise_ValueError(mpexception_os_resource_not_avaliable);
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
} else if (args[1].u_obj != mp_const_none) {
|
||||
uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
|
||||
if (ch_id != pin_ch_id) {
|
||||
@ -277,7 +278,7 @@ STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) {
|
||||
|
||||
// the channel must be enabled
|
||||
if (!self->enabled) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// wait until a new value is available
|
||||
|
109
cc3200/mods/pybflash.c
Normal file
109
cc3200/mods/pybflash.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2017 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
|
||||
#include "fatfs/src/drivers/sflash_diskio.h"
|
||||
#include "mods/pybflash.h"
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings to expose the internal flash as an object with the
|
||||
// block protocol.
|
||||
|
||||
// there is a singleton Flash object
|
||||
STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type};
|
||||
|
||||
STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return singleton object
|
||||
return (mp_obj_t)&pyb_flash_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
|
||||
DRESULT res = sflash_disk_read(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SFLASH_SECTOR_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks);
|
||||
|
||||
STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
DRESULT res = sflash_disk_write(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SFLASH_SECTOR_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks);
|
||||
|
||||
STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(sflash_disk_init() != RES_OK);
|
||||
case BP_IOCTL_DEINIT: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SYNC: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_COUNT);
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_SIZE);
|
||||
default: return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_flash_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&pyb_flash_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&pyb_flash_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&pyb_flash_ioctl_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_flash_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Flash,
|
||||
.make_new = pyb_flash_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_flash_locals_dict,
|
||||
};
|
||||
|
||||
void pyb_flash_init_vfs(fs_user_mount_t *vfs) {
|
||||
vfs->base.type = &mp_fat_vfs_type;
|
||||
vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
|
||||
vfs->fatfs.drv = vfs;
|
||||
vfs->readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj;
|
||||
vfs->readblocks[1] = (mp_obj_t)&pyb_flash_obj;
|
||||
vfs->readblocks[2] = (mp_obj_t)sflash_disk_read; // native version
|
||||
vfs->writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj;
|
||||
vfs->writeblocks[1] = (mp_obj_t)&pyb_flash_obj;
|
||||
vfs->writeblocks[2] = (mp_obj_t)sflash_disk_write; // native version
|
||||
vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj;
|
||||
vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
|
||||
* Copyright (c) 2017 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -23,12 +23,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_HELP_H__
|
||||
#define __MICROPY_INCLUDED_SHARED_BINDINGS_HELP_H__
|
||||
#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H
|
||||
#define MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
extern void shared_module_help(void);
|
||||
extern const mp_obj_type_t pyb_flash_type;
|
||||
|
||||
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_HELP_H__
|
||||
void pyb_flash_init_vfs(fs_user_mount_t *vfs);
|
||||
|
||||
#endif // MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
@ -58,8 +59,6 @@ typedef struct _pyb_i2c_obj_t {
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBI2C_MASTER (0)
|
||||
|
||||
#define PYBI2C_MIN_BAUD_RATE_HZ (50000)
|
||||
#define PYBI2C_MAX_BAUD_RATE_HZ (400000)
|
||||
|
||||
@ -78,7 +77,6 @@ typedef struct _pyb_i2c_obj_t {
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0};
|
||||
STATIC const mp_obj_t pyb_i2c_def_pin[2] = {&pin_GP13, &pin_GP23};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
@ -144,7 +142,7 @@ STATIC bool pyb_i2c_transaction(uint cmd) {
|
||||
STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +254,7 @@ STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
|
||||
// receive the data
|
||||
if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,8 +273,10 @@ STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
if (pyb_i2c_mem_addr_write (i2c_addr, (byte *)&mem_addr, mem_addr_size)) {
|
||||
// Read the specified length of data
|
||||
if (!pyb_i2c_read (i2c_addr, (byte *)vstr->buf, vstr->len)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
} else {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,33 +286,34 @@ STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_i2c_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "I2C(0, I2C.MASTER, baudrate=%u)", self->baudrate);
|
||||
mp_printf(print, "I2C(0, baudrate=%u)", self->baudrate);
|
||||
} else {
|
||||
mp_print_str(print, "I2C(0)");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *args) {
|
||||
// verify that mode is master
|
||||
if (args[0].u_int != PYBI2C_MASTER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_scl, ARG_sda, ARG_freq };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// make sure the baudrate is between the valid range
|
||||
self->baudrate = MIN(MAX(args[1].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
self->baudrate = MIN(MAX(args[ARG_freq].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[2].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_i2c_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, 2, &pins);
|
||||
mp_obj_t pins[2] = {&pin_GP13, &pin_GP23}; // default (SDA, SCL) pins
|
||||
if (args[ARG_scl].u_obj != MP_OBJ_NULL) {
|
||||
pins[1] = args[ARG_scl].u_obj;
|
||||
}
|
||||
pin_assign_pins_af (pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
if (args[ARG_sda].u_obj != MP_OBJ_NULL) {
|
||||
pins[0] = args[ARG_sda].u_obj;
|
||||
}
|
||||
pin_assign_pins_af(pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
|
||||
// init the I2C bus
|
||||
i2c_init(self);
|
||||
@ -321,44 +322,34 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t pyb_i2c_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = PYBI2C_MASTER} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// check the id argument, if given
|
||||
if (n_args > 0) {
|
||||
if (all_args[0] != MP_OBJ_NEW_SMALL_INT(0)) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
--n_args;
|
||||
++all_args;
|
||||
}
|
||||
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_i2c_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_i2c_obj_t *self = &pyb_i2c_obj;
|
||||
self->base.type = &pyb_i2c_type;
|
||||
|
||||
// start the peripheral
|
||||
pyb_i2c_init_helper(self, &args[1]);
|
||||
pyb_i2c_init_helper(self, n_args, all_args, &kw_args);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_i2c_init_args[1], args);
|
||||
return pyb_i2c_init_helper(pos_args[0], args);
|
||||
STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
return pyb_i2c_init_helper(pos_args[0], n_args - 1, pos_args + 1, kw_args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
|
||||
|
||||
@ -445,7 +436,7 @@ STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m
|
||||
|
||||
// send the data
|
||||
if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
// return the number of bytes written
|
||||
@ -486,7 +477,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem_into(mp_uint_t n_args, const mp_obj_t *pos_
|
||||
// get the buffer to read into
|
||||
vstr_t vstr;
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_int(vstr.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
|
||||
|
||||
@ -510,11 +501,10 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
|
||||
// write the register address to write to.
|
||||
if (pyb_i2c_mem_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len)) {
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem);
|
||||
|
||||
@ -529,9 +519,6 @@ STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem), (mp_obj_t)&pyb_i2c_readfrom_mem_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem_into), (mp_obj_t)&pyb_i2c_readfrom_mem_into_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeto_mem), (mp_obj_t)&pyb_i2c_writeto_mem_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYBI2C_MASTER) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
|
||||
|
@ -684,13 +684,6 @@ STATIC mp_obj_t pin_value(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value);
|
||||
|
||||
STATIC mp_obj_t pin_toggle(mp_obj_t self_in) {
|
||||
pin_obj_t *self = self_in;
|
||||
MAP_GPIOPinWrite(self->port, self->bit, ~MAP_GPIOPinRead(self->port, self->bit));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_toggle_obj, pin_toggle);
|
||||
|
||||
STATIC mp_obj_t pin_id(mp_obj_t self_in) {
|
||||
pin_obj_t *self = self_in;
|
||||
return MP_OBJ_NEW_QSTR(self->name);
|
||||
@ -913,7 +906,6 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pin_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&pin_value_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_toggle), (mp_obj_t)&pin_toggle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_id), (mp_obj_t)&pin_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mode), (mp_obj_t)&pin_mode_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pull), (mp_obj_t)&pin_pull_obj },
|
||||
|
@ -25,11 +25,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <std.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
@ -38,7 +38,6 @@
|
||||
#include "pybrtc.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "timeutils.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
@ -197,7 +196,7 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
|
||||
// set date and time
|
||||
mp_obj_t *items;
|
||||
uint len;
|
||||
size_t len;
|
||||
mp_obj_get_array(datetime, &len, &items);
|
||||
|
||||
// verify the tuple
|
||||
@ -294,7 +293,7 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
@ -362,7 +361,7 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
|
||||
// check the alarm id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
uint32_t f_seconds;
|
||||
@ -397,7 +396,7 @@ STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// get the current time
|
||||
@ -415,7 +414,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc
|
||||
STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
// disable the alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@ -36,8 +40,6 @@
|
||||
#include "prcm.h"
|
||||
#include "gpio.h"
|
||||
#include "sdhost.h"
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "pybsd.h"
|
||||
#include "mpexception.h"
|
||||
@ -107,7 +109,7 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args)
|
||||
|
||||
pyb_sd_hw_init (self);
|
||||
if (sd_disk_init() != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
// register it with the sleep module
|
||||
@ -132,7 +134,7 @@ STATIC mp_obj_t pyb_sd_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup and initialize the object
|
||||
@ -163,9 +165,50 @@ STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_sd_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
|
||||
DRESULT res = sd_disk_read(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SD_SECTOR_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_readblocks_obj, pyb_sd_readblocks);
|
||||
|
||||
STATIC mp_obj_t pyb_sd_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
DRESULT res = sd_disk_write(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SD_SECTOR_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_writeblocks_obj, pyb_sd_writeblocks);
|
||||
|
||||
STATIC mp_obj_t pyb_sd_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT:
|
||||
case BP_IOCTL_DEINIT:
|
||||
case BP_IOCTL_SYNC:
|
||||
// nothing to do
|
||||
return MP_OBJ_NEW_SMALL_INT(0); // success
|
||||
|
||||
case BP_IOCTL_SEC_COUNT:
|
||||
return MP_OBJ_NEW_SMALL_INT(sd_disk_info.ulNofBlock * (sd_disk_info.ulBlockSize / 512));
|
||||
|
||||
case BP_IOCTL_SEC_SIZE:
|
||||
return MP_OBJ_NEW_SMALL_INT(SD_SECTOR_SIZE);
|
||||
|
||||
default: // unknown command
|
||||
return MP_OBJ_NEW_SMALL_INT(-1); // error
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_ioctl_obj, pyb_sd_ioctl);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_sd_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_sd_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_sd_deinit_obj },
|
||||
// block device protocol
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&pyb_sd_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&pyb_sd_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&pyb_sd_ioctl_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_sd_locals_dict, pyb_sd_locals_dict_table);
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_mcspi.h"
|
||||
@ -131,7 +132,7 @@ STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) {
|
||||
|
||||
STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) {
|
||||
if (!self->baudrate) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
// send and receive the data
|
||||
MAP_SPICSEnable(GSPI_BASE);
|
||||
@ -234,7 +235,7 @@ STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@ -329,7 +330,7 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||
// create a new Timer object
|
||||
int32_t timer_idx = mp_obj_get_int(args[0]);
|
||||
if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx];
|
||||
@ -370,7 +371,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
|
||||
|
||||
// verify that the timer has been already initialized
|
||||
if (!tim->config) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) {
|
||||
// invalid channel
|
||||
|
@ -279,7 +279,7 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,10 +375,13 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a
|
||||
config |= UART_CONFIG_PAR_NONE;
|
||||
} else {
|
||||
uint parity = mp_obj_get_int(args[2].u_obj);
|
||||
if (parity != UART_CONFIG_PAR_ODD && parity != UART_CONFIG_PAR_EVEN) {
|
||||
if (parity == 0) {
|
||||
config |= UART_CONFIG_PAR_EVEN;
|
||||
} else if (parity == 1) {
|
||||
config |= UART_CONFIG_PAR_ODD;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
config |= parity;
|
||||
}
|
||||
// stop bits
|
||||
config |= (args[3].u_int == 1 ? UART_CONFIG_STOP_ONE : UART_CONFIG_STOP_TWO);
|
||||
@ -388,7 +391,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a
|
||||
uint flowcontrol = UART_FLOWCONTROL_NONE;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
size_t n_pins = 2;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_uart_def_pin[self->uart_id];
|
||||
@ -454,7 +457,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
if (args[5].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
size_t n_pins = 2;
|
||||
mp_obj_get_array(args[5].u_obj, &n_pins, &pins);
|
||||
// check the Tx pin (or the Rx if Tx is None)
|
||||
if (pins[0] == mp_const_none) {
|
||||
@ -471,7 +474,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size
|
||||
}
|
||||
|
||||
if (uart_id > PYB_UART_1) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// get the correct uart instance
|
||||
@ -577,8 +580,6 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
@ -596,8 +597,8 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
|
||||
|
||||
// wait for first char to become available
|
||||
if (!uart_rx_wait(self)) {
|
||||
// return EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
*errcode = EAGAIN;
|
||||
// return MP_EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
*errcode = MP_EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
@ -619,7 +620,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
|
||||
|
||||
// write the data
|
||||
if (!uart_tx_strn(self, buf, size)) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@ -639,7 +640,7 @@ STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t a
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
} else {
|
||||
*errcode = EINVAL;
|
||||
*errcode = MP_EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
@ -664,7 +665,7 @@ const mp_obj_type_t pyb_uart_type = {
|
||||
.name = MP_QSTR_UART,
|
||||
.print = pyb_uart_print,
|
||||
.make_new = pyb_uart_make_new,
|
||||
.getiter = mp_identity,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &uart_stream_p,
|
||||
.locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
@ -100,14 +101,14 @@ STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_wdt_init_args, args);
|
||||
|
||||
if (args[0].u_obj != mp_const_none && mp_obj_get_int(args[0].u_obj) > 0) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable);
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
uint timeout_ms = args[1].u_int;
|
||||
if (timeout_ms < PYBWDT_MIN_TIMEOUT_MS) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
if (pyb_wdt_obj.running) {
|
||||
mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible);
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// Enable the WDT peripheral clock
|
||||
|
@ -55,7 +55,7 @@
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
#define MICROPY_READER_FATFS (1)
|
||||
#define MICROPY_READER_VFS (1)
|
||||
#ifndef DEBUG // we need ram on the launchxl while debugging
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#else
|
||||
@ -68,18 +68,21 @@
|
||||
#define MICROPY_FATFS_MAX_LFN (MICROPY_ALLOC_PATH_MAX)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE (437) // 1=SFN/ANSI 437=LFN/U.S.(OEM)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_VOLUMES (2)
|
||||
#define MICROPY_FATFS_REENTRANT (1)
|
||||
#define MICROPY_FATFS_TIMEOUT (2500)
|
||||
#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t
|
||||
#define MICROPY_FSUSERMOUNT_ADHOC (1)
|
||||
|
||||
#define MICROPY_STREAMS_NON_BLOCK (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_USE_INTERNAL_ERRNO (1)
|
||||
#define MICROPY_VFS (1)
|
||||
#define MICROPY_VFS_FAT (1)
|
||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
||||
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#define MICROPY_PY_BUILTINS_INPUT (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP_TEXT cc3200_help_text
|
||||
#ifndef DEBUG
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
|
||||
@ -104,6 +107,8 @@
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_IO_FILEIO (1)
|
||||
#define MICROPY_PY_UERRNO (1)
|
||||
#define MICROPY_PY_UERRNO_ERRORCODE (0)
|
||||
#define MICROPY_PY_THREAD (1)
|
||||
#define MICROPY_PY_THREAD_GIL (1)
|
||||
#define MICROPY_PY_UBINASCII (0)
|
||||
@ -114,14 +119,30 @@
|
||||
#define MICROPY_PY_UHEAPQ (0)
|
||||
#define MICROPY_PY_UHASHLIB (0)
|
||||
#define MICROPY_PY_USELECT (1)
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
|
||||
|
||||
// We define our own list of errno constants to include in uerrno module
|
||||
#define MICROPY_PY_UERRNO_LIST \
|
||||
X(EPERM) \
|
||||
X(EIO) \
|
||||
X(ENODEV) \
|
||||
X(EINVAL) \
|
||||
X(ETIMEDOUT) \
|
||||
|
||||
// TODO these should be generic, not bound to fatfs
|
||||
#define mp_type_fileio fatfs_type_fileio
|
||||
#define mp_type_textio fatfs_type_textio
|
||||
|
||||
// use vfs's functions for import stat and builtin open
|
||||
#define mp_import_stat mp_vfs_import_stat
|
||||
#define mp_builtin_open mp_vfs_open
|
||||
#define mp_builtin_open_obj mp_vfs_open_obj
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, \
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
@ -149,6 +170,7 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ussl), (mp_obj_t)&mp_module_ussl }, \
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
|
||||
@ -173,13 +195,11 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
mp_obj_list_t pyb_sleep_obj_list; \
|
||||
mp_obj_list_t mp_irq_obj_list; \
|
||||
mp_obj_list_t pyb_timer_channel_obj_list; \
|
||||
mp_obj_list_t mount_obj_list; \
|
||||
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
|
||||
struct _os_term_dup_obj_t *os_term_dup_obj; \
|
||||
|
||||
|
||||
// type definitions for the specific machine
|
||||
#define BYTES_PER_WORD (4)
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
#define MP_SSIZE_MAX (0x7FFFFFFF)
|
||||
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@ -47,7 +52,6 @@
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "gccollect.h"
|
||||
#include "gchelper.h"
|
||||
#include "readline.h"
|
||||
#include "mperror.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@ -56,13 +60,12 @@
|
||||
#include "serverstask.h"
|
||||
#include "telnet.h"
|
||||
#include "debug.h"
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "mpexception.h"
|
||||
#include "random.h"
|
||||
#include "pybi2c.h"
|
||||
#include "pins.h"
|
||||
#include "mods/pybflash.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybtimer.h"
|
||||
#include "cryptohash.h"
|
||||
@ -94,7 +97,7 @@ OsiTaskHandle svTaskHandle;
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static FATFS *sflash_fatfs;
|
||||
static fs_user_mount_t *sflash_vfs_fat;
|
||||
|
||||
static const char fresh_main_py[] = "# main.py -- put your code here!\r\n";
|
||||
static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n"
|
||||
@ -149,7 +152,6 @@ soft_reset:
|
||||
timer_init0();
|
||||
readline_init0();
|
||||
mod_network_init0();
|
||||
moduos_init0();
|
||||
rng_init0();
|
||||
|
||||
pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause();
|
||||
@ -270,7 +272,7 @@ STATIC void mptask_pre_init (void) {
|
||||
ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY));
|
||||
|
||||
// Allocate memory for the flash file system
|
||||
ASSERT ((sflash_fatfs = mem_Malloc(sizeof(FATFS))) != NULL);
|
||||
ASSERT ((sflash_vfs_fat = mem_Malloc(sizeof(*sflash_vfs_fat))) != NULL);
|
||||
|
||||
// this one allocates memory for the nvic vault
|
||||
pyb_sleep_pre_init();
|
||||
@ -296,17 +298,19 @@ STATIC void mptask_pre_init (void) {
|
||||
|
||||
STATIC void mptask_init_sflash_filesystem (void) {
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
// Initialise the local flash filesystem.
|
||||
// init the vfs object
|
||||
fs_user_mount_t *vfs_fat = sflash_vfs_fat;
|
||||
vfs_fat->flags = 0;
|
||||
pyb_flash_init_vfs(vfs_fat);
|
||||
|
||||
// Create it if needed, and mount in on /flash.
|
||||
FRESULT res = f_mount(sflash_fatfs, "/flash", 1);
|
||||
FRESULT res = f_mount(&vfs_fat->fatfs);
|
||||
if (res == FR_NO_FILESYSTEM) {
|
||||
// no filesystem, so create a fresh one
|
||||
res = f_mkfs("/flash", 1, 0);
|
||||
uint8_t working_buf[_MAX_SS];
|
||||
res = f_mkfs(&vfs_fat->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
|
||||
if (res == FR_OK) {
|
||||
// success creating fresh LFS
|
||||
} else {
|
||||
@ -316,33 +320,46 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
mptask_create_main_py();
|
||||
} else if (res == FR_OK) {
|
||||
// mount sucessful
|
||||
if (FR_OK != f_stat("/flash/main.py", &fno)) {
|
||||
if (FR_OK != f_stat(&vfs_fat->fatfs, "/main.py", &fno)) {
|
||||
// create empty main.py
|
||||
mptask_create_main_py();
|
||||
}
|
||||
} else {
|
||||
fail:
|
||||
__fatal_error("failed to create /flash");
|
||||
}
|
||||
|
||||
// mount the flash device (there should be no other devices mounted at this point)
|
||||
// we allocate this structure on the heap because vfs->next is a root pointer
|
||||
mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t);
|
||||
if (vfs == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
vfs->str = "/flash";
|
||||
vfs->len = 6;
|
||||
vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
|
||||
vfs->next = NULL;
|
||||
MP_STATE_VM(vfs_mount_table) = vfs;
|
||||
|
||||
// The current directory is used as the boot up directory.
|
||||
// It is set to the internal flash filesystem by default.
|
||||
f_chdrive("/flash");
|
||||
MP_STATE_PORT(vfs_cur) = vfs;
|
||||
|
||||
// create /flash/sys, /flash/lib and /flash/cert if they don't exist
|
||||
if (FR_OK != f_chdir ("/flash/sys")) {
|
||||
f_mkdir("/flash/sys");
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/sys")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/sys");
|
||||
}
|
||||
if (FR_OK != f_chdir ("/flash/lib")) {
|
||||
f_mkdir("/flash/lib");
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/lib")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/lib");
|
||||
}
|
||||
if (FR_OK != f_chdir ("/flash/cert")) {
|
||||
f_mkdir("/flash/cert");
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/cert")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/cert");
|
||||
}
|
||||
|
||||
f_chdir ("/flash");
|
||||
f_chdir(&vfs_fat->fatfs, "/");
|
||||
|
||||
// make sure we have a /flash/boot.py. Create it if needed.
|
||||
res = f_stat("/flash/boot.py", &fno);
|
||||
res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno);
|
||||
if (res == FR_OK) {
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
// exists as a directory
|
||||
@ -354,7 +371,7 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
} else {
|
||||
// doesn't exist, create fresh file
|
||||
FIL fp;
|
||||
f_open(&fp, "/flash/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_open(&vfs_fat->fatfs, &fp, "/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
UINT n;
|
||||
f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
|
||||
// TODO check we could write n bytes
|
||||
@ -374,7 +391,7 @@ STATIC void mptask_enter_ap_mode (void) {
|
||||
STATIC void mptask_create_main_py (void) {
|
||||
// create empty main.py
|
||||
FIL fp;
|
||||
f_open(&fp, "/flash/main.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_open(&sflash_vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
UINT n;
|
||||
f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
|
||||
f_close(&fp);
|
||||
|
@ -163,7 +163,7 @@ extern "C" {
|
||||
|
||||
\warning
|
||||
*/
|
||||
#define SL_INC_STD_BSD_API_NAMING
|
||||
/* #define SL_INC_STD_BSD_API_NAMING */
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -296,23 +296,23 @@ static void telnet_wait_for_enabled (void) {
|
||||
|
||||
static bool telnet_create_socket (void) {
|
||||
SlSockNonblocking_t nonBlockingOption;
|
||||
sockaddr_in sServerAddress;
|
||||
SlSockAddrIn_t sServerAddress;
|
||||
_i16 result;
|
||||
|
||||
// Open a socket for telnet
|
||||
ASSERT ((telnet_data.sd = sl_Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0);
|
||||
ASSERT ((telnet_data.sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_IPPROTO_TCP)) > 0);
|
||||
if (telnet_data.sd > 0) {
|
||||
// add the socket to the network administration
|
||||
modusocket_socket_add(telnet_data.sd, false);
|
||||
|
||||
// Enable non-blocking mode
|
||||
nonBlockingOption.NonblockingEnabled = 1;
|
||||
ASSERT ((result = sl_SetSockOpt(telnet_data.sd, SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
|
||||
ASSERT ((result = sl_SetSockOpt(telnet_data.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
|
||||
|
||||
// Bind the socket to a port number
|
||||
sServerAddress.sin_family = AF_INET;
|
||||
sServerAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
sServerAddress.sin_port = htons(TELNET_PORT);
|
||||
sServerAddress.sin_family = SL_AF_INET;
|
||||
sServerAddress.sin_addr.s_addr = SL_INADDR_ANY;
|
||||
sServerAddress.sin_port = sl_Htons(TELNET_PORT);
|
||||
|
||||
ASSERT ((result |= sl_Bind(telnet_data.sd, (const SlSockAddr_t *)&sServerAddress, sizeof(sServerAddress))) == SL_SOC_OK);
|
||||
|
||||
@ -330,7 +330,7 @@ static bool telnet_create_socket (void) {
|
||||
|
||||
static void telnet_wait_for_connection (void) {
|
||||
SlSocklen_t in_addrSize;
|
||||
sockaddr_in sClientAddress;
|
||||
SlSockAddrIn_t sClientAddress;
|
||||
|
||||
// accepts a connection from a TCP client, if there is any, otherwise returns SL_EAGAIN
|
||||
telnet_data.n_sd = sl_Accept(telnet_data.sd, (SlSockAddr_t *)&sClientAddress, (SlSocklen_t *)&in_addrSize);
|
||||
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This file is needed because in some cases we can't include stdio.h,
|
||||
// because the CC3100 socket driver has name clashes with it.
|
||||
|
||||
typedef unsigned int size_t;
|
||||
|
||||
int printf(const char *fmt, ...);
|
||||
int snprintf(char *str, size_t size, const char *fmt, ...);
|
||||
|
||||
// Convenience function, defined in main.c.
|
||||
void stoupper (char *str);
|
8
conf.py
8
conf.py
@ -182,7 +182,7 @@ else:
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
html_favicon = 'favicon.ico'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
@ -257,7 +257,7 @@ latex_elements = {
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'MicroPython.tex', 'MicroPython Documentation',
|
||||
'Damien P. George and contributors', 'manual'),
|
||||
'Damien P. George, Paul Sokolovsky, and contributors', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@ -287,7 +287,7 @@ latex_documents = [
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'micropython', 'MicroPython Documentation',
|
||||
['Damien P. George and contributors'], 1),
|
||||
['Damien P. George, Paul Sokolovsky, and contributors'], 1),
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@ -301,7 +301,7 @@ man_pages = [
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'MicroPython', 'MicroPython Documentation',
|
||||
'Damien P. George and contributors', 'MicroPython', 'One line description of project.',
|
||||
'Damien P. George, Paul Sokolovsky, and contributors', 'MicroPython', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
191
docs/Makefile
Normal file
191
docs/Makefile
Normal file
@ -0,0 +1,191 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python3
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = build/$(MICROPY_PORT)
|
||||
CPYDIFFDIR = ../tools
|
||||
CPYDIFF = gen-cpydiff.py
|
||||
GENRSTDIR = genrst
|
||||
# Run "make FORCE= ..." to avoid rebuilding from scratch (and risk
|
||||
# producing incorrect docs).
|
||||
FORCE = -E
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " cpydiff to generate the MicroPython differences from CPython"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
rm -f $(GENRSTDIR)/*
|
||||
|
||||
cpydiff:
|
||||
@echo "Generating MicroPython Differences."
|
||||
rm -f $(GENRSTDIR)/*
|
||||
cd $(CPYDIFFDIR) && $(PYTHON) $(CPYDIFF)
|
||||
|
||||
html: cpydiff
|
||||
$(SPHINXBUILD) $(FORCE) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/MicroPython.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/MicroPython.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/MicroPython"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/MicroPython"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex: cpydiff
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf: cpydiff
|
||||
$(SPHINXBUILD) $(FORCE) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja: cpydiff
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
8
docs/differences/index_template.txt
Normal file
8
docs/differences/index_template.txt
Normal file
@ -0,0 +1,8 @@
|
||||
MicroPython Differences from CPython
|
||||
====================================
|
||||
|
||||
The operations listed in this section produce conflicting results in MicroPython when compared to standard Python.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
@ -107,8 +107,16 @@ This will allow to keep the structure of your application clear, as well as
|
||||
allow to install multiple applications on a board, and switch among them.
|
||||
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
Real-time clock
|
||||
---------------
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
RTC in ESP8266 has very bad accuracy, drift may be seconds per minute. As
|
||||
a workaround, to measure short enough intervals you can use
|
||||
``utime.time()``, etc. functions, and for wall clock time, synchronize from
|
||||
the net using included ``ntpdate.py`` module.
|
||||
|
||||
Due to limitations of the ESP8266 chip the internal real-time clock (RTC)
|
||||
will overflow every 7:45h. If a long-term working RTC time is required then
|
||||
|
@ -88,7 +88,7 @@ Use the :mod:`time <utime>` module::
|
||||
Timers
|
||||
------
|
||||
|
||||
Virtual (RTOS-based) timers are supported. Use the ``machine.Timer`` class
|
||||
Virtual (RTOS-based) timers are supported. Use the :ref:`machine.Timer <machine.Timer>` class
|
||||
with timer ID of -1::
|
||||
|
||||
from machine import Timer
|
||||
@ -102,14 +102,14 @@ The period is in milliseconds.
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
Use the ``machine.Pin`` class::
|
||||
Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
|
||||
p0.high() # set pin to high
|
||||
p0.low() # set pin to low
|
||||
p0.value(1) # set pin to high
|
||||
p0.on() # set pin to "on" (high) level
|
||||
p0.off() # set pin to "off" (low) level
|
||||
p0.value(1) # set pin to on/high
|
||||
|
||||
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
|
||||
print(p2.value()) # get value, 0 or 1
|
||||
@ -155,7 +155,7 @@ ADC (analog to digital conversion)
|
||||
ADC is available on a dedicated pin.
|
||||
Note that input voltages on the ADC pin must be between 0v and 1.0v.
|
||||
|
||||
Use the ``machine.ADC`` class::
|
||||
Use the :ref:`machine.ADC <machine.ADC>` class::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
@ -166,7 +166,8 @@ Software SPI bus
|
||||
----------------
|
||||
|
||||
There are two SPI drivers. One is implemented in software (bit-banging)
|
||||
and works on all pins::
|
||||
and works on all pins, and is accessed via the :ref:`machine.SPI <machine.SPI>`
|
||||
class::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
@ -208,7 +209,8 @@ constructor and init (as those are fixed)::
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
The I2C driver is implemented in software and works on all pins::
|
||||
The I2C driver is implemented in software and works on all pins,
|
||||
and is accessed via the :ref:`machine.I2C <machine.I2C>` class::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
|
@ -20,9 +20,12 @@ characteristic of a board is how much flash it has, how the GPIO pins are
|
||||
connected to the outside world, and whether it includes a built-in USB-serial
|
||||
convertor to make the UART available to your PC.
|
||||
|
||||
The minimum requirement for flash size is 512k. A board with this amount of
|
||||
flash will not have room for a filesystem, but otherwise is fully functional.
|
||||
If your board has 1Mbyte or more of flash then it will support a filesystem.
|
||||
The minimum requirement for flash size is 1Mbyte. There is also a special
|
||||
build for boards with 512KB, but it is highly limited comparing to the
|
||||
normal build: there is no support for filesystem, and thus features which
|
||||
depend on it won't work (WebREPL, upip, etc.). As such, 512KB build will
|
||||
be more interesting for users who build from source and fine-tune parameters
|
||||
for their particular application.
|
||||
|
||||
Names of pins will be given in this tutorial using the chip names (eg GPIO0)
|
||||
and it should be straightforward to find which pin this corresponds to on your
|
||||
@ -72,15 +75,17 @@ For best results it is recommended to first erase the entire flash of your
|
||||
device before putting on new MicroPython firmware.
|
||||
|
||||
Currently we only support esptool.py to copy across the firmware. You can find
|
||||
this tool here: `<https://github.com/themadinventor/esptool/>`__, or install it
|
||||
using pip (at least version 1.2.1 is required)::
|
||||
this tool here: `<https://github.com/espressif/esptool/>`__, or install it
|
||||
using pip::
|
||||
|
||||
pip install esptool
|
||||
|
||||
It requires Python 2.7, so you may need to use ``pip2`` instead of ``pip`` in
|
||||
the command above. Any other
|
||||
flashing program should work, so feel free to try them out, or refer to the
|
||||
documentation for your board to see its recommendations.
|
||||
Versions starting with 1.3 support both Python 2.7 and Python 3.4 (or newer).
|
||||
An older version (at least 1.2.1 is needed) works fine but will require Python
|
||||
2.7.
|
||||
|
||||
Any other flashing program should work, so feel free to try them out or refer
|
||||
to the documentation for your board to see its recommendations.
|
||||
|
||||
Using esptool.py you can erase the flash with the command::
|
||||
|
||||
@ -88,7 +93,7 @@ Using esptool.py you can erase the flash with the command::
|
||||
|
||||
And then deploy the new firmware using::
|
||||
|
||||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-2016-05-03-v1.8.bin
|
||||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
|
||||
|
||||
You might need to change the "port" setting to something else relevant for your
|
||||
PC. You may also need to reduce the baudrate if you get errors when flashing
|
||||
@ -99,7 +104,7 @@ For some boards with a particular FlashROM configuration (e.g. some variants of
|
||||
a NodeMCU board) you may need to use the following command to deploy
|
||||
the firmware (note the ``-fm dio`` option)::
|
||||
|
||||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-2016-05-03-v1.8.bin
|
||||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin
|
||||
|
||||
If the above commands run without error then MicroPython should be installed on
|
||||
your board!
|
||||
@ -158,7 +163,9 @@ after it, here are troubleshooting recommendations:
|
||||
esptool.py, which had a different programming algorithm::
|
||||
pip install esptool==1.0.1
|
||||
This version doesn't support ``--flash_size=detect`` option, so you will
|
||||
need to specify FlashROM size explicitly (in megabits).
|
||||
need to specify FlashROM size explicitly (in megabits). It also requires
|
||||
Python 2.7, so you may need to use ``pip2`` instead of ``pip`` in the
|
||||
command above.
|
||||
|
||||
* The ``--flash_size`` option in the commands above is mandatory. Omitting
|
||||
it will lead to a corrupted firmware.
|
||||
@ -179,7 +186,7 @@ after it, here are troubleshooting recommendations:
|
||||
application in the ESP8266 community.
|
||||
|
||||
* If you still experience problems with even flashing the firmware, please
|
||||
refer to esptool.py project page, https://github.com/themadinventor/esptool
|
||||
refer to esptool.py project page, https://github.com/espressif/esptool
|
||||
for additional documentation and bug tracker where you can report problems.
|
||||
|
||||
* If you are able to flash firmware, but ``--verify`` option or
|
||||
|
@ -35,8 +35,8 @@ Then set its value using::
|
||||
|
||||
Or::
|
||||
|
||||
>>> pin.low()
|
||||
>>> pin.high()
|
||||
>>> pin.off()
|
||||
>>> pin.on()
|
||||
|
||||
External interrupts
|
||||
-------------------
|
||||
|
@ -24,7 +24,7 @@ terminal programs that will work, so pick your favourite!
|
||||
|
||||
For example, on Linux you can try running::
|
||||
|
||||
picocom /dev/ttyUSB0
|
||||
picocom /dev/ttyUSB0 -b115200
|
||||
|
||||
Once you have made the connection over the serial port you can test if it is
|
||||
working by hitting enter a few times. You should see the Python REPL prompt,
|
||||
@ -101,11 +101,12 @@ turn it on and off using the following code::
|
||||
|
||||
>>> import machine
|
||||
>>> pin = machine.Pin(2, machine.Pin.OUT)
|
||||
>>> pin.high()
|
||||
>>> pin.low()
|
||||
>>> pin.on()
|
||||
>>> pin.off()
|
||||
|
||||
Note that ``high`` might turn the LED off and ``low`` might turn it on (or vice
|
||||
versa), depending on how the LED is wired on your board.
|
||||
Note that ``on`` method of a Pin might turn the LED off and ``off`` might
|
||||
turn it on (or vice versa), depending on how the LED is wired on your board.
|
||||
To resolve this, machine.Signal class is provided.
|
||||
|
||||
Line editing
|
||||
~~~~~~~~~~~~
|
||||
|
12
docs/esp8266_contents.rst
Normal file
12
docs/esp8266_contents.rst
Normal file
@ -0,0 +1,12 @@
|
||||
MicroPython documentation contents
|
||||
==================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
esp8266/quickref.rst
|
||||
esp8266/general.rst
|
||||
esp8266/tutorial/index.rst
|
||||
library/index.rst
|
||||
reference/index.rst
|
||||
genrst/index.rst
|
||||
license.rst
|
17
docs/esp8266_index.rst
Normal file
17
docs/esp8266_index.rst
Normal file
@ -0,0 +1,17 @@
|
||||
MicroPython documentation and references
|
||||
========================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
esp8266/quickref.rst
|
||||
library/index.rst
|
||||
genrst/index.rst
|
||||
license.rst
|
||||
esp8266_contents.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
144
docs/library/btree.rst
Normal file
144
docs/library/btree.rst
Normal file
@ -0,0 +1,144 @@
|
||||
:mod:`btree` -- simple BTree database
|
||||
=====================================
|
||||
|
||||
.. module:: btree
|
||||
:synopsis: simple BTree database
|
||||
|
||||
The ``btree`` module implements a simple key-value database using external
|
||||
storage (disk files, or in general case, a random-access stream). Keys are
|
||||
stored sorted in the database, and besides efficient retrieval by a key
|
||||
value, a database also supports efficient ordered range scans (retrieval
|
||||
of values with the keys in a given range). On the application interface
|
||||
side, BTree database work as close a possible to a way standard `dict`
|
||||
type works, one notable difference is that both keys and values must
|
||||
be `bytes` objects (so, if you want to store objects of other types, you
|
||||
need to serialize them to `bytes` first).
|
||||
|
||||
The module is based on the well-known BerkelyDB library, version 1.xx.
|
||||
|
||||
Example::
|
||||
|
||||
import btree
|
||||
|
||||
# First, we need to open a stream which holds a database
|
||||
# This is usually a file, but can be in-memory database
|
||||
# using uio.BytesIO, a raw flash section, etc.
|
||||
f = open("mydb", "w+b")
|
||||
|
||||
# Now open a database itself
|
||||
db = btree.open(f)
|
||||
|
||||
# The keys you add will be sorted internally in the database
|
||||
db[b"3"] = b"three"
|
||||
db[b"1"] = b"one"
|
||||
db[b"2"] = b"two"
|
||||
|
||||
# Prints b'two'
|
||||
print(db[b"2"])
|
||||
|
||||
# Iterate over sorted keys in the database, starting from b"2"
|
||||
# until the end of the database, returning only values.
|
||||
# Mind that arguments passed to values() method are *key* values.
|
||||
# Prints:
|
||||
# b'two'
|
||||
# b'three'
|
||||
for word in db.values(b"2"):
|
||||
print(word)
|
||||
|
||||
del db[b"2"]
|
||||
|
||||
# No longer true, prints False
|
||||
print(b"2" in db)
|
||||
|
||||
# Prints:
|
||||
# b"1"
|
||||
# b"3"
|
||||
for key in db:
|
||||
print(key)
|
||||
|
||||
db.close()
|
||||
|
||||
# Don't forget to close the underlying stream!
|
||||
f.close()
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: open(stream, \*, flags=0, cachesize=0, pagesize=0, minkeypage=0)
|
||||
|
||||
Open a database from a random-access `stream` (like an open file). All
|
||||
other parameters are optional and keyword-only, and allow to tweak advanced
|
||||
parameters of the database operation (most users will not need them):
|
||||
|
||||
* `flags` - Currently unused.
|
||||
* `cachesize` - Suggested maximum memory cache size in bytes. For a
|
||||
board with enough memory using larger values may improve performance.
|
||||
The value is only a recommendation, the module may use more memory if
|
||||
values set too low.
|
||||
* `pagesize` - Page size used for the nodes in BTree. Acceptable range
|
||||
is 512-65536. If 0, underlying I/O block size will be used (the best
|
||||
compromise between memory usage and performance).
|
||||
* `minkeypage` - Minimum number of keys to store per page. Default value
|
||||
of 0 equivalent to 2.
|
||||
|
||||
Returns a `BTree` object, which implements a dictionary protocol (set
|
||||
of methods), and some additional methods described below.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: btree.close()
|
||||
|
||||
Close the database. It's mandatory to close the database at the end of
|
||||
processing, as some unwritten data may be still in the cache. Note that
|
||||
this does not close underlying streamw with which the database was opened,
|
||||
it should be closed separately (which is also mandatory to make sure that
|
||||
data flushed from buffer to the underlying storage).
|
||||
|
||||
.. method:: btree.flush()
|
||||
|
||||
Flush any data in cache to the underlying stream.
|
||||
|
||||
.. method:: btree.__getitem__(key)
|
||||
.. method:: btree.get(key, default=None)
|
||||
.. method:: btree.__setitem__(key, val)
|
||||
.. method:: btree.__detitem__(key)
|
||||
.. method:: btree.__contains__(key)
|
||||
|
||||
Standard dictionary methods.
|
||||
|
||||
.. method:: btree.__iter__()
|
||||
|
||||
A BTree object can be iterated over directly (similar to a dictionary)
|
||||
to get access to all keys in order.
|
||||
|
||||
.. method:: btree.keys([start_key, [end_key, [flags]]])
|
||||
.. method:: btree.values([start_key, [end_key, [flags]]])
|
||||
.. method:: btree.items([start_key, [end_key, [flags]]])
|
||||
|
||||
These methods are similar to standard dictionary methods, but also can
|
||||
take optional parameters to iterate over a key sub-range, instead of
|
||||
the entire database. Note that for all 3 methods, `start_key` and
|
||||
`end_key` arguments represent key values. For example, ``values()``
|
||||
method will iterate over values corresponding to they key range
|
||||
given. None values for `start_key` means "from the first key", no
|
||||
`end_key` or its value of None means "until the end of database".
|
||||
By default, range is inclusive of `start_key` and exclusive of
|
||||
`end_key`, you can include `end_key` in iteration by passing `flags`
|
||||
of `btree.INCL`. You can iterate in descending key direction
|
||||
by passing `flags` of `btree.DESC`. The flags values can be ORed
|
||||
together.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: INCL
|
||||
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be inclusive of the end key.
|
||||
|
||||
.. data:: DESC
|
||||
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be in descending direction of keys.
|
@ -67,6 +67,16 @@ All builtin functions are described here. They are also available via
|
||||
|
||||
.. class:: int()
|
||||
|
||||
.. classmethod:: from_bytes(bytes, byteorder)
|
||||
|
||||
In MicroPython, `byteorder` parameter must be positional (this is
|
||||
compatible with CPython).
|
||||
|
||||
.. method:: to_bytes(size, byteorder)
|
||||
|
||||
In MicroPython, `byteorder` parameter must be positional (this is
|
||||
compatible with CPython).
|
||||
|
||||
.. function:: isinstance()
|
||||
|
||||
.. function:: issubclass()
|
||||
|
152
docs/library/framebuf.rst
Normal file
152
docs/library/framebuf.rst
Normal file
@ -0,0 +1,152 @@
|
||||
:mod:`framebuf` --- Frame buffer manipulation
|
||||
=============================================
|
||||
|
||||
.. module:: framebuf
|
||||
:synopsis: Frame buffer manipulation
|
||||
|
||||
This module provides a general frame buffer which can be used to create
|
||||
bitmap images, which can then be sent to a display.
|
||||
|
||||
class FrameBuffer
|
||||
-----------------
|
||||
|
||||
The FrameBuffer class provides a pixel buffer which can be drawn upon with
|
||||
pixels, lines, rectangles, text and even other FrameBuffer's. It is useful
|
||||
when generating output for displays.
|
||||
|
||||
For example::
|
||||
|
||||
import framebuf
|
||||
|
||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||
fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
|
||||
|
||||
fbuf.fill(0)
|
||||
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
||||
fbuf.hline(0, 10, 96, 0xffff)
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width)
|
||||
|
||||
Construct a FrameBuffer object. The parameters are:
|
||||
|
||||
- `buffer` is an object with a buffer protocol which must be large
|
||||
enough to contain every pixel defined by the width, height and
|
||||
format of the FrameBuffer.
|
||||
- `width` is the width of the FrameBuffer in pixels
|
||||
- `height` is the height of the FrameBuffer in pixels
|
||||
- `format` specifies the type of pixel used in the FrameBuffer;
|
||||
valid values are ``framebuf.MVLSB``, ``framebuf.RGB565``
|
||||
and ``framebuf.GS4_HMSB``. MVLSB is monochrome 1-bit color,
|
||||
RGB565 is RGB 16-bit color, and GS4_HMSB is grayscale 4-bit color.
|
||||
Where a color value c is passed to a method, c is a small integer
|
||||
with an encoding that is dependent on the format of the FrameBuffer.
|
||||
- `stride` is the number of pixels between each horizontal line
|
||||
of pixels in the FrameBuffer. This defaults to `width` but may
|
||||
need adjustments when implementing a FrameBuffer within another
|
||||
larger FrameBuffer or screen. The `buffer` size must accommodate
|
||||
an increased step size.
|
||||
|
||||
One must specify valid `buffer`, `width`, `height`, `format` and
|
||||
optionally `stride`. Invalid `buffer` size or dimensions may lead to
|
||||
unexpected errors.
|
||||
|
||||
Drawing primitive shapes
|
||||
------------------------
|
||||
|
||||
The following methods draw shapes onto the FrameBuffer.
|
||||
|
||||
.. method:: FrameBuffer.fill(c)
|
||||
|
||||
Fill the entire FrameBuffer with the specified color.
|
||||
|
||||
.. method:: FrameBuffer.pixel(x, y[, c])
|
||||
|
||||
If `c` is not given, get the color value of the specified pixel.
|
||||
If `c` is given, set the specified pixel to the given color.
|
||||
|
||||
.. method:: FrameBuffer.hline(x, y, w, c)
|
||||
.. method:: FrameBuffer.vline(x, y, h, c)
|
||||
.. method:: FrameBuffer.line(x1, y1, x2, y2, c)
|
||||
|
||||
Draw a line from a set of coordinates using the given color and
|
||||
a thickness of 1 pixel. The `line` method draws the line up to
|
||||
a second set of coordinates whereas the `hline` and `vline`
|
||||
methods draw horizontal and vertical lines respectively up to
|
||||
a given length.
|
||||
|
||||
.. method:: FrameBuffer.rect(x, y, w, h, c)
|
||||
.. method:: FrameBuffer.fill_rect(x, y, w, h, c)
|
||||
|
||||
Draw a rectangle at the given location, size and color. The `rect`
|
||||
method draws only a 1 pixel outline whereas the `fill_rect` method
|
||||
draws both the outline and interior.
|
||||
|
||||
Drawing text
|
||||
------------
|
||||
|
||||
.. method:: FrameBuffer.text(s, x, y[, c])
|
||||
|
||||
Write text to the FrameBuffer using the the coordinates as the upper-left
|
||||
corner of the text. The color of the text can be defined by the optional
|
||||
argument but is otherwise a default value of 1. All characters have
|
||||
dimensions of 8x8 pixels and there is currently no way to change the font.
|
||||
|
||||
|
||||
Other methods
|
||||
-------------
|
||||
|
||||
.. method:: FrameBuffer.scroll(xstep, ystep)
|
||||
|
||||
Shift the contents of the FrameBuffer by the given vector. This may
|
||||
leave a footprint of the previous colors in the FrameBuffer.
|
||||
|
||||
.. method:: FrameBuffer.blit(fbuf, x, y[, key])
|
||||
|
||||
Draw another FrameBuffer on top of the current one at the given coordinates.
|
||||
If `key` is specified then it should be a color integer and the
|
||||
corresponding color will be considered transparent: all pixels with that
|
||||
color value will not be drawn.
|
||||
|
||||
This method works between FrameBuffer's utilising different formats, but the
|
||||
resulting colors may be unexpected due to the mismatch in color formats.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: framebuf.MONO_VLSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are vertically mapped with
|
||||
bit 0 being nearest the top of the screen. Consequently each byte occupies
|
||||
8 vertical pixels. Subsequent bytes appear at successive horizontal
|
||||
locations until the rightmost edge is reached. Further bytes are rendered
|
||||
at locations starting at the leftmost edge, 8 pixels lower.
|
||||
|
||||
.. data:: framebuf.MONO_HLSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
||||
.. data:: framebuf.MONO_HMSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
||||
.. data:: framebuf.RGB565
|
||||
|
||||
Red Green Blue (16-bit, 5+6+5) color format
|
||||
|
||||
.. data:: framebuf.GS4_HMSB
|
||||
|
||||
Grayscale (4-bit) color format
|
@ -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 and CircuitPython. There are a few categories of modules:
|
||||
|
||||
@ -153,6 +164,8 @@ the following libraries.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
btree.rst
|
||||
framebuf.rst
|
||||
machine.rst
|
||||
micropython.rst
|
||||
network.rst
|
||||
@ -170,6 +183,7 @@ the following libraries.
|
||||
:maxdepth: 2
|
||||
|
||||
pyb.rst
|
||||
lcd160cr.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
|
394
docs/library/lcd160cr.rst
Normal file
394
docs/library/lcd160cr.rst
Normal file
@ -0,0 +1,394 @@
|
||||
:mod:`lcd160cr` --- control of LCD160CR display
|
||||
===============================================
|
||||
|
||||
.. module:: lcd160cr
|
||||
:synopsis: control of LCD160CR display
|
||||
|
||||
This module provides control of the MicroPython LCD160CR display.
|
||||
|
||||
.. image:: http://micropython.org/resources/LCD160CRv10-persp.jpg
|
||||
:alt: LCD160CRv1.0 picture
|
||||
:width: 640px
|
||||
|
||||
Further resources are available via the following links:
|
||||
|
||||
* `LCD160CRv1.0 reference manual <http://micropython.org/resources/LCD160CRv10-refmanual.pdf>`_ (100KiB PDF)
|
||||
* `LCD160CRv1.0 schematics <http://micropython.org/resources/LCD160CRv10-schematics.pdf>`_ (1.6MiB PDF)
|
||||
|
||||
class LCD160CR
|
||||
--------------
|
||||
|
||||
The LCD160CR class provides an interface to the display. Create an
|
||||
instance of this class and use its methods to draw to the LCD and get
|
||||
the status of the touch panel.
|
||||
|
||||
For example::
|
||||
|
||||
import lcd160cr
|
||||
|
||||
lcd = lcd160cr.LCD160CR('X')
|
||||
lcd.set_orient(lcd160cr.PORTRAIT)
|
||||
lcd.set_pos(0, 0)
|
||||
lcd.set_text_color(lcd.rgb(255, 0, 0), lcd.rgb(0, 0, 0))
|
||||
lcd.set_font(1)
|
||||
lcd.write('Hello MicroPython!')
|
||||
print('touch:', lcd.get_touch())
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: LCD160CR(connect=None, \*, pwr=None, i2c=None, spi=None, i2c_addr=98)
|
||||
|
||||
Construct an LCD160CR object. The parameters are:
|
||||
|
||||
- `connect` is a string specifying the physical connection of the LCD
|
||||
display to the board; valid values are "X", "Y", "XY", "YX".
|
||||
Use "X" when the display is connected to a pyboard in the X-skin
|
||||
position, and "Y" when connected in the Y-skin position. "XY"
|
||||
and "YX" are used when the display is connected to the right or
|
||||
left side of the pyboard, respectively.
|
||||
- `pwr` is a Pin object connected to the LCD's power/enabled pin.
|
||||
- `i2c` is an I2C object connected to the LCD's I2C interface.
|
||||
- `spi` is an SPI object connected to the LCD's SPI interface.
|
||||
- `i2c_addr` is the I2C address of the display.
|
||||
|
||||
One must specify either a valid `connect` or all of `pwr`, `i2c` and `spi`.
|
||||
If a valid `connect` is given then any of `pwr`, `i2c` or `spi` which are
|
||||
not passed as parameters (ie they are `None`) will be created based on the
|
||||
value of `connect`. This allows to override the default interface to the
|
||||
display if needed.
|
||||
|
||||
The default values are:
|
||||
|
||||
- "X" is for the X-skin and uses:
|
||||
``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")``
|
||||
- "Y" is for the Y-skin and uses:
|
||||
``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")``
|
||||
- "XY" is for the right-side and uses:
|
||||
``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")``
|
||||
- "YX" is for the left-side and uses:
|
||||
``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")``
|
||||
|
||||
See `this image <http://micropython.org/resources/LCD160CRv10-positions.jpg>`_
|
||||
for how the display can be connected to the pyboard.
|
||||
|
||||
Static methods
|
||||
--------------
|
||||
|
||||
.. staticmethod:: LCD160CR.rgb(r, g, b)
|
||||
|
||||
Return a 16-bit integer representing the given rgb color values. The
|
||||
16-bit value can be used to set the font color (see
|
||||
:meth:`LCD160CR.set_text_color`) pen color (see :meth:`LCD160CR.set_pen`)
|
||||
and draw individual pixels.
|
||||
|
||||
.. staticmethod:: LCD160CR.clip_line(data, w, h):
|
||||
|
||||
Clip the given line data. This is for internal use.
|
||||
|
||||
Instance members
|
||||
----------------
|
||||
|
||||
The following instance members are publicly accessible.
|
||||
|
||||
.. data:: LCD160CR.w
|
||||
.. data:: LCD160CR.h
|
||||
|
||||
The width and height of the display, respectively, in pixels. These
|
||||
members are updated when calling :meth:`LCD160CR.set_orient` and should
|
||||
be considered read-only.
|
||||
|
||||
Setup commands
|
||||
--------------
|
||||
|
||||
.. method:: LCD160CR.set_power(on)
|
||||
|
||||
Turn the display on or off, depending on the given value of `on`: 0 or `False`
|
||||
will turn the display off, and 1 or `True` will turn it on.
|
||||
|
||||
.. method:: LCD160CR.set_orient(orient)
|
||||
|
||||
Set the orientation of the display. The `orient` parameter can be one
|
||||
of `PORTRAIT`, `LANDSCAPE`, `PORTRAIT_UPSIDEDOWN`, `LANDSCAPE_UPSIDEDOWN`.
|
||||
|
||||
.. method:: LCD160CR.set_brightness(value)
|
||||
|
||||
Set the brightness of the display, between 0 and 31.
|
||||
|
||||
.. method:: LCD160CR.set_i2c_addr(addr)
|
||||
|
||||
Set the I2C address of the display. The `addr` value must have the
|
||||
lower 2 bits cleared.
|
||||
|
||||
.. method:: LCD160CR.set_uart_baudrate(baudrate)
|
||||
|
||||
Set the baudrate of the UART interface.
|
||||
|
||||
.. method:: LCD160CR.set_startup_deco(value)
|
||||
|
||||
Set the start-up decoration of the display. The `value` parameter can be a
|
||||
logical or of `STARTUP_DECO_NONE`, `STARTUP_DECO_MLOGO`, `STARTUP_DECO_INFO`.
|
||||
|
||||
.. method:: LCD160CR.save_to_flash()
|
||||
|
||||
Save the following parameters to flash so they persist on restart and power up:
|
||||
initial decoration, orientation, brightness, UART baud rate, I2C address.
|
||||
|
||||
Pixel access methods
|
||||
--------------------
|
||||
|
||||
The following methods manipulate individual pixels on the display.
|
||||
|
||||
.. method:: LCD160CR.set_pixel(x, y, c)
|
||||
|
||||
Set the specified pixel to the given color. The color should be a 16-bit
|
||||
integer and can be created by :meth:`LCD160CR.rgb`.
|
||||
|
||||
.. method:: LCD160CR.get_pixel(x, y)
|
||||
|
||||
Get the 16-bit value of the specified pixel.
|
||||
|
||||
.. method:: LCD160CR.get_line(x, y, buf)
|
||||
|
||||
Low-level method to get a line of pixels into the given buffer.
|
||||
To read `n` pixels `buf` should be `2*n+1` bytes in length. The first byte
|
||||
is a dummy byte and should be ignored, and subsequent bytes represent the
|
||||
pixels in the line starting at coordinate `(x, y)`.
|
||||
|
||||
.. method:: LCD160CR.screen_dump(buf, x=0, y=0, w=None, h=None)
|
||||
|
||||
Dump the contents of the screen to the given buffer. The parameters `x` and `y`
|
||||
specify the starting coordinate, and `w` and `h` the size of the region. If `w`
|
||||
or `h` are `None` then they will take on their maximum values, set by the size
|
||||
of the screen minus the given `x` and `y` values. `buf` should be large enough
|
||||
to hold `2*w*h` bytes. If it's smaller then only the initial horizontal lines
|
||||
will be stored.
|
||||
|
||||
.. method:: LCD160CR.screen_load(buf)
|
||||
|
||||
Load the entire screen from the given buffer.
|
||||
|
||||
Drawing text
|
||||
------------
|
||||
|
||||
To draw text one sets the position, color and font, and then uses
|
||||
`write` to draw the text.
|
||||
|
||||
.. method:: LCD160CR.set_pos(x, y)
|
||||
|
||||
Set the position for text output using :meth:`LCD160CR.write`. The position
|
||||
is the upper-left corner of the text.
|
||||
|
||||
.. method:: LCD160CR.set_text_color(fg, bg)
|
||||
|
||||
Set the foreground and background color of the text.
|
||||
|
||||
.. method:: LCD160CR.set_font(font, scale=0, bold=0, trans=0, scroll=0)
|
||||
|
||||
Set the font for the text. Subsequent calls to `write` will use the newly
|
||||
configured font. The parameters are:
|
||||
|
||||
- `font` is the font family to use, valid values are 0, 1, 2, 3.
|
||||
- `scale` is a scaling value for each character pixel, where the pixels
|
||||
are drawn as a square with side length equal to `scale + 1`. The value
|
||||
can be between 0 and 63.
|
||||
- `bold` controls the number of pixels to overdraw each character pixel,
|
||||
making a bold effect. The lower 2 bits of `bold` are the number of
|
||||
pixels to overdraw in the horizontal direction, and the next 2 bits are
|
||||
for the vertical direction. For example, a `bold` value of 5 will
|
||||
overdraw 1 pixel in both the horizontal and vertical directions.
|
||||
- `trans` can be either 0 or 1 and if set to 1 the characters will be
|
||||
drawn with a transparent background.
|
||||
- `scroll` can be either 0 or 1 and if set to 1 the display will do a
|
||||
soft scroll if the text moves to the next line.
|
||||
|
||||
.. method:: LCD160CR.write(s)
|
||||
|
||||
Write text to the display, using the current position, color and font.
|
||||
As text is written the position is automatically incremented. The
|
||||
display supports basic VT100 control codes such as newline and backspace.
|
||||
|
||||
Drawing primitive shapes
|
||||
------------------------
|
||||
|
||||
Primitive drawing commands use a foreground and background color set by the
|
||||
`set_pen` method.
|
||||
|
||||
.. method:: LCD160CR.set_pen(line, fill)
|
||||
|
||||
Set the line and fill color for primitive shapes.
|
||||
|
||||
.. method:: LCD160CR.erase()
|
||||
|
||||
Erase the entire display to the pen fill color.
|
||||
|
||||
.. method:: LCD160CR.dot(x, y)
|
||||
|
||||
Draw a single pixel at the given location using the pen line color.
|
||||
|
||||
.. method:: LCD160CR.rect(x, y, w, h)
|
||||
.. method:: LCD160CR.rect_outline(x, y, w, h)
|
||||
.. method:: LCD160CR.rect_interior(x, y, w, h)
|
||||
|
||||
Draw a rectangle at the given location and size using the pen line
|
||||
color for the outline, and the pen fill color for the interior.
|
||||
The `rect` method draws the outline and interior, while the other methods
|
||||
just draw one or the other.
|
||||
|
||||
.. method:: LCD160CR.line(x1, y1, x2, y2)
|
||||
|
||||
Draw a line between the given coordinates using the pen line color.
|
||||
|
||||
.. method:: LCD160CR.dot_no_clip(x, y)
|
||||
.. method:: LCD160CR.rect_no_clip(x, y, w, h)
|
||||
.. method:: LCD160CR.rect_outline_no_clip(x, y, w, h)
|
||||
.. method:: LCD160CR.rect_interior_no_clip(x, y, w, h)
|
||||
.. method:: LCD160CR.line_no_clip(x1, y1, x2, y2)
|
||||
|
||||
These methods are as above but don't do any clipping on the input
|
||||
coordinates. They are faster than the clipping versions and can be
|
||||
used when you know that the coordinates are within the display.
|
||||
|
||||
.. method:: LCD160CR.poly_dot(data)
|
||||
|
||||
Draw a sequence of dots using the pen line color.
|
||||
The `data` should be a buffer of bytes, with each successive pair of
|
||||
bytes corresponding to coordinate pairs (x, y).
|
||||
|
||||
.. method:: LCD160CR.poly_line(data)
|
||||
|
||||
Similar to :meth:`LCD160CR.poly_dot` but draws lines between the dots.
|
||||
|
||||
Touch screen methods
|
||||
--------------------
|
||||
|
||||
.. method:: LCD160CR.touch_config(calib=False, save=False, irq=None)
|
||||
|
||||
Configure the touch panel:
|
||||
|
||||
- If `calib` is `True` then the call will trigger a touch calibration of
|
||||
the resistive touch sensor. This requires the user to touch various
|
||||
parts of the screen.
|
||||
- If `save` is `True` then the touch parameters will be saved to NVRAM
|
||||
to persist across reset/power up.
|
||||
- If `irq` is `True` then the display will be configured to pull the IRQ
|
||||
line low when a touch force is detected. If `irq` is `False` then this
|
||||
feature is disabled. If `irq` is `None` (the default value) then no
|
||||
change is made to this setting.
|
||||
|
||||
.. method:: LCD160CR.is_touched()
|
||||
|
||||
Returns a boolean: `True` if there is currently a touch force on the screen,
|
||||
`False` otherwise.
|
||||
|
||||
.. method:: LCD160CR.get_touch()
|
||||
|
||||
Returns a 3-tuple of: (active, x, y). If there is currently a touch force
|
||||
on the screen then `active` is 1, otherwise it is 0. The `x` and `y` values
|
||||
indicate the position of the current or most recent touch.
|
||||
|
||||
Advanced commands
|
||||
-----------------
|
||||
|
||||
.. method:: LCD160CR.set_spi_win(x, y, w, h)
|
||||
|
||||
Set the window that SPI data is written to.
|
||||
|
||||
.. method:: LCD160CR.fast_spi(flush=True)
|
||||
|
||||
Ready the display to accept RGB pixel data on the SPI bus, resetting the location
|
||||
of the first byte to go to the top-left corner of the window set by
|
||||
:meth:`LCD160CR.set_spi_win`.
|
||||
The method returns an SPI object which can be used to write the pixel data.
|
||||
|
||||
Pixels should be sent as 16-bit RGB values in the 5-6-5 format. The destination
|
||||
counter will increase as data is sent, and data can be sent in arbitrary sized
|
||||
chunks. Once the destination counter reaches the end of the window specified by
|
||||
:meth:`LCD160CR.set_spi_win` it will wrap around to the top-left corner of that window.
|
||||
|
||||
.. method:: LCD160CR.show_framebuf(buf)
|
||||
|
||||
Show the given buffer on the display. `buf` should be an array of bytes containing
|
||||
the 16-bit RGB values for the pixels, and they will be written to the area
|
||||
specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner.
|
||||
|
||||
The `framebuf <framebuf.html>`_ module can be used to construct frame buffers
|
||||
and provides drawing primitives. Using a frame buffer will improve
|
||||
performance of animations when compared to drawing directly to the screen.
|
||||
|
||||
.. method:: LCD160CR.set_scroll(on)
|
||||
|
||||
Turn scrolling on or off. This controls globally whether any window regions will
|
||||
scroll.
|
||||
|
||||
.. method:: LCD160CR.set_scroll_win(win, x=-1, y=0, w=0, h=0, vec=0, pat=0, fill=0x07e0, color=0)
|
||||
|
||||
Configure a window region for scrolling:
|
||||
|
||||
- `win` is the window id to configure. There are 0..7 standard windows for
|
||||
general purpose use. Window 8 is the text scroll window (the ticker).
|
||||
- `x`, `y`, `w`, `h` specify the location of the window in the display.
|
||||
- `vec` specifies the direction and speed of scroll: it is a 16-bit value
|
||||
of the form ``0bF.ddSSSSSSSSSSSS``. `dd` is 0, 1, 2, 3 for +x, +y, -x,
|
||||
-y scrolling. `F` sets the speed format, with 0 meaning that the window
|
||||
is shifted `S % 256` pixel every frame, and 1 meaning that the window
|
||||
is shifted 1 pixel every `S` frames.
|
||||
- `pat` is a 16-bit pattern mask for the background.
|
||||
- `fill` is the fill color.
|
||||
- `color` is the extra color, either of the text or pattern foreground.
|
||||
|
||||
.. method:: LCD160CR.set_scroll_win_param(win, param, value)
|
||||
|
||||
Set a single parameter of a scrolling window region:
|
||||
|
||||
- `win` is the window id, 0..8.
|
||||
- `param` is the parameter number to configure, 0..7, and corresponds
|
||||
to the parameters in the `set_scroll_win` method.
|
||||
- `value` is the value to set.
|
||||
|
||||
.. method:: LCD160CR.set_scroll_buf(s)
|
||||
|
||||
Set the string for scrolling in window 8. The parameter `s` must be a string
|
||||
with length 32 or less.
|
||||
|
||||
.. method:: LCD160CR.jpeg(buf)
|
||||
|
||||
Display a JPEG. `buf` should contain the entire JPEG data. JPEG data should
|
||||
not include EXIF information. The following encodings are supported: Baseline
|
||||
DCT, Huffman coding, 8 bits per sample, 3 color components, YCbCr4:2:2.
|
||||
The origin of the JPEG is set by :meth:`LCD160CR.set_pos`.
|
||||
|
||||
.. method:: LCD160CR.jpeg_start(total_len)
|
||||
.. method:: LCD160CR.jpeg_data(buf)
|
||||
|
||||
Display a JPEG with the data split across multiple buffers. There must be
|
||||
a single call to `jpeg_start` to begin with, specifying the total number of
|
||||
bytes in the JPEG. Then this number of bytes must be transferred to the
|
||||
display using one or more calls to the `jpeg_data` command.
|
||||
|
||||
.. method:: LCD160CR.feed_wdt()
|
||||
|
||||
The first call to this method will start the display's internal watchdog
|
||||
timer. Subsequent calls will feed the watchdog. The timeout is roughly 30
|
||||
seconds.
|
||||
|
||||
.. method:: LCD160CR.reset()
|
||||
|
||||
Reset the display.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: lcd160cr.PORTRAIT
|
||||
.. data:: lcd160cr.LANDSCAPE
|
||||
.. data:: lcd160cr.PORTRAIT_UPSIDEDOWN
|
||||
.. data:: lcd160cr.LANDSCAPE_UPSIDEDOWN
|
||||
|
||||
orientation of the display, used by :meth:`LCD160CR.set_orient`
|
||||
|
||||
.. data:: lcd160cr.STARTUP_DECO_NONE
|
||||
.. data:: lcd160cr.STARTUP_DECO_MLOGO
|
||||
.. data:: lcd160cr.STARTUP_DECO_INFO
|
||||
|
||||
type of start-up decoration, can be or'd together, used by
|
||||
:meth:`LCD160CR.set_startup_deco`
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.ADC:
|
||||
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.I2C:
|
||||
|
||||
class I2C -- a two-wire serial protocol
|
||||
=======================================
|
||||
@ -9,49 +10,30 @@ level it consists of 2 wires: SCL and SDA, the clock and data lines respectively
|
||||
I2C objects are created attached to a specific bus. They can be initialised
|
||||
when created, or initialised later on.
|
||||
|
||||
.. only:: port_wipy
|
||||
Printing the I2C object gives you information about its configuration.
|
||||
|
||||
Example::
|
||||
Example usage::
|
||||
|
||||
from machine import I2C
|
||||
|
||||
i2c = I2C(0) # create on bus 0
|
||||
i2c = I2C(0, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.deinit() # turn off the peripheral
|
||||
i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz
|
||||
# depending on the port, extra parameters may be required
|
||||
# to select the peripheral and/or pins to use
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
i2c.scan() # scan for slaves, returning a list of 7-bit addresses
|
||||
|
||||
.. only:: port_wipy
|
||||
i2c.writeto(42, b'123') # write 3 bytes to slave with 7-bit address 42
|
||||
i2c.readfrom(42, 4) # read 4 bytes from slave with 7-bit address 42
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
|
||||
i2c.writeto(addr=0x42, b'456') # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
|
||||
i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of slave 42,
|
||||
# starting at memory-address 8 in the slave
|
||||
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of slave 42
|
||||
# starting at address 2 in the slave
|
||||
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: I2C(bus, ...)
|
||||
|
||||
Construct an I2C object on the given bus. `bus` can only be 0.
|
||||
If the bus is not given, the default one will be selected (0).
|
||||
|
||||
.. only:: not port_wipy
|
||||
|
||||
.. class:: I2C(id=-1, \*, scl, sda, freq=400000)
|
||||
.. class:: I2C(id=-1, \*, scl, sda, freq=400000)
|
||||
|
||||
Construct and return a new I2C object using the following parameters:
|
||||
|
||||
@ -70,19 +52,7 @@ Constructors
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: I2C.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``I2C.MASTER``
|
||||
- ``baudrate`` is the SCL clock rate
|
||||
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
|
||||
|
||||
.. only:: port_esp8266
|
||||
|
||||
.. method:: I2C.init(scl, sda, \*, freq=400000)
|
||||
.. method:: I2C.init(scl, sda, \*, freq=400000)
|
||||
|
||||
Initialise the I2C bus with the given arguments:
|
||||
|
||||
@ -100,9 +70,7 @@ General Methods
|
||||
|
||||
Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
|
||||
those that respond. A device responds if it pulls the SDA line low after
|
||||
its address (including a read bit) is sent on the bus.
|
||||
|
||||
Note: on WiPy the I2C object must be in master mode for this method to be valid.
|
||||
its address (including a write bit) is sent on the bus.
|
||||
|
||||
Primitive I2C operations
|
||||
------------------------
|
||||
@ -192,8 +160,7 @@ methods are convenience functions to communicate with such devices.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
|
||||
On WiPy the return value is the number of bytes read. Otherwise the
|
||||
return value is `None`.
|
||||
The method returns `None`.
|
||||
|
||||
.. method:: I2C.writeto_mem(addr, memaddr, buf, \*, addrsize=8)
|
||||
|
||||
@ -202,14 +169,4 @@ methods are convenience functions to communicate with such devices.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
|
||||
On WiPy the return value is the number of bytes written. Otherwise the
|
||||
return value is `None`.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: I2C.MASTER
|
||||
|
||||
for initialising the bus to master mode
|
||||
|
||||
Availability: WiPy.
|
||||
The method returns `None`.
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Pin:
|
||||
|
||||
class Pin -- control I/O pins
|
||||
=============================
|
||||
@ -38,58 +39,6 @@ Usage Model::
|
||||
# configure an irq callback
|
||||
p0.irq(lambda p:print(p))
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
On the WiPy board the pins are identified by their string id::
|
||||
|
||||
from machine import Pin
|
||||
g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1)
|
||||
|
||||
You can also configure the Pin to generate interrupts. For instance::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
def pincb(pin):
|
||||
print(pin.id())
|
||||
|
||||
pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN)
|
||||
pin_int.irq(trigger=Pin.IRQ_RISING, handler=pincb)
|
||||
# the callback can be triggered manually
|
||||
pin_int.irq()()
|
||||
# to disable the callback
|
||||
pin_int.irq().disable()
|
||||
|
||||
Now every time a falling edge is seen on the gpio pin, the callback will be
|
||||
executed. Caution: mechanical push buttons have "bounce" and pushing or
|
||||
releasing a switch will often generate multiple edges.
|
||||
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
|
||||
explanation, along with various techniques for debouncing.
|
||||
|
||||
All pin objects go through the pin mapper to come up with one of the
|
||||
gpio pins.
|
||||
|
||||
For the ``drive`` parameter the strengths are:
|
||||
|
||||
- ``Pin.LOW_POWER`` - 2mA drive capability.
|
||||
- ``Pin.MED_POWER`` - 4mA drive capability.
|
||||
- ``Pin.HIGH_POWER`` - 6mA drive capability.
|
||||
|
||||
For the ``alt`` parameter please refer to the pinout and alternate functions
|
||||
table at <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
for the specific alternate functions that each pin supports.
|
||||
|
||||
For interrupts, the ``priority`` can take values in the range 1-7. And the
|
||||
``wake`` parameter has the following properties:
|
||||
|
||||
- If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board.
|
||||
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1
|
||||
of this pins can be enabled as a wake source at the same time, so, only
|
||||
the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect.
|
||||
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the
|
||||
6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@ -197,31 +146,19 @@ Methods
|
||||
|
||||
When setting the value this method returns ``None``.
|
||||
|
||||
.. method:: Pin.out_value()
|
||||
|
||||
Return the value stored in the output buffer of a pin, regardless of its mode.
|
||||
|
||||
Not all ports implement this method.
|
||||
|
||||
.. method:: Pin.__call__([x])
|
||||
|
||||
Pin objects are callable. The call method provides a (fast) shortcut to set
|
||||
and get the value of the pin. It is equivalent to Pin.value([x]).
|
||||
See :meth:`Pin.value` for more details.
|
||||
|
||||
.. method:: Pin.toggle()
|
||||
.. method:: Pin.on()
|
||||
|
||||
Toggle the output value of the pin. Equivalent to ``pin.value(not pin.out_value())``.
|
||||
Returns ``None``.
|
||||
Set pin to "1" output level.
|
||||
|
||||
Not all ports implement this method.
|
||||
.. method:: Pin.off()
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
.. method:: Pin.id()
|
||||
|
||||
Get the pin identifier. This may return the ``id`` as specified in the
|
||||
constructor. Or it may return a canonical software-specific pin id.
|
||||
Set pin to "0" output level.
|
||||
|
||||
.. method:: Pin.mode([mode])
|
||||
|
||||
@ -277,29 +214,6 @@ Methods
|
||||
|
||||
This method returns a callback object.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: Pin.alt_list()
|
||||
|
||||
Returns a list of the alternate functions supported by the pin. List items are
|
||||
a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)``
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
.. class:: Pin.board
|
||||
|
||||
Contains all ``Pin`` objects supported by the board. Examples::
|
||||
|
||||
Pin.board.GP25
|
||||
led = Pin(Pin.board.GP25, mode=Pin.OUT)
|
||||
Pin.board.GP2.alt_list()
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.RTC:
|
||||
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SD:
|
||||
|
||||
class SD -- secure digital memory card
|
||||
======================================
|
||||
@ -33,7 +34,7 @@ Methods
|
||||
|
||||
.. method:: SD.init(id=0, pins=('GP10', 'GP11', 'GP15'))
|
||||
|
||||
Enable the SD card. In order to initalize the card, give it a 3-tuple:
|
||||
Enable the SD card. In order to initialize the card, give it a 3-tuple:
|
||||
``(clk_pin, cmd_pin, dat0_pin)``.
|
||||
|
||||
.. method:: SD.deinit()
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SPI:
|
||||
|
||||
class SPI -- a Serial Peripheral Interface bus protocol (master side)
|
||||
=====================================================================
|
||||
@ -6,22 +7,10 @@ class SPI -- a Serial Peripheral Interface bus protocol (master side)
|
||||
SPI is a synchronous serial protocol that is driven by a master. At the
|
||||
physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices
|
||||
can share the same bus. Each device should have a separate, 4th signal,
|
||||
SS (Slave Select), to select a particualr device on a bus with which
|
||||
SS (Slave Select), to select a particular device on a bus with which
|
||||
communication takes place. Management of an SS signal should happen in
|
||||
user code (via machine.Pin class).
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
See usage model of I2C; SPI is very similar. Main difference is
|
||||
parameters to init the SPI bus::
|
||||
|
||||
from machine import SPI
|
||||
spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
|
||||
|
||||
Only required parameter is mode, must be SPI.MASTER. Polarity can be 0 or
|
||||
1, and is the level the idle clock line sits at. Phase can be 0 or 1 to
|
||||
sample data on the first or second clock edge respectively.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@ -51,12 +40,12 @@ Methods
|
||||
- ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware.
|
||||
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
|
||||
- ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most
|
||||
hardware SPI blocks (as selected by ``id`` parameter to the constructore), pins are fixed
|
||||
hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed
|
||||
and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for
|
||||
a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver
|
||||
(``id`` = -1).
|
||||
- ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to
|
||||
specify them as a tuple of ``pins`` paramter.
|
||||
specify them as a tuple of ``pins`` parameter.
|
||||
|
||||
.. method:: SPI.deinit()
|
||||
|
||||
|
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.
|
@ -1,53 +1,18 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Timer:
|
||||
|
||||
class Timer -- control internal timers
|
||||
class Timer -- control hardware timers
|
||||
======================================
|
||||
|
||||
.. only:: port_wipy
|
||||
Hardware timers deal with timing of periods and events. Timers are perhaps
|
||||
the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
|
||||
differently greatly from a model to a model. MicroPython's Timer class
|
||||
defines a baseline operation of executing a callback with a given period
|
||||
(or once after some delay), and allow specific boards to define more
|
||||
non-standard behavior (which thus won't be portable to other boards).
|
||||
|
||||
Timers can be used for a great variety of tasks, calling a function periodically,
|
||||
counting events, and generating a PWM signal are among the most common use cases.
|
||||
Each timer consists of two 16-bit channels and this channels can be tied together to
|
||||
form one 32-bit timer. The operating mode needs to be configured per timer, but then
|
||||
the period (or the frequency) can be independently configured on each channel.
|
||||
By using the callback method, the timer event can call a Python function.
|
||||
|
||||
Example usage to toggle an LED at a fixed frequency::
|
||||
|
||||
from machine import Timer
|
||||
from machine import Pin
|
||||
led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED
|
||||
tim = Timer(3) # create a timer object using timer 3
|
||||
tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
|
||||
tim_ch = tim.channel(Timer.A, freq=5) # configure channel A at a frequency of 5Hz
|
||||
tim_ch.irq(handler=lambda t:led.toggle(), trigger=Timer.TIMEOUT) # toggle a LED on every cycle of the timer
|
||||
|
||||
Example using named function for the callback::
|
||||
|
||||
from machine import Timer
|
||||
from machine import Pin
|
||||
tim = Timer(1, mode=Timer.PERIODIC, width=32)
|
||||
tim_a = tim.channel(Timer.A | Timer.B, freq=1) # 1 Hz frequency requires a 32 bit timer
|
||||
|
||||
led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED
|
||||
|
||||
def tick(timer): # we will receive the timer object when being called
|
||||
global led
|
||||
led.toggle() # toggle the LED
|
||||
|
||||
tim_a.irq(handler=tick, trigger=Timer.TIMEOUT) # create the interrupt
|
||||
|
||||
Further examples::
|
||||
|
||||
from machine import Timer
|
||||
tim1 = Timer(1, mode=Timer.ONE_SHOT) # initialize it in one shot mode
|
||||
tim2 = Timer(2, mode=Timer.PWM) # initialize it in PWM mode
|
||||
tim1_ch = tim1.channel(Timer.A, freq=10, polarity=Timer.POSITIVE) # start the event counter with a frequency of 10Hz and triggered by positive edges
|
||||
tim2_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=5000) # start the PWM on channel B with a 50% duty cycle
|
||||
tim2_ch.freq(20) # set the frequency (can also get)
|
||||
tim2_ch.duty_cycle(3010) # set the duty cycle to 30.1% (can also get)
|
||||
tim2_ch.duty_cycle(3020, Timer.NEGATIVE) # set the duty cycle to 30.2% and change the polarity to negative
|
||||
tim2_ch.period(2000000) # change the period to 2 seconds
|
||||
See discussion of :ref:`important constraints <machine_callbacks>` on
|
||||
Timer callbacks.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -61,10 +26,8 @@ Constructors
|
||||
|
||||
.. class:: Timer(id, ...)
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Construct a new timer object of the given id. ``id`` can take values from 0 to 3.
|
||||
|
||||
Construct a new timer object of the given id. Id of -1 constructs a
|
||||
virtual timer (if supported by a board).
|
||||
|
||||
Methods
|
||||
-------
|
||||
@ -94,8 +57,7 @@ Methods
|
||||
|
||||
.. method:: Timer.deinit()
|
||||
|
||||
Deinitialises the timer. Disables all channels and associated IRQs.
|
||||
Stops the timer, and disables the timer peripheral.
|
||||
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
@ -138,18 +100,18 @@ Methods
|
||||
- ``GP10`` on Timer 3 channel A.
|
||||
- ``GP11`` on Timer 3 channel B.
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
|
||||
Timer channels are used to generate/capture a signal using a timer.
|
||||
|
||||
TimerChannel objects are created using the Timer.channel() method.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
|
||||
Timer channels are used to generate/capture a signal using a timer.
|
||||
|
||||
TimerChannel objects are created using the Timer.channel() method.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None)
|
||||
|
||||
The behavior of this callback is heavily dependent on the operating
|
||||
@ -194,22 +156,5 @@ Constants
|
||||
|
||||
.. data:: Timer.ONE_SHOT
|
||||
.. data:: Timer.PERIODIC
|
||||
.. data:: Timer.PWM
|
||||
|
||||
Selects the timer operating mode.
|
||||
|
||||
.. data:: Timer.A
|
||||
.. data:: Timer.B
|
||||
|
||||
Selects the timer channel. Must be ORed (``Timer.A`` | ``Timer.B``) when
|
||||
using a 32-bit timer.
|
||||
|
||||
.. data:: Timer.POSITIVE
|
||||
.. data:: Timer.NEGATIVE
|
||||
|
||||
Timer channel polarity selection (only relevant in PWM mode).
|
||||
|
||||
.. data:: Timer.TIMEOUT
|
||||
.. data:: Timer.MATCH
|
||||
|
||||
Timer channel IRQ triggers.
|
||||
Timer operating mode.
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.UART:
|
||||
|
||||
class UART -- duplex serial communication bus
|
||||
=============================================
|
||||
@ -15,17 +16,13 @@ UART objects can be created and initialised using::
|
||||
uart = UART(1, 9600) # init with given baudrate
|
||||
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
|
||||
|
||||
.. only:: port_machineoard
|
||||
Supported parameters differ on a board:
|
||||
|
||||
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Bits can be 5, 6, 7, 8. Parity can be ``None``, ``UART.EVEN`` or ``UART.ODD``. Stop can be 1 or 2.
|
||||
Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With `parity=None`,
|
||||
only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits
|
||||
are supported.
|
||||
|
||||
WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2.
|
||||
|
||||
A UART object acts like a stream object and reading and writing is done
|
||||
using the standard stream methods::
|
||||
@ -36,33 +33,12 @@ using the standard stream methods::
|
||||
uart.readinto(buf) # read and store into the given buffer
|
||||
uart.write('abc') # write the 3 characters
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
Individual characters can be read/written using::
|
||||
|
||||
uart.readchar() # read 1 character and returns it as an integer
|
||||
uart.writechar(42) # write 1 character
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns True if any characters waiting
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns the number of characters available for reading
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. class:: UART(id, ...)
|
||||
|
||||
.. class:: UART(bus, ...)
|
||||
|
||||
Construct a UART object on the given bus. ``bus`` can be 0 or 1.
|
||||
If the bus is not given, the default one will be selected (0) or the selection
|
||||
will be made based on the given pins.
|
||||
Construct a UART object of the given id.
|
||||
|
||||
Methods
|
||||
-------
|
||||
@ -75,7 +51,7 @@ Methods
|
||||
|
||||
- ``baudrate`` is the clock rate.
|
||||
- ``bits`` is the number of bits per character, 7, 8 or 9.
|
||||
- ``parity`` is the parity, ``None``, ``UART.EVEN`` or ``UART.ODD``.
|
||||
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- ``stop`` is the number of stop bits, 1 or 2.
|
||||
- ``pins`` is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
|
||||
Any of the pins can be None if one wants the UART to operate with limited functionality.
|
||||
@ -83,15 +59,22 @@ Methods
|
||||
When no pins are given, then the default set of TX and RX pins is taken, and hardware
|
||||
flow control will be disabled. If pins=None, no pin assignment will be made.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
|
||||
.. method:: UART.deinit()
|
||||
.. method:: UART.deinit()
|
||||
|
||||
Turn off the UART bus.
|
||||
|
||||
.. method:: UART.any()
|
||||
.. method:: UART.any()
|
||||
|
||||
Return the number of characters available for reading.
|
||||
Returns an integer counting the number of characters that can be read without
|
||||
blocking. It will return 0 if there are no characters available and a positive
|
||||
number if there are characters. The method may return 1 even if there is more
|
||||
than one character available for reading.
|
||||
|
||||
For more sophisticated querying of available characters use select.poll::
|
||||
|
||||
poll = select.poll()
|
||||
poll.register(uart, select.POLLIN)
|
||||
poll.poll(timeout)
|
||||
|
||||
.. method:: UART.read([nbytes])
|
||||
|
||||
@ -121,13 +104,10 @@ Methods
|
||||
|
||||
Return value: number of bytes written or ``None`` on timeout.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
|
||||
.. method:: UART.sendbreak()
|
||||
.. method:: UART.sendbreak()
|
||||
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
of 13 bits.
|
||||
Return value: ``None``.
|
||||
longer than required for a normal transmission of a character.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
@ -154,16 +134,9 @@ Methods
|
||||
|
||||
Returns an irq object.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: UART.EVEN
|
||||
.. data:: UART.ODD
|
||||
|
||||
parity types (along with ``None``)
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
|
||||
IRQ trigger sources
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.WDT:
|
||||
|
||||
class WDT -- watchdog timer
|
||||
===========================
|
||||
|
@ -1,10 +1,23 @@
|
||||
:mod:`machine` --- functions related to the board
|
||||
=================================================
|
||||
:mod:`machine` --- functions related to the hardware
|
||||
====================================================
|
||||
|
||||
.. module:: machine
|
||||
:synopsis: functions related to the board
|
||||
:synopsis: functions related to the hardware
|
||||
|
||||
The ``machine`` module contains specific functions related to the board.
|
||||
The ``machine`` module contains specific functions related to the hardware
|
||||
on a particular board. Most functions in this module allow to achieve direct
|
||||
and unrestricted access to and control of hardware blocks on a system
|
||||
(like CPU, timers, buses, etc.). Used incorrectly, this can lead to
|
||||
malfunction, lockups, crashes of your board, and in extreme cases, hardware
|
||||
damage.
|
||||
|
||||
.. _machine_callbacks:
|
||||
|
||||
A note of callbacks used by functions and class methods of ``machine`` module:
|
||||
all these callbacks should be considered as executing in an interrupt context.
|
||||
This is true for both physical devices with IDs >= 0 and "virtual" devices
|
||||
with negative IDs like -1 (these "virtual" devices are still thin shims on
|
||||
top of real hardware and real hardware interrupts). See :ref:`isr_rules`.
|
||||
|
||||
Reset related functions
|
||||
-----------------------
|
||||
@ -39,17 +52,8 @@ Power related functions
|
||||
|
||||
.. function:: freq()
|
||||
|
||||
.. only:: not port_wipy
|
||||
|
||||
Returns CPU frequency in hertz.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Returns a tuple of clock frequencies: ``(sysclk,)``
|
||||
These correspond to:
|
||||
|
||||
- sysclk: frequency of the CPU
|
||||
|
||||
.. function:: idle()
|
||||
|
||||
Gates the clock to the CPU, useful to reduce power consumption at any time during
|
||||
@ -81,13 +85,6 @@ Miscellaneous functions
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: main(filename)
|
||||
|
||||
Set the filename of the main script to run after boot.py is finished. If
|
||||
this function is not called then the default file main.py will be executed.
|
||||
|
||||
It only makes sense to call this function from within boot.py.
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
@ -105,12 +102,15 @@ Miscellaneous functions
|
||||
microseconds. The `pulse_level` argument should be 0 to time a low pulse
|
||||
or 1 to time a high pulse.
|
||||
|
||||
The function first waits while the pin input is different to the `pulse_level`
|
||||
parameter, then times the duration that the pin is equal to `pulse_level`.
|
||||
If the current input value of the pin is different to `pulse_level`,
|
||||
the function first (*) waits until the pin input becomes equal to `pulse_level`,
|
||||
then (**) times the duration that the pin is equal to `pulse_level`.
|
||||
If the pin is already equal to `pulse_level` then timing starts straight away.
|
||||
|
||||
The function will raise an OSError with ETIMEDOUT if either of the waits is
|
||||
longer than the given timeout value (which is in microseconds).
|
||||
The function will return -2 if there was timeout waiting for condition marked
|
||||
(*) above, and -1 if there was timeout during the main measurement, marked (**)
|
||||
above. The timeout is the same for both cases and given by `timeout_us` (which
|
||||
is in microseconds).
|
||||
|
||||
.. _machine_constants:
|
||||
|
||||
@ -118,37 +118,53 @@ Constants
|
||||
---------
|
||||
|
||||
.. data:: machine.IDLE
|
||||
.. data:: machine.SLEEP
|
||||
.. data:: machine.DEEPSLEEP
|
||||
machine.SLEEP
|
||||
machine.DEEPSLEEP
|
||||
|
||||
irq wake values
|
||||
IRQ wake values.
|
||||
|
||||
.. data:: machine.PWRON_RESET
|
||||
.. data:: machine.HARD_RESET
|
||||
.. data:: machine.WDT_RESET
|
||||
.. data:: machine.DEEPSLEEP_RESET
|
||||
.. data:: machine.SOFT_RESET
|
||||
machine.HARD_RESET
|
||||
machine.WDT_RESET
|
||||
machine.DEEPSLEEP_RESET
|
||||
machine.SOFT_RESET
|
||||
|
||||
reset causes
|
||||
Reset causes.
|
||||
|
||||
.. data:: machine.WLAN_WAKE
|
||||
.. data:: machine.PIN_WAKE
|
||||
.. data:: machine.RTC_WAKE
|
||||
machine.PIN_WAKE
|
||||
machine.RTC_WAKE
|
||||
|
||||
wake reasons
|
||||
Wake-up reasons.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. toctree::
|
||||
.. only:: not port_wipy
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
machine.ADC.rst
|
||||
machine.I2C.rst
|
||||
machine.Pin.rst
|
||||
machine.RTC.rst
|
||||
machine.SD.rst
|
||||
machine.SPI.rst
|
||||
machine.Timer.rst
|
||||
machine.Signal.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.WDT.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
machine.Pin.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.WDT.rst
|
||||
machine.ADC.rst
|
||||
machine.SD.rst
|
||||
|
@ -7,25 +7,31 @@
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. only:: port_pyboard or port_unix
|
||||
.. function:: const(expr)
|
||||
|
||||
.. function:: mem_info([verbose])
|
||||
Used to declare that the expression is a constant so that the compile can
|
||||
optimise it. The use of this function should be as follows::
|
||||
|
||||
Print information about currently used memory. If the ``verbose`` argument
|
||||
is given then extra information is printed.
|
||||
from micropython import const
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the amount of stack and heap used. In verbose mode it prints out
|
||||
the entire heap indicating which blocks are used and which are free.
|
||||
CONST_X = const(123)
|
||||
CONST_Y = const(2 * CONST_X + 1)
|
||||
|
||||
.. function:: qstr_info([verbose])
|
||||
Constants declared this way are still accessible as global variables from
|
||||
outside the module they are declared in. On the other hand, if a constant
|
||||
begins with an underscore then it is hidden, it is not available as a global
|
||||
variable, and does not take up any memory during execution.
|
||||
|
||||
Print information about currently interned strings. If the ``verbose``
|
||||
argument is given then extra information is printed.
|
||||
This `const` function is recognised directly by the MicroPython parser and is
|
||||
provided as part of the `micropython` module mainly so that scripts can be
|
||||
written which run under both CPython and MicroPython, by following the above
|
||||
pattern.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the number of interned strings and the amount of RAM they use. In
|
||||
verbose mode it prints out the names of all RAM-interned strings.
|
||||
.. function:: opt_level([level])
|
||||
|
||||
If `level` is given then this function sets the optimisation level for subsequent
|
||||
compilation of scripts, and returns `None`. Otherwise it returns the current
|
||||
optimisation level.
|
||||
|
||||
.. function:: alloc_emergency_exception_buf(size)
|
||||
|
||||
@ -37,3 +43,74 @@ Functions
|
||||
A good way to use this function is to put it at the start of your main script
|
||||
(eg boot.py or main.py) and then the emergency exception buffer will be active
|
||||
for all the code following it.
|
||||
|
||||
.. function:: mem_info([verbose])
|
||||
|
||||
Print information about currently used memory. If the ``verbose`` argument
|
||||
is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the amount of stack and heap used. In verbose mode it prints out
|
||||
the entire heap indicating which blocks are used and which are free.
|
||||
|
||||
.. function:: qstr_info([verbose])
|
||||
|
||||
Print information about currently interned strings. If the ``verbose``
|
||||
argument is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the number of interned strings and the amount of RAM they use. In
|
||||
verbose mode it prints out the names of all RAM-interned strings.
|
||||
|
||||
.. function:: stack_use()
|
||||
|
||||
Return an integer representing the current amount of stack that is being
|
||||
used. The absolute value of this is not particularly useful, rather it
|
||||
should be used to compute differences in stack usage at different points.
|
||||
|
||||
.. function:: heap_lock()
|
||||
.. function:: heap_unlock()
|
||||
|
||||
Lock or unlock the heap. When locked no memory allocation can occur and a
|
||||
`MemoryError` will be raised if any heap allocation is attempted.
|
||||
|
||||
These functions can be nested, ie `heap_lock()` can be called multiple times
|
||||
in a row and the lock-depth will increase, and then `heap_unlock()` must be
|
||||
called the same number of times to make the heap available again.
|
||||
|
||||
.. function:: kbd_intr(chr)
|
||||
|
||||
Set the character that will raise a `KeyboardInterrupt` exception. By
|
||||
default this is set to 3 during script execution, corresponding to Ctrl-C.
|
||||
Passing -1 to this function will disable capture of Ctrl-C, and passing 3
|
||||
will restore it.
|
||||
|
||||
This function can be used to prevent the capturing of Ctrl-C on the
|
||||
incoming stream of characters that is usually used for the REPL, in case
|
||||
that stream is used for other purposes.
|
||||
|
||||
.. function:: schedule(fun, arg)
|
||||
|
||||
Schedule the function `fun` to be executed "very soon". The function
|
||||
is passed the value `arg` as its single argument. "very soon" means that
|
||||
the MicroPython runtime will do its best to execute the function at the
|
||||
earliest possible time, given that it is also trying to be efficient, and
|
||||
that the following conditions hold:
|
||||
|
||||
- A scheduled function will never preempt another scheduled function.
|
||||
- Scheduled functions are always executed "between opcodes" which means
|
||||
that all fundamental Python operations (such as appending to a list)
|
||||
are guaranteed to be atomic.
|
||||
- A given port may define "critical regions" within which scheduled
|
||||
functions will never be executed. Functions may be scheduled within
|
||||
a critical region but they will not be executed until that region
|
||||
is exited. An example of a critical region is a preempting interrupt
|
||||
handler (an IRQ).
|
||||
|
||||
A use for this function is to schedule a callback from a preempting IRQ.
|
||||
Such an IRQ puts restrictions on the code that runs in the IRQ (for example
|
||||
the heap may be locked) and scheduling a function to call later will lift
|
||||
those restrictions.
|
||||
|
||||
There is a finite stack to hold the scheduled functions and `schedule`
|
||||
will raise a `RuntimeError` if the stack is full.
|
||||
|
@ -14,14 +14,20 @@ module.
|
||||
|
||||
For example::
|
||||
|
||||
# configure a specific network interface
|
||||
# connect/ show IP config a specific network interface
|
||||
# see below for examples of specific drivers
|
||||
import network
|
||||
import utime
|
||||
nic = network.Driver(...)
|
||||
if not nic.isconnected():
|
||||
nic.connect()
|
||||
print("Waiting for connection...")
|
||||
while not nic.isconnected():
|
||||
utime.sleep(1)
|
||||
print(nic.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
import socket
|
||||
# now use usocket as usual
|
||||
import usocket as socket
|
||||
addr = socket.getaddrinfo('micropython.org', 80)[0][-1]
|
||||
s = socket.socket()
|
||||
s.connect(addr)
|
||||
@ -29,51 +35,102 @@ For example::
|
||||
data = s.recv(1000)
|
||||
s.close()
|
||||
|
||||
.. only:: port_wipy
|
||||
Common network adapter interface
|
||||
================================
|
||||
|
||||
.. _network.Server:
|
||||
This section describes an (implied) abstract base class for all network
|
||||
interface classes implemented by different ports of MicroPython for
|
||||
different hardware. This means that MicroPython does not actually
|
||||
provide `AbstractNIC` class, but any actual NIC class, as described
|
||||
in the following sections, implements methods as described here.
|
||||
|
||||
class Server
|
||||
============
|
||||
.. class:: AbstractNIC(id=None, ...)
|
||||
|
||||
The ``Server`` class controls the behaviour and the configuration of the FTP and telnet
|
||||
services running on the WiPy. Any changes performed using this class' methods will
|
||||
affect both.
|
||||
Instantiate a network interface object. Parameters are network interface
|
||||
dependent. If there are more than one interface of the same type, the first
|
||||
parameter should be `id`.
|
||||
|
||||
Example::
|
||||
.. method:: active([is_active])
|
||||
|
||||
import network
|
||||
server = network.Server()
|
||||
server.deinit() # disable the server
|
||||
# enable the server again with new settings
|
||||
server.init(login=('user', 'password'), timeout=600)
|
||||
Activate ("up") or deactivate ("down") the network interface, if
|
||||
a boolean argument is passed. Otherwise, query current state if
|
||||
no argument is provided. Most other methods require an active
|
||||
interface (behavior of calling them on inactive interface is
|
||||
undefined).
|
||||
|
||||
Constructors
|
||||
------------
|
||||
.. method:: connect([service_id, key=None, \*, ...])
|
||||
|
||||
.. class:: network.Server(id, ...)
|
||||
Connect the interface to a network. This method is optional, and
|
||||
available only for interfaces which are not "always connected".
|
||||
If no parameters are given, connect to the default (or the only)
|
||||
service. If a single parameter is given, it is the primary identifier
|
||||
of a service to connect to. It may be accompanied by a key
|
||||
(password) required to access said service. There can be further
|
||||
arbitrary keyword-only parameters, depending on the networking medium
|
||||
type and/or particular device. Parameters can be used to: a)
|
||||
specify alternative service identifer types; b) provide additional
|
||||
connection parameters. For various medium types, there are different
|
||||
sets of predefined/recommended parameters, among them:
|
||||
|
||||
Create a server instance, see ``init`` for parameters of initialization.
|
||||
* WiFi: `bssid` keyword to connect by BSSID (MAC address) instead
|
||||
of access point name
|
||||
|
||||
Methods
|
||||
-------
|
||||
.. method:: disconnect()
|
||||
|
||||
.. method:: server.init(\*, login=('micro', 'python'), timeout=300)
|
||||
Disconnect from network.
|
||||
|
||||
Init (and effectively start the server). Optionally a new ``user``, ``password``
|
||||
and ``timeout`` (in seconds) can be passed.
|
||||
.. method:: isconnected()
|
||||
|
||||
.. method:: server.deinit()
|
||||
Returns ``True`` if connected to network, otherwise returns ``False``.
|
||||
|
||||
Stop the server
|
||||
.. method:: scan(\*, ...)
|
||||
|
||||
.. method:: server.timeout([timeout_in_seconds])
|
||||
Scan for the available network services/connections. Returns a
|
||||
list of tuples with discovered service parameters. For various
|
||||
network media, there are different variants of predefined/
|
||||
recommended tuple formats, among them:
|
||||
|
||||
Get or set the server timeout.
|
||||
* WiFi: (ssid, bssid, channel, RSSI, authmode, hidden). There
|
||||
may be further fields, specific to a particular device.
|
||||
|
||||
.. method:: server.isrunning()
|
||||
The function may accept additional keyword arguments to filter scan
|
||||
results (e.g. scan for a particular service, on a particular channel,
|
||||
for services of a particular set, etc.), and to affect scan
|
||||
duration and other parameters. Where possible, parameter names
|
||||
should match those in connect().
|
||||
|
||||
Returns ``True`` if the server is running, ``False`` otherwise.
|
||||
.. method:: status()
|
||||
|
||||
Return detailed status of the interface, values are dependent
|
||||
on the network medium/technology.
|
||||
|
||||
.. method:: ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP-level network interface parameters: IP address, subnet mask,
|
||||
gateway and DNS server. When called with no arguments, this method returns
|
||||
a 4-tuple with the above information. To set the above values, pass a
|
||||
4-tuple with the required information. For example::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: config('param')
|
||||
config(param=value, ...)
|
||||
|
||||
Get or set general network interface parameters. These methods allow to work
|
||||
with additional parameters beyond standard IP configuration (as dealt with by
|
||||
``ifconfig()``). These include network-specific and hardware-specific
|
||||
parameters and status values. For setting parameters, the keyword argument
|
||||
syntax should be used, and multiple parameters can be set at once. For
|
||||
querying, a parameter name should be quoted as a string, and only one
|
||||
parameter can be queried at a time::
|
||||
|
||||
# Set WiFi access point name (formally known as ESSID) and WiFi channel
|
||||
ap.config(essid='My AP', channel=11)
|
||||
# Query params one by one
|
||||
print(ap.config('essid'))
|
||||
print(ap.config('channel'))
|
||||
# Extended status information also available this way
|
||||
print(sta.config('rssi'))
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
|
@ -21,7 +21,7 @@ Usage Model:
|
||||
CPU pins which correspond to the board pins are available
|
||||
as ``pyb.cpu.Name``. For the CPU pins, the names are the port letter
|
||||
followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and
|
||||
``pyb.Pin.cpu.B6`` are the same pin.
|
||||
``pyb.Pin.cpu.A0`` are the same pin.
|
||||
|
||||
You can also use strings::
|
||||
|
||||
|
@ -80,6 +80,19 @@ Reset related functions
|
||||
|
||||
Activate the bootloader without BOOT\* pins.
|
||||
|
||||
.. function:: fault_debug(value)
|
||||
|
||||
Enable or disable hard-fault debugging. A hard-fault is when there is a fatal
|
||||
error in the underlying system, like an invalid memory access.
|
||||
|
||||
If the `value` argument is `False` then the board will automatically reset if
|
||||
there is a hard fault.
|
||||
|
||||
If `value` is `True` then, when the board has a hard fault, it will print the
|
||||
registers and the stack trace, and then cycle the LEDs indefinitely.
|
||||
|
||||
The default value is disabled, i.e. to automatically reset.
|
||||
|
||||
Interrupt related functions
|
||||
---------------------------
|
||||
|
||||
|
@ -1,63 +1,41 @@
|
||||
:mod:`uhashlib` -- hashing algorithm
|
||||
====================================
|
||||
:mod:`uhashlib` -- hashing algorithms
|
||||
=====================================
|
||||
|
||||
.. module:: uhashlib
|
||||
:synopsis: hashing algorithm
|
||||
:synopsis: hashing algorithms
|
||||
|
||||
.. only:: port_pyboard
|
||||
This module implements binary data hashing algorithms. The exact inventory
|
||||
of available algorithms depends on a board. Among the algorithms which may
|
||||
be implemented:
|
||||
|
||||
This module implements binary data hashing algorithms. Currently, it
|
||||
implements SHA256 algorithm. Choosing SHA256 was a deliberate choice,
|
||||
as a modern, cryptographically secure algorithm. This means that a
|
||||
single algorithm can cover both use cases of "any hash algorithm" and
|
||||
security-related usage, and thus save space omitting legacy algorithms
|
||||
like MD5 or SHA1.
|
||||
* SHA256 - The current generation, modern hashing algorithm (of SHA2 series).
|
||||
It is suitable for cryptographically-secure purposes. Included in the
|
||||
MicroPython core and any board is recommended to provide this, unless
|
||||
it has particular code size constraints.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
This module implements binary data hashing algorithms. Currently, it
|
||||
implements SHA1 and SHA256 algorithms only. These two algorithms are
|
||||
more than enough for today's web applications.
|
||||
* SHA1 - A previous generation algorithm. Not recommended for new usages,
|
||||
but SHA1 is a part of number of Internet standards and existing
|
||||
applications, so boards targeting network connectivity and
|
||||
interoperatiability will try to provide this.
|
||||
|
||||
* MD5 - A legacy algorithm, not considered cryptographically secure. Only
|
||||
selected boards, targeting interoperatibility with legacy applications,
|
||||
will offer this.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. class:: uhashlib.sha256([data])
|
||||
|
||||
.. class:: uhashlib.sha256([data])
|
||||
Create an SHA256 hasher object and optionally feed ``data`` into it.
|
||||
|
||||
Create a hasher object and optionally feed ``data`` into it.
|
||||
.. class:: uhashlib.sha1([data])
|
||||
|
||||
.. only:: port_wipy
|
||||
Create an SHA1 hasher object and optionally feed ``data`` into it.
|
||||
|
||||
.. class:: uhashlib.sha1([data[, block_size]])
|
||||
.. class:: uhashlib.md5([data])
|
||||
|
||||
Create a sha1 hasher object and optionally feed ``data`` or ``data and block_size`` into it.
|
||||
|
||||
.. class:: uhashlib.sha256([data[, block_size]])
|
||||
|
||||
Create a sha256 hasher object and optionally feed ``data`` or ``data and block_size`` into it.
|
||||
|
||||
.. admonition:: CPython extension
|
||||
:class: attention
|
||||
|
||||
Due to hardware implementation details of the WiPy, data must be buffered before being
|
||||
digested, which would make it impossible to calculate the hash of big blocks of data that
|
||||
do not fit in RAM. In this case, since most likely the total size of the data is known
|
||||
in advance, the size can be passed to the constructor and hence the HASH hardware engine
|
||||
of the WiPy can be properly initialized without needing buffering. If ``block_size`` is
|
||||
to be given, an initial chunk of ``data`` must be passed as well. **When using this extension,
|
||||
care must be taken to make sure that the length of all intermediate chunks (including the
|
||||
initial one) is a multiple of 4 bytes.** The last chunk may be of any length.
|
||||
|
||||
Example::
|
||||
|
||||
hash = uhashlib.sha1('abcd1234', 1001) # length of the initial piece is multiple of 4 bytes
|
||||
hash.update('1234') # also multiple of 4 bytes
|
||||
...
|
||||
hash.update('12345') # last chunk may be of any length
|
||||
hash.digest()
|
||||
Create an MD5 hasher object and optionally feed ``data`` into it.
|
||||
|
||||
Methods
|
||||
-------
|
||||
@ -69,11 +47,7 @@ Methods
|
||||
.. method:: hash.digest()
|
||||
|
||||
Return hash for all data passed through hash, as a bytes object. After this
|
||||
method is called, more data cannot be fed into hash any longer.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
SHA1 hashes are 20-byte long. SHA256 hashes are 32-byte long.
|
||||
method is called, more data cannot be fed into the hash any longer.
|
||||
|
||||
.. method:: hash.hexdigest()
|
||||
|
||||
|
@ -7,6 +7,71 @@
|
||||
This module contains additional types of stream (file-like) objects
|
||||
and helper functions.
|
||||
|
||||
Conceptual hierarchy
|
||||
--------------------
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
Conceptual hierarchy of stream base classes is simplified in MicroPython,
|
||||
as described in this section.
|
||||
|
||||
(Abstract) base stream classes, which serve as a foundation for behavior
|
||||
of all the concrete classes, adhere to few dichotomies (pair-wise
|
||||
classifications) in CPython. In MicroPython, they are somewhat simplified
|
||||
and made implicit to achieve higher efficiencies and save resources.
|
||||
|
||||
An important dichotomy in CPython is unbuffered vs buffered streams. In
|
||||
MicroPython, all streams are currently unbuffered. This is because all
|
||||
modern OSes, and even many RTOSes and filesystem drivers already perform
|
||||
buffering on their side. Adding another layer of buffering is counter-
|
||||
productive (an issue known as "bufferbloat") and takes precious memory.
|
||||
Note that there still cases where buffering may be useful, so we may
|
||||
introduce optional buffering support at a later time.
|
||||
|
||||
But in CPython, another important dichotomy is tied with "bufferedness" -
|
||||
it's whether a stream may incur short read/writes or not. A short read
|
||||
is when a user asks e.g. 10 bytes from a stream, but gets less, similarly
|
||||
for writes. In CPython, unbuffered streams are automatically short
|
||||
operation susceptible, while buffered are guarantee against them. The
|
||||
no short read/writes is an important trait, as it allows to develop
|
||||
more concise and efficient programs - something which is highly desirable
|
||||
for MicroPython. So, while MicroPython doesn't support buffered streams,
|
||||
it still provides for no-short-operations streams. Whether there will
|
||||
be short operations or not depends on each particular class' needs, but
|
||||
developers are strongly advised to favor no-short-operations behavior
|
||||
for the reasons stated above. For example, MicroPython sockets are
|
||||
guaranteed to avoid short read/writes. Actually, at this time, there is
|
||||
no example of a short-operations stream class in the core, and one would
|
||||
be a port-specific class, where such a need is governed by hardware
|
||||
peculiarities.
|
||||
|
||||
The no-short-operations behavior gets tricky in case of non-blocking
|
||||
streams, blocking vs non-blocking behavior being another CPython dichotomy,
|
||||
fully supported by MicroPython. Non-blocking streams never wait for
|
||||
data either to arrive or be written - they read/write whatever possible,
|
||||
or signal lack of data (or ability to write data). Clearly, this conflicts
|
||||
with "no-short-operations" policy, and indeed, a case of non-blocking
|
||||
buffered (and this no-short-ops) streams is convoluted in CPython - in
|
||||
some places, such combination is prohibited, in some it's undefined or
|
||||
just not documented, in some cases it raises verbose exceptions. The
|
||||
matter is much simpler in MicroPython: non-blocking stream are important
|
||||
for efficient asynchronous operations, so this property prevails on
|
||||
the "no-short-ops" one. So, while blocking streams will avoid short
|
||||
reads/writes whenever possible (the only case to get a short read is
|
||||
if end of file is reached, or in case of error (but errors don't
|
||||
return short data, but raise exceptions)), non-blocking streams may
|
||||
produce short data to avoid blocking the operation.
|
||||
|
||||
The final dichotomy is binary vs text streams. MicroPython of course
|
||||
supports these, but while in CPython text streams are inherently
|
||||
buffered, they aren't in MicroPython. (Indeed, that's one of the cases
|
||||
for which we may introduce buffering support.)
|
||||
|
||||
Note that for efficiency, MicroPython doesn't provide abstract base
|
||||
classes corresponding to the hierarchy above, and it's not possible
|
||||
to implement, or subclass, a stream class in pure Python.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
|
@ -4,28 +4,9 @@
|
||||
.. module:: uos
|
||||
:synopsis: basic "operating system" services
|
||||
|
||||
The ``os`` module contains functions for filesystem access and ``urandom``
|
||||
The ``uos`` module contains functions for filesystem access and ``urandom``
|
||||
function.
|
||||
|
||||
Port specifics
|
||||
--------------
|
||||
|
||||
The filesystem has ``/`` as the root directory and the
|
||||
available physical drives are accessible from here. They are currently:
|
||||
|
||||
``/flash`` -- the internal flash filesystem
|
||||
|
||||
``/sd`` -- the SD card (if it exists)
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
On boot up, the current directory is ``/flash`` if no SD card is inserted,
|
||||
otherwise it is ``/sd``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
On boot up, the current directory is ``/flash``.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
@ -37,6 +18,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.
|
||||
@ -61,9 +57,7 @@ Functions
|
||||
|
||||
Get the status of a file or directory.
|
||||
|
||||
.. only:: port_unix or port_pyboard or port_esp8266
|
||||
|
||||
.. function:: statvfs(path)
|
||||
.. function:: statvfs(path)
|
||||
|
||||
Get the status of a fileystem.
|
||||
|
||||
@ -90,36 +84,11 @@ Functions
|
||||
|
||||
.. function:: urandom(n)
|
||||
|
||||
Return a bytes object with n random bytes, generated by the hardware
|
||||
random number generator.
|
||||
Return a bytes object with n random bytes. Whenever possible, it is
|
||||
generated by the hardware random number generator.
|
||||
|
||||
.. only:: port_wipy
|
||||
.. function:: dupterm(stream_object)
|
||||
|
||||
.. function:: mount(block_device, mount_point, \*, readonly=False)
|
||||
|
||||
Mounts a block device (like an ``SD`` object) in the specified mount
|
||||
point. Example::
|
||||
|
||||
os.mount(sd, '/sd')
|
||||
|
||||
.. function:: unmount(path)
|
||||
|
||||
Unmounts a previously mounted block device from the given path.
|
||||
|
||||
.. function:: mkfs(block_device or path)
|
||||
|
||||
Formats the specified path, must be either ``/flash`` or ``/sd``.
|
||||
A block device can also be passed like an ``SD`` object before
|
||||
being mounted.
|
||||
|
||||
.. function:: dupterm(stream_object)
|
||||
|
||||
Duplicate the terminal (the REPL) on the passed stream-like object.
|
||||
The given object must at least implement the ``.read()`` and ``.write()`` methods.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: sep
|
||||
|
||||
separation character used in paths
|
||||
Duplicate or switch MicroPython terminal (the REPL) on the passed stream-like
|
||||
object. The given object must implement the `.readinto()` and `.write()`
|
||||
methods. If ``None`` is passed, previously set redirection is cancelled.
|
||||
|
@ -7,13 +7,28 @@
|
||||
|
||||
This module provides access to the BSD socket interface.
|
||||
|
||||
See corresponding `CPython module <https://docs.python.org/3/library/socket.html>`_ for
|
||||
comparison.
|
||||
See the corresponding `CPython module <https://docs.python.org/3/library/socket.html>`_
|
||||
for comparison.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
CPython used to have a ``socket.error`` exception which is now deprecated,
|
||||
and is an alias of OSError. In MicroPython, use OSError directly.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
For efficiency and consistency, socket objects in MicroPython implement a stream
|
||||
(file-like) interface directly. In CPython, you need to convert a socket to
|
||||
a file-like object using ``makefile()`` method. This method is still supported
|
||||
by MicroPython (but is a no-op), so where compatibility with CPython matters,
|
||||
be sure to use it.
|
||||
|
||||
Socket address format(s)
|
||||
------------------------
|
||||
|
||||
Functions below which expect a network address, accept it in the format of
|
||||
The functions below which expect a network address, accept it in the format of
|
||||
`(ipv4_address, port)`, where `ipv4_address` is a string with dot-notation numeric
|
||||
IPv4 address, e.g. ``"8.8.8.8"``, and port is integer port number in the range
|
||||
1-65535. Note the domain names are not accepted as `ipv4_address`, they should be
|
||||
@ -26,18 +41,6 @@ Functions
|
||||
|
||||
Create a new socket using the given address family, socket type and protocol number.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. note::
|
||||
|
||||
SSL sockets need to be created the following way before wrapping them with
|
||||
``ssl.wrap_socket``::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
|
||||
.. function:: socket.getaddrinfo(host, port)
|
||||
|
||||
Translate the host/port argument into a sequence of 5-tuples that contain all the
|
||||
@ -51,33 +54,50 @@ Functions
|
||||
s = socket.socket()
|
||||
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
|
||||
|
||||
.. only:: port_wipy
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. data:: socket.error
|
||||
.. data:: socket.timeout
|
||||
CPython raises a ``socket.gaierror`` exception (OSError subclass) in case
|
||||
of error in this function. MicroPython doesn't have ``socket.gaierror``
|
||||
and raises OSError directly. Note that error numbers of ``getaddrinfo()``
|
||||
form a separate namespace and may not match error numbers from
|
||||
``uerrno`` module. To distinguish ``getaddrinfo()`` errors, they are
|
||||
represented by negative numbers, whereas standard system errors are
|
||||
positive numbers (error numbers are accessible using ``e.args[0]`` property
|
||||
from an exception object). The use of negative values is a provisional
|
||||
detail which may change in the future.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: socket.AF_INET
|
||||
socket.AF_INET6
|
||||
|
||||
family types
|
||||
Address family types. Availability depends on a particular board.
|
||||
|
||||
.. data:: socket.SOCK_STREAM
|
||||
.. data:: socket.SOCK_DGRAM
|
||||
socket.SOCK_DGRAM
|
||||
|
||||
socket types
|
||||
Socket types.
|
||||
|
||||
.. data:: socket.IPPROTO_UDP
|
||||
.. data:: socket.IPPROTO_TCP
|
||||
.. only:: port_wipy
|
||||
socket.IPPROTO_TCP
|
||||
|
||||
.. data:: socket.IPPROTO_SEC
|
||||
IP protocol numbers.
|
||||
|
||||
protocol numbers
|
||||
.. data:: socket.SOL_*
|
||||
|
||||
Socket option levels (an argument to ``setsockopt()``). The exact inventory depends on a board.
|
||||
|
||||
.. data:: socket.SO_*
|
||||
|
||||
Socket options (an argument to ``setsockopt()``). The exact inventory depends on a board.
|
||||
|
||||
Constants specific to WiPy:
|
||||
|
||||
.. data:: socket.IPPROTO_SEC
|
||||
|
||||
Special protocol value to create SSL-compatible socket.
|
||||
|
||||
class socket
|
||||
============
|
||||
@ -85,7 +105,7 @@ class socket
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: socket.close
|
||||
.. method:: socket.close
|
||||
|
||||
Mark the socket closed. Once that happens, all future operations on the socket
|
||||
object will fail. The remote end will receive no more data (after queued data is flushed).
|
||||
@ -93,59 +113,68 @@ Methods
|
||||
Sockets are automatically closed when they are garbage-collected, but it is recommended
|
||||
to close() them explicitly, or to use a with statement around them.
|
||||
|
||||
.. method:: socket.bind(address)
|
||||
.. method:: socket.bind(address)
|
||||
|
||||
Bind the socket to address. The socket must not already be bound.
|
||||
|
||||
.. method:: socket.listen([backlog])
|
||||
.. method:: socket.listen([backlog])
|
||||
|
||||
Enable a server to accept connections. If backlog is specified, it must be at least 0
|
||||
(if it's lower, it will be set to 0); and specifies the number of unaccepted connections
|
||||
that the system will allow before refusing new connections. If not specified, a default
|
||||
reasonable value is chosen.
|
||||
|
||||
.. method:: socket.accept()
|
||||
.. method:: socket.accept()
|
||||
|
||||
Accept a connection. The socket must be bound to an address and listening for connections.
|
||||
The return value is a pair (conn, address) where conn is a new socket object usable to send
|
||||
and receive data on the connection, and address is the address bound to the socket on the
|
||||
other end of the connection.
|
||||
|
||||
.. method:: socket.connect(address)
|
||||
.. method:: socket.connect(address)
|
||||
|
||||
Connect to a remote socket at address.
|
||||
|
||||
.. method:: socket.send(bytes)
|
||||
.. method:: socket.send(bytes)
|
||||
|
||||
Send data to the socket. The socket must be connected to a remote socket.
|
||||
Returns number of bytes sent, which may be smaller than the length of data
|
||||
("short write").
|
||||
|
||||
.. method:: socket.sendall(bytes)
|
||||
.. method:: socket.sendall(bytes)
|
||||
|
||||
Send data to the socket. The socket must be connected to a remote socket.
|
||||
Send all data to the socket. The socket must be connected to a remote socket.
|
||||
Unlike ``send()``, this method will try to send all of data, by sending data
|
||||
chunk by chunk consecutively.
|
||||
|
||||
.. method:: socket.recv(bufsize)
|
||||
The behavior of this method on non-blocking sockets is undefined. Due to this,
|
||||
on MicroPython, it's recommended to use ``write()`` method instead, which
|
||||
has the same "no short writes" policy for blocking sockets, and will return
|
||||
number of bytes sent on non-blocking sockets.
|
||||
|
||||
.. method:: socket.recv(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a bytes object representing the data
|
||||
received. The maximum amount of data to be received at once is specified by bufsize.
|
||||
|
||||
.. method:: socket.sendto(bytes, address)
|
||||
.. method:: socket.sendto(bytes, address)
|
||||
|
||||
Send data to the socket. The socket should not be connected to a remote socket, since the
|
||||
destination socket is specified by `address`.
|
||||
|
||||
.. method:: socket.recvfrom(bufsize)
|
||||
.. method:: socket.recvfrom(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a pair (bytes, address) where bytes is a
|
||||
bytes object representing the data received and address is the address of the socket sending
|
||||
the data.
|
||||
|
||||
.. method:: socket.setsockopt(level, optname, value)
|
||||
.. method:: socket.setsockopt(level, optname, value)
|
||||
|
||||
Set the value of the given socket option. The needed symbolic constants are defined in the
|
||||
socket module (SO_* etc.). The value can be an integer or a bytes-like object representing
|
||||
a buffer.
|
||||
|
||||
.. method:: socket.settimeout(value)
|
||||
.. method:: socket.settimeout(value)
|
||||
|
||||
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
|
||||
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
|
||||
@ -161,24 +190,27 @@ Methods
|
||||
instead. If you use ``except OSError:`` to catch the exception,
|
||||
your code will work both in MicroPython and CPython.
|
||||
|
||||
.. method:: socket.setblocking(flag)
|
||||
.. method:: socket.setblocking(flag)
|
||||
|
||||
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking,
|
||||
else to blocking mode.
|
||||
|
||||
This method is a shorthand for certain ``settimeout()`` calls::
|
||||
This method is a shorthand for certain ``settimeout()`` calls:
|
||||
|
||||
sock.setblocking(True) is equivalent to sock.settimeout(None)
|
||||
sock.setblocking(False) is equivalent to sock.settimeout(0.0)
|
||||
* ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)``
|
||||
* ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)``
|
||||
|
||||
.. method:: socket.makefile(mode='rb')
|
||||
.. method:: socket.makefile(mode='rb', buffering=0)
|
||||
|
||||
Return a file object associated with the socket. The exact returned type depends on the arguments
|
||||
given to makefile(). The support is limited to binary modes only ('rb' and 'wb').
|
||||
given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb').
|
||||
CPython's arguments: ``encoding``, ``errors`` and ``newline`` are not supported.
|
||||
|
||||
The socket must be in blocking mode; it can have a timeout, but the file object’s internal buffer
|
||||
may end up in a inconsistent state if a timeout occurs.
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
As MicroPython doesn't support buffered streams, values of ``buffering``
|
||||
parameter is ignored and treated as if it was 0 (unbuffered).
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
@ -186,27 +218,33 @@ Methods
|
||||
Closing the file object returned by makefile() WILL close the
|
||||
original socket as well.
|
||||
|
||||
.. method:: socket.read([size])
|
||||
.. method:: socket.read([size])
|
||||
|
||||
Read up to size bytes from the socket. Return a bytes object. If ``size`` is not given, it
|
||||
reads all data available from the socket until ``EOF``; as such the method will not return until
|
||||
the socket is closed.
|
||||
the socket is closed. This function tries to read as much data as
|
||||
requested (no "short reads"). This may be not possible with
|
||||
non-blocking socket though, and then less data will be returned.
|
||||
|
||||
.. method:: socket.readinto(buf[, nbytes])
|
||||
.. method:: socket.readinto(buf[, nbytes])
|
||||
|
||||
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
|
||||
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
|
||||
that many bytes. Otherwise, read at most ``len(buf)`` bytes. Just as
|
||||
``read()``, this method follows "no short reads" policy.
|
||||
|
||||
Return value: number of bytes read and stored into ``buf``.
|
||||
|
||||
.. method:: socket.readline()
|
||||
.. method:: socket.readline()
|
||||
|
||||
Read a line, ending in a newline character.
|
||||
|
||||
Return value: the line read.
|
||||
|
||||
.. method:: socket.write(buf)
|
||||
.. method:: socket.write(buf)
|
||||
|
||||
Write the buffer of bytes to the socket.
|
||||
Write the buffer of bytes to the socket. This function will try to
|
||||
write all data to a socket (no "short writes"). This may be not possible
|
||||
with a non-blocking socket though, and returned value will be less than
|
||||
the length of ``buf``.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
@ -1,19 +1,17 @@
|
||||
:mod:`ussl` -- ssl module
|
||||
===============================
|
||||
:mod:`ussl` -- SSL/TLS module
|
||||
=============================
|
||||
|
||||
.. module:: ussl
|
||||
:synopsis: TLS/SSL wrapper for socket objects
|
||||
|
||||
This module provides access to Transport Layer Security (often known as
|
||||
“Secure Sockets Layer”) encryption and peer authentication facilities for
|
||||
network sockets, both client-side and server-side.
|
||||
This module provides access to Transport Layer Security (previously and
|
||||
widely known as “Secure Sockets Layer”) encryption and peer authentication
|
||||
facilities for network sockets, both client-side and server-side.
|
||||
|
||||
.. only:: not port_wipy
|
||||
Functions
|
||||
---------
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: ssl.wrap_socket(sock, server_side=False)
|
||||
.. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)
|
||||
|
||||
Takes a stream `sock` (usually usocket.socket instance of ``SOCK_STREAM`` type),
|
||||
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
|
||||
@ -23,64 +21,26 @@ network sockets, both client-side and server-side.
|
||||
server-side SSL socket should be created from a normal socket returned from
|
||||
`accept()` on a non-SSL listening server socket.
|
||||
|
||||
.. warning::
|
||||
Depending on the underlying module implementation for a particular board,
|
||||
some or all keyword arguments above may be not supported.
|
||||
|
||||
Currently, this function does NOT validate server certificates, which makes
|
||||
an SSL connection established prone to man-in-the-middle attacks.
|
||||
.. warning::
|
||||
|
||||
Some implementations of ``ssl`` module do NOT validate server certificates,
|
||||
which makes an SSL connection established prone to man-in-the-middle attacks.
|
||||
|
||||
.. only:: port_wipy
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
Functions
|
||||
---------
|
||||
.. data:: ssl.SSLError
|
||||
|
||||
.. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None)
|
||||
This exception does NOT exist. Instead its base class, OSError, is used.
|
||||
|
||||
Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of
|
||||
``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM``
|
||||
socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example::
|
||||
Constants
|
||||
---------
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
|
||||
.. data:: ssl.CERT_NONE
|
||||
ssl.CERT_OPTIONAL
|
||||
ssl.CERT_REQUIRED
|
||||
|
||||
Certificates must be used in order to validate the other side of the connection, and also to
|
||||
authenticate ourselves with the other end. Such certificates must be stored as files using the
|
||||
FTP server, and they must be placed in specific paths with specific names.
|
||||
|
||||
- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'**
|
||||
- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'**
|
||||
- The key for our own certificate goes in: **'/flash/cert/private.key'**
|
||||
|
||||
.. note::
|
||||
|
||||
When these files are stored, they are placed inside the internal **hidden** file system
|
||||
(just like firmware updates), and therefore they are never visible.
|
||||
|
||||
For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located
|
||||
in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_
|
||||
and put it in '/flash/cert/'. Then do::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
|
||||
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
|
||||
|
||||
SSL sockets inherit all methods and from the standard sockets, see the :mod:`usocket` module.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. data:: ssl.SSLError
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: ssl.CERT_NONE
|
||||
.. data:: ssl.CERT_OPTIONAL
|
||||
.. data:: ssl.CERT_REQUIRED
|
||||
|
||||
supported values in ``cert_reqs``
|
||||
Supported values for `cert_reqs` parameter.
|
||||
|
@ -55,44 +55,34 @@ Functions
|
||||
which expresses a time as per localtime. It returns an integer which is
|
||||
the number of seconds since Jan 1, 2000.
|
||||
|
||||
.. only:: port_unix or port_pyboard or port_esp8266
|
||||
.. function:: sleep(seconds)
|
||||
|
||||
.. function:: sleep(seconds)
|
||||
Sleep for the given number of seconds. Some boards may accept `seconds` as a
|
||||
floating-point number to sleep for a fractional number of seconds. Note that
|
||||
other boards may not accept a floating-point argument, for compatibility with
|
||||
them use ``sleep_ms()`` and ``sleep_us()`` functions.
|
||||
|
||||
Sleep for the given number of seconds. Seconds can be a floating-point number to
|
||||
sleep for a fractional number of seconds. Note that other MicroPython ports may
|
||||
not accept floating-point argument, for compatibility with them use ``sleep_ms()``
|
||||
and ``sleep_us()`` functions.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: sleep(seconds)
|
||||
|
||||
Sleep for the given number of seconds.
|
||||
|
||||
.. only:: port_unix or port_pyboard or port_wipy or port_esp8266
|
||||
|
||||
.. function:: sleep_ms(ms)
|
||||
.. function:: sleep_ms(ms)
|
||||
|
||||
Delay for given number of milliseconds, should be positive or 0.
|
||||
|
||||
.. function:: sleep_us(us)
|
||||
.. function:: sleep_us(us)
|
||||
|
||||
Delay for given number of microseconds, should be positive or 0
|
||||
Delay for given number of microseconds, should be positive or 0.
|
||||
|
||||
.. function:: ticks_ms()
|
||||
.. function:: ticks_ms()
|
||||
|
||||
Returns an increasing millisecond counter with an arbitrary reference point,
|
||||
that wraps around after some value. This value is not explicitly exposed,
|
||||
but we will refer to it as `TICKS_MAX` to simplify discussion. Period of
|
||||
the values is `TICKS_PERIOD = TICKS_MAX + 1`. `TICKS_PERIOD` is guaranteed
|
||||
to be a power of two, but otherwise may differ from port to port. The same
|
||||
period value is used for all of ticks_ms(), ticks_us(), ticks_cpu() functions
|
||||
(for simplicity). Thus, these functions will return a value in range
|
||||
[0 .. `TICKS_MAX`], inclusive, total `TICKS_PERIOD` values. Note that only
|
||||
non-negative values are used. For the most part, you should treat values
|
||||
returned by these functions as opaque. The only operations available for them
|
||||
are ``ticks_diff()`` and ``ticks_add()`` functions described below.
|
||||
Returns an increasing millisecond counter with an arbitrary reference point, that
|
||||
wraps around after some value. This value is not explicitly exposed, but we will
|
||||
refer to it as ``TICKS_MAX`` to simplify discussion. Period of the values is
|
||||
``TICKS_PERIOD = TICKS_MAX + 1``. ``TICKS_PERIOD`` is guaranteed to be a power of
|
||||
two, but otherwise may differ from port to port. The same period value is used
|
||||
for all of ``ticks_ms()``, ``ticks_us()``, ``ticks_cpu()`` functions (for
|
||||
simplicity). Thus, these functions will return a value in range [``0`` ..
|
||||
``TICKS_MAX``], inclusive, total ``TICKS_PERIOD`` values. Note that only
|
||||
non-negative values are used. For the most part, you should treat values returned
|
||||
by these functions as opaque. The only operations available for them are
|
||||
``ticks_diff()`` and ``ticks_add()`` functions described below.
|
||||
|
||||
Note: Performing standard mathematical operations (+, -) or relational
|
||||
operators (<, <=, >, >=) directly on these value will lead to invalid
|
||||
@ -100,15 +90,15 @@ Functions
|
||||
as arguments to ``ticks_diff()`` or ``ticks_add()`` will also lead to
|
||||
invalid results from the latter functions.
|
||||
|
||||
.. function:: ticks_us()
|
||||
.. function:: ticks_us()
|
||||
|
||||
Just like ``ticks_ms`` above, but in microseconds.
|
||||
Just like ``ticks_ms()`` above, but in microseconds.
|
||||
|
||||
.. function:: ticks_cpu()
|
||||
|
||||
Similar to ``ticks_ms`` and ``ticks_us``, but with the highest possible resolution
|
||||
Similar to ``ticks_ms()`` and ``ticks_us()``, but with the highest possible resolution
|
||||
in the system. This is usually CPU clocks, and that's why the function is named that
|
||||
way. But it doesn't have to a CPU clock, some other timing source available in a
|
||||
way. But it doesn't have to be a CPU clock, some other timing source available in a
|
||||
system (e.g. high-resolution timer) can be used instead. The exact timing unit
|
||||
(resolution) of this function is not specified on ``utime`` module level, but
|
||||
documentation for a specific port may provide more specific information. This
|
||||
@ -124,7 +114,7 @@ Functions
|
||||
Given a ``ticks`` value, this function allows to calculate ticks value ``delta``
|
||||
ticks before or after it, following modular-arithmetic definition of tick values
|
||||
(see ``ticks_ms()`` above). ``ticks`` parameter must be a direct result of call
|
||||
to ``tick_ms()``, ``ticks_us()``, ``ticks_cpu()`` functions (or from previous
|
||||
to ``ticks_ms()``, ``ticks_us()``, or ``ticks_cpu()`` functions (or from previous
|
||||
call to ``ticks_add()``). However, ``delta`` can be an arbitrary integer number
|
||||
or numeric expression. ``ticks_add()`` is useful for calculating deadlines for
|
||||
events/tasks. (Note: you must use ``ticks_diff()`` function to work with
|
||||
@ -133,35 +123,37 @@ Functions
|
||||
Examples::
|
||||
|
||||
# Find out what ticks value there was 100ms ago
|
||||
print(tick_add(time.ticks_ms(), -100))
|
||||
print(ticks_add(time.ticks_ms(), -100))
|
||||
|
||||
# Calculate deadline for operation and test for it
|
||||
deadline = tick_add(time.ticks_ms(), 200)
|
||||
deadline = ticks_add(time.ticks_ms(), 200)
|
||||
while ticks_diff(deadline, time.ticks_ms()) > 0:
|
||||
do_a_little_of_something()
|
||||
|
||||
# Find out TICKS_MAX used by this port
|
||||
print(tick_add(0, -1))
|
||||
print(ticks_add(0, -1))
|
||||
|
||||
|
||||
.. function:: ticks_diff(ticks1, ticks2)
|
||||
|
||||
Measure ticks difference between values returned from ticks_ms(), ticks_us(), or ticks_cpu()
|
||||
functions. The argument order is the same as for subtraction operator,
|
||||
``tick_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. However, values returned by
|
||||
ticks_ms(), etc. functions may wrap around, so directly using subtraction on them will
|
||||
produce incorrect result. That is why ticks_diff() is needed, it implements modular
|
||||
(or more specifically, ring) arithmetics to produce correct result even for wrap-around
|
||||
values (as long as they not too distant inbetween, see below). The function returns
|
||||
**signed** value in the range [`-TICKS_PERIOD/2` .. `TICKS_PERIOD/2-1`] (that's a typical
|
||||
range definition for two's-complement signed binary integers). If the result is negative,
|
||||
it means that `ticks1` occured earlier in time than `ticks2`. Otherwise, it means that
|
||||
`ticks1` occured after `ticks2`. This holds `only` if `ticks1` and `ticks2` are apart from
|
||||
each other for no more than `TICKS_PERIOD/2-1` ticks. If that does not hold, incorrect
|
||||
result will be returned. Specifically, if 2 tick values are apart for `TICKS_PERIOD/2-1`
|
||||
ticks, that value will be returned by the function. However, if `TICKS_PERIOD/2` of
|
||||
real-time ticks has passed between them, the function will return `-TICKS_PERIOD/2`
|
||||
instead, i.e. result value will wrap around to the negative range of possible values.
|
||||
Measure ticks difference between values returned from ``ticks_ms()``, ``ticks_us()``,
|
||||
or ``ticks_cpu()`` functions. The argument order is the same as for subtraction
|
||||
operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``.
|
||||
However, values returned by ``ticks_ms()``, etc. functions may wrap around, so
|
||||
directly using subtraction on them will produce incorrect result. That is why
|
||||
``ticks_diff()`` is needed, it implements modular (or more specifically, ring)
|
||||
arithmetics to produce correct result even for wrap-around values (as long as they not
|
||||
too distant inbetween, see below). The function returns **signed** value in the range
|
||||
[``-TICKS_PERIOD/2`` .. ``TICKS_PERIOD/2-1``] (that's a typical range definition for
|
||||
two's-complement signed binary integers). If the result is negative, it means that
|
||||
``ticks1`` occurred earlier in time than ``ticks2``. Otherwise, it means that
|
||||
``ticks1`` occurred after ``ticks2``. This holds ``only`` if ``ticks1`` and ``ticks2``
|
||||
are apart from each other for no more than ``TICKS_PERIOD/2-1`` ticks. If that does
|
||||
not hold, incorrect result will be returned. Specifically, if two tick values are
|
||||
apart for ``TICKS_PERIOD/2-1`` ticks, that value will be returned by the function.
|
||||
However, if ``TICKS_PERIOD/2`` of real-time ticks has passed between them, the
|
||||
function will return ``-TICKS_PERIOD/2`` instead, i.e. result value will wrap around
|
||||
to the negative range of possible values.
|
||||
|
||||
Informal rationale of the constraints above: Suppose you are locked in a room with no
|
||||
means to monitor passing of time except a standard 12-notch clock. Then if you look at
|
||||
@ -200,20 +192,21 @@ Functions
|
||||
print("Oops, running late, tell task to run faster!")
|
||||
task.run(run_faster=true)
|
||||
|
||||
Note: Do not pass ``time()`` values to ``ticks_diff()``, and should use
|
||||
Note: Do not pass ``time()`` values to ``ticks_diff()``, you should use
|
||||
normal mathematical operations on them. But note that ``time()`` may (and will)
|
||||
also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
|
||||
|
||||
|
||||
.. function:: time()
|
||||
|
||||
Returns the number of seconds, as an integer, since the Epoch, assuming that underlying
|
||||
RTC is set and maintained as described above. If an RTC is not set, this function returns
|
||||
number of seconds since a port-specific reference point in time (for embedded boards without
|
||||
a battery-backed RTC, usually since power up or reset). If you want to develop portable
|
||||
MicroPython application, you should not rely on this function to provide higher than second
|
||||
precision. If you need higher precision, use ``ticks_ms()`` and ``ticks_us()`` functions,
|
||||
if you need calendar time, ``localtime()`` without an argument is a better choice.
|
||||
Returns the number of seconds, as an integer, since the Epoch, assuming that
|
||||
underlying RTC is set and maintained as described above. If an RTC is not set, this
|
||||
function returns number of seconds since a port-specific reference point in time (for
|
||||
embedded boards without a battery-backed RTC, usually since power up or reset). If you
|
||||
want to develop portable MicroPython application, you should not rely on this function
|
||||
to provide higher than second precision. If you need higher precision, use
|
||||
``ticks_ms()`` and ``ticks_us()`` functions, if you need calendar time,
|
||||
``localtime()`` without an argument is a better choice.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user