ports/nrf: Upmerging port with upstream master
This commit is contained in:
commit
bcab2ba0a8
|
@ -15,16 +15,13 @@
|
|||
# These should also not be modified by git.
|
||||
tests/basics/string_cr_conversion.py -text
|
||||
tests/basics/string_crlf_conversion.py -text
|
||||
stmhal/pybcdc.inf_template -text
|
||||
stmhal/usbd_* -text
|
||||
stmhal/boards/*/stm32f4xx_hal_conf.h -text
|
||||
stmhal/cmsis/** -text
|
||||
stmhal/hal/** -text
|
||||
stmhal/usbdev/** -text
|
||||
stmhal/usbhost/** -text
|
||||
cc3200/hal/aes.c -text
|
||||
cc3200/hal/aes.h -text
|
||||
cc3200/hal/des.c -text
|
||||
cc3200/hal/i2s.c -text
|
||||
cc3200/hal/i2s.h -text
|
||||
cc3200/version.h -text
|
||||
ports/stm32/pybcdc.inf_template -text
|
||||
ports/stm32/usbd_* -text
|
||||
ports/stm32/usbdev/** -text
|
||||
ports/stm32/usbhost/** -text
|
||||
ports/cc3200/hal/aes.c -text
|
||||
ports/cc3200/hal/aes.h -text
|
||||
ports/cc3200/hal/des.c -text
|
||||
ports/cc3200/hal/i2s.c -text
|
||||
ports/cc3200/hal/i2s.h -text
|
||||
ports/cc3200/version.h -text
|
||||
|
|
|
@ -11,3 +11,7 @@
|
|||
[submodule "lib/berkeley-db-1.xx"]
|
||||
path = lib/berkeley-db-1.xx
|
||||
url = https://github.com/pfalcon/berkeley-db-1.xx
|
||||
[submodule "lib/stm32lib"]
|
||||
path = lib/stm32lib
|
||||
url = https://github.com/micropython/stm32lib
|
||||
branch = work-F4-1.13.1+F7-1.5.0+L4-1.3.0
|
||||
|
|
51
.travis.yml
51
.travis.yml
|
@ -19,49 +19,48 @@ before_script:
|
|||
- sudo apt-get install -y --force-yes gcc-arm-none-eabi
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
# For coverage testing
|
||||
# cpp-coveralls 0.4 conflicts with urllib3 preinstalled in Travis VM
|
||||
- sudo pip install cpp-coveralls==0.3.12
|
||||
# For coverage testing (upgrade is used to get latest urllib3 version)
|
||||
- sudo pip install --upgrade cpp-coveralls
|
||||
- gcc --version
|
||||
- arm-none-eabi-gcc --version
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make -C mpy-cross
|
||||
- make -C minimal CROSS=1 build/firmware.bin
|
||||
- ls -l minimal/build/firmware.bin
|
||||
- make -C ports/minimal CROSS=1 build/firmware.bin
|
||||
- ls -l ports/minimal/build/firmware.bin
|
||||
- tools/check_code_size.sh
|
||||
- mkdir -p ${HOME}/persist
|
||||
# Save new firmware for reference, but only if building a main branch, not a pull request
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp minimal/build/firmware.bin ${HOME}/persist/; fi'
|
||||
- make -C unix deplibs
|
||||
- make -C unix
|
||||
- make -C unix nanbox
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm test
|
||||
- make -C stmhal
|
||||
- make -C stmhal BOARD=PYBV11 MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1
|
||||
- make -C stmhal BOARD=STM32F769DISC
|
||||
- make -C stmhal BOARD=STM32L476DISC
|
||||
- make -C teensy
|
||||
- make -C cc3200 BTARGET=application BTYPE=release
|
||||
- make -C cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make -C windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi'
|
||||
- make -C ports/unix deplibs
|
||||
- make -C ports/unix
|
||||
- make -C ports/unix nanbox
|
||||
- make -C ports/bare-arm
|
||||
- make -C ports/qemu-arm test
|
||||
- make -C ports/stm32
|
||||
- make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1
|
||||
- make -C ports/stm32 BOARD=STM32F769DISC
|
||||
- make -C ports/stm32 BOARD=STM32L476DISC
|
||||
- make -C ports/teensy
|
||||
- make -C ports/cc3200 BTARGET=application BTYPE=release
|
||||
- make -C ports/cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
|
||||
# run tests without coverage info
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native)
|
||||
|
||||
# run tests with coverage info
|
||||
- make -C unix coverage
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests -d thread)
|
||||
- (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)
|
||||
- make -C ports/unix coverage
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float)
|
||||
|
||||
# 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)
|
||||
- (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
- (grep "FAIL" qemu-arm/build/console.out)
|
||||
- (grep "FAIL" ports/qemu-arm/build/console.out)
|
||||
|
|
58
README.md
58
README.md
|
@ -34,10 +34,10 @@ Major components in this repository:
|
|||
core library.
|
||||
- mpy-cross/ -- the MicroPython cross-compiler which is used to turn scripts
|
||||
into precompiled bytecode.
|
||||
- unix/ -- a version of MicroPython that runs on Unix.
|
||||
- stmhal/ -- a version of MicroPython that runs on the PyBoard and similar
|
||||
- ports/unix/ -- a version of MicroPython that runs on Unix.
|
||||
- ports/stm32/ -- a version of MicroPython that runs on the PyBoard and similar
|
||||
STM32 boards (using ST's Cube HAL drivers).
|
||||
- minimal/ -- a minimal MicroPython port. Start with this if you want
|
||||
- ports/minimal/ -- a minimal MicroPython port. Start with this if you want
|
||||
to port MicroPython to another microcontroller.
|
||||
- tests/ -- test framework and test scripts.
|
||||
- docs/ -- user documentation in Sphinx reStructuredText format. Rendered
|
||||
|
@ -45,13 +45,13 @@ Major components in this repository:
|
|||
to select needed board/port at the bottom left corner).
|
||||
|
||||
Additional components:
|
||||
- bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
|
||||
- ports/bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
|
||||
mostly to control code size.
|
||||
- teensy/ -- a version of MicroPython that runs on the Teensy 3.1
|
||||
- ports/teensy/ -- a version of MicroPython that runs on the Teensy 3.1
|
||||
(preliminary but functional).
|
||||
- pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
|
||||
- esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- ports/pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
|
||||
- ports/cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
|
||||
- ports/esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- extmod/ -- additional (non-core) modules implemented in C.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
- examples/ -- a few example Python scripts.
|
||||
|
@ -72,7 +72,8 @@ Alternatively, fallback implementation based on setjmp/longjmp can be used.
|
|||
|
||||
To build (see section below for required dependencies):
|
||||
|
||||
$ cd unix
|
||||
$ git submodule update --init
|
||||
$ cd ports/unix
|
||||
$ make axtls
|
||||
$ make
|
||||
|
||||
|
@ -104,44 +105,49 @@ Standard library modules come from
|
|||
External dependencies
|
||||
---------------------
|
||||
|
||||
Building Unix version requires some dependencies installed. For
|
||||
Building MicroPython ports may require some dependencies installed.
|
||||
|
||||
For Unix port, `libffi` library and `pkg-config` tool are required. On
|
||||
Debian/Ubuntu/Mint derivative Linux distros, install `build-essential`
|
||||
(includes toolchain and make), `libffi-dev`, and `pkg-config` packages.
|
||||
|
||||
Other dependencies can be built together with MicroPython. Oftentimes,
|
||||
you need to do this to enable extra features or capabilities. To build
|
||||
Other dependencies can be built together with MicroPython. This may
|
||||
be required to enable extra features or capabilities, and in recent
|
||||
versions of MicroPython, these may be enabled by default. To build
|
||||
these additional dependencies, first fetch git submodules for them:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
Use this same command to get the latest versions of dependencies, as
|
||||
they are updated from time to time. After that, in `unix/` dir, execute:
|
||||
Use the same command to get the latest versions of dependencies, as
|
||||
they are updated from time to time. After that, in the port directory
|
||||
(e.g. `ports/unix/`), execute:
|
||||
|
||||
$ make deplibs
|
||||
|
||||
This will build all available dependencies (regardless whether they
|
||||
are used or not). If you intend to build MicroPython with additional
|
||||
options (like cross-compiling), the same set of options should be passed
|
||||
to `make deplibs`. To actually enabled use of dependencies, edit
|
||||
`unix/mpconfigport.mk` file, which has inline descriptions of the options.
|
||||
For example, to build SSL module (required for `upip` tool described above),
|
||||
set `MICROPY_PY_USSL` to 1.
|
||||
to `make deplibs`. To actually enable/disable use of dependencies, edit
|
||||
`ports/unix/mpconfigport.mk` file, which has inline descriptions of the options.
|
||||
For example, to build SSL module (required for `upip` tool described above,
|
||||
and so enabled by dfeault), `MICROPY_PY_USSL` should be set to 1.
|
||||
|
||||
In `unix/mpconfigport.mk`, you can also disable some dependencies enabled
|
||||
by default, like FFI support, which requires libffi development files to
|
||||
be installed.
|
||||
For some ports, building required dependences is transparent, and happens
|
||||
automatically. They still need to be fetched with the git submodule command
|
||||
above.
|
||||
|
||||
The STM version
|
||||
---------------
|
||||
The STM32 version
|
||||
-----------------
|
||||
|
||||
The "stmhal" port requires an ARM compiler, arm-none-eabi-gcc, and associated
|
||||
The "stm32" port requires an ARM compiler, arm-none-eabi-gcc, and associated
|
||||
bin-utils. For those using Arch Linux, you need arm-none-eabi-binutils and
|
||||
arm-none-eabi-gcc packages. Otherwise, try here:
|
||||
https://launchpad.net/gcc-arm-embedded
|
||||
|
||||
To build:
|
||||
|
||||
$ cd stmhal
|
||||
$ git submodule update --init
|
||||
$ cd ports/stm32
|
||||
$ make
|
||||
|
||||
You then need to get your board into DFU mode. On the pyboard, connect the
|
||||
|
@ -155,4 +161,4 @@ Then to flash the code via USB DFU to your device:
|
|||
This will use the included `tools/pydfu.py` script. If flashing the firmware
|
||||
does not work it may be because you don't have the correct permissions, and
|
||||
need to use `sudo make deploy`.
|
||||
See the README.md file in the stmhal/ directory for further details.
|
||||
See the README.md file in the ports/stm32/ directory for further details.
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
include ../py/mkenv.mk
|
||||
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h
|
||||
|
||||
# include py core make definitions
|
||||
include ../py/py.mk
|
||||
|
||||
CROSS_COMPILE = arm-none-eabi-
|
||||
|
||||
INC += -I.
|
||||
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 -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -ggdb
|
||||
else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
|
||||
LIBS =
|
||||
|
||||
SRC_C = \
|
||||
main.c \
|
||||
# printf.c \
|
||||
string0.c \
|
||||
malloc0.c \
|
||||
gccollect.c \
|
||||
|
||||
SRC_S = \
|
||||
# startup_stm32f40xx.s \
|
||||
gchelper.s \
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
|
||||
|
||||
all: $(BUILD)/firmware.elf
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
include ../py/mkrules.mk
|
|
@ -1,97 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#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) {
|
||||
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);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
// uncaught exception
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
mp_init();
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
|
||||
do_str("for i in range(10):\n print(i)", MP_PARSE_FILE_INPUT);
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
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) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||
__fatal_error("Assertion failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
int _lseek() {return 0;}
|
||||
int _read() {return 0;}
|
||||
int _write() {return 0;}
|
||||
int _close() {return 0;}
|
||||
void _exit(int x) {for(;;){}}
|
||||
int _sbrk() {return 0;}
|
||||
int _kill() {return 0;}
|
||||
int _getpid() {return 0;}
|
||||
int _fstat() {return 0;}
|
||||
int _isatty() {return 0;}
|
||||
*/
|
||||
|
||||
void *malloc(size_t n) {return NULL;}
|
||||
void *calloc(size_t nmemb, size_t size) {return NULL;}
|
||||
void *realloc(void *ptr, size_t size) {return NULL;}
|
||||
void free(void *p) {}
|
||||
int printf(const char *m, ...) {return 0;}
|
||||
void *memcpy(void *dest, const void *src, size_t n) {return NULL;}
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {return 0;}
|
||||
void *memmove(void *dest, const void *src, size_t n) {return NULL;}
|
||||
void *memset(void *s, int c, size_t n) {return NULL;}
|
||||
int strcmp(const char *s1, const char* s2) {return 0;}
|
||||
int strncmp(const char *s1, const char* s2, size_t n) {return 0;}
|
||||
size_t strlen(const char *s) {return 0;}
|
||||
char *strcat(char *dest, const char *src) {return NULL;}
|
||||
char *strchr(const char *dest, int c) {return NULL;}
|
||||
#include <stdarg.h>
|
||||
int vprintf(const char *format, va_list ap) {return 0;}
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {return 0;}
|
||||
|
||||
#undef putchar
|
||||
int putchar(int c) {return 0;}
|
||||
int puts(const char *s) {return 0;}
|
||||
|
||||
void _start(void) {main(0, NULL);}
|
|
@ -1,66 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// options to control how MicroPython is built
|
||||
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#define MICROPY_COMP_CONST (0)
|
||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_REVERSED (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_ATTRTUPLE (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (0)
|
||||
#define MICROPY_PY_STRUCT (0)
|
||||
#define MICROPY_PY_SYS (0)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_USE_INTERNAL_PRINTF (0)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
|
||||
#define UINT_FMT "%lu"
|
||||
#define INT_FMT "%ld"
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// dummy print
|
||||
#define MP_PLAT_PRINT_STRN(str, len) (void)0
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
|
@ -1,63 +0,0 @@
|
|||
# Select the board to build for: if not given on the command line,
|
||||
# then default to WIPY
|
||||
BOARD ?= WIPY
|
||||
ifeq ($(wildcard boards/$(BOARD)/.),)
|
||||
$(error Invalid BOARD specified)
|
||||
endif
|
||||
|
||||
# Make 'release' the default build type
|
||||
BTYPE ?= release
|
||||
|
||||
# Port for flashing firmware
|
||||
PORT ?= /dev/ttyUSB1
|
||||
|
||||
# If the build directory is not given, make it reflect the board name.
|
||||
BUILD ?= build/$(BOARD)/$(BTYPE)
|
||||
|
||||
include ../py/mkenv.mk
|
||||
-include ../../localconfig.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 -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
|
||||
|
||||
FLASH_SIZE_WIPY = 2M
|
||||
FLASH_SIZE_LAUNCHXL = 1M
|
||||
|
||||
ifeq ($(BTARGET), application)
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h
|
||||
# include MicroPython make definitions
|
||||
include ../py/py.mk
|
||||
include application.mk
|
||||
else
|
||||
ifeq ($(BTARGET), bootloader)
|
||||
include bootmgr/bootloader.mk
|
||||
else
|
||||
$(error Invalid BTARGET specified)
|
||||
endif
|
||||
endif
|
||||
|
||||
# always include MicroPython make rules
|
||||
include ../py/mkrules.mk
|
||||
|
||||
erase:
|
||||
cc3200tool -p $(PORT) format_flash --size $(FLASH_SIZE_$(BOARD))
|
||||
|
||||
deploy:
|
||||
cc3200tool -p $(PORT) \
|
||||
write_file bootmgr/build/$(BOARD)/$(BTYPE)/bootloader.bin /sys/mcuimg.bin \
|
||||
write_file build/$(BOARD)/$(BTYPE)/mcuimg.bin /sys/factimg.bin
|
||||
|
||||
# Files *.ucf and *ucf.signed.bin come from CC3200SDK-SERVICEPACK
|
||||
# package from http://www.ti.com/tool/cc3200sdk
|
||||
servicepack:
|
||||
cc3200tool -p $(PORT) \
|
||||
write_file --file-size=0x20000 --signature ota_1.0.1.6-2.7.0.0.ucf.signed.bin \
|
||||
ota_1.0.1.6-2.7.0.0.ucf /sys/servicepack.ucf
|
|
@ -1,239 +0,0 @@
|
|||
APP_INC = -I.
|
||||
APP_INC += -I..
|
||||
APP_INC += -Ifatfs/src
|
||||
APP_INC += -Ifatfs/src/drivers
|
||||
APP_INC += -IFreeRTOS
|
||||
APP_INC += -IFreeRTOS/Source/include
|
||||
APP_INC += -IFreeRTOS/Source/portable/GCC/ARM_CM3
|
||||
APP_INC += -Iftp
|
||||
APP_INC += -Ihal
|
||||
APP_INC += -Ihal/inc
|
||||
APP_INC += -Imisc
|
||||
APP_INC += -Imods
|
||||
APP_INC += -I../drivers/cc3100/inc
|
||||
APP_INC += -Isimplelink
|
||||
APP_INC += -Isimplelink/oslib
|
||||
APP_INC += -Itelnet
|
||||
APP_INC += -Iutil
|
||||
APP_INC += -Ibootmgr
|
||||
APP_INC += -I$(BUILD)
|
||||
APP_INC += -I$(BUILD)/genhdr
|
||||
APP_INC += -I../stmhal
|
||||
|
||||
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 \
|
||||
)
|
||||
|
||||
APP_RTOS_SRC_C = $(addprefix FreeRTOS/Source/,\
|
||||
croutine.c \
|
||||
event_groups.c \
|
||||
list.c \
|
||||
queue.c \
|
||||
tasks.c \
|
||||
timers.c \
|
||||
portable/GCC/ARM_CM3/port.c \
|
||||
portable/MemMang/heap_4.c \
|
||||
)
|
||||
|
||||
APP_FTP_SRC_C = $(addprefix ftp/,\
|
||||
ftp.c \
|
||||
updater.c \
|
||||
)
|
||||
|
||||
APP_HAL_SRC_C = $(addprefix hal/,\
|
||||
adc.c \
|
||||
aes.c \
|
||||
cc3200_hal.c \
|
||||
cpu.c \
|
||||
crc.c \
|
||||
des.c \
|
||||
gpio.c \
|
||||
i2c.c \
|
||||
i2s.c \
|
||||
interrupt.c \
|
||||
pin.c \
|
||||
prcm.c \
|
||||
sdhost.c \
|
||||
shamd5.c \
|
||||
spi.c \
|
||||
startup_gcc.c \
|
||||
systick.c \
|
||||
timer.c \
|
||||
uart.c \
|
||||
utils.c \
|
||||
wdt.c \
|
||||
)
|
||||
|
||||
APP_MISC_SRC_C = $(addprefix misc/,\
|
||||
antenna.c \
|
||||
FreeRTOSHooks.c \
|
||||
help.c \
|
||||
mpirq.c \
|
||||
mperror.c \
|
||||
mpexception.c \
|
||||
)
|
||||
|
||||
APP_MODS_SRC_C = $(addprefix mods/,\
|
||||
modmachine.c \
|
||||
modnetwork.c \
|
||||
modubinascii.c \
|
||||
moduos.c \
|
||||
modusocket.c \
|
||||
modussl.c \
|
||||
modutime.c \
|
||||
modwipy.c \
|
||||
modwlan.c \
|
||||
pybadc.c \
|
||||
pybpin.c \
|
||||
pybi2c.c \
|
||||
pybrtc.c \
|
||||
pybflash.c \
|
||||
pybsd.c \
|
||||
pybsleep.c \
|
||||
pybspi.c \
|
||||
pybtimer.c \
|
||||
pybuart.c \
|
||||
pybwdt.c \
|
||||
)
|
||||
|
||||
APP_CC3100_SRC_C = $(addprefix drivers/cc3100/src/,\
|
||||
device.c \
|
||||
driver.c \
|
||||
flowcont.c \
|
||||
fs.c \
|
||||
netapp.c \
|
||||
netcfg.c \
|
||||
socket.c \
|
||||
wlan.c \
|
||||
)
|
||||
|
||||
APP_SL_SRC_C = $(addprefix simplelink/,\
|
||||
oslib/osi_freertos.c \
|
||||
cc_pal.c \
|
||||
)
|
||||
|
||||
APP_TELNET_SRC_C = $(addprefix telnet/,\
|
||||
telnet.c \
|
||||
)
|
||||
|
||||
APP_UTIL_SRC_C = $(addprefix util/,\
|
||||
cryptohash.c \
|
||||
fifo.c \
|
||||
gccollect.c \
|
||||
random.c \
|
||||
socketfifo.c \
|
||||
)
|
||||
|
||||
APP_UTIL_SRC_S = $(addprefix util/,\
|
||||
gchelper.s \
|
||||
sleeprestore.s \
|
||||
)
|
||||
|
||||
APP_MAIN_SRC_C = \
|
||||
main.c \
|
||||
mptask.c \
|
||||
mpthreadport.c \
|
||||
serverstask.c \
|
||||
fatfs_port.c \
|
||||
|
||||
APP_LIB_SRC_C = $(addprefix lib/,\
|
||||
oofatfs/ff.c \
|
||||
oofatfs/option/unicode.c \
|
||||
libc/string0.c \
|
||||
mp-readline/readline.c \
|
||||
netutils/netutils.c \
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/sys_stdio_mphal.c \
|
||||
)
|
||||
|
||||
APP_STM_SRC_C = $(addprefix stmhal/,\
|
||||
bufhelper.c \
|
||||
irq.c \
|
||||
)
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(APP_FATFS_SRC_C:.c=.o) $(APP_RTOS_SRC_C:.c=.o) $(APP_FTP_SRC_C:.c=.o) $(APP_HAL_SRC_C:.c=.o) $(APP_MISC_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(APP_MODS_SRC_C:.c=.o) $(APP_CC3100_SRC_C:.c=.o) $(APP_SL_SRC_C:.c=.o) $(APP_TELNET_SRC_C:.c=.o) $(APP_UTIL_SRC_C:.c=.o) $(APP_UTIL_SRC_S:.s=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(APP_MAIN_SRC_C:.c=.o) $(APP_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o))
|
||||
OBJ += $(BUILD)/pins.o
|
||||
|
||||
# List of sources for qstr extraction
|
||||
SRC_QSTR += $(APP_MODS_SRC_C) $(APP_MISC_SRC_C) $(APP_STM_SRC_C)
|
||||
# Append any auto-generated sources that are needed by sources listed in
|
||||
# SRC_QSTR
|
||||
SRC_QSTR_AUTO_DEPS +=
|
||||
|
||||
# Add the linker script
|
||||
LINKER_SCRIPT = application.lds
|
||||
LDFLAGS += -T $(LINKER_SCRIPT)
|
||||
|
||||
# Add the application specific CFLAGS
|
||||
CFLAGS += $(APP_CPPDEFINES) $(APP_INC)
|
||||
|
||||
# Disable strict aliasing for the simplelink driver
|
||||
$(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing
|
||||
|
||||
# Check if we would like to debug the port code
|
||||
ifeq ($(BTYPE), release)
|
||||
CFLAGS += -DNDEBUG
|
||||
else
|
||||
ifeq ($(BTYPE), debug)
|
||||
CFLAGS += -DNDEBUG
|
||||
else
|
||||
$(error Invalid BTYPE specified)
|
||||
endif
|
||||
endif
|
||||
|
||||
SHELL = bash
|
||||
APP_SIGN = appsign.sh
|
||||
UPDATE_WIPY ?= tools/update-wipy.py
|
||||
WIPY_IP ?= '192.168.1.1'
|
||||
WIPY_USER ?= 'micro'
|
||||
WIPY_PWD ?= 'python'
|
||||
|
||||
all: $(BUILD)/mcuimg.bin
|
||||
|
||||
.PHONY: deploy-ota
|
||||
|
||||
deploy-ota: $(BUILD)/mcuimg.bin
|
||||
$(ECHO) "Writing $< to the board"
|
||||
$(Q)$(PYTHON) $(UPDATE_WIPY) --verify --ip $(WIPY_IP) --user $(WIPY_USER) --password $(WIPY_PWD) --file $<
|
||||
|
||||
$(BUILD)/application.axf: $(OBJ) $(LINKER_SCRIPT)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
$(BUILD)/application.bin: $(BUILD)/application.axf
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
|
||||
$(BUILD)/mcuimg.bin: $(BUILD)/application.bin
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(SHELL) $(APP_SIGN) $(BUILD)
|
||||
|
||||
MAKE_PINS = boards/make-pins.py
|
||||
BOARD_PINS = boards/$(BOARD)/pins.csv
|
||||
AF_FILE = boards/cc3200_af.csv
|
||||
PREFIX_FILE = boards/cc3200_prefix.c
|
||||
GEN_PINS_SRC = $(BUILD)/pins.c
|
||||
GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
|
||||
GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
|
||||
|
||||
# Making OBJ use an order-only dependency on the generated pins.h file
|
||||
# has the side effect of making the pins.h file before we actually compile
|
||||
# any of the objects. The normal dependency generation will deal with the
|
||||
# case when pins.h is modified. But when it doesn't exist, we don't know
|
||||
# which source files might need it.
|
||||
$(OBJ): | $(GEN_PINS_HDR)
|
||||
|
||||
# Call make-pins.py to generate both pins_gen.c and pins.h
|
||||
$(GEN_PINS_SRC) $(GEN_PINS_HDR) $(GEN_PINS_QSTR): $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) > $(GEN_PINS_SRC)
|
||||
|
||||
$(BUILD)/pins.o: $(BUILD)/pins.c
|
||||
$(call compile_c)
|
|
@ -1,233 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""Generates the pins file for the CC3200."""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import csv
|
||||
|
||||
|
||||
SUPPORTED_AFS = { 'UART': ('TX', 'RX', 'RTS', 'CTS'),
|
||||
'SPI': ('CLK', 'MOSI', 'MISO', 'CS0'),
|
||||
#'I2S': ('CLK', 'FS', 'DAT0', 'DAT1'),
|
||||
'I2C': ('SDA', 'SCL'),
|
||||
'TIM': ('PWM'),
|
||||
'SD': ('CLK', 'CMD', 'DAT0'),
|
||||
'ADC': ('CH0', 'CH1', 'CH2', 'CH3')
|
||||
}
|
||||
|
||||
def parse_port_pin(name_str):
|
||||
"""Parses a string and returns a (port, gpio_bit) tuple."""
|
||||
if len(name_str) < 3:
|
||||
raise ValueError("Expecting pin name to be at least 3 characters")
|
||||
if name_str[:2] != 'GP':
|
||||
raise ValueError("Expecting pin name to start with GP")
|
||||
if not name_str[2:].isdigit():
|
||||
raise ValueError("Expecting numeric GPIO number")
|
||||
port = int(int(name_str[2:]) / 8)
|
||||
gpio_bit = 1 << int(int(name_str[2:]) % 8)
|
||||
return (port, gpio_bit)
|
||||
|
||||
|
||||
class AF:
|
||||
"""Holds the description of an alternate function"""
|
||||
def __init__(self, name, idx, fn, unit, type):
|
||||
self.name = name
|
||||
self.idx = idx
|
||||
if self.idx > 15:
|
||||
self.idx = -1
|
||||
self.fn = fn
|
||||
self.unit = unit
|
||||
self.type = type
|
||||
|
||||
def print(self):
|
||||
print (' AF({:16s}, {:4d}, {:8s}, {:4d}, {:8s}), // {}'.format(self.name, self.idx, self.fn, self.unit, self.type, self.name))
|
||||
|
||||
|
||||
class Pin:
|
||||
"""Holds the information associated with a pin."""
|
||||
def __init__(self, name, port, gpio_bit, pin_num):
|
||||
self.name = name
|
||||
self.port = port
|
||||
self.gpio_bit = gpio_bit
|
||||
self.pin_num = pin_num
|
||||
self.board_pin = False
|
||||
self.afs = []
|
||||
|
||||
def add_af(self, af):
|
||||
self.afs.append(af)
|
||||
|
||||
def print(self):
|
||||
print('// {}'.format(self.name))
|
||||
if len(self.afs):
|
||||
print('const pin_af_t pin_{}_af[] = {{'.format(self.name))
|
||||
for af in self.afs:
|
||||
af.print()
|
||||
print('};')
|
||||
print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, pin_{}_af, {});\n'.format(
|
||||
self.name, self.name, self.port, self.gpio_bit, self.pin_num, self.name, len(self.afs)))
|
||||
else:
|
||||
print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, NULL, 0);\n'.format(
|
||||
self.name, self.name, self.port, self.gpio_bit, self.pin_num))
|
||||
|
||||
def print_header(self, hdr_file):
|
||||
hdr_file.write('extern pin_obj_t pin_{:s};\n'.format(self.name))
|
||||
|
||||
|
||||
class Pins:
|
||||
def __init__(self):
|
||||
self.board_pins = [] # list of pin objects
|
||||
|
||||
def find_pin(self, port, gpio_bit):
|
||||
for pin in self.board_pins:
|
||||
if pin.port == port and pin.gpio_bit == gpio_bit:
|
||||
return pin
|
||||
|
||||
def find_pin_by_num(self, pin_num):
|
||||
for pin in self.board_pins:
|
||||
if pin.pin_num == pin_num:
|
||||
return pin
|
||||
|
||||
def find_pin_by_name(self, name):
|
||||
for pin in self.board_pins:
|
||||
if pin.name == name:
|
||||
return pin
|
||||
|
||||
def parse_af_file(self, filename, pin_col, pinname_col, af_start_col):
|
||||
with open(filename, 'r') as csvfile:
|
||||
rows = csv.reader(csvfile)
|
||||
for row in rows:
|
||||
try:
|
||||
(port_num, gpio_bit) = parse_port_pin(row[pinname_col])
|
||||
except:
|
||||
continue
|
||||
if not row[pin_col].isdigit():
|
||||
raise ValueError("Invalid pin number {:s} in row {:s}".format(row[pin_col]), row)
|
||||
# Pin numbers must start from 0 when used with the TI API
|
||||
pin_num = int(row[pin_col]) - 1;
|
||||
pin = Pin(row[pinname_col], port_num, gpio_bit, pin_num)
|
||||
self.board_pins.append(pin)
|
||||
af_idx = 0
|
||||
for af in row[af_start_col:]:
|
||||
af_splitted = af.split('_')
|
||||
fn_name = af_splitted[0].rstrip('0123456789')
|
||||
if fn_name in SUPPORTED_AFS:
|
||||
type_name = af_splitted[1]
|
||||
if type_name in SUPPORTED_AFS[fn_name]:
|
||||
unit_idx = af_splitted[0][-1]
|
||||
pin.add_af(AF(af, af_idx, fn_name, int(unit_idx), type_name))
|
||||
af_idx += 1
|
||||
|
||||
def parse_board_file(self, filename, cpu_pin_col):
|
||||
with open(filename, 'r') as csvfile:
|
||||
rows = csv.reader(csvfile)
|
||||
for row in rows:
|
||||
# Pin numbers must start from 0 when used with the TI API
|
||||
if row[cpu_pin_col].isdigit():
|
||||
pin = self.find_pin_by_num(int(row[cpu_pin_col]) - 1)
|
||||
else:
|
||||
pin = self.find_pin_by_name(row[cpu_pin_col])
|
||||
if pin:
|
||||
pin.board_pin = True
|
||||
|
||||
def print_named(self, label, pins):
|
||||
print('')
|
||||
print('STATIC const mp_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
|
||||
for pin in pins:
|
||||
if pin.board_pin:
|
||||
print(' {{ MP_OBJ_NEW_QSTR(MP_QSTR_{:6s}), (mp_obj_t)&pin_{:6s} }},'.format(pin.name, pin.name))
|
||||
print('};')
|
||||
print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
|
||||
|
||||
def print(self):
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin.print()
|
||||
self.print_named('board', self.board_pins)
|
||||
print('')
|
||||
|
||||
def print_header(self, hdr_filename):
|
||||
with open(hdr_filename, 'wt') as hdr_file:
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin.print_header(hdr_file)
|
||||
|
||||
def print_qstr(self, qstr_filename):
|
||||
with open(qstr_filename, 'wt') as qstr_file:
|
||||
pin_qstr_set = set([])
|
||||
af_qstr_set = set([])
|
||||
for pin in self.board_pins:
|
||||
if pin.board_pin:
|
||||
pin_qstr_set |= set([pin.name])
|
||||
for af in pin.afs:
|
||||
af_qstr_set |= set([af.name])
|
||||
print('// Board pins', file=qstr_file)
|
||||
for qstr in sorted(pin_qstr_set):
|
||||
print('Q({})'.format(qstr), file=qstr_file)
|
||||
print('\n// Pin AFs', file=qstr_file)
|
||||
for qstr in sorted(af_qstr_set):
|
||||
print('Q({})'.format(qstr), file=qstr_file)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="make-pins.py",
|
||||
usage="%(prog)s [options] [command]",
|
||||
description="Generate board specific pin file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a", "--af",
|
||||
dest="af_filename",
|
||||
help="Specifies the alternate function file for the chip",
|
||||
default="cc3200_af.csv"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b", "--board",
|
||||
dest="board_filename",
|
||||
help="Specifies the board file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", "--prefix",
|
||||
dest="prefix_filename",
|
||||
help="Specifies beginning portion of generated pins file",
|
||||
default="cc3200_prefix.c"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q", "--qstr",
|
||||
dest="qstr_filename",
|
||||
help="Specifies name of generated qstr header file",
|
||||
default="build/pins_qstr.h"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r", "--hdr",
|
||||
dest="hdr_filename",
|
||||
help="Specifies name of generated pin header file",
|
||||
default="build/pins.h"
|
||||
)
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
pins = Pins()
|
||||
|
||||
print('// This file was automatically generated by make-pins.py')
|
||||
print('//')
|
||||
if args.af_filename:
|
||||
print('// --af {:s}'.format(args.af_filename))
|
||||
pins.parse_af_file(args.af_filename, 0, 1, 3)
|
||||
|
||||
if args.board_filename:
|
||||
print('// --board {:s}'.format(args.board_filename))
|
||||
pins.parse_board_file(args.board_filename, 1)
|
||||
|
||||
if args.prefix_filename:
|
||||
print('// --prefix {:s}'.format(args.prefix_filename))
|
||||
print('')
|
||||
with open(args.prefix_filename, 'r') as prefix_file:
|
||||
print(prefix_file.read())
|
||||
pins.print()
|
||||
pins.print_qstr(args.qstr_filename)
|
||||
pins.print_header(args.hdr_filename)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,132 +0,0 @@
|
|||
BUILD = bootmgr/build/$(BOARD)/$(BTYPE)
|
||||
|
||||
BOOT_INC = -Ibootmgr
|
||||
BOOT_INC += -Ibootmgr/sl
|
||||
BOOT_INC += -Ihal
|
||||
BOOT_INC += -Ihal/inc
|
||||
BOOT_INC += -I../drivers/cc3100/inc
|
||||
BOOT_INC += -Imisc
|
||||
BOOT_INC += -Imods
|
||||
BOOT_INC += -Isimplelink
|
||||
BOOT_INC += -Isimplelink/oslib
|
||||
BOOT_INC += -Iutil
|
||||
BOOT_INC += -I..
|
||||
BOOT_INC += -I.
|
||||
BOOT_INC += -I$(BUILD)
|
||||
|
||||
BOOT_CPPDEFINES = -Dgcc -DBOOTLOADER -DTARGET_IS_CC3200 -DSL_TINY
|
||||
|
||||
BOOT_HAL_SRC_C = $(addprefix hal/,\
|
||||
cpu.c \
|
||||
interrupt.c \
|
||||
gpio.c \
|
||||
pin.c \
|
||||
prcm.c \
|
||||
shamd5.c \
|
||||
spi.c \
|
||||
startup_gcc.c \
|
||||
systick.c \
|
||||
utils.c \
|
||||
)
|
||||
|
||||
BOOT_CC3100_SRC_C = $(addprefix drivers/cc3100/,\
|
||||
src/device.c \
|
||||
src/driver.c \
|
||||
src/flowcont.c \
|
||||
src/fs.c \
|
||||
src/netapp.c \
|
||||
src/netcfg.c \
|
||||
src/nonos.c \
|
||||
src/socket.c \
|
||||
src/spawn.c \
|
||||
src/wlan.c \
|
||||
)
|
||||
|
||||
BOOT_MISC_SRC_C = $(addprefix misc/,\
|
||||
antenna.c \
|
||||
mperror.c \
|
||||
)
|
||||
|
||||
BOOT_SL_SRC_C = $(addprefix simplelink/,\
|
||||
cc_pal.c \
|
||||
)
|
||||
|
||||
BOOT_UTIL_SRC_C = $(addprefix util/,\
|
||||
cryptohash.c \
|
||||
)
|
||||
|
||||
BOOT_MAIN_SRC_C = \
|
||||
bootmgr/main.c
|
||||
|
||||
BOOT_MAIN_SRC_S = \
|
||||
bootmgr/runapp.s
|
||||
|
||||
BOOT_PY_SRC_C = $(addprefix py/,\
|
||||
mpprint.c \
|
||||
)
|
||||
|
||||
BOOT_LIB_SRC_C = $(addprefix lib/,\
|
||||
libc/string0.c \
|
||||
utils/printf.c \
|
||||
)
|
||||
|
||||
OBJ = $(addprefix $(BUILD)/, $(BOOT_HAL_SRC_C:.c=.o) $(BOOT_SL_SRC_C:.c=.o) $(BOOT_CC3100_SRC_C:.c=.o) $(BOOT_UTIL_SRC_C:.c=.o) $(BOOT_MISC_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(BOOT_LIB_SRC_C:.c=.o))
|
||||
|
||||
# Add the linker script
|
||||
LINKER_SCRIPT = bootmgr/bootmgr.lds
|
||||
LDFLAGS += -T $(LINKER_SCRIPT)
|
||||
|
||||
# Add the bootloader specific CFLAGS
|
||||
CFLAGS += $(BOOT_CPPDEFINES) $(BOOT_INC)
|
||||
|
||||
# Disable strict aliasing for the simplelink driver
|
||||
$(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing
|
||||
|
||||
# Check if we would like to debug the port code
|
||||
ifeq ($(BTYPE), release)
|
||||
# Optimize everything and define the NDEBUG flag
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
else
|
||||
ifeq ($(BTYPE), debug)
|
||||
# Define the DEBUG flag
|
||||
CFLAGS += -DDEBUG=DEBUG
|
||||
# Optimize the stable sources only
|
||||
$(BUILD)/hal/%.o: CFLAGS += -Os
|
||||
$(BUILD)/misc/%.o: CFLAGS += -Os
|
||||
$(BUILD)/simplelink/%.o: CFLAGS += -Os
|
||||
$(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os
|
||||
$(BUILD)/py/%.o: CFLAGS += -Os
|
||||
$(BUILD)/stmhal/%.o: CFLAGS += -Os
|
||||
else
|
||||
$(error Invalid BTYPE specified)
|
||||
endif
|
||||
endif
|
||||
|
||||
SHELL = bash
|
||||
BOOT_GEN = bootmgr/bootgen.sh
|
||||
HEADER_BUILD = $(BUILD)/genhdr
|
||||
|
||||
all: $(BUILD)/bootloader.bin
|
||||
|
||||
$(BUILD)/bootmgr.axf: $(OBJ) $(LINKER_SCRIPT)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
$(BUILD)/bootmgr.bin: $(BUILD)/bootmgr.axf
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
|
||||
$(BUILD)/bootloader.bin: $(BUILD)/bootmgr.bin
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)$(SHELL) $(BOOT_GEN) $(BUILD)
|
||||
|
||||
# Create an empty "qstrdefs.generated.h" needed by py/mkrules.mk
|
||||
$(HEADER_BUILD)/qstrdefs.generated.h: | $(HEADER_BUILD)
|
||||
touch $@
|
||||
|
||||
# Create an empty "mpversion.h" needed by py/mkrules.mk
|
||||
$(HEADER_BUILD)/mpversion.h: | $(HEADER_BUILD)
|
||||
touch $@
|
1153
cc3200/ftp/ftp.c
1153
cc3200/ftp/ftp.c
File diff suppressed because it is too large
Load Diff
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
IMPORTS
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objstr.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "systick.h"
|
||||
#include "prcm.h"
|
||||
#include "pin.h"
|
||||
#include "mpexception.h"
|
||||
#include "telnet.h"
|
||||
#include "pybuart.h"
|
||||
#include "utils.h"
|
||||
#include "irq.h"
|
||||
#include "moduos.h"
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
#ifndef USE_FREERTOS
|
||||
static void hal_TickInit (void);
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE LOCAL DATA
|
||||
******************************************************************************/
|
||||
static volatile uint32_t HAL_tickCount;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE IMPORTED DATA
|
||||
******************************************************************************/
|
||||
extern void (* const g_pfnVectors[256])(void);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
__attribute__ ((section (".boot")))
|
||||
void HAL_SystemInit (void) {
|
||||
MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
|
||||
|
||||
// in the case of a release image, these steps are already performed by
|
||||
// the bootloader so we can skip it and gain some code space
|
||||
#ifdef DEBUG
|
||||
MAP_IntMasterEnable();
|
||||
PRCMCC3200MCUInit();
|
||||
#endif
|
||||
|
||||
#ifndef USE_FREERTOS
|
||||
hal_TickInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void HAL_SystemDeInit (void) {
|
||||
}
|
||||
|
||||
void HAL_IncrementTick(void) {
|
||||
HAL_tickCount++;
|
||||
}
|
||||
|
||||
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) {
|
||||
MP_THREAD_GIL_EXIT();
|
||||
#ifdef USE_FREERTOS
|
||||
vTaskDelay (delay / portTICK_PERIOD_MS);
|
||||
#else
|
||||
uint32_t start = HAL_tickCount;
|
||||
// wraparound of tick is taken care of by 2's complement arithmetic.
|
||||
while (HAL_tickCount - start < delay) {
|
||||
// enter sleep mode, waiting for (at least) the SysTick interrupt.
|
||||
__WFI();
|
||||
}
|
||||
#endif
|
||||
MP_THREAD_GIL_ENTER();
|
||||
} else {
|
||||
for (int ms = 0; ms < delay; ms++) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_set_interrupt_char (int c) {
|
||||
mpexception_set_interrupt_char (c);
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_str(const char *str) {
|
||||
mp_hal_stdout_tx_strn(str, strlen(str));
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn(const char *str, size_t len) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj)) {
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len);
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len);
|
||||
mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write);
|
||||
}
|
||||
}
|
||||
// and also to telnet
|
||||
telnet_tx_strn(str, len);
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn_cooked (const char *str, size_t len) {
|
||||
int32_t nslen = 0;
|
||||
const char *_str = str;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
mp_hal_stdout_tx_strn("\r\n", 2);
|
||||
_str += nslen + 1;
|
||||
nslen = 0;
|
||||
} else {
|
||||
nslen++;
|
||||
}
|
||||
}
|
||||
if (_str < str + len) {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
}
|
||||
}
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
for ( ;; ) {
|
||||
// read telnet first
|
||||
if (telnet_rx_any()) {
|
||||
return telnet_rx_char();
|
||||
} else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) {
|
||||
return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o);
|
||||
}
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1);
|
||||
mp_obj_t data = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read);
|
||||
// data len is > 0
|
||||
if (mp_obj_is_true(data)) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
return ((int *)(bufinfo.buf))[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
mp_hal_delay_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef USE_FREERTOS
|
||||
static void hal_TickInit (void) {
|
||||
HAL_tickCount = 0;
|
||||
MAP_SysTickIntRegister(HAL_IncrementTick);
|
||||
MAP_IntEnable(FAULT_SYSTICK);
|
||||
MAP_SysTickIntEnable();
|
||||
MAP_SysTickPeriodSet(HAL_FCPU_HZ / HAL_SYSTICK_PERIOD_US);
|
||||
// Force a reload of the SysTick counter register
|
||||
HWREG(NVIC_ST_CURRENT) = 0;
|
||||
MAP_SysTickEnable();
|
||||
}
|
||||
#endif
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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/builtin.h"
|
||||
|
||||
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";
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void mpexception_set_user_interrupt (int chr, void *data);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
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";
|
||||
|
||||
int user_interrupt_char = -1;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC void *user_interrupt_data = NULL;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void mpexception_init0 (void) {
|
||||
// Create an exception object for interrupting through the stdin uart
|
||||
MP_STATE_PORT(mp_const_user_interrupt) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
|
||||
mpexception_set_user_interrupt (-1, MP_STATE_PORT(mp_const_user_interrupt));
|
||||
}
|
||||
|
||||
void mpexception_set_interrupt_char (int c) {
|
||||
if (c != -1) {
|
||||
mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_const_user_interrupt));
|
||||
}
|
||||
mpexception_set_user_interrupt(c, MP_STATE_PORT(mp_const_user_interrupt));
|
||||
}
|
||||
|
||||
// Call this function to raise a pending exception during an interrupt.
|
||||
// It will try to raise the exception "softly" by setting the
|
||||
// mp_pending_exception variable hoping that the VM will notice it.
|
||||
void mpexception_nlr_jump (void *o) {
|
||||
if (MP_STATE_PORT(mp_pending_exception) == MP_OBJ_NULL) {
|
||||
MP_STATE_PORT(mp_pending_exception) = o;
|
||||
}
|
||||
}
|
||||
|
||||
void mpexception_keyboard_nlr_jump (void) {
|
||||
mpexception_nlr_jump (user_interrupt_data);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
STATIC void mpexception_set_user_interrupt (int chr, void *data) {
|
||||
user_interrupt_char = chr;
|
||||
user_interrupt_data = data;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H
|
||||
#define MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H
|
||||
|
||||
extern const char mpexception_value_invalid_arguments[];
|
||||
extern const char mpexception_num_type_invalid_arguments[];
|
||||
extern const char mpexception_uncaught[];
|
||||
|
||||
extern int user_interrupt_char;
|
||||
|
||||
|
||||
extern void mpexception_init0 (void);
|
||||
extern void mpexception_set_interrupt_char (int c);
|
||||
extern void mpexception_nlr_jump (void *o);
|
||||
extern void mpexception_keyboard_nlr_jump (void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H
|
|
@ -1,201 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
#include "mpirq.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
const mp_arg_t mp_irq_init_args[] = {
|
||||
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority
|
||||
{ MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4,
|
||||
INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mp_irq_init0 (void) {
|
||||
// initialize the callback objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0);
|
||||
}
|
||||
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) {
|
||||
mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t);
|
||||
self->base.type = &mp_irq_type;
|
||||
self->handler = handler;
|
||||
self->parent = parent;
|
||||
self->methods = (mp_irq_methods_t *)methods;
|
||||
self->isenabled = true;
|
||||
// remove it in case it was already registered
|
||||
mp_irq_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self);
|
||||
return self;
|
||||
}
|
||||
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->parent == parent) {
|
||||
return callback_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mp_irq_wake_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->isenabled) {
|
||||
callback_obj->methods->enable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mp_irq_disable_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
callback_obj->methods->disable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_irq_remove (const mp_obj_t parent) {
|
||||
mp_irq_obj_t *callback_obj;
|
||||
if ((callback_obj = mp_irq_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj);
|
||||
}
|
||||
}
|
||||
|
||||
uint mp_irq_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
return mp_irq_priorities[priority - 1];
|
||||
}
|
||||
|
||||
void mp_irq_handler (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
if (self && self->handler != mp_const_none) {
|
||||
// when executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations.
|
||||
gc_lock();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_1(self->handler, self->parent);
|
||||
nlr_pop();
|
||||
}
|
||||
else {
|
||||
// uncaught exception; disable the callback so that it doesn't run again
|
||||
self->methods->disable (self->parent);
|
||||
self->handler = mp_const_none;
|
||||
// signal the error using the heart beat led and
|
||||
// by printing a message
|
||||
printf("Uncaught exception in callback handler\n");
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
mperror_signal_error();
|
||||
}
|
||||
gc_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_irq_obj_t *self = pos_args[0];
|
||||
// this is a bit of a hack, but it let us reuse the callback_create method from our parent
|
||||
((mp_obj_t *)pos_args)[0] = self->parent;
|
||||
self->methods->init (n_args, pos_args, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init);
|
||||
|
||||
STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->enable(self->parent);
|
||||
self->isenabled = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable);
|
||||
|
||||
STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->disable(self->parent);
|
||||
self->isenabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable);
|
||||
|
||||
STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
return mp_obj_new_int(self->methods->flags(self->parent));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);
|
||||
|
||||
STATIC mp_obj_t mp_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
mp_irq_handler (self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_irq_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t mp_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_irq,
|
||||
.call = mp_irq_call,
|
||||
.locals_dict = (mp_obj_t)&mp_irq_locals_dict,
|
||||
};
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H
|
||||
#define MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define mp_irq_INIT_NUM_ARGS 4
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef void (*mp_irq_void_method_t) (mp_obj_t self);
|
||||
typedef int (*mp_irq_int_method_t) (mp_obj_t self);
|
||||
|
||||
typedef struct {
|
||||
mp_irq_init_t init;
|
||||
mp_irq_void_method_t enable;
|
||||
mp_irq_void_method_t disable;
|
||||
mp_irq_int_method_t flags;
|
||||
} mp_irq_methods_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t parent;
|
||||
mp_obj_t handler;
|
||||
mp_irq_methods_t *methods;
|
||||
bool isenabled;
|
||||
} mp_irq_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
extern const mp_arg_t mp_irq_init_args[];
|
||||
extern const mp_obj_type_t mp_irq_type;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mp_irq_init0 (void);
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods);
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent);
|
||||
void mp_irq_wake_all (void);
|
||||
void mp_irq_disable_all (void);
|
||||
void mp_irq_remove (const mp_obj_t parent);
|
||||
void mp_irq_handler (mp_obj_t self_in);
|
||||
uint mp_irq_translate_priority (uint priority);
|
||||
|
||||
#endif // MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "irq.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_uart.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "moduos.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "portable.h"
|
||||
#include "task.h"
|
||||
#include "mpexception.h"
|
||||
#include "random.h"
|
||||
#include "pybadc.h"
|
||||
#include "pybi2c.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybwdt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybspi.h"
|
||||
#include "pybtimer.h"
|
||||
#include "utils.h"
|
||||
#include "gccollect.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
extern OsiTaskHandle mpTaskHandle;
|
||||
extern OsiTaskHandle svTaskHandle;
|
||||
extern OsiTaskHandle xSimpleLinkSpawnTaskHndl;
|
||||
#endif
|
||||
|
||||
|
||||
/// \module machine - functions related to the SoC
|
||||
///
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings;
|
||||
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
// disable wlan
|
||||
wlan_stop(SL_STOP_TIMEOUT_LONG);
|
||||
// reset the cpu and it's peripherals
|
||||
MAP_PRCMMCUReset(true);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
||||
#ifdef DEBUG
|
||||
STATIC mp_obj_t machine_info(uint n_args, const mp_obj_t *args) {
|
||||
// FreeRTOS info
|
||||
{
|
||||
printf("---------------------------------------------\n");
|
||||
printf("FreeRTOS\n");
|
||||
printf("---------------------------------------------\n");
|
||||
printf("Total heap: %u\n", configTOTAL_HEAP_SIZE);
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
printf("MpTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)mpTaskHandle));
|
||||
printf("ServersTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)svTaskHandle));
|
||||
printf("SlTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xSimpleLinkSpawnTaskHndl));
|
||||
printf("IdleTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xTaskGetIdleTaskHandle()));
|
||||
|
||||
uint32_t *pstack = (uint32_t *)&_stack;
|
||||
while (*pstack == 0x55555555) {
|
||||
pstack++;
|
||||
}
|
||||
printf("MAIN min free stack: %u\n", pstack - ((uint32_t *)&_stack));
|
||||
printf("---------------------------------------------\n");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t machine_freq(void) {
|
||||
return mp_obj_new_int(HAL_FCPU_HZ);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
|
||||
|
||||
STATIC mp_obj_t machine_unique_id(void) {
|
||||
uint8_t mac[SL_BSSID_LENGTH];
|
||||
wlan_get_mac (mac);
|
||||
return mp_obj_new_bytes(mac, SL_BSSID_LENGTH);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
STATIC mp_obj_t machine_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
MP_STATE_PORT(machine_config_main) = main;
|
||||
} else {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(machine_main_obj, machine_main);
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
__WFI();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC mp_obj_t machine_sleep (void) {
|
||||
pyb_sleep_sleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
|
||||
|
||||
STATIC mp_obj_t machine_deepsleep (void) {
|
||||
pyb_sleep_deepsleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
|
||||
|
||||
STATIC mp_obj_t machine_reset_cause (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_reset_cause());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC mp_obj_t machine_wake_reason (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_wake_reason());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason);
|
||||
|
||||
STATIC const mp_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_umachine) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&machine_reset_obj },
|
||||
#ifdef DEBUG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&machine_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&machine_unique_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&machine_main_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&machine_rng_get_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&machine_idle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&machine_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deepsleep), (mp_obj_t)&machine_deepsleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&machine_reset_cause_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&machine_wake_reason_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, // legacy constant
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWRON_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t machine_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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/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"
|
||||
#include "serverstask.h"
|
||||
#include "simplelink.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
} network_server_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC network_server_obj_t network_server_obj;
|
||||
STATIC const mp_obj_type_t network_server_type;
|
||||
|
||||
/// \module network - network configuration
|
||||
///
|
||||
/// This module provides network drivers and server configuration.
|
||||
|
||||
void mod_network_init0(void) {
|
||||
}
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC mp_obj_t network_server_init_helper(mp_obj_t self, const mp_arg_val_t *args) {
|
||||
const char *user = SERVERS_DEF_USER;
|
||||
const char *pass = SERVERS_DEF_PASS;
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *login;
|
||||
mp_obj_get_array_fixed_n(args[0].u_obj, 2, &login);
|
||||
user = mp_obj_str_get_str(login[0]);
|
||||
pass = mp_obj_str_get_str(login[1]);
|
||||
}
|
||||
|
||||
uint32_t timeout = SERVERS_DEF_TIMEOUT_MS / 1000;
|
||||
if (args[1].u_obj != MP_OBJ_NULL) {
|
||||
timeout = mp_obj_get_int(args[1].u_obj);
|
||||
}
|
||||
|
||||
// configure the new login
|
||||
servers_set_login ((char *)user, (char *)pass);
|
||||
|
||||
// configure the timeout
|
||||
servers_set_timeout(timeout * 1000);
|
||||
|
||||
// start the servers
|
||||
servers_start();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t network_server_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_login, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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(network_server_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), network_server_args, 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_OSError(MP_ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
// setup the object and initialize it
|
||||
network_server_obj_t *self = &network_server_obj;
|
||||
self->base.type = &network_server_type;
|
||||
network_server_init_helper(self, &args[1]);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t network_server_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(network_server_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &network_server_args[1], args);
|
||||
return network_server_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_server_init_obj, 1, network_server_init);
|
||||
|
||||
// timeout value given in seconds
|
||||
STATIC mp_obj_t network_server_timeout(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 1) {
|
||||
uint32_t timeout = mp_obj_get_int(args[1]);
|
||||
servers_set_timeout(timeout * 1000);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
// get
|
||||
return mp_obj_new_int(servers_get_timeout() / 1000);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 1, 2, network_server_timeout);
|
||||
|
||||
STATIC mp_obj_t network_server_running(mp_obj_t self_in) {
|
||||
// get
|
||||
return mp_obj_new_bool(servers_are_enabled());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_running_obj, network_server_running);
|
||||
|
||||
STATIC mp_obj_t network_server_deinit(mp_obj_t self_in) {
|
||||
// simply stop the servers
|
||||
servers_stop();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_deinit_obj, network_server_deinit);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&mod_network_nic_type_wlan },
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Server), (mp_obj_t)&network_server_type },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_network = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC const mp_map_elem_t network_server_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&network_server_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&network_server_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&network_server_timeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isrunning), (mp_obj_t)&network_server_running_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t network_server_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Server,
|
||||
.make_new = network_server_make_new,
|
||||
.locals_dict = (mp_obj_t)&network_server_locals_dict,
|
||||
};
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
* 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/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "extmod/modubinascii.h"
|
||||
#include "modubinascii.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "inc/hw_dthe.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "crc.h"
|
||||
#include "cryptohash.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_binascii_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hexlify), (mp_obj_t)&mod_binascii_hexlify_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_a2b_base64), (mp_obj_t)&mod_binascii_a2b_base64_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_b2a_base64), (mp_obj_t)&mod_binascii_b2a_base64_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ubinascii = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_binascii_globals,
|
||||
};
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
* 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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "inc/hw_shamd5.h"
|
||||
#include "inc/hw_dthe.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "shamd5.h"
|
||||
#include "cryptohash.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _mp_obj_hash_t {
|
||||
mp_obj_base_t base;
|
||||
uint8_t *buffer;
|
||||
uint32_t b_size;
|
||||
uint32_t c_size;
|
||||
uint8_t algo;
|
||||
uint8_t h_size;
|
||||
bool fixedlen;
|
||||
bool digested;
|
||||
uint8_t hash[32];
|
||||
} mp_obj_hash_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest);
|
||||
STATIC mp_obj_t hash_read (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) {
|
||||
mp_obj_hash_t *self = self_in;
|
||||
mp_buffer_info_t bufinfo;
|
||||
|
||||
if (data) {
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
}
|
||||
|
||||
if (digest) {
|
||||
CRYPTOHASH_SHAMD5Start (self->algo, self->b_size);
|
||||
}
|
||||
|
||||
if (self->c_size < self->b_size || !data || !self->fixedlen) {
|
||||
if (digest || self->fixedlen) {
|
||||
// no data means we want to process our internal buffer
|
||||
CRYPTOHASH_SHAMD5Update (data ? bufinfo.buf : self->buffer, data ? bufinfo.len : self->b_size);
|
||||
self->c_size += data ? bufinfo.len : 0;
|
||||
} else {
|
||||
self->buffer = m_renew(byte, self->buffer, self->b_size, self->b_size + bufinfo.len);
|
||||
mp_seq_copy((byte*)self->buffer + self->b_size, bufinfo.buf, bufinfo.len, byte);
|
||||
self->b_size += bufinfo.len;
|
||||
self->digested = false;
|
||||
}
|
||||
} else {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hash_read (mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = self_in;
|
||||
|
||||
if (!self->fixedlen) {
|
||||
if (!self->digested) {
|
||||
hash_update_internal(self, MP_OBJ_NULL, true);
|
||||
}
|
||||
} else if (self->c_size < self->b_size) {
|
||||
// it's a fixed len block which is still incomplete
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
if (!self->digested) {
|
||||
CRYPTOHASH_SHAMD5Read ((uint8_t *)self->hash);
|
||||
self->digested = true;
|
||||
}
|
||||
return mp_obj_new_bytes(self->hash, self->h_size);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
/// \classmethod \constructor([data[, block_size]])
|
||||
/// initial data must be given if block_size wants to be passed
|
||||
STATIC mp_obj_t hash_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 2, false);
|
||||
mp_obj_hash_t *self = m_new0(mp_obj_hash_t, 1);
|
||||
self->base.type = type_in;
|
||||
if (self->base.type->name == MP_QSTR_sha1) {
|
||||
self->algo = SHAMD5_ALGO_SHA1;
|
||||
self->h_size = 20;
|
||||
} else /* if (self->base.type->name == MP_QSTR_sha256) */ {
|
||||
self->algo = SHAMD5_ALGO_SHA256;
|
||||
self->h_size = 32;
|
||||
} /* else {
|
||||
self->algo = SHAMD5_ALGO_MD5;
|
||||
self->h_size = 32;
|
||||
} */
|
||||
|
||||
if (n_args) {
|
||||
// CPython extension to avoid buffering the data before digesting it
|
||||
// Note: care must be taken to provide all intermediate blocks as multiple
|
||||
// of four bytes, otherwise the resulting hash will be incorrect.
|
||||
// the final block can be of any length
|
||||
if (n_args > 1) {
|
||||
// block size given, we will feed the data directly into the hash engine
|
||||
self->fixedlen = true;
|
||||
self->b_size = mp_obj_get_int(args[1]);
|
||||
hash_update_internal(self, args[0], true);
|
||||
} else {
|
||||
hash_update_internal(self, args[0], false);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = self_in;
|
||||
hash_update_internal(self, arg, false);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
|
||||
|
||||
STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
|
||||
return hash_read(self_in);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
|
||||
|
||||
STATIC const mp_map_elem_t hash_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_update), (mp_obj_t) &hash_update_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_digest), (mp_obj_t) &hash_digest_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table);
|
||||
|
||||
//STATIC const mp_obj_type_t md5_type = {
|
||||
// { &mp_type_type },
|
||||
// .name = MP_QSTR_md5,
|
||||
// .make_new = hash_make_new,
|
||||
// .locals_dict = (mp_obj_t)&hash_locals_dict,
|
||||
//};
|
||||
|
||||
STATIC const mp_obj_type_t sha1_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_sha1,
|
||||
.make_new = hash_make_new,
|
||||
.locals_dict = (mp_obj_t)&hash_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t sha256_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_sha256,
|
||||
.make_new = hash_make_new,
|
||||
.locals_dict = (mp_obj_t)&hash_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_hashlib_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib) },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_md5), (mp_obj_t)&md5_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sha1), (mp_obj_t)&sha1_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sha256), (mp_obj_t)&sha256_type },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uhashlib = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
|
||||
};
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/nlr.h"
|
||||
#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 "sflash_diskio.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_fat.h"
|
||||
#include "random.h"
|
||||
#include "mpexception.h"
|
||||
#include "version.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybuart.h"
|
||||
|
||||
/// \module os - basic "operating system" services
|
||||
///
|
||||
/// The `os` module contains functions for filesystem access and `urandom`.
|
||||
///
|
||||
/// The filesystem has `/` as the root directory, and the available physical
|
||||
/// drives are accessible from here. They are currently:
|
||||
///
|
||||
/// /flash -- the serial flash filesystem
|
||||
///
|
||||
/// On boot up, the current directory is `/flash`.
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC os_term_dup_obj_t os_term_dup_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
//
|
||||
|
||||
STATIC const qstr os_uname_info_fields[] = {
|
||||
MP_QSTR_sysname, MP_QSTR_nodename,
|
||||
MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
|
||||
};
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, WIPY_SW_VERSION_NUMBER);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
|
||||
STATIC MP_DEFINE_ATTRTUPLE(
|
||||
os_uname_info_obj,
|
||||
os_uname_info_fields,
|
||||
5,
|
||||
(mp_obj_t)&os_uname_info_sysname_obj,
|
||||
(mp_obj_t)&os_uname_info_nodename_obj,
|
||||
(mp_obj_t)&os_uname_info_release_obj,
|
||||
(mp_obj_t)&os_uname_info_version_obj,
|
||||
(mp_obj_t)&os_uname_info_machine_obj
|
||||
);
|
||||
|
||||
STATIC mp_obj_t os_uname(void) {
|
||||
return (mp_obj_t)&os_uname_info_obj;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
|
||||
STATIC mp_obj_t os_sync(void) {
|
||||
sflash_disk_flush();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
|
||||
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
vstr.buf[i] = rng_get();
|
||||
}
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
|
||||
|
||||
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) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return MP_STATE_PORT(os_term_dup_obj)->stream_o;
|
||||
}
|
||||
} else {
|
||||
mp_obj_t stream_o = args[0];
|
||||
if (stream_o == mp_const_none) {
|
||||
MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) {
|
||||
// must be a stream-like object providing at least read and write methods
|
||||
mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
|
||||
mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
|
||||
}
|
||||
os_term_dup_obj.stream_o = stream_o;
|
||||
MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
|
||||
|
||||
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)&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
|
||||
// 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 },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uos = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&os_module_globals,
|
||||
};
|
|
@ -1,824 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/netutils/netutils.h"
|
||||
#include "modnetwork.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];
|
||||
|
||||
#define SOCKET_TIMEOUT_QUANTA_MS (20)
|
||||
|
||||
STATIC int convert_sl_errno(int sl_errno) {
|
||||
return -sl_errno;
|
||||
}
|
||||
|
||||
// This function is left as non-static so it's not inlined.
|
||||
int check_timedout(mod_network_socket_obj_t *s, int ret, uint32_t *timeout_ms, int *_errno) {
|
||||
if (*timeout_ms == 0 || ret != SL_EAGAIN) {
|
||||
if (s->sock_base.timeout_ms > 0 && ret == SL_EAGAIN) {
|
||||
*_errno = MP_ETIMEDOUT;
|
||||
} else {
|
||||
*_errno = convert_sl_errno(ret);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
mp_hal_delay_ms(SOCKET_TIMEOUT_QUANTA_MS);
|
||||
if (*timeout_ms < SOCKET_TIMEOUT_QUANTA_MS) {
|
||||
*timeout_ms = 0;
|
||||
} else {
|
||||
*timeout_ms -= SOCKET_TIMEOUT_QUANTA_MS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
for (;;) {
|
||||
sd = sl_Accept(s->sock_base.sd, &addr, &addr_len);
|
||||
if (sd >= 0) {
|
||||
// save the socket descriptor
|
||||
s2->sock_base.sd = sd;
|
||||
// return ip and port
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return 0;
|
||||
}
|
||||
if (check_timedout(s, sd, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
|
||||
MAKE_SOCKADDR(addr, ip, port)
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
|
||||
// For a non-blocking connect the CC3100 will return SL_EALREADY while the
|
||||
// connection is in progress.
|
||||
|
||||
for (;;) {
|
||||
int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr));
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if we are in non-blocking mode and the connection is in progress
|
||||
if (s->sock_base.timeout_ms == 0 && ret == SL_EALREADY) {
|
||||
// To match BSD we return EINPROGRESS here
|
||||
*_errno = MP_EINPROGRESS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We are in blocking mode, so if the connection isn't in progress then error out
|
||||
if (ret != SL_EALREADY) {
|
||||
*_errno = convert_sl_errno(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (check_timedout(s, SL_EAGAIN, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
for (;;) {
|
||||
int ret = sl_Send(s->sock_base.sd, (const void *)buf, len, 0);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
if (check_timedout(s, ret, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
for (;;) {
|
||||
int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
if (check_timedout(s, ret, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
for (;;) {
|
||||
int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr));
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
if (check_timedout(s, ret, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t timeout_ms = s->sock_base.timeout_ms;
|
||||
for (;;) {
|
||||
int ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len);
|
||||
if (ret >= 0) {
|
||||
UNPACK_SOCKADDR(addr, ip, *port);
|
||||
return ret;
|
||||
}
|
||||
if (check_timedout(s, ret, &timeout_ms, _errno)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
SlSockNonblocking_t option;
|
||||
if (timeout_s == 0 || timeout_s == -1) {
|
||||
if (timeout_s == 0) {
|
||||
// set non-blocking mode
|
||||
option.NonblockingEnabled = 1;
|
||||
} else {
|
||||
// set blocking mode
|
||||
option.NonblockingEnabled = 0;
|
||||
}
|
||||
timeout_s = 0;
|
||||
} else {
|
||||
// synthesize timeout via non-blocking behaviour with a loop
|
||||
option.NonblockingEnabled = 1;
|
||||
}
|
||||
|
||||
int ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option));
|
||||
if (ret != 0) {
|
||||
*_errno = convert_sl_errno(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->sock_base.timeout_ms = timeout_s * 1000;
|
||||
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
|
||||
******************************************************************************/
|
||||
#define MOD_NETWORK_MAX_SOCKETS 10
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int16_t sd;
|
||||
bool user;
|
||||
} modusocket_sock_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t socket_type;
|
||||
STATIC OsiLockObj_t modusocket_LockObj;
|
||||
STATIC modusocket_sock_t modusocket_sockets[MOD_NETWORK_MAX_SOCKETS] = {{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1},
|
||||
{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void modusocket_pre_init (void) {
|
||||
// create the wlan lock
|
||||
ASSERT(OSI_OK == sl_LockObjCreate(&modusocket_LockObj, "SockLock"));
|
||||
sl_LockObjUnlock (&modusocket_LockObj);
|
||||
}
|
||||
|
||||
void modusocket_socket_add (int16_t sd, bool user) {
|
||||
sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
|
||||
for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
|
||||
if (modusocket_sockets[i].sd < 0) {
|
||||
modusocket_sockets[i].sd = sd;
|
||||
modusocket_sockets[i].user = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sl_LockObjUnlock (&modusocket_LockObj);
|
||||
}
|
||||
|
||||
void modusocket_socket_delete (int16_t sd) {
|
||||
sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
|
||||
for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
|
||||
if (modusocket_sockets[i].sd == sd) {
|
||||
modusocket_sockets[i].sd = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sl_LockObjUnlock (&modusocket_LockObj);
|
||||
}
|
||||
|
||||
void modusocket_enter_sleep (void) {
|
||||
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) {
|
||||
SL_FD_SET(sd, &socketset);
|
||||
maxfd = (maxfd > sd) ? maxfd : sd;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxfd > 0) {
|
||||
// wait for any of the sockets to become ready...
|
||||
sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void modusocket_close_all_user_sockets (void) {
|
||||
sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
|
||||
for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
|
||||
if (modusocket_sockets[i].sd >= 0 && modusocket_sockets[i].user) {
|
||||
sl_Close(modusocket_sockets[i].sd);
|
||||
modusocket_sockets[i].sd = -1;
|
||||
}
|
||||
}
|
||||
sl_LockObjUnlock (&modusocket_LockObj);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// socket class
|
||||
|
||||
// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None)
|
||||
STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 4, false);
|
||||
|
||||
// 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 = 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.timeout_ms = 0;
|
||||
s->sock_base.cert_req = false;
|
||||
|
||||
if (n_args > 0) {
|
||||
s->sock_base.u_param.domain = mp_obj_get_int(args[0]);
|
||||
if (n_args > 1) {
|
||||
s->sock_base.u_param.type = mp_obj_get_int(args[1]);
|
||||
if (n_args > 2) {
|
||||
s->sock_base.u_param.proto = mp_obj_get_int(args[2]);
|
||||
if (n_args > 3) {
|
||||
s->sock_base.u_param.fileno = mp_obj_get_int(args[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the socket
|
||||
int _errno;
|
||||
if (wlan_socket_socket(s, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
// add the socket to the list
|
||||
modusocket_socket_add(s->sock_base.sd, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
// method socket.close()
|
||||
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
wlan_socket_close(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
|
||||
|
||||
// method socket.bind(address)
|
||||
STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
|
||||
// get address
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// call the NIC to bind the socket
|
||||
int _errno = 0;
|
||||
if (wlan_socket_bind(self, ip, port, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
|
||||
|
||||
// method socket.listen([backlog])
|
||||
STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
|
||||
int32_t backlog = 0;
|
||||
if (n_args > 1) {
|
||||
backlog = mp_obj_get_int(args[1]);
|
||||
backlog = (backlog < 0) ? 0 : backlog;
|
||||
}
|
||||
|
||||
int _errno;
|
||||
if (wlan_socket_listen(self, backlog, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
|
||||
|
||||
// method socket.accept()
|
||||
STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
|
||||
// create new socket object
|
||||
mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
|
||||
// the new socket inherits all properties from its parent
|
||||
memcpy (socket2, self, sizeof(mod_network_socket_obj_t));
|
||||
|
||||
// accept the incoming connection
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port = 0;
|
||||
int _errno = 0;
|
||||
if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
// add the socket to the list
|
||||
modusocket_socket_add(socket2->sock_base.sd, true);
|
||||
|
||||
// make the return value
|
||||
mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
|
||||
client->items[0] = socket2;
|
||||
client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
|
||||
return client;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
|
||||
|
||||
// method socket.connect(address)
|
||||
STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
|
||||
// get address
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// connect the socket
|
||||
int _errno;
|
||||
if (wlan_socket_connect(self, ip, port, &_errno) != 0) {
|
||||
if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) {
|
||||
return mp_const_none;
|
||||
}
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
|
||||
|
||||
// method socket.send(bytes)
|
||||
STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
int _errno;
|
||||
mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno);
|
||||
if (ret < 0) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
return mp_obj_new_int_from_uint(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
|
||||
|
||||
// method socket.recv(bufsize)
|
||||
STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_int_t len = mp_obj_get_int(len_in);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, len);
|
||||
int _errno;
|
||||
mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
|
||||
if (ret < 0) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
if (ret == 0) {
|
||||
return mp_const_empty_bytes;
|
||||
}
|
||||
vstr.len = ret;
|
||||
vstr.buf[vstr.len] = '\0';
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
|
||||
|
||||
// method socket.sendto(bytes, address)
|
||||
STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
|
||||
// get the data
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// get address
|
||||
uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
|
||||
mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
|
||||
|
||||
// call the nic to sendto
|
||||
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);
|
||||
}
|
||||
return mp_obj_new_int(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
|
||||
|
||||
// method socket.recvfrom(bufsize)
|
||||
STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, mp_obj_get_int(len_in));
|
||||
byte ip[4];
|
||||
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) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
mp_obj_t tuple[2];
|
||||
if (ret == 0) {
|
||||
tuple[0] = mp_const_empty_bytes;
|
||||
} else {
|
||||
vstr.len = ret;
|
||||
vstr.buf[vstr.len] = '\0';
|
||||
tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
|
||||
|
||||
// method socket.setsockopt(level, optname, value)
|
||||
STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
|
||||
mp_int_t level = mp_obj_get_int(args[1]);
|
||||
mp_int_t opt = mp_obj_get_int(args[2]);
|
||||
|
||||
const void *optval;
|
||||
mp_uint_t optlen;
|
||||
mp_int_t val;
|
||||
if (mp_obj_is_integer(args[3])) {
|
||||
val = mp_obj_get_int_truncated(args[3]);
|
||||
optval = &val;
|
||||
optlen = sizeof(val);
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
|
||||
optval = bufinfo.buf;
|
||||
optlen = bufinfo.len;
|
||||
}
|
||||
|
||||
int _errno;
|
||||
if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
|
||||
mp_raise_OSError(-_errno);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
|
||||
|
||||
// method socket.settimeout(value)
|
||||
// timeout=0 means non-blocking
|
||||
// timeout=None means blocking
|
||||
// otherwise, timeout is in seconds
|
||||
STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_uint_t timeout;
|
||||
if (timeout_in == mp_const_none) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
timeout = mp_obj_get_int(timeout_in);
|
||||
}
|
||||
int _errno = 0;
|
||||
if (wlan_socket_settimeout(self, timeout, &_errno) != 0) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
|
||||
|
||||
// method socket.setblocking(flag)
|
||||
STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
|
||||
if (mp_obj_is_true(blocking)) {
|
||||
return socket_settimeout(self_in, mp_const_none);
|
||||
} else {
|
||||
return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
|
||||
|
||||
STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
return args[0];
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
|
||||
|
||||
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&socket_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj },
|
||||
|
||||
// stream methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read1_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
|
||||
};
|
||||
|
||||
MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
|
||||
|
||||
STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_int_t ret = wlan_socket_recv(self, buf, size, errcode);
|
||||
if (ret < 0) {
|
||||
// we need to ignore the socket closed error here because a read() without params
|
||||
// only returns when the socket is closed by the other end
|
||||
if (*errcode != -SL_ESECCLOSED) {
|
||||
ret = MP_STREAM_ERROR;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
mp_int_t ret = wlan_socket_send(self, buf, size, errcode);
|
||||
if (ret < 0) {
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
return wlan_socket_ioctl(self, request, arg, errcode);
|
||||
}
|
||||
|
||||
const mp_stream_p_t socket_stream_p = {
|
||||
.read = socket_read,
|
||||
.write = socket_write,
|
||||
.ioctl = socket_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t socket_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_socket,
|
||||
.make_new = socket_make_new,
|
||||
.protocol = &socket_stream_p,
|
||||
.locals_dict = (mp_obj_t)&socket_locals_dict,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// usocket module
|
||||
|
||||
// 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) {
|
||||
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, 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(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);
|
||||
return mp_obj_new_list(1, (mp_obj_t*)&tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) },
|
||||
|
||||
{ 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 constants
|
||||
{ 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(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(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);
|
||||
|
||||
const mp_obj_module_t mp_module_usocket = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
|
||||
};
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "simplelink.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modusocket.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define SSL_CERT_NONE (0)
|
||||
#define SSL_CERT_OPTIONAL (1)
|
||||
#define SSL_CERT_REQUIRED (2)
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _mp_obj_ssl_socket_t {
|
||||
mp_obj_base_t base;
|
||||
mod_network_socket_base_t sock_base;
|
||||
mp_obj_t o_sock;
|
||||
} mp_obj_ssl_socket_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t ssl_socket_type;
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings; SSL class
|
||||
|
||||
// ssl sockets inherit from normal socket, so we take its
|
||||
// locals and stream methods
|
||||
STATIC const mp_obj_type_t ssl_socket_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ussl,
|
||||
.getiter = NULL,
|
||||
.iternext = NULL,
|
||||
.protocol = &socket_stream_p,
|
||||
.locals_dict = (mp_obj_t)&socket_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_keyfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} },
|
||||
{ MP_QSTR_ssl_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SO_SEC_METHOD_TLSV1} },
|
||||
{ MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// parse arguments
|
||||
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);
|
||||
|
||||
// chech if ca validation is required
|
||||
if (args[4].u_int != SSL_CERT_NONE && args[5].u_obj == mp_const_none) {
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
// retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
|
||||
const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
|
||||
const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
|
||||
const char *cafile = (args[6].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
NULL : &(mp_obj_str_get_str(args[6].u_obj)[6]);
|
||||
|
||||
// server side requires both certfile and keyfile
|
||||
if (args[3].u_bool && (!keyfile || !certfile)) {
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
_i16 _errno;
|
||||
_i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
|
||||
|
||||
// set the requested SSL method
|
||||
_u8 method = args[5].u_int;
|
||||
if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (keyfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, keyfile, strlen(keyfile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (certfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, certfile, strlen(certfile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
if (cafile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, cafile, strlen(cafile))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
|
||||
// create the ssl socket
|
||||
mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
|
||||
// ssl sockets inherit all properties from the original socket
|
||||
memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
|
||||
ssl_sock->base.type = &ssl_socket_type;
|
||||
ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
|
||||
ssl_sock->o_sock = args[0].u_obj;
|
||||
|
||||
return ssl_sock;
|
||||
|
||||
socket_error:
|
||||
mp_raise_OSError(_errno);
|
||||
|
||||
arg_error:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wrap_socket), (mp_obj_t)&mod_ssl_wrap_socket_obj },
|
||||
|
||||
// class exceptions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SSLError), (mp_obj_t)&mp_type_OSError },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_NONE), MP_OBJ_NEW_SMALL_INT(SSL_CERT_NONE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_OPTIONAL), MP_OBJ_NEW_SMALL_INT(SSL_CERT_OPTIONAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_REQUIRED), MP_OBJ_NEW_SMALL_INT(SSL_CERT_REQUIRED) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_SSLv3), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_SSLV3) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1_1), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1_1) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1_2), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1_2) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ussl_globals, mp_module_ussl_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ussl = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ussl_globals,
|
||||
};
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/smallint.h"
|
||||
#include "py/mphal.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"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "systick.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpexception.h"
|
||||
#include "utils.h"
|
||||
|
||||
/// \module time - time related functions
|
||||
///
|
||||
/// The `time` module provides functions for getting the current time and date,
|
||||
/// and for sleeping.
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
/// \function localtime([secs])
|
||||
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
/// If secs is not provided or None, then the current time from the RTC is used.
|
||||
/// year includes the century (for example 2015)
|
||||
/// month is 1-12
|
||||
/// mday is 1-31
|
||||
/// hour is 0-23
|
||||
/// minute is 0-59
|
||||
/// second is 0-59
|
||||
/// weekday is 0-6 for Mon-Sun.
|
||||
/// yearday is 1-366
|
||||
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
timeutils_struct_time_t tm;
|
||||
|
||||
// get the seconds from the RTC
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
mp_obj_new_int(tm.tm_mday),
|
||||
mp_obj_new_int(tm.tm_hour),
|
||||
mp_obj_new_int(tm.tm_min),
|
||||
mp_obj_new_int(tm.tm_sec),
|
||||
mp_obj_new_int(tm.tm_wday),
|
||||
mp_obj_new_int(tm.tm_yday)
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
mp_int_t seconds = mp_obj_get_int(args[0]);
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
tuple[0] = mp_obj_new_int(tm.tm_year),
|
||||
tuple[1] = mp_obj_new_int(tm.tm_mon),
|
||||
tuple[2] = mp_obj_new_int(tm.tm_mday),
|
||||
tuple[3] = mp_obj_new_int(tm.tm_hour),
|
||||
tuple[4] = mp_obj_new_int(tm.tm_min),
|
||||
tuple[5] = mp_obj_new_int(tm.tm_sec),
|
||||
tuple[6] = mp_obj_new_int(tm.tm_wday),
|
||||
tuple[7] = mp_obj_new_int(tm.tm_yday),
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
|
||||
|
||||
STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
size_t len;
|
||||
mp_obj_t *elem;
|
||||
|
||||
mp_obj_get_array(tuple, &len, &elem);
|
||||
|
||||
// localtime generates a tuple of len 8. CPython uses 9, so we accept both.
|
||||
if (len < 8 || len > 9) {
|
||||
mp_raise_TypeError(mpexception_num_type_invalid_arguments);
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]),
|
||||
mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
|
||||
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
return mp_obj_new_int(pyb_rtc_get_seconds());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
|
||||
|
||||
STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
|
||||
int32_t sleep_s = mp_obj_get_int(seconds_o);
|
||||
if (sleep_s > 0) {
|
||||
mp_hal_delay_ms(sleep_s * 1000);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
|
||||
|
||||
STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
|
||||
{ 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)&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);
|
||||
|
||||
const mp_obj_module_t mp_module_utime = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&time_module_globals,
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC mp_obj_t mod_wipy_heartbeat (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args) {
|
||||
mperror_enable_heartbeat (mp_obj_is_true(args[0]));
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return mp_obj_new_bool(mperror_is_heartbeat_enabled());
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_wipy_heartbeat_obj, 0, 1, mod_wipy_heartbeat);
|
||||
|
||||
STATIC const mp_map_elem_t wipy_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_wipy) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat), (mp_obj_t)&mod_wipy_heartbeat_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
|
||||
|
||||
const mp_obj_module_t wipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&wipy_module_globals,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -1,312 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/nlr.h"
|
||||
#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"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "pin.h"
|
||||
#include "gpio.h"
|
||||
#include "prcm.h"
|
||||
#include "adc.h"
|
||||
#include "pybadc.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pins.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYB_ADC_NUM_CHANNELS 4
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bool enabled;
|
||||
} pyb_adc_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
pin_obj_t *pin;
|
||||
byte channel;
|
||||
byte id;
|
||||
bool enabled;
|
||||
} pyb_adc_channel_obj_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_adc_channel_obj_t pyb_adc_channel_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 0, .enabled = false},
|
||||
{.pin = &pin_GP3, .channel = ADC_CH_1, .id = 1, .enabled = false},
|
||||
{.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2, .enabled = false},
|
||||
{.pin = &pin_GP5, .channel = ADC_CH_3, .id = 3, .enabled = false} };
|
||||
STATIC pyb_adc_obj_t pyb_adc_obj = {.enabled = false};
|
||||
|
||||
STATIC const mp_obj_type_t pyb_adc_channel_type;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_adc_init (pyb_adc_obj_t *self) {
|
||||
// enable and configure the timer
|
||||
MAP_ADCTimerConfig(ADC_BASE, (1 << 17) - 1);
|
||||
MAP_ADCTimerEnable(ADC_BASE);
|
||||
// enable the ADC peripheral
|
||||
MAP_ADCEnable(ADC_BASE);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_adc_check_init(void) {
|
||||
// not initialized
|
||||
if (!pyb_adc_obj.enabled) {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_adc_channel_init (pyb_adc_channel_obj_t *self) {
|
||||
// the ADC block must be enabled first
|
||||
pyb_adc_check_init();
|
||||
// configure the pin in analog mode
|
||||
pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA);
|
||||
// enable the ADC channel
|
||||
MAP_ADCChannelEnable(ADC_BASE, self->channel);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_adc_deinit_all_channels (void) {
|
||||
for (int i = 0; i < PYB_ADC_NUM_CHANNELS; i++) {
|
||||
adc_channel_deinit(&pyb_adc_channel_obj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* MicroPython bindings : adc object */
|
||||
|
||||
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
if (self->enabled) {
|
||||
mp_printf(print, "ADC(0, bits=12)");
|
||||
} else {
|
||||
mp_printf(print, "ADC(0)");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t pyb_adc_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 12} },
|
||||
};
|
||||
STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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_adc_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_adc_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// check the number of bits
|
||||
if (args[1].u_int != 12) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_adc_obj_t *self = &pyb_adc_obj;
|
||||
self->base.type = &pyb_adc_type;
|
||||
|
||||
// initialize and register with the sleep module
|
||||
pyb_adc_init(self);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t adc_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_adc_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args);
|
||||
// check the number of bits
|
||||
if (args[0].u_int != 12) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
pyb_adc_init(pos_args[0]);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_init_obj, 1, adc_init);
|
||||
|
||||
STATIC mp_obj_t adc_deinit(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *self = self_in;
|
||||
// first deinit all channels
|
||||
pyb_adc_deinit_all_channels();
|
||||
MAP_ADCDisable(ADC_BASE);
|
||||
self->enabled = false;
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit);
|
||||
|
||||
STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_adc_channel_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_channel_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args);
|
||||
|
||||
uint ch_id;
|
||||
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_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) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_adc_channel_obj_t *self = &pyb_adc_channel_obj[ch_id];
|
||||
self->base.type = &pyb_adc_channel_type;
|
||||
pyb_adc_channel_init (self);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
|
||||
return self;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel);
|
||||
|
||||
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&adc_channel_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_adc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.print = adc_print,
|
||||
.make_new = adc_make_new,
|
||||
.locals_dict = (mp_obj_t)&adc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC void adc_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
if (self->enabled) {
|
||||
mp_printf(print, "ADCChannel(%u, pin=%q)", self->id, self->pin->name);
|
||||
} else {
|
||||
mp_printf(print, "ADCChannel(%u)", self->id);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t adc_channel_init(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
// re-enable it
|
||||
pyb_adc_channel_init(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_init_obj, adc_channel_init);
|
||||
|
||||
STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
|
||||
MAP_ADCChannelDisable(ADC_BASE, self->channel);
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
self->enabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_deinit_obj, adc_channel_deinit);
|
||||
|
||||
STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) {
|
||||
pyb_adc_channel_obj_t *self = self_in;
|
||||
uint32_t value;
|
||||
|
||||
// the channel must be enabled
|
||||
if (!self->enabled) {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// wait until a new value is available
|
||||
while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel));
|
||||
// read the sample
|
||||
value = MAP_ADCFIFORead(ADC_BASE, self->channel);
|
||||
// the 12 bit sampled value is stored in bits [13:2]
|
||||
return MP_OBJ_NEW_SMALL_INT((value & 0x3FFF) >> 2);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_value_obj, adc_channel_value);
|
||||
|
||||
STATIC mp_obj_t adc_channel_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
return adc_channel_value (self_in);
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t adc_channel_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_channel_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_channel_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&adc_channel_value_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_channel_locals_dict, adc_channel_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pyb_adc_channel_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADCChannel,
|
||||
.print = adc_channel_print,
|
||||
.call = adc_channel_call,
|
||||
.locals_dict = (mp_obj_t)&adc_channel_locals_dict,
|
||||
};
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,532 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "bufhelper.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_i2c.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "pin.h"
|
||||
#include "prcm.h"
|
||||
#include "i2c.h"
|
||||
#include "pybi2c.h"
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "utils.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class I2C - a two-wire serial protocol
|
||||
|
||||
typedef struct _pyb_i2c_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint baudrate;
|
||||
} pyb_i2c_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBI2C_MIN_BAUD_RATE_HZ (50000)
|
||||
#define PYBI2C_MAX_BAUD_RATE_HZ (400000)
|
||||
|
||||
#define PYBI2C_TRANSC_TIMEOUT_MS (20)
|
||||
#define PYBI2C_TRANSAC_WAIT_DELAY_US (10)
|
||||
|
||||
#define PYBI2C_TIMEOUT_TO_COUNT(to_us, baud) (((baud) * to_us) / 16000000)
|
||||
|
||||
#define RET_IF_ERR(Func) { \
|
||||
if (!Func) { \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
// only master mode is available for the moment
|
||||
STATIC void i2c_init (pyb_i2c_obj_t *self) {
|
||||
// Enable the I2C Peripheral
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
MAP_PRCMPeripheralReset(PRCM_I2CA0);
|
||||
// Configure I2C module with the specified baudrate
|
||||
MAP_I2CMasterInitExpClk(I2CA0_BASE, self->baudrate);
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_transaction(uint cmd) {
|
||||
// Convert the timeout to microseconds
|
||||
int32_t timeout = PYBI2C_TRANSC_TIMEOUT_MS * 1000;
|
||||
// Sanity check, t_timeout must be between 1 and 255
|
||||
uint t_timeout = MIN(PYBI2C_TIMEOUT_TO_COUNT(timeout, pyb_i2c_obj.baudrate), 255);
|
||||
// Clear all interrupts
|
||||
MAP_I2CMasterIntClearEx(I2CA0_BASE, MAP_I2CMasterIntStatusEx(I2CA0_BASE, false));
|
||||
// Set the time-out in terms of clock cycles. Not to be used with breakpoints.
|
||||
MAP_I2CMasterTimeoutSet(I2CA0_BASE, t_timeout);
|
||||
// Initiate the transfer.
|
||||
MAP_I2CMasterControl(I2CA0_BASE, cmd);
|
||||
// Wait until the current byte has been transferred.
|
||||
// Poll on the raw interrupt status.
|
||||
while ((MAP_I2CMasterIntStatusEx(I2CA0_BASE, false) & (I2C_MASTER_INT_DATA | I2C_MASTER_INT_TIMEOUT)) == 0) {
|
||||
if (timeout < 0) {
|
||||
// the peripheral is not responding, so stop
|
||||
return false;
|
||||
}
|
||||
// wait for a few microseconds
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US));
|
||||
timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US;
|
||||
}
|
||||
|
||||
// Check for any errors in the transfer
|
||||
if (MAP_I2CMasterErr(I2CA0_BASE) != I2C_MASTER_ERR_NONE) {
|
||||
switch(cmd) {
|
||||
case I2C_MASTER_CMD_BURST_SEND_START:
|
||||
case I2C_MASTER_CMD_BURST_SEND_CONT:
|
||||
case I2C_MASTER_CMD_BURST_SEND_STOP:
|
||||
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
|
||||
break;
|
||||
case I2C_MASTER_CMD_BURST_RECEIVE_START:
|
||||
case I2C_MASTER_CMD_BURST_RECEIVE_CONT:
|
||||
case I2C_MASTER_CMD_BURST_RECEIVE_FINISH:
|
||||
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_scan_device(byte devAddr) {
|
||||
bool ret = false;
|
||||
// Set the I2C slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true);
|
||||
// Initiate the transfer.
|
||||
if (pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE)) {
|
||||
ret = true;
|
||||
}
|
||||
// Send the stop bit to cancel the read transaction
|
||||
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
|
||||
if (!ret) {
|
||||
uint8_t data = 0;
|
||||
if (pyb_i2c_write(devAddr, &data, sizeof(data), true)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_mem_addr_write (byte addr, byte *mem_addr, uint mem_addr_len) {
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false);
|
||||
// Write the first byte to the controller.
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_START));
|
||||
|
||||
// Loop until the completion of transfer or error
|
||||
while (--mem_addr_len) {
|
||||
// Write the next byte of data
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++);
|
||||
// Transact over I2C to send the next byte
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_mem_write (byte addr, byte *mem_addr, uint mem_addr_len, byte *data, uint data_len) {
|
||||
if (pyb_i2c_mem_addr_write (addr, mem_addr, mem_addr_len)) {
|
||||
// Loop until the completion of transfer or error
|
||||
while (data_len--) {
|
||||
// Write the next byte of data
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *data++);
|
||||
// Transact over I2C to send the byte
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
// send the stop bit
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop) {
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false);
|
||||
// Write the first byte to the controller.
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *data++);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_START));
|
||||
|
||||
// Loop until the completion of transfer or error
|
||||
while (--len) {
|
||||
// Write the next byte of data
|
||||
MAP_I2CMasterDataPut(I2CA0_BASE, *data++);
|
||||
// Transact over I2C to send the byte
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT));
|
||||
}
|
||||
|
||||
// If a stop bit is to be sent, do it.
|
||||
if (stop) {
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool pyb_i2c_read(byte addr, byte *data, uint len) {
|
||||
// Initiate a burst or single receive sequence
|
||||
uint cmd = --len > 0 ? I2C_MASTER_CMD_BURST_RECEIVE_START : I2C_MASTER_CMD_SINGLE_RECEIVE;
|
||||
// Set I2C codec slave address
|
||||
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, true);
|
||||
// Initiate the transfer.
|
||||
RET_IF_ERR(pyb_i2c_transaction(cmd));
|
||||
// Loop until the completion of reception or error
|
||||
while (len) {
|
||||
// Receive the byte over I2C
|
||||
*data++ = MAP_I2CMasterDataGet(I2CA0_BASE);
|
||||
if (--len) {
|
||||
// Continue with reception
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_CONT));
|
||||
} else {
|
||||
// Complete the last reception
|
||||
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_FINISH));
|
||||
}
|
||||
}
|
||||
|
||||
// Receive the last byte over I2C
|
||||
*data = MAP_I2CMasterDataGet(I2CA0_BASE);
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
// get the buffer to receive into
|
||||
pyb_buf_get_for_recv(args[1].u_obj, vstr);
|
||||
|
||||
// receive the data
|
||||
if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
// get the buffer to receive into
|
||||
pyb_buf_get_for_recv(args[2].u_obj, vstr);
|
||||
|
||||
// get the addresses
|
||||
mp_uint_t i2c_addr = args[0].u_int;
|
||||
mp_uint_t mem_addr = args[1].u_int;
|
||||
// determine the width of mem_addr (1 or 2 bytes)
|
||||
mp_uint_t mem_addr_size = args[3].u_int >> 3;
|
||||
|
||||
// write the register address to be read from
|
||||
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_OSError(MP_EIO);
|
||||
}
|
||||
} else {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* MicroPython bindings */
|
||||
/******************************************************************************/
|
||||
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, baudrate=%u)", self->baudrate);
|
||||
} else {
|
||||
mp_print_str(print, "I2C(0)");
|
||||
}
|
||||
}
|
||||
|
||||
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[ARG_freq].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
|
||||
// assign the 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;
|
||||
}
|
||||
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);
|
||||
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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, n_args, all_args, &kw_args);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
|
||||
// disable the peripheral
|
||||
MAP_I2CMasterDisable(I2CA0_BASE);
|
||||
MAP_PRCMPeripheralClkDisable(PRCM_I2CA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// invalidate the baudrate
|
||||
pyb_i2c_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove ((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
||||
for (uint addr = 0x08; addr <= 0x77; addr++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (pyb_i2c_scan_device(addr)) {
|
||||
mp_obj_list_append(list, mp_obj_new_int(addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_args, args);
|
||||
|
||||
vstr_t vstr;
|
||||
pyb_i2c_read_into(args, &vstr);
|
||||
|
||||
// return the received data
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_obj, 3, pyb_i2c_readfrom);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_into_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_into_args, args);
|
||||
|
||||
vstr_t vstr;
|
||||
pyb_i2c_read_into(args, &vstr);
|
||||
|
||||
// return the number of bytes received
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 1, pyb_i2c_readfrom_into);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_writeto_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_writeto_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_writeto_args, args);
|
||||
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
|
||||
// get the buffer to send from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(args[1].u_obj, &bufinfo, data);
|
||||
|
||||
// send the data
|
||||
if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_args, args);
|
||||
|
||||
vstr_t vstr;
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 1, pyb_i2c_readfrom_mem);
|
||||
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_into_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_mem_into(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_readfrom_mem_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_into_args, args);
|
||||
|
||||
// get the buffer to read into
|
||||
vstr_t vstr;
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_writeto_mem(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_readfrom_mem_into_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args), pyb_i2c_readfrom_mem_into_args, args);
|
||||
|
||||
pyb_i2c_check_init(&pyb_i2c_obj);
|
||||
|
||||
// get the buffer to write from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(args[2].u_obj, &bufinfo, data);
|
||||
|
||||
// get the addresses
|
||||
mp_uint_t i2c_addr = args[0].u_int;
|
||||
mp_uint_t mem_addr = args[1].u_int;
|
||||
// determine the width of mem_addr (1 or 2 bytes)
|
||||
mp_uint_t mem_addr_size = args[3].u_int >> 3;
|
||||
|
||||
// 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 mp_const_none;
|
||||
}
|
||||
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_i2c_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_i2c_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom), (mp_obj_t)&pyb_i2c_readfrom_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_into), (mp_obj_t)&pyb_i2c_readfrom_into_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeto), (mp_obj_t)&pyb_i2c_writeto_obj },
|
||||
{ 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 },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_i2c_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_I2C,
|
||||
.print = pyb_i2c_print,
|
||||
.make_new = pyb_i2c_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_i2c_locals_dict,
|
||||
};
|
|
@ -1,965 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "pin.h"
|
||||
#include "prcm.h"
|
||||
#include "gpio.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybpin.h"
|
||||
#include "mpirq.h"
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class Pin - control I/O pins
|
||||
///
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name);
|
||||
STATIC pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit);
|
||||
STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);
|
||||
STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type);
|
||||
STATIC void pin_deassign (pin_obj_t* pin);
|
||||
STATIC void pin_obj_configure (const pin_obj_t *self);
|
||||
STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx);
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in);
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority);
|
||||
STATIC void pin_validate_mode (uint mode);
|
||||
STATIC void pin_validate_pull (uint pull);
|
||||
STATIC void pin_validate_drive (uint strength);
|
||||
STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8_t *unit, uint8_t *type);
|
||||
STATIC uint8_t pin_get_value(const pin_obj_t* self);
|
||||
STATIC void GPIOA0IntHandler (void);
|
||||
STATIC void GPIOA1IntHandler (void);
|
||||
STATIC void GPIOA2IntHandler (void);
|
||||
STATIC void GPIOA3IntHandler (void);
|
||||
STATIC void EXTI_Handler(uint port);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBPIN_NUM_WAKE_PINS (6)
|
||||
#define PYBPIN_WAKES_NOT (-1)
|
||||
|
||||
#define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module
|
||||
#define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode
|
||||
|
||||
#define PYB_PIN_FALLING_EDGE 0x01
|
||||
#define PYB_PIN_RISING_EDGE 0x02
|
||||
#define PYB_PIN_LOW_LEVEL 0x04
|
||||
#define PYB_PIN_HIGH_LEVEL 0x08
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
bool active;
|
||||
int8_t lpds;
|
||||
int8_t hib;
|
||||
} pybpin_wake_pin_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_irq_methods_t pin_irq_methods;
|
||||
STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] =
|
||||
{ {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT} } ;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void pin_init0(void) {
|
||||
// this initalization also reconfigures the JTAG/SWD pins
|
||||
#ifndef DEBUG
|
||||
// assign all pins to the GPIO module so that peripherals can be connected to any
|
||||
// pins without conflicts after a soft reset
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
|
||||
for (uint i = 0; i < named_map->used - 1; i++) {
|
||||
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
|
||||
pin_deassign (pin);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// C API used to convert a user-supplied pin name into an ordinal pin number.
|
||||
pin_obj_t *pin_find(mp_obj_t user_obj) {
|
||||
pin_obj_t *pin_obj;
|
||||
|
||||
// if a pin was provided, use it
|
||||
if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) {
|
||||
pin_obj = user_obj;
|
||||
return pin_obj;
|
||||
}
|
||||
|
||||
// otherwise see if the pin name matches a cpu pin
|
||||
pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj);
|
||||
if (pin_obj) {
|
||||
return pin_obj;
|
||||
}
|
||||
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint strength) {
|
||||
self->mode = mode, self->pull = pull, self->strength = strength;
|
||||
// if af is -1, then we want to keep it as it is
|
||||
if (af != -1) {
|
||||
self->af = af;
|
||||
}
|
||||
|
||||
// if value is -1, then we want to keep it as it is
|
||||
if (value != -1) {
|
||||
self->value = value;
|
||||
}
|
||||
|
||||
// mark the pin as used
|
||||
self->used = true;
|
||||
pin_obj_configure ((const pin_obj_t *)self);
|
||||
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure);
|
||||
}
|
||||
|
||||
void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit) {
|
||||
for (int i = 0; i < n_pins; i++) {
|
||||
pin_free_af_from_pins(fn, unit, i);
|
||||
if (pins[i] != mp_const_none) {
|
||||
pin_obj_t *pin = pin_find(pins[i]);
|
||||
pin_config (pin, pin_find_af_index(pin, fn, unit, i), 0, pull, -1, PIN_STRENGTH_2MA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type) {
|
||||
pin_obj_t *pin_o = pin_find(pin);
|
||||
for (int i = 0; i < pin_o->num_afs; i++) {
|
||||
if (pin_o->af_list[i].fn == fn && pin_o->af_list[i].type == type) {
|
||||
return pin_o->af_list[i].unit;
|
||||
}
|
||||
}
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) {
|
||||
pin_obj_t *pin_o = pin_find(pin);
|
||||
for (int i = 0; i < pin_o->num_afs; i++) {
|
||||
if (pin_o->af_list[i].fn == fn && pin_o->af_list[i].unit == unit) {
|
||||
return pin_o->af_list[i].type;
|
||||
}
|
||||
}
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) {
|
||||
int8_t af = pin_obj_find_af(pin, fn, unit, type);
|
||||
if (af < 0) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
return af;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins);
|
||||
mp_map_elem_t *named_elem = mp_map_lookup(named_map, name, MP_MAP_LOOKUP);
|
||||
if (named_elem != NULL && named_elem->value != NULL) {
|
||||
return named_elem->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins);
|
||||
for (uint i = 0; i < named_map->used; i++) {
|
||||
if ((((pin_obj_t *)named_map->table[i].value)->port == port) &&
|
||||
(((pin_obj_t *)named_map->table[i].value)->bit == bit)) {
|
||||
return named_map->table[i].value;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) {
|
||||
for (int i = 0; i < pin->num_afs; i++) {
|
||||
if (pin->af_list[i].fn == fn && pin->af_list[i].unit == unit && pin->af_list[i].type == type) {
|
||||
return pin->af_list[i].idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
|
||||
for (uint i = 0; i < named_map->used - 1; i++) {
|
||||
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
|
||||
// af is different than GPIO
|
||||
if (pin->af > PIN_MODE_0) {
|
||||
// check if the pin supports the target af
|
||||
int af = pin_obj_find_af(pin, fn, unit, type);
|
||||
if (af > 0 && af == pin->af) {
|
||||
// the pin supports the target af, de-assign it
|
||||
pin_deassign (pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_deassign (pin_obj_t* pin) {
|
||||
pin_config (pin, PIN_MODE_0, GPIO_DIR_MODE_IN, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA);
|
||||
pin->used = false;
|
||||
}
|
||||
|
||||
STATIC void pin_obj_configure (const pin_obj_t *self) {
|
||||
uint32_t type;
|
||||
if (self->mode == PIN_TYPE_ANALOG) {
|
||||
type = PIN_TYPE_ANALOG;
|
||||
} else {
|
||||
type = self->pull;
|
||||
uint32_t direction = self->mode;
|
||||
if (direction == PIN_TYPE_OD || direction == GPIO_DIR_MODE_ALT_OD) {
|
||||
direction = GPIO_DIR_MODE_OUT;
|
||||
type |= PIN_TYPE_OD;
|
||||
}
|
||||
if (self->mode != GPIO_DIR_MODE_ALT && self->mode != GPIO_DIR_MODE_ALT_OD) {
|
||||
// enable the peripheral clock for the GPIO port of this pin
|
||||
switch (self->port) {
|
||||
case PORT_A0:
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_GPIOA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
break;
|
||||
case PORT_A1:
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
break;
|
||||
case PORT_A2:
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_GPIOA2, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
break;
|
||||
case PORT_A3:
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// configure the direction
|
||||
MAP_GPIODirModeSet(self->port, self->bit, direction);
|
||||
// set the pin value
|
||||
if (self->value) {
|
||||
MAP_GPIOPinWrite(self->port, self->bit, self->bit);
|
||||
} else {
|
||||
MAP_GPIOPinWrite(self->port, self->bit, 0);
|
||||
}
|
||||
}
|
||||
// now set the alternate function
|
||||
MAP_PinModeSet (self->pin_num, self->af);
|
||||
}
|
||||
MAP_PinConfigSet(self->pin_num, self->strength, type);
|
||||
}
|
||||
|
||||
STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin, uint *idx) {
|
||||
// pin_num is actually : (package_pin - 1)
|
||||
switch (self->pin_num) {
|
||||
case 56: // GP2
|
||||
*hib_pin = PRCM_HIB_GPIO2;
|
||||
*idx = 0;
|
||||
break;
|
||||
case 58: // GP4
|
||||
*hib_pin = PRCM_HIB_GPIO4;
|
||||
*idx = 1;
|
||||
break;
|
||||
case 3: // GP13
|
||||
*hib_pin = PRCM_HIB_GPIO13;
|
||||
*idx = 2;
|
||||
break;
|
||||
case 7: // GP17
|
||||
*hib_pin = PRCM_HIB_GPIO17;
|
||||
*idx = 3;
|
||||
break;
|
||||
case 1: // GP11
|
||||
*hib_pin = PRCM_HIB_GPIO11;
|
||||
*idx = 4;
|
||||
break;
|
||||
case 16: // GP24
|
||||
*hib_pin = PRCM_HIB_GPIO24;
|
||||
*idx = 5;
|
||||
break;
|
||||
default:
|
||||
*idx = 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
pin_get_hibernate_pin_and_idx (self, &hib_pin, &idx);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
// enable GPIO as a wake source during LPDS
|
||||
MAP_PRCMLPDSWakeUpGPIOSelect(idx, pybpin_wake_pin[idx].lpds);
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
|
||||
if (pybpin_wake_pin[idx].hib != PYBPIN_WAKES_NOT) {
|
||||
// enable GPIO as a wake source during hibernate
|
||||
MAP_PRCMHibernateWakeUpGPIOSelect(hib_pin, pybpin_wake_pin[idx].hib);
|
||||
MAP_PRCMHibernateWakeupSourceEnable(hib_pin);
|
||||
}
|
||||
else {
|
||||
MAP_PRCMHibernateWakeupSourceDisable(hib_pin);
|
||||
}
|
||||
}
|
||||
// if idx is invalid, the pin supports active interrupts for sure
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS || pybpin_wake_pin[idx].active) {
|
||||
MAP_GPIOIntClear(self->port, self->bit);
|
||||
MAP_GPIOIntEnable(self->port, self->bit);
|
||||
}
|
||||
// in case it was enabled before
|
||||
else if (idx < PYBPIN_NUM_WAKE_PINS && !pybpin_wake_pin[idx].active) {
|
||||
MAP_GPIOIntDisable(self->port, self->bit);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
pin_get_hibernate_pin_and_idx (self, &hib_pin, &idx);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
// disable GPIO as a wake source during LPDS
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
if (pybpin_wake_pin[idx].hib != PYBPIN_WAKES_NOT) {
|
||||
// disable GPIO as a wake source during hibernate
|
||||
MAP_PRCMHibernateWakeupSourceDisable(hib_pin);
|
||||
}
|
||||
}
|
||||
// not need to check for the active flag, it's safe to disable it anyway
|
||||
MAP_GPIOIntDisable(self->port, self->bit);
|
||||
}
|
||||
|
||||
STATIC int pin_irq_flags (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) {
|
||||
void *handler;
|
||||
uint32_t intnum;
|
||||
|
||||
// configure the interrupt type
|
||||
MAP_GPIOIntTypeSet(self->port, self->bit, intmode);
|
||||
switch (self->port) {
|
||||
case GPIOA0_BASE:
|
||||
handler = GPIOA0IntHandler;
|
||||
intnum = INT_GPIOA0;
|
||||
break;
|
||||
case GPIOA1_BASE:
|
||||
handler = GPIOA1IntHandler;
|
||||
intnum = INT_GPIOA1;
|
||||
break;
|
||||
case GPIOA2_BASE:
|
||||
handler = GPIOA2IntHandler;
|
||||
intnum = INT_GPIOA2;
|
||||
break;
|
||||
case GPIOA3_BASE:
|
||||
default:
|
||||
handler = GPIOA3IntHandler;
|
||||
intnum = INT_GPIOA3;
|
||||
break;
|
||||
}
|
||||
MAP_GPIOIntRegister(self->port, handler);
|
||||
// set the interrupt to the lowest priority, to make sure that
|
||||
// no other ISRs will be preemted by this one
|
||||
MAP_IntPrioritySet(intnum, priority);
|
||||
}
|
||||
|
||||
STATIC void pin_validate_mode (uint mode) {
|
||||
if (mode != GPIO_DIR_MODE_IN && mode != GPIO_DIR_MODE_OUT && mode != PIN_TYPE_OD &&
|
||||
mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
}
|
||||
STATIC void pin_validate_pull (uint pull) {
|
||||
if (pull != PIN_TYPE_STD && pull != PIN_TYPE_STD_PU && pull != PIN_TYPE_STD_PD) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_validate_drive(uint strength) {
|
||||
if (strength != PIN_STRENGTH_2MA && strength != PIN_STRENGTH_4MA && strength != PIN_STRENGTH_6MA) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8_t *unit, uint8_t *type) {
|
||||
for (int i = 0; i < pin->num_afs; i++) {
|
||||
if (pin->af_list[i].idx == idx) {
|
||||
*fn = pin->af_list[i].fn;
|
||||
*unit = pin->af_list[i].unit;
|
||||
*type = pin->af_list[i].type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC uint8_t pin_get_value (const pin_obj_t* self) {
|
||||
uint32_t value;
|
||||
bool setdir = false;
|
||||
if (self->mode == PIN_TYPE_OD || self->mode == GPIO_DIR_MODE_ALT_OD) {
|
||||
setdir = true;
|
||||
// configure the direction to IN for a moment in order to read the pin value
|
||||
MAP_GPIODirModeSet(self->port, self->bit, GPIO_DIR_MODE_IN);
|
||||
}
|
||||
// now get the value
|
||||
value = MAP_GPIOPinRead(self->port, self->bit);
|
||||
if (setdir) {
|
||||
// set the direction back to output
|
||||
MAP_GPIODirModeSet(self->port, self->bit, GPIO_DIR_MODE_OUT);
|
||||
if (self->value) {
|
||||
MAP_GPIOPinWrite(self->port, self->bit, self->bit);
|
||||
} else {
|
||||
MAP_GPIOPinWrite(self->port, self->bit, 0);
|
||||
}
|
||||
}
|
||||
// return it
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
STATIC void GPIOA0IntHandler (void) {
|
||||
EXTI_Handler(GPIOA0_BASE);
|
||||
}
|
||||
|
||||
STATIC void GPIOA1IntHandler (void) {
|
||||
EXTI_Handler(GPIOA1_BASE);
|
||||
}
|
||||
|
||||
STATIC void GPIOA2IntHandler (void) {
|
||||
EXTI_Handler(GPIOA2_BASE);
|
||||
}
|
||||
|
||||
STATIC void GPIOA3IntHandler (void) {
|
||||
EXTI_Handler(GPIOA3_BASE);
|
||||
}
|
||||
|
||||
// common interrupt handler
|
||||
STATIC void EXTI_Handler(uint port) {
|
||||
uint32_t bits = MAP_GPIOIntStatus(port, true);
|
||||
MAP_GPIOIntClear(port, bits);
|
||||
|
||||
// might be that we have more than one pin interrupt pending
|
||||
// therefore we must loop through all of the 8 possible bits
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint32_t bit = (1 << i);
|
||||
if (bit & bits) {
|
||||
pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit);
|
||||
if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
// read the pin value (hoping that the pin level has remained stable)
|
||||
self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE;
|
||||
} else {
|
||||
// same as the triggers
|
||||
self->irq_flags = self->irq_trigger;
|
||||
}
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
// always clear the flags after leaving the user handler
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC const mp_arg_t pin_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} },
|
||||
{ MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
#define pin_INIT_NUM_ARGS MP_ARRAY_SIZE(pin_init_args)
|
||||
|
||||
STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[pin_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args);
|
||||
|
||||
// get the io mode
|
||||
uint mode;
|
||||
// default is input
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
mode = GPIO_DIR_MODE_IN;
|
||||
} else {
|
||||
mode = mp_obj_get_int(args[0].u_obj);
|
||||
pin_validate_mode (mode);
|
||||
}
|
||||
|
||||
// get the pull type
|
||||
uint pull;
|
||||
if (args[1].u_obj == mp_const_none) {
|
||||
pull = PIN_TYPE_STD;
|
||||
} else {
|
||||
pull = mp_obj_get_int(args[1].u_obj);
|
||||
pin_validate_pull (pull);
|
||||
}
|
||||
|
||||
// get the value
|
||||
int value = -1;
|
||||
if (args[2].u_obj != MP_OBJ_NULL) {
|
||||
if (mp_obj_is_true(args[2].u_obj)) {
|
||||
value = 1;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// get the strenght
|
||||
uint strength = args[3].u_int;
|
||||
pin_validate_drive(strength);
|
||||
|
||||
// get the alternate function
|
||||
int af = args[4].u_int;
|
||||
if (mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) {
|
||||
if (af == -1) {
|
||||
af = 0;
|
||||
} else {
|
||||
goto invalid_args;
|
||||
}
|
||||
} else if (af < -1 || af > 15) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// check for a valid af and then free it from any other pins
|
||||
if (af > PIN_MODE_0) {
|
||||
uint8_t fn, unit, type;
|
||||
pin_validate_af (self, af, &fn, &unit, &type);
|
||||
pin_free_af_from_pins(fn, unit, type);
|
||||
}
|
||||
pin_config (self, af, mode, pull, value, strength);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pin_obj_t *self = self_in;
|
||||
uint32_t pull = self->pull;
|
||||
uint32_t drive = self->strength;
|
||||
|
||||
// pin name
|
||||
mp_printf(print, "Pin('%q'", self->name);
|
||||
|
||||
// pin mode
|
||||
qstr mode_qst;
|
||||
uint32_t mode = self->mode;
|
||||
if (mode == GPIO_DIR_MODE_IN) {
|
||||
mode_qst = MP_QSTR_IN;
|
||||
} else if (mode == GPIO_DIR_MODE_OUT) {
|
||||
mode_qst = MP_QSTR_OUT;
|
||||
} else if (mode == GPIO_DIR_MODE_ALT) {
|
||||
mode_qst = MP_QSTR_ALT;
|
||||
} else if (mode == GPIO_DIR_MODE_ALT_OD) {
|
||||
mode_qst = MP_QSTR_ALT_OPEN_DRAIN;
|
||||
} else {
|
||||
mode_qst = MP_QSTR_OPEN_DRAIN;
|
||||
}
|
||||
mp_printf(print, ", mode=Pin.%q", mode_qst);
|
||||
|
||||
// pin pull
|
||||
qstr pull_qst;
|
||||
if (pull == PIN_TYPE_STD) {
|
||||
mp_printf(print, ", pull=%q", MP_QSTR_None);
|
||||
} else {
|
||||
if (pull == PIN_TYPE_STD_PU) {
|
||||
pull_qst = MP_QSTR_PULL_UP;
|
||||
} else {
|
||||
pull_qst = MP_QSTR_PULL_DOWN;
|
||||
}
|
||||
mp_printf(print, ", pull=Pin.%q", pull_qst);
|
||||
}
|
||||
|
||||
// pin drive
|
||||
qstr drv_qst;
|
||||
if (drive == PIN_STRENGTH_2MA) {
|
||||
drv_qst = MP_QSTR_LOW_POWER;
|
||||
} else if (drive == PIN_STRENGTH_4MA) {
|
||||
drv_qst = MP_QSTR_MED_POWER;
|
||||
} else {
|
||||
drv_qst = MP_QSTR_HIGH_POWER;
|
||||
}
|
||||
mp_printf(print, ", drive=Pin.%q", drv_qst);
|
||||
|
||||
// pin af
|
||||
int alt = (self->af == 0) ? -1 : self->af;
|
||||
mp_printf(print, ", alt=%d)", alt);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// Run an argument through the mapper and return the result.
|
||||
pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]);
|
||||
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
|
||||
|
||||
return (mp_obj_t)pin;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init);
|
||||
|
||||
STATIC mp_obj_t pin_value(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pin_obj_t *self = args[0];
|
||||
if (n_args == 1) {
|
||||
// get the value
|
||||
return MP_OBJ_NEW_SMALL_INT(pin_get_value(self));
|
||||
} else {
|
||||
// set the pin value
|
||||
if (mp_obj_is_true(args[1])) {
|
||||
self->value = 1;
|
||||
MAP_GPIOPinWrite(self->port, self->bit, self->bit);
|
||||
} else {
|
||||
self->value = 0;
|
||||
MAP_GPIOPinWrite(self->port, self->bit, 0);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value);
|
||||
|
||||
STATIC mp_obj_t pin_id(mp_obj_t self_in) {
|
||||
pin_obj_t *self = self_in;
|
||||
return MP_OBJ_NEW_QSTR(self->name);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_id_obj, pin_id);
|
||||
|
||||
STATIC mp_obj_t pin_mode(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pin_obj_t *self = args[0];
|
||||
if (n_args == 1) {
|
||||
return mp_obj_new_int(self->mode);
|
||||
} else {
|
||||
uint32_t mode = mp_obj_get_int(args[1]);
|
||||
pin_validate_mode (mode);
|
||||
self->mode = mode;
|
||||
pin_obj_configure(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mode_obj, 1, 2, pin_mode);
|
||||
|
||||
STATIC mp_obj_t pin_pull(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pin_obj_t *self = args[0];
|
||||
if (n_args == 1) {
|
||||
if (self->pull == PIN_TYPE_STD) {
|
||||
return mp_const_none;
|
||||
}
|
||||
return mp_obj_new_int(self->pull);
|
||||
} else {
|
||||
uint32_t pull;
|
||||
if (args[1] == mp_const_none) {
|
||||
pull = PIN_TYPE_STD;
|
||||
} else {
|
||||
pull = mp_obj_get_int(args[1]);
|
||||
pin_validate_pull (pull);
|
||||
}
|
||||
self->pull = pull;
|
||||
pin_obj_configure(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_pull_obj, 1, 2, pin_pull);
|
||||
|
||||
STATIC mp_obj_t pin_drive(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pin_obj_t *self = args[0];
|
||||
if (n_args == 1) {
|
||||
return mp_obj_new_int(self->strength);
|
||||
} else {
|
||||
uint32_t strength = mp_obj_get_int(args[1]);
|
||||
pin_validate_drive (strength);
|
||||
self->strength = strength;
|
||||
pin_obj_configure(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_drive_obj, 1, 2, pin_drive);
|
||||
|
||||
STATIC mp_obj_t pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_t _args[2] = {self_in, *args};
|
||||
return pin_value (n_args + 1, _args);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) {
|
||||
pin_obj_t *self = self_in;
|
||||
mp_obj_t af[2];
|
||||
mp_obj_t afs = mp_obj_new_list(0, NULL);
|
||||
|
||||
for (int i = 0; i < self->num_afs; i++) {
|
||||
af[0] = MP_OBJ_NEW_QSTR(self->af_list[i].name);
|
||||
af[1] = mp_obj_new_int(self->af_list[i].idx);
|
||||
mp_obj_list_append(afs, mp_obj_new_tuple(MP_ARRAY_SIZE(af), af));
|
||||
}
|
||||
return afs;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pin_obj_t *self = pos_args[0];
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// verify and translate the interrupt mode
|
||||
uint mp_trigger = mp_obj_get_int(args[0].u_obj);
|
||||
uint trigger;
|
||||
if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
trigger = GPIO_BOTH_EDGES;
|
||||
} else {
|
||||
switch (mp_trigger) {
|
||||
case PYB_PIN_FALLING_EDGE:
|
||||
trigger = GPIO_FALLING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_RISING_EDGE:
|
||||
trigger = GPIO_RISING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_LOW_LEVEL:
|
||||
trigger = GPIO_LOW_LEVEL;
|
||||
break;
|
||||
case PYB_PIN_HIGH_LEVEL:
|
||||
trigger = GPIO_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the wake info from this pin
|
||||
uint hib_pin, idx;
|
||||
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in LDPS
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_LPDS_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_LPDS_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_LPDS_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_LPDS_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// first clear the lpds value from all wake-able pins
|
||||
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
|
||||
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// enable this pin as a wake-up source during LPDS
|
||||
pybpin_wake_pin[idx].lpds = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
// this pin was the previous LPDS wake source, so disable it completely
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in hibernate
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_HIB_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_HIB_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_HIB_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_HIB_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// enable this pin as wake-up source during hibernate
|
||||
pybpin_wake_pin[idx].hib = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// we need to update the callback atomically, so we disable the
|
||||
// interrupt before we update anything.
|
||||
pin_irq_disable(self);
|
||||
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// register the interrupt
|
||||
pin_extint_register((pin_obj_t *)self, trigger, priority);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = true;
|
||||
}
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = false;
|
||||
}
|
||||
|
||||
// all checks have passed, we can create the irq object
|
||||
mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
pyb_sleep_set_gpio_lpds_callback (_irq);
|
||||
}
|
||||
|
||||
// save the mp_trigge for later
|
||||
self->irq_trigger = mp_trigger;
|
||||
|
||||
// enable the interrupt just before leaving
|
||||
pin_irq_enable(self);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
|
||||
|
||||
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_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 },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_drive), (mp_obj_t)&pin_drive_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alt_list), (mp_obj_t)&pin_alt_list_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pin_irq_obj },
|
||||
|
||||
// class attributes
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_MODE_IN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OUT), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_MODE_OUT) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(PIN_TYPE_OD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALT), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_MODE_ALT) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_MODE_ALT_OD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(PIN_TYPE_STD_PU) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(PIN_TYPE_STD_PD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_2MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MED_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_4MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_6MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_FALLING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_RISING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_LOW_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_HIGH_LEVEL) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pin_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Pin,
|
||||
.print = pin_print,
|
||||
.make_new = pin_make_new,
|
||||
.call = pin_call,
|
||||
.locals_dict = (mp_obj_t)&pin_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_irq_methods_t pin_irq_methods = {
|
||||
.init = pin_irq,
|
||||
.enable = pin_irq_enable,
|
||||
.disable = pin_irq_disable,
|
||||
.flags = pin_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pin_named_pins_obj_t *self = self_in;
|
||||
mp_printf(print, "<Pin.%q>", self->name);
|
||||
}
|
||||
|
||||
const mp_obj_type_t pin_board_pins_obj_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_board,
|
||||
.print = pin_named_pins_obj_print,
|
||||
.locals_dict = (mp_obj_t)&pin_board_pins_locals_dict,
|
||||
};
|
||||
|
|
@ -1,485 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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/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"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class RTC - real time clock
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj;
|
||||
|
||||
/******************************************************************************
|
||||
FUNCTION-LIKE MACROS
|
||||
******************************************************************************/
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs);
|
||||
STATIC uint32_t pyb_rtc_reset (void);
|
||||
STATIC void pyb_rtc_disable_interupt (void);
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in);
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in);
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds);
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime);
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds);
|
||||
STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pyb_rtc_pre_init(void) {
|
||||
// only if comming out of a power-on reset
|
||||
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
|
||||
// Mark the RTC in use first
|
||||
MAP_PRCMRTCInUseSet();
|
||||
// reset the time and date
|
||||
pyb_rtc_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) {
|
||||
uint16_t cycles;
|
||||
MAP_PRCMRTCGet (secs, &cycles);
|
||||
*msecs = RTC_CYCLES_U16MS(cycles);
|
||||
}
|
||||
|
||||
uint32_t pyb_rtc_get_seconds (void) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) {
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
// calculate the future seconds
|
||||
*f_seconds = c_seconds + (a_mseconds / 1000);
|
||||
// calculate the "remaining" future mseconds
|
||||
*f_mseconds = a_mseconds % 1000;
|
||||
// add the current milliseconds
|
||||
rtc_msec_add (c_mseconds, f_seconds, f_mseconds);
|
||||
}
|
||||
|
||||
void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
|
||||
if (self->repeat) {
|
||||
uint32_t f_seconds, c_seconds;
|
||||
uint16_t f_mseconds, c_mseconds;
|
||||
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// substract the time elapsed between waking up and setting up the alarm again
|
||||
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
|
||||
int32_t next_alarm = self->alarm_ms - wake_ms;
|
||||
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
|
||||
pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds);
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_disable_alarm (void) {
|
||||
pyb_rtc_obj.alarmset = false;
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) {
|
||||
// add the RTC access time
|
||||
rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs);
|
||||
// convert from mseconds to cycles
|
||||
msecs = RTC_U16MS_CYCLES(msecs);
|
||||
// now set the time
|
||||
MAP_PRCMRTCSet(secs, msecs);
|
||||
}
|
||||
|
||||
STATIC uint32_t pyb_rtc_reset (void) {
|
||||
// fresh reset; configure the RTC Calendar
|
||||
// set the date to 1st Jan 2015
|
||||
// set the time to 00:00:00
|
||||
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
|
||||
// disable any running alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
// Now set the RTC calendar time
|
||||
pyb_rtc_set_time(seconds, 0);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_disable_interupt (void) {
|
||||
uint primsk = disable_irq();
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
(void)MAP_PRCMIntStatus();
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// we always need interrupts if repeat is enabled
|
||||
if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
} else { // just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
if (!self->repeat) { // we always need interrupts if repeat is enabled
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t useconds;
|
||||
|
||||
// set date and time
|
||||
mp_obj_t *items;
|
||||
size_t len;
|
||||
mp_obj_get_array(datetime, &len, &items);
|
||||
|
||||
// verify the tuple
|
||||
if (len < 3 || len > 8) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
tm.tm_year = mp_obj_get_int(items[0]);
|
||||
tm.tm_mon = mp_obj_get_int(items[1]);
|
||||
tm.tm_mday = mp_obj_get_int(items[2]);
|
||||
if (len < 7) {
|
||||
useconds = 0;
|
||||
} else {
|
||||
useconds = mp_obj_get_int(items[6]);
|
||||
}
|
||||
if (len < 6) {
|
||||
tm.tm_sec = 0;
|
||||
} else {
|
||||
tm.tm_sec = mp_obj_get_int(items[5]);
|
||||
}
|
||||
if (len < 5) {
|
||||
tm.tm_min = 0;
|
||||
} else {
|
||||
tm.tm_min = mp_obj_get_int(items[4]);
|
||||
}
|
||||
if (len < 4) {
|
||||
tm.tm_hour = 0;
|
||||
} else {
|
||||
tm.tm_hour = mp_obj_get_int(items[3]);
|
||||
}
|
||||
*seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
return useconds;
|
||||
}
|
||||
|
||||
/// The 8-tuple has the same format as CPython's datetime object:
|
||||
///
|
||||
/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None)
|
||||
///
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) {
|
||||
uint32_t seconds;
|
||||
uint32_t useconds;
|
||||
|
||||
if (datetime != MP_OBJ_NULL) {
|
||||
useconds = pyb_rtc_datetime_s_us(datetime, &seconds);
|
||||
pyb_rtc_set_time (seconds, useconds / 1000);
|
||||
} else {
|
||||
seconds = pyb_rtc_reset();
|
||||
}
|
||||
|
||||
// set WLAN time and date, this is needed to verify certificates
|
||||
wlan_set_current_time(seconds);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) {
|
||||
// disable the interrupt before updating anything
|
||||
if (self->irq_enabled) {
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds));
|
||||
self->alarmset = true;
|
||||
self->alarm_time_s = seconds;
|
||||
self->alarm_time_ms = mseconds;
|
||||
// enabled the interrupts again if applicable
|
||||
if (self->irq_enabled || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) {
|
||||
if (msecs_1 + *msecs_2 >= 1000) { // larger than one second
|
||||
*msecs_2 = (msecs_1 + *msecs_2) - 1000;
|
||||
*secs += 1; // carry flag
|
||||
} else {
|
||||
// simply add the mseconds
|
||||
*msecs_2 = msecs_1 + *msecs_2;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC const mp_arg_t pyb_rtc_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_datetime, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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_rtc_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_rtc_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_rtc_obj_t *self = &pyb_rtc_obj;
|
||||
self->base.type = &pyb_rtc_type;
|
||||
|
||||
// set the time and date
|
||||
pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj);
|
||||
|
||||
// pass it to the sleep module
|
||||
pyb_sleep_set_rtc_obj (self);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_rtc_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_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_rtc_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_rtc_init_args[1], args);
|
||||
return pyb_rtc_datetime(pos_args[0], args[0].u_obj);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_init_obj, 1, pyb_rtc_init);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the time from the RTC
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
mp_obj_new_int(tm.tm_mday),
|
||||
mp_obj_new_int(tm.tm_hour),
|
||||
mp_obj_new_int(tm.tm_min),
|
||||
mp_obj_new_int(tm.tm_sec),
|
||||
mp_obj_new_int(mseconds * 1000),
|
||||
mp_const_none
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) {
|
||||
pyb_rtc_reset();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
// check the alarm id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
bool repeat = args[2].u_bool;
|
||||
if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given
|
||||
// repeat cannot be used with a datetime tuple
|
||||
if (repeat) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000;
|
||||
} else { // then it must be an integer
|
||||
self->alarm_ms = mp_obj_get_int(args[1].u_obj);
|
||||
pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds);
|
||||
}
|
||||
|
||||
// store the repepat flag
|
||||
self->repeat = repeat;
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_rtc_obj_t *self = args[0];
|
||||
int32_t ms_left;
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// calculate the ms left
|
||||
ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds);
|
||||
if (!self->alarmset || ms_left < 0) {
|
||||
ms_left = 0;
|
||||
}
|
||||
return mp_obj_new_int(ms_left);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
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_OSError(MP_ENODEV);
|
||||
}
|
||||
// disable the alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
|
||||
// save the power mode data for later
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// check the trigger
|
||||
if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) {
|
||||
self->pwrmode = pwrmode;
|
||||
pyb_rtc_irq_enable((mp_obj_t)self);
|
||||
} else {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup irqs are always called first when resuming from sleep
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods);
|
||||
self->irq_obj = _irq;
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_rtc_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_rtc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_RTC,
|
||||
.make_new = pyb_rtc_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_rtc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods = {
|
||||
.init = pyb_rtc_irq,
|
||||
.enable = pyb_rtc_irq_enable,
|
||||
.disable = pyb_rtc_irq_disable,
|
||||
.flags = pyb_rtc_irq_flags
|
||||
};
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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/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"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "pin.h"
|
||||
#include "prcm.h"
|
||||
#include "gpio.h"
|
||||
#include "sdhost.h"
|
||||
#include "sd_diskio.h"
|
||||
#include "pybsd.h"
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBSD_FREQUENCY_HZ 15000000 // 15MHz
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
pybsd_obj_t pybsd_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_t pyb_sd_def_pin[3] = {&pin_GP10, &pin_GP11, &pin_GP15};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_sd_hw_init (pybsd_obj_t *self);
|
||||
STATIC mp_obj_t pyb_sd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
/// Initalizes the sd card hardware driver
|
||||
STATIC void pyb_sd_hw_init (pybsd_obj_t *self) {
|
||||
if (self->pin_clk) {
|
||||
// Configure the clock pin as output only
|
||||
MAP_PinDirModeSet(((pin_obj_t *)(self->pin_clk))->pin_num, PIN_DIR_MODE_OUT);
|
||||
}
|
||||
// Enable SD peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// Reset MMCHS
|
||||
MAP_PRCMPeripheralReset(PRCM_SDHOST);
|
||||
// Initialize MMCHS
|
||||
MAP_SDHostInit(SDHOST_BASE);
|
||||
// Configure the card clock
|
||||
MAP_SDHostSetExpClk(SDHOST_BASE, MAP_PRCMPeripheralClockGet(PRCM_SDHOST), PYBSD_FREQUENCY_HZ);
|
||||
// Set card rd/wr block len
|
||||
MAP_SDHostBlockSizeSet(SDHOST_BASE, SD_SECTOR_SIZE);
|
||||
self->enabled = true;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) {
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[0].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_sd_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, MP_ARRAY_SIZE(pyb_sd_def_pin), &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, MP_ARRAY_SIZE(pyb_sd_def_pin), PIN_TYPE_STD_PU, PIN_FN_SD, 0);
|
||||
// save the pins clock
|
||||
self->pin_clk = pin_find(pins[0]);
|
||||
}
|
||||
|
||||
pyb_sd_hw_init (self);
|
||||
if (sd_disk_init() != 0) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
//
|
||||
|
||||
STATIC const mp_arg_t pyb_sd_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_sd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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_sd_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_sd_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup and initialize the object
|
||||
mp_obj_t self = &pybsd_obj;
|
||||
pybsd_obj.base.type = &pyb_sd_type;
|
||||
pyb_sd_init_helper (self, &args[1]);
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_sd_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_sd_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_sd_init_args[1], args);
|
||||
return pyb_sd_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_sd_init_obj, 1, pyb_sd_init);
|
||||
|
||||
STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) {
|
||||
pybsd_obj_t *self = self_in;
|
||||
// disable the peripheral
|
||||
self->enabled = false;
|
||||
MAP_PRCMPeripheralClkDisable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// de-initialze the sd card at diskio level
|
||||
sd_disk_deinit();
|
||||
// unregister it from the sleep module
|
||||
pyb_sleep_remove (self);
|
||||
return mp_const_none;
|
||||
}
|
||||
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);
|
||||
|
||||
const mp_obj_type_t pyb_sd_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SD,
|
||||
.make_new = pyb_sd_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_sd_locals_dict,
|
||||
};
|
|
@ -1,657 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "inc/hw_common_reg.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "cc3200_asm.h"
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "systick.h"
|
||||
#include "prcm.h"
|
||||
#include "spi.h"
|
||||
#include "pin.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybpin.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "osi.h"
|
||||
#include "debug.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
#include "sleeprestore.h"
|
||||
#include "serverstask.h"
|
||||
#include "antenna.h"
|
||||
#include "cryptohash.h"
|
||||
#include "pybrtc.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define SPIFLASH_INSTR_READ_STATUS (0x05)
|
||||
#define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9)
|
||||
#define SPIFLASH_STATUS_BUSY (0x01)
|
||||
|
||||
#define LPDS_UP_TIME (425) // 13 msec
|
||||
#define LPDS_DOWN_TIME (98) // 3 msec
|
||||
#define USER_OFFSET (131) // 4 smec
|
||||
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
|
||||
#define WAKEUP_TIME_HIB (32768) // 1 s
|
||||
|
||||
#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
|
||||
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
// storage memory for Cortex M4 registers
|
||||
typedef struct {
|
||||
uint32_t msp;
|
||||
uint32_t psp;
|
||||
uint32_t psr;
|
||||
uint32_t primask;
|
||||
uint32_t faultmask;
|
||||
uint32_t basepri;
|
||||
uint32_t control;
|
||||
} arm_cm4_core_regs_t;
|
||||
|
||||
// storage memory for the NVIC registers
|
||||
typedef struct {
|
||||
uint32_t vector_table; // Vector Table Offset
|
||||
uint32_t aux_ctrl; // Auxiliary control register
|
||||
uint32_t int_ctrl_state; // Interrupt Control and State
|
||||
uint32_t app_int; // Application Interrupt Reset control
|
||||
uint32_t sys_ctrl; // System control
|
||||
uint32_t config_ctrl; // Configuration control
|
||||
uint32_t sys_pri_1; // System Handler Priority 1
|
||||
uint32_t sys_pri_2; // System Handler Priority 2
|
||||
uint32_t sys_pri_3; // System Handler Priority 3
|
||||
uint32_t sys_hcrs; // System Handler control and state register
|
||||
uint32_t systick_ctrl; // SysTick Control Status
|
||||
uint32_t systick_reload; // SysTick Reload
|
||||
uint32_t systick_calib; // SysTick Calibration
|
||||
uint32_t int_en[6]; // Interrupt set enable
|
||||
uint32_t int_priority[49]; // Interrupt priority
|
||||
} nvic_reg_store_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t obj;
|
||||
WakeUpCB_t wakeup;
|
||||
} pyb_sleep_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
wlan_obj_t *wlan_obj;
|
||||
pyb_rtc_obj_t *rtc_obj;
|
||||
} pybsleep_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC nvic_reg_store_t *nvic_reg_store;
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
|
||||
volatile arm_cm4_core_regs_t vault_arm_registers;
|
||||
STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
|
||||
STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
|
||||
STATIC const mp_obj_type_t pyb_sleep_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_sleep,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
|
||||
STATIC void pyb_sleep_flash_powerdown (void);
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void);
|
||||
void pyb_sleep_suspend_exit (void);
|
||||
STATIC void pyb_sleep_obj_wakeup (void);
|
||||
STATIC void PRCMInterruptHandler (void);
|
||||
STATIC void pyb_sleep_iopark (bool hibernate);
|
||||
STATIC bool setup_timer_lpds_wake (void);
|
||||
STATIC bool setup_timer_hibernate_wake (void);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pyb_sleep_pre_init (void) {
|
||||
// allocate memory for nvic registers vault
|
||||
ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
|
||||
}
|
||||
|
||||
void pyb_sleep_init0 (void) {
|
||||
// initialize the sleep objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
|
||||
|
||||
// register and enable the PRCM interrupt
|
||||
osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
|
||||
|
||||
// disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
|
||||
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
|
||||
|
||||
// check the reset casue (if it's soft reset, leave it as it is)
|
||||
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
|
||||
switch (MAP_PRCMSysResetCauseGet()) {
|
||||
case PRCM_POWER_ON:
|
||||
pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
|
||||
break;
|
||||
case PRCM_CORE_RESET:
|
||||
case PRCM_MCU_RESET:
|
||||
case PRCM_SOC_RESET:
|
||||
pybsleep_reset_cause = PYB_SLP_HARD_RESET;
|
||||
break;
|
||||
case PRCM_WDT_RESET:
|
||||
pybsleep_reset_cause = PYB_SLP_WDT_RESET;
|
||||
break;
|
||||
case PRCM_HIB_EXIT:
|
||||
if (PRCMGetSpecialBit(PRCM_WDT_RESET_BIT)) {
|
||||
pybsleep_reset_cause = PYB_SLP_WDT_RESET;
|
||||
}
|
||||
else {
|
||||
pybsleep_reset_cause = PYB_SLP_HIB_RESET;
|
||||
// set the correct wake reason
|
||||
switch (MAP_PRCMHibernateWakeupCauseGet()) {
|
||||
case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
// TODO repeat the alarm
|
||||
break;
|
||||
case PRCM_HIB_WAKEUP_CAUSE_GPIO:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_sleep_signal_soft_reset (void) {
|
||||
pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
|
||||
}
|
||||
|
||||
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
|
||||
pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
|
||||
sleep_obj->base.type = &pyb_sleep_type;
|
||||
sleep_obj->obj = obj;
|
||||
sleep_obj->wakeup = wakeup;
|
||||
// remove it in case it was already registered
|
||||
pyb_sleep_remove (obj);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
|
||||
void pyb_sleep_remove (const mp_obj_t obj) {
|
||||
pyb_sleep_obj_t *sleep_obj;
|
||||
if ((sleep_obj = pyb_sleep_find(obj))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.gpio_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
|
||||
pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
|
||||
}
|
||||
|
||||
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
|
||||
pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
|
||||
}
|
||||
|
||||
void pyb_sleep_sleep (void) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_obj->irq_enabled) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
} else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
// entering and exiting suspended mode must be an atomic operation
|
||||
// therefore interrupts need to be disabled
|
||||
uint primsk = disable_irq();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
pyb_sleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
void pyb_sleep_deepsleep (void) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as hibernate wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
}
|
||||
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pyb_sleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
pyb_sleep_iopark(true);
|
||||
MAP_PRCMHibernateEnter();
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
|
||||
return pybsleep_reset_cause;
|
||||
}
|
||||
|
||||
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
|
||||
return pybsleep_wake_reason;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
// search for the object and then remove it
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
|
||||
if (sleep_obj->obj == obj) {
|
||||
return sleep_obj;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC void pyb_sleep_flash_powerdown (void) {
|
||||
uint32_t status;
|
||||
|
||||
// Enable clock for SSPI module
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// Reset SSPI at PRCM level and wait for reset to complete
|
||||
MAP_PRCMPeripheralReset(PRCM_SSPI);
|
||||
while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI));
|
||||
|
||||
// Reset SSPI at module level
|
||||
MAP_SPIReset(SSPI_BASE);
|
||||
// Configure SSPI module
|
||||
MAP_SPIConfigSetExpClk (SSPI_BASE, PRCMPeripheralClockGet(PRCM_SSPI),
|
||||
20000000, SPI_MODE_MASTER,SPI_SUB_MODE_0,
|
||||
(SPI_SW_CTRL_CS |
|
||||
SPI_4PIN_MODE |
|
||||
SPI_TURBO_OFF |
|
||||
SPI_CS_ACTIVELOW |
|
||||
SPI_WL_8));
|
||||
|
||||
// Enable SSPI module
|
||||
MAP_SPIEnable(SSPI_BASE);
|
||||
// Enable chip select for the spi flash.
|
||||
MAP_SPICSEnable(SSPI_BASE);
|
||||
// Wait for the spi flash
|
||||
do {
|
||||
// Send the status register read instruction and read back a dummy byte.
|
||||
MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_READ_STATUS);
|
||||
MAP_SPIDataGet(SSPI_BASE, &status);
|
||||
|
||||
// Write a dummy byte then read back the actual status.
|
||||
MAP_SPIDataPut(SSPI_BASE, 0xFF);
|
||||
MAP_SPIDataGet(SSPI_BASE, &status);
|
||||
} while ((status & 0xFF) == SPIFLASH_STATUS_BUSY);
|
||||
|
||||
// Disable chip select for the spi flash.
|
||||
MAP_SPICSDisable(SSPI_BASE);
|
||||
// Start another CS enable sequence for Power down command.
|
||||
MAP_SPICSEnable(SSPI_BASE);
|
||||
// Send Deep Power Down command to spi flash
|
||||
MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN);
|
||||
// Disable chip select for the spi flash.
|
||||
MAP_SPICSDisable(SSPI_BASE);
|
||||
}
|
||||
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void) {
|
||||
// enable full RAM retention
|
||||
MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
|
||||
|
||||
// save the NVIC control registers
|
||||
nvic_reg_store->vector_table = HWREG(NVIC_VTABLE);
|
||||
nvic_reg_store->aux_ctrl = HWREG(NVIC_ACTLR);
|
||||
nvic_reg_store->int_ctrl_state = HWREG(NVIC_INT_CTRL);
|
||||
nvic_reg_store->app_int = HWREG(NVIC_APINT);
|
||||
nvic_reg_store->sys_ctrl = HWREG(NVIC_SYS_CTRL);
|
||||
nvic_reg_store->config_ctrl = HWREG(NVIC_CFG_CTRL);
|
||||
nvic_reg_store->sys_pri_1 = HWREG(NVIC_SYS_PRI1);
|
||||
nvic_reg_store->sys_pri_2 = HWREG(NVIC_SYS_PRI2);
|
||||
nvic_reg_store->sys_pri_3 = HWREG(NVIC_SYS_PRI3);
|
||||
nvic_reg_store->sys_hcrs = HWREG(NVIC_SYS_HND_CTRL);
|
||||
|
||||
// save the systick registers
|
||||
nvic_reg_store->systick_ctrl = HWREG(NVIC_ST_CTRL);
|
||||
nvic_reg_store->systick_reload = HWREG(NVIC_ST_RELOAD);
|
||||
nvic_reg_store->systick_calib = HWREG(NVIC_ST_CAL);
|
||||
|
||||
// save the interrupt enable registers
|
||||
uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0;
|
||||
for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
|
||||
nvic_reg_store->int_en[i] = base_reg_addr[i];
|
||||
}
|
||||
|
||||
// save the interrupt priority registers
|
||||
base_reg_addr = (uint32_t *)NVIC_PRI0;
|
||||
for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
|
||||
nvic_reg_store->int_priority[i] = base_reg_addr[i];
|
||||
}
|
||||
|
||||
// switch off the heartbeat led (this makes sure it will blink as soon as we wake up)
|
||||
mperror_heartbeat_switch_off();
|
||||
|
||||
// park the gpio pins
|
||||
pyb_sleep_iopark(false);
|
||||
|
||||
// store the cpu registers
|
||||
sleep_store();
|
||||
|
||||
// save the restore info and enter LPDS
|
||||
MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore);
|
||||
MAP_PRCMLPDSEnter();
|
||||
|
||||
// let the cpu fade away...
|
||||
for ( ; ; );
|
||||
}
|
||||
|
||||
void pyb_sleep_suspend_exit (void) {
|
||||
// take the I2C semaphore
|
||||
uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
|
||||
reg = (reg & ~0x3) | 0x1;
|
||||
HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg;
|
||||
|
||||
// take the GPIO semaphore
|
||||
reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register);
|
||||
reg = (reg & ~0x3FF) | 0x155;
|
||||
HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg;
|
||||
|
||||
// restore de NVIC control registers
|
||||
HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table;
|
||||
HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl;
|
||||
HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state;
|
||||
HWREG(NVIC_APINT) = nvic_reg_store->app_int;
|
||||
HWREG(NVIC_SYS_CTRL) = nvic_reg_store->sys_ctrl;
|
||||
HWREG(NVIC_CFG_CTRL) = nvic_reg_store->config_ctrl;
|
||||
HWREG(NVIC_SYS_PRI1) = nvic_reg_store->sys_pri_1;
|
||||
HWREG(NVIC_SYS_PRI2) = nvic_reg_store->sys_pri_2;
|
||||
HWREG(NVIC_SYS_PRI3) = nvic_reg_store->sys_pri_3;
|
||||
HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store->sys_hcrs;
|
||||
|
||||
// restore the systick register
|
||||
HWREG(NVIC_ST_CTRL) = nvic_reg_store->systick_ctrl;
|
||||
HWREG(NVIC_ST_RELOAD) = nvic_reg_store->systick_reload;
|
||||
HWREG(NVIC_ST_CAL) = nvic_reg_store->systick_calib;
|
||||
|
||||
// restore the interrupt priority registers
|
||||
uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0;
|
||||
for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) {
|
||||
base_reg_addr[i] = nvic_reg_store->int_priority[i];
|
||||
}
|
||||
|
||||
// restore the interrupt enable registers
|
||||
base_reg_addr = (uint32_t *)NVIC_EN0;
|
||||
for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) {
|
||||
base_reg_addr[i] = nvic_reg_store->int_en[i];
|
||||
}
|
||||
|
||||
HAL_INTRODUCE_SYNC_BARRIER();
|
||||
|
||||
// ungate the clock to the shared spi bus
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
// re-configure the antenna selection pins
|
||||
antenna_init0();
|
||||
#endif
|
||||
|
||||
// reinitialize simplelink's interface
|
||||
sl_IfOpen (NULL, 0);
|
||||
|
||||
// restore the configuration of all active peripherals
|
||||
pyb_sleep_obj_wakeup();
|
||||
|
||||
// reconfigure all the previously enabled interrupts
|
||||
mp_irq_wake_all();
|
||||
|
||||
// we need to init the crypto hash engine again
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
// trigger a sw interrupt
|
||||
MAP_IntPendSet(INT_PRCM);
|
||||
|
||||
// force an exception to go back to the point where suspend mode was entered
|
||||
nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));
|
||||
}
|
||||
|
||||
STATIC void PRCMInterruptHandler (void) {
|
||||
// reading the interrupt status automatically clears the interrupt
|
||||
if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
|
||||
// reconfigure it again (if repeat is true)
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// need to check if irq's are enabled from the user point of view
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
}
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
} else {
|
||||
// interrupt has been triggered while waking up from LPDS
|
||||
switch (MAP_PRCMLPDSWakeupCauseGet()) {
|
||||
case PRCM_LPDS_HOST_IRQ:
|
||||
pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
|
||||
mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
|
||||
pybsleep_data.wlan_obj->irq_flags = 0;
|
||||
break;
|
||||
case PRCM_LPDS_GPIO:
|
||||
mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
break;
|
||||
case PRCM_LPDS_TIMER:
|
||||
// reconfigure it again if repeat is true
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// next one clears the wake cause flag
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_sleep_obj_wakeup (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
|
||||
sleep_obj->wakeup(sleep_obj->obj);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_sleep_iopark (bool hibernate) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
|
||||
for (uint i = 0; i < named_map->used; i++) {
|
||||
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
|
||||
switch (pin->pin_num) {
|
||||
#ifdef DEBUG
|
||||
// skip the JTAG pins
|
||||
case PIN_16:
|
||||
case PIN_17:
|
||||
case PIN_19:
|
||||
case PIN_20:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// enable a weak pull-up if the pin is unused
|
||||
if (!pin->used) {
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
|
||||
}
|
||||
if (hibernate) {
|
||||
// make it an input
|
||||
MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// park the sflash pins
|
||||
HWREG(0x4402E0E8) &= ~(0x3 << 8);
|
||||
HWREG(0x4402E0E8) |= (0x2 << 8);
|
||||
HWREG(0x4402E0EC) &= ~(0x3 << 8);
|
||||
HWREG(0x4402E0EC) |= (0x2 << 8);
|
||||
HWREG(0x4402E0F0) &= ~(0x3 << 8);
|
||||
HWREG(0x4402E0F0) |= (0x2 << 8);
|
||||
HWREG(0x4402E0F4) &= ~(0x3 << 8);
|
||||
HWREG(0x4402E0F4) |= (0x1 << 8);
|
||||
|
||||
// if the board has antenna diversity, only park the antenna
|
||||
// selection pins when going into hibernation
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
if (hibernate) {
|
||||
#endif
|
||||
// park the antenna selection pins
|
||||
// (tri-stated with pull down enabled)
|
||||
HWREG(0x4402E108) = 0x00000E61;
|
||||
HWREG(0x4402E10C) = 0x00000E61;
|
||||
#if MICROPY_HW_ANTENNA_DIVERSITY
|
||||
} else {
|
||||
// park the antenna selection pins
|
||||
// (tri-stated without changing the pull up/down resistors)
|
||||
HWREG(0x4402E108) &= ~0x000000FF;
|
||||
HWREG(0x4402E108) |= 0x00000C61;
|
||||
HWREG(0x4402E10C) &= ~0x000000FF;
|
||||
HWREG(0x4402E10C) |= 0x00000C61;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_lpds_wake (void) {
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes to wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_hibernate_wake (void) {
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,388 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "pin.h"
|
||||
#include "prcm.h"
|
||||
#include "spi.h"
|
||||
#include "pybspi.h"
|
||||
#include "mpexception.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class SPI - a master-driven serial protocol
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _pyb_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint baudrate;
|
||||
uint config;
|
||||
byte polarity;
|
||||
byte phase;
|
||||
byte submode;
|
||||
byte wlen;
|
||||
} pyb_spi_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBSPI_FIRST_BIT_MSB 0
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_spi_obj_t pyb_spi_obj = {.baudrate = 0};
|
||||
|
||||
STATIC const mp_obj_t pyb_spi_def_pin[3] = {&pin_GP14, &pin_GP16, &pin_GP30};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
// only master mode is available for the moment
|
||||
STATIC void pybspi_init (const pyb_spi_obj_t *self) {
|
||||
// enable the peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_GSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
MAP_PRCMPeripheralReset(PRCM_GSPI);
|
||||
MAP_SPIReset(GSPI_BASE);
|
||||
|
||||
// configure the interface (only master mode supported)
|
||||
MAP_SPIConfigSetExpClk (GSPI_BASE, MAP_PRCMPeripheralClockGet(PRCM_GSPI),
|
||||
self->baudrate, SPI_MODE_MASTER, self->submode, self->config);
|
||||
|
||||
// enable the interface
|
||||
MAP_SPIEnable(GSPI_BASE);
|
||||
}
|
||||
|
||||
STATIC void pybspi_tx (pyb_spi_obj_t *self, const void *data) {
|
||||
uint32_t txdata;
|
||||
switch (self->wlen) {
|
||||
case 1:
|
||||
txdata = (uint8_t)(*(char *)data);
|
||||
break;
|
||||
case 2:
|
||||
txdata = (uint16_t)(*(uint16_t *)data);
|
||||
break;
|
||||
case 4:
|
||||
txdata = (uint32_t)(*(uint32_t *)data);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
MAP_SPIDataPut (GSPI_BASE, txdata);
|
||||
}
|
||||
|
||||
STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) {
|
||||
uint32_t rxdata;
|
||||
MAP_SPIDataGet (GSPI_BASE, &rxdata);
|
||||
if (data) {
|
||||
switch (self->wlen) {
|
||||
case 1:
|
||||
*(char *)data = rxdata;
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)data = rxdata;
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t *)data = rxdata;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_OSError(MP_EPERM);
|
||||
}
|
||||
// send and receive the data
|
||||
MAP_SPICSEnable(GSPI_BASE);
|
||||
for (int i = 0; i < len; i += self->wlen) {
|
||||
pybspi_tx(self, txdata ? (const void *)&txdata[i] : txchar);
|
||||
pybspi_rx(self, rxdata ? (void *)&rxdata[i] : NULL);
|
||||
}
|
||||
MAP_SPICSDisable(GSPI_BASE);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* MicroPython bindings */
|
||||
/******************************************************************************/
|
||||
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_spi_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "SPI(0, baudrate=%u, bits=%u, polarity=%u, phase=%u, firstbit=SPI.MSB)",
|
||||
self->baudrate, (self->wlen * 8), self->polarity, self->phase);
|
||||
} else {
|
||||
mp_print_str(print, "SPI(0)");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *args) {
|
||||
uint bits;
|
||||
switch (args[1].u_int) {
|
||||
case 8:
|
||||
bits = SPI_WL_8;
|
||||
break;
|
||||
case 16:
|
||||
bits = SPI_WL_16;
|
||||
break;
|
||||
case 32:
|
||||
bits = SPI_WL_32;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
uint polarity = args[2].u_int;
|
||||
uint phase = args[3].u_int;
|
||||
if (polarity > 1 || phase > 1) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
uint firstbit = args[4].u_int;
|
||||
if (firstbit != PYBSPI_FIRST_BIT_MSB) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// build the configuration
|
||||
self->baudrate = args[0].u_int;
|
||||
self->wlen = args[1].u_int >> 3;
|
||||
self->config = bits | SPI_CS_ACTIVELOW | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF;
|
||||
self->polarity = polarity;
|
||||
self->phase = phase;
|
||||
self->submode = (polarity << 1) | phase;
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[5].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_spi_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, 3, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, 3, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
|
||||
}
|
||||
|
||||
// init the bus
|
||||
pybspi_init((const pyb_spi_obj_t *)self);
|
||||
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
static const mp_arg_t pyb_spi_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, // 1MHz
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_FIRST_BIT_MSB} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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_spi_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_spi_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_spi_obj_t *self = &pyb_spi_obj;
|
||||
self->base.type = &pyb_spi_type;
|
||||
|
||||
// start the peripheral
|
||||
pyb_spi_init_helper(self, &args[1]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_spi_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_spi_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_spi_init_args[1], args);
|
||||
return pyb_spi_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
|
||||
|
||||
/// \method deinit()
|
||||
/// Turn off the spi bus.
|
||||
STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
|
||||
// disable the peripheral
|
||||
MAP_SPIDisable(GSPI_BASE);
|
||||
MAP_PRCMPeripheralClkDisable(PRCM_GSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
// invalidate the baudrate
|
||||
pyb_spi_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write (mp_obj_t self_in, mp_obj_t buf) {
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = self_in;
|
||||
|
||||
// get the buffer to send from
|
||||
mp_buffer_info_t bufinfo;
|
||||
uint8_t data[1];
|
||||
pyb_buf_get_for_send(buf, &bufinfo, data);
|
||||
|
||||
// just send
|
||||
pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len, NULL);
|
||||
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
pyb_buf_get_for_recv(args[0].u_obj, &vstr);
|
||||
|
||||
// just receive
|
||||
uint32_t write = args[1].u_int;
|
||||
pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write);
|
||||
|
||||
// return the received data
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_readinto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, },
|
||||
{ MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
pyb_spi_obj_t *self = pos_args[0];
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args);
|
||||
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
pyb_buf_get_for_recv(args[0].u_obj, &vstr);
|
||||
|
||||
// just receive
|
||||
uint32_t write = args[1].u_int;
|
||||
pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write);
|
||||
|
||||
// return the number of bytes received
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_readinto_obj, 1, pyb_spi_readinto);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj_t readbuf) {
|
||||
// get buffers to write from/read to
|
||||
mp_buffer_info_t bufinfo_write;
|
||||
uint8_t data_send[1];
|
||||
mp_buffer_info_t bufinfo_read;
|
||||
|
||||
if (writebuf == readbuf) {
|
||||
// same object for writing and reading, it must be a r/w buffer
|
||||
mp_get_buffer_raise(writebuf, &bufinfo_write, MP_BUFFER_RW);
|
||||
bufinfo_read = bufinfo_write;
|
||||
} else {
|
||||
// get the buffer to write from
|
||||
pyb_buf_get_for_send(writebuf, &bufinfo_write, data_send);
|
||||
|
||||
// get the read buffer
|
||||
mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE);
|
||||
if (bufinfo_read.len != bufinfo_write.len) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// send and receive
|
||||
pybspi_transfer(self, (const char *)bufinfo_write.buf, bufinfo_read.buf, bufinfo_write.len, NULL);
|
||||
|
||||
// return the number of transferred bytes
|
||||
return mp_obj_new_int(bufinfo_write.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_spi_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_spi_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_spi_write_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_spi_read_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&pyb_spi_readinto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)&pyb_spi_write_readinto_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(PYBSPI_FIRST_BIT_MSB) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_spi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SPI,
|
||||
.print = pyb_spi_print,
|
||||
.make_new = pyb_spi_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_spi_locals_dict,
|
||||
};
|
|
@ -1,735 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#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"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "inc/hw_timer.h"
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "prcm.h"
|
||||
#include "timer.h"
|
||||
#include "pin.h"
|
||||
#include "pybtimer.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class Timer - generate periodic events, count events, and create PWM signals.
|
||||
///
|
||||
/// Each timer consists of a counter that counts up at a certain rate. The rate
|
||||
/// at which it counts is the peripheral clock frequency (in Hz) divided by the
|
||||
/// timer prescaler. When the counter reaches the timer period it triggers an
|
||||
/// event, and the counter resets back to zero. By using the irq method,
|
||||
/// the timer event can call a Python function.
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBTIMER_NUM_TIMERS (4)
|
||||
#define PYBTIMER_POLARITY_POS (0x01)
|
||||
#define PYBTIMER_POLARITY_NEG (0x02)
|
||||
|
||||
#define PYBTIMER_TIMEOUT_TRIGGER (0x01)
|
||||
#define PYBTIMER_MATCH_TRIGGER (0x02)
|
||||
|
||||
#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _pyb_timer_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t timer;
|
||||
uint32_t config;
|
||||
uint16_t irq_trigger;
|
||||
uint16_t irq_flags;
|
||||
uint8_t peripheral;
|
||||
uint8_t id;
|
||||
} pyb_timer_obj_t;
|
||||
|
||||
typedef struct _pyb_timer_channel_obj_t {
|
||||
mp_obj_base_t base;
|
||||
struct _pyb_timer_obj_t *timer;
|
||||
uint32_t frequency;
|
||||
uint32_t period;
|
||||
uint16_t channel;
|
||||
uint16_t duty_cycle;
|
||||
uint8_t polarity;
|
||||
} pyb_timer_channel_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods;
|
||||
STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0},
|
||||
{.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1},
|
||||
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
|
||||
{.timer = TIMERA3_BASE, .peripheral = PRCM_TIMERA3}};
|
||||
STATIC const mp_obj_type_t pyb_timer_channel_type;
|
||||
STATIC const mp_obj_t pyb_timer_pwm_pin[8] = {&pin_GP24, MP_OBJ_NULL, &pin_GP25, MP_OBJ_NULL, MP_OBJ_NULL, &pin_GP9, &pin_GP10, &pin_GP11};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim);
|
||||
STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch);
|
||||
STATIC void TIMER0AIntHandler(void);
|
||||
STATIC void TIMER0BIntHandler(void);
|
||||
STATIC void TIMER1AIntHandler(void);
|
||||
STATIC void TIMER1BIntHandler(void);
|
||||
STATIC void TIMER2AIntHandler(void);
|
||||
STATIC void TIMER2BIntHandler(void);
|
||||
STATIC void TIMER3AIntHandler(void);
|
||||
STATIC void TIMER3BIntHandler(void);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void timer_init0 (void) {
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
return self->timer->irq_flags;
|
||||
}
|
||||
|
||||
STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) {
|
||||
pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i]));
|
||||
// any 32-bit timer must be matched by any of its 16-bit versions
|
||||
if (ch->timer->timer == timer && ((ch->channel & TIMER_A) == channel_n || (ch->channel & TIMER_B) == channel_n)) {
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
pyb_timer_channel_obj_t *channel;
|
||||
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove((const mp_obj_t)channel);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
// remove it in case it already exists
|
||||
pyb_timer_channel_remove(ch);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
|
||||
}
|
||||
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim) {
|
||||
// disable all timers and it's interrupts
|
||||
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
|
||||
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
|
||||
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
|
||||
pyb_timer_channel_obj_t *ch;
|
||||
// disable its channels
|
||||
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_A))) {
|
||||
pyb_sleep_remove(ch);
|
||||
}
|
||||
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_B))) {
|
||||
pyb_sleep_remove(ch);
|
||||
}
|
||||
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
}
|
||||
|
||||
// computes prescaler period and match value so timer triggers at freq-Hz
|
||||
STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t *ch, uint32_t *period_out, uint32_t *match_out) {
|
||||
uint32_t maxcount = (ch->channel == (TIMER_A | TIMER_B)) ? 0xFFFFFFFF : 0xFFFF;
|
||||
uint32_t prescaler;
|
||||
uint32_t period_c = (ch->frequency > 0) ? PYBTIMER_SRC_FREQ_HZ / ch->frequency : ((PYBTIMER_SRC_FREQ_HZ / 1000000) * ch->period);
|
||||
|
||||
period_c = MAX(1, period_c) - 1;
|
||||
if (period_c == 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
prescaler = period_c >> 16; // The prescaler is an extension of the timer counter
|
||||
*period_out = period_c;
|
||||
|
||||
if (prescaler > 0xFF && maxcount == 0xFFFF) {
|
||||
goto error;
|
||||
}
|
||||
// check limit values for the duty cycle
|
||||
if (ch->duty_cycle == 0) {
|
||||
*match_out = period_c - 1;
|
||||
} else {
|
||||
if (period_c > 0xFFFF) {
|
||||
uint32_t match = (period_c * 100) / 10000;
|
||||
*match_out = period_c - ((match * ch->duty_cycle) / 100);
|
||||
} else {
|
||||
*match_out = period_c - ((period_c * ch->duty_cycle) / 10000);
|
||||
}
|
||||
}
|
||||
return prescaler;
|
||||
|
||||
error:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC void timer_init (pyb_timer_obj_t *tim) {
|
||||
MAP_PRCMPeripheralClkEnable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
MAP_PRCMPeripheralReset(tim->peripheral);
|
||||
MAP_TimerConfigure(tim->timer, tim->config);
|
||||
}
|
||||
|
||||
STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) {
|
||||
// calculate the period, the prescaler and the match value
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
uint32_t prescaler = compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
|
||||
// set the prescaler
|
||||
MAP_TimerPrescaleSet(ch->timer->timer, ch->channel, (prescaler < 0xFF) ? prescaler : 0);
|
||||
|
||||
// set the load value
|
||||
MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c);
|
||||
|
||||
// configure the pwm if we are in such mode
|
||||
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) {
|
||||
// invert the timer output if required
|
||||
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
|
||||
// set the match value (which is simply the duty cycle translated to ticks)
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
|
||||
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// stall the timer when the processor is halted while debugging
|
||||
MAP_TimerControlStall(ch->timer->timer, ch->channel, true);
|
||||
#endif
|
||||
|
||||
// now enable the timer channel
|
||||
MAP_TimerEnable(ch->timer->timer, ch->channel);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* MicroPython bindings */
|
||||
|
||||
STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_timer_obj_t *tim = self_in;
|
||||
uint32_t mode = tim->config & 0xFF;
|
||||
|
||||
// timer mode
|
||||
qstr mode_qst = MP_QSTR_PWM;
|
||||
switch(mode) {
|
||||
case TIMER_CFG_A_ONE_SHOT_UP:
|
||||
mode_qst = MP_QSTR_ONE_SHOT;
|
||||
break;
|
||||
case TIMER_CFG_A_PERIODIC_UP:
|
||||
mode_qst = MP_QSTR_PERIODIC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mp_printf(print, "Timer(%u, mode=Timer.%q)", tim->id, mode_qst);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
{ MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
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);
|
||||
|
||||
// check the mode
|
||||
uint32_t _mode = args[0].u_int;
|
||||
if (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP && _mode != TIMER_CFG_A_PWM) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// check the width
|
||||
if (args[1].u_int != 16 && args[1].u_int != 32) {
|
||||
goto error;
|
||||
}
|
||||
bool is16bit = (args[1].u_int == 16);
|
||||
|
||||
if (!is16bit && _mode == TIMER_CFG_A_PWM) {
|
||||
// 32-bit mode is only available when in free running modes
|
||||
goto error;
|
||||
}
|
||||
tim->config = is16bit ? ((_mode | (_mode << 8)) | TIMER_CFG_SPLIT_PAIR) : _mode;
|
||||
|
||||
timer_init(tim);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
error:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_timer_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, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// 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_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx];
|
||||
tim->base.type = &pyb_timer_type;
|
||||
tim->id = timer_idx;
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// start the peripheral
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
return (mp_obj_t)tim;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
||||
pyb_timer_obj_t *self = self_in;
|
||||
timer_disable(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBTIMER_POLARITY_POS} },
|
||||
{ MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
|
||||
pyb_timer_obj_t *tim = pos_args[0];
|
||||
mp_int_t channel_n = mp_obj_get_int(pos_args[1]);
|
||||
|
||||
// verify that the timer has been already initialized
|
||||
if (!tim->config) {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) {
|
||||
// invalid channel
|
||||
goto error;
|
||||
}
|
||||
if (channel_n == (TIMER_A | TIMER_B) && (tim->config & TIMER_CFG_SPLIT_PAIR)) {
|
||||
// 32-bit channel selected when the timer is in 16-bit mode
|
||||
goto error;
|
||||
}
|
||||
|
||||
// if only the channel number is given return the previously
|
||||
// allocated channel (or None if no previous channel)
|
||||
if (n_args == 2 && kw_args->used == 0) {
|
||||
pyb_timer_channel_obj_t *ch;
|
||||
if ((ch = pyb_timer_channel_find(tim->timer, channel_n))) {
|
||||
return ch;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// parse the arguments
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// throw an exception if both frequency and period are given
|
||||
if (args[0].u_int != 0 && args[1].u_int != 0) {
|
||||
goto error;
|
||||
}
|
||||
// check that at least one of them has a valid value
|
||||
if (args[0].u_int <= 0 && args[1].u_int <= 0) {
|
||||
goto error;
|
||||
}
|
||||
// check that the polarity is not 'both' in pwm mode
|
||||
if ((tim->config & TIMER_A) == TIMER_CFG_A_PWM && args[2].u_int == (PYBTIMER_POLARITY_POS | PYBTIMER_POLARITY_NEG)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// allocate a new timer channel
|
||||
pyb_timer_channel_obj_t *ch = m_new_obj(pyb_timer_channel_obj_t);
|
||||
ch->base.type = &pyb_timer_channel_type;
|
||||
ch->timer = tim;
|
||||
ch->channel = channel_n;
|
||||
|
||||
// get the frequency the polarity and the duty cycle
|
||||
ch->frequency = args[0].u_int;
|
||||
ch->period = args[1].u_int;
|
||||
ch->polarity = args[2].u_int;
|
||||
ch->duty_cycle = MIN(10000, MAX(0, args[3].u_int));
|
||||
|
||||
timer_channel_init(ch);
|
||||
|
||||
// assign the pin
|
||||
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) {
|
||||
uint32_t ch_idx = (ch->channel == TIMER_A) ? 0 : 1;
|
||||
// use the default pin if available
|
||||
mp_obj_t pin_o = (mp_obj_t)pyb_timer_pwm_pin[(ch->timer->id * 2) + ch_idx];
|
||||
if (pin_o != MP_OBJ_NULL) {
|
||||
pin_obj_t *pin = pin_find(pin_o);
|
||||
pin_config (pin, pin_find_af_index(pin, PIN_FN_TIM, ch->timer->id, PIN_TYPE_TIM_PWM),
|
||||
0, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA);
|
||||
}
|
||||
}
|
||||
|
||||
// add the timer to the list
|
||||
pyb_timer_channel_add(ch);
|
||||
|
||||
return ch;
|
||||
|
||||
error:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_timer_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_timer_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&pyb_timer_channel_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_A), MP_OBJ_NEW_SMALL_INT(TIMER_A) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_B), MP_OBJ_NEW_SMALL_INT(TIMER_B) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT_UP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC_UP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PWM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POSITIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_POS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_NEG) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TIMEOUT), MP_OBJ_NEW_SMALL_INT(PYBTIMER_TIMEOUT_TRIGGER) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MATCH), MP_OBJ_NEW_SMALL_INT(PYBTIMER_MATCH_TRIGGER) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_timer_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Timer,
|
||||
.print = pyb_timer_print,
|
||||
.make_new = pyb_timer_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
|
||||
.init = pyb_timer_channel_irq,
|
||||
.enable = pyb_timer_channel_irq_enable,
|
||||
.disable = pyb_timer_channel_irq_disable,
|
||||
.flags = pyb_timer_channel_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
pyb_timer_channel_obj_t *self;
|
||||
uint32_t status;
|
||||
if ((self = pyb_timer_channel_find(timer, channel))) {
|
||||
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
|
||||
MAP_TimerIntClear(self->timer->timer, status);
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void TIMER0AIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA0_BASE, TIMER_A);
|
||||
}
|
||||
|
||||
STATIC void TIMER0BIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA0_BASE, TIMER_B);
|
||||
}
|
||||
|
||||
STATIC void TIMER1AIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA1_BASE, TIMER_A);
|
||||
}
|
||||
|
||||
STATIC void TIMER1BIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA1_BASE, TIMER_B);
|
||||
}
|
||||
|
||||
STATIC void TIMER2AIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA2_BASE, TIMER_A);
|
||||
}
|
||||
|
||||
STATIC void TIMER2BIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA2_BASE, TIMER_B);
|
||||
}
|
||||
|
||||
STATIC void TIMER3AIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA3_BASE, TIMER_A);
|
||||
}
|
||||
|
||||
STATIC void TIMER3BIntHandler(void) {
|
||||
TIMERGenericIntHandler(TIMERA3_BASE, TIMER_B);
|
||||
}
|
||||
|
||||
STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_timer_channel_obj_t *ch = self_in;
|
||||
char *ch_id = "AB";
|
||||
// timer channel
|
||||
if (ch->channel == TIMER_A) {
|
||||
ch_id = "A";
|
||||
} else if (ch->channel == TIMER_B) {
|
||||
ch_id = "B";
|
||||
}
|
||||
|
||||
mp_printf(print, "timer.channel(Timer.%s, %q=%u", ch_id, MP_QSTR_freq, ch->frequency);
|
||||
|
||||
uint32_t mode = ch->timer->config & 0xFF;
|
||||
if (mode == TIMER_CFG_A_PWM) {
|
||||
mp_printf(print, ", %q=Timer.", MP_QSTR_polarity);
|
||||
switch (ch->polarity) {
|
||||
case PYBTIMER_POLARITY_POS:
|
||||
mp_printf(print, "POSITIVE");
|
||||
break;
|
||||
case PYBTIMER_POLARITY_NEG:
|
||||
mp_printf(print, "NEGATIVE");
|
||||
break;
|
||||
default:
|
||||
mp_printf(print, "BOTH");
|
||||
break;
|
||||
}
|
||||
mp_printf(print, ", %q=%u.%02u", MP_QSTR_duty_cycle, ch->duty_cycle / 100, ch->duty_cycle % 100);
|
||||
}
|
||||
mp_printf(print, ")");
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return mp_obj_new_int(ch->frequency);
|
||||
} else {
|
||||
// set
|
||||
int32_t _frequency = mp_obj_get_int(args[1]);
|
||||
if (_frequency <= 0) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
ch->frequency = _frequency;
|
||||
ch->period = 1000000 / _frequency;
|
||||
timer_channel_init(ch);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_freq_obj, 1, 2, pyb_timer_channel_freq);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return mp_obj_new_int(ch->period);
|
||||
} else {
|
||||
// set
|
||||
int32_t _period = mp_obj_get_int(args[1]);
|
||||
if (_period <= 0) {
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
ch->period = _period;
|
||||
ch->frequency = 1000000 / _period;
|
||||
timer_channel_init(ch);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_period_obj, 1, 2, pyb_timer_channel_period);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_timer_channel_obj_t *ch = args[0];
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return mp_obj_new_int(ch->duty_cycle);
|
||||
} else {
|
||||
// duty cycle must be converted from percentage to ticks
|
||||
// calculate the period, the prescaler and the match value
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
ch->duty_cycle = MIN(10000, MAX(0, mp_obj_get_int(args[1])));
|
||||
compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
if (n_args == 3) {
|
||||
// set the new polarity if requested
|
||||
ch->polarity = mp_obj_get_int(args[2]);
|
||||
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
|
||||
}
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
|
||||
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
|
||||
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_timer_channel_obj_t *ch = pos_args[0];
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// validate the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_irq_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT_UP:
|
||||
case TIMER_CFG_A_PERIODIC_UP:
|
||||
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
|
||||
if (trigger != PYBTIMER_TIMEOUT_TRIGGER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
if (trigger != PYBTIMER_MATCH_TRIGGER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_irq_enable(ch);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_timer_channel_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_period), (mp_obj_t)&pyb_timer_channel_period_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pyb_timer_channel_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_TimerChannel,
|
||||
.print = pyb_timer_channel_print,
|
||||
.locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict,
|
||||
};
|
||||
|
|
@ -1,671 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objlist.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 "inc/hw_uart.h"
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "prcm.h"
|
||||
#include "uart.h"
|
||||
#include "pybuart.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpexception.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "osi.h"
|
||||
#include "utils.h"
|
||||
#include "pin.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#include "moduos.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class UART - duplex serial communication bus
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
*******-***********************************************************************/
|
||||
#define PYBUART_FRAME_TIME_US(baud) ((11 * 1000000) / baud)
|
||||
#define PYBUART_2_FRAMES_TIME_US(baud) (PYBUART_FRAME_TIME_US(baud) * 2)
|
||||
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud) * 8) // we need at least characters in the FIFO
|
||||
|
||||
#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1)
|
||||
#define PYBUART_TX_MAX_TIMEOUT_MS (5)
|
||||
|
||||
#define PYBUART_RX_BUFFER_LEN (256)
|
||||
|
||||
// interrupt triggers
|
||||
#define UART_TRIGGER_RX_ANY (0x01)
|
||||
#define UART_TRIGGER_RX_HALF (0x02)
|
||||
#define UART_TRIGGER_RX_FULL (0x04)
|
||||
#define UART_TRIGGER_TX_DONE (0x08)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void uart_init (pyb_uart_obj_t *self);
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self);
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self);
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler);
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id);
|
||||
STATIC void UART0IntHandler(void);
|
||||
STATIC void UART1IntHandler(void);
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in);
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
struct _pyb_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
pyb_uart_id_t uart_id;
|
||||
uint reg;
|
||||
uint baudrate;
|
||||
uint config;
|
||||
uint flowcontrol;
|
||||
byte *read_buf; // read buffer pointer
|
||||
volatile uint16_t read_buf_head; // indexes first empty slot
|
||||
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
|
||||
byte peripheral;
|
||||
byte irq_trigger;
|
||||
bool irq_enabled;
|
||||
byte irq_flags;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0},
|
||||
{.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} };
|
||||
STATIC const mp_irq_methods_t uart_irq_methods;
|
||||
|
||||
STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void uart_init0 (void) {
|
||||
// save references of the UART objects, to prevent the read buffers from being trashed by the gc
|
||||
MP_STATE_PORT(pyb_uart_objs)[0] = &pyb_uart_obj[0];
|
||||
MP_STATE_PORT(pyb_uart_objs)[1] = &pyb_uart_obj[1];
|
||||
}
|
||||
|
||||
uint32_t uart_rx_any(pyb_uart_obj_t *self) {
|
||||
if (self->read_buf_tail != self->read_buf_head) {
|
||||
// buffering via irq
|
||||
return (self->read_buf_head > self->read_buf_tail) ? self->read_buf_head - self->read_buf_tail :
|
||||
PYBUART_RX_BUFFER_LEN - self->read_buf_tail + self->read_buf_head;
|
||||
}
|
||||
return MAP_UARTCharsAvail(self->reg) ? 1 : 0;
|
||||
}
|
||||
|
||||
int uart_rx_char(pyb_uart_obj_t *self) {
|
||||
if (self->read_buf_tail != self->read_buf_head) {
|
||||
// buffering via irq
|
||||
int data = self->read_buf[self->read_buf_tail];
|
||||
self->read_buf_tail = (self->read_buf_tail + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
return data;
|
||||
} else {
|
||||
// no buffering
|
||||
return MAP_UARTCharGetNonBlocking(self->reg);
|
||||
}
|
||||
}
|
||||
|
||||
bool uart_tx_char(pyb_uart_obj_t *self, int c) {
|
||||
uint32_t timeout = 0;
|
||||
while (!MAP_UARTCharPutNonBlocking(self->reg, c)) {
|
||||
if (timeout++ > ((PYBUART_TX_MAX_TIMEOUT_MS * 1000) / PYBUART_TX_WAIT_US(self->baudrate))) {
|
||||
return false;
|
||||
}
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_TX_WAIT_US(self->baudrate)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
for (const char *top = str + len; str < top; str++) {
|
||||
if (!uart_tx_char(self, *str)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
// assumes init parameters have been set up correctly
|
||||
STATIC void uart_init (pyb_uart_obj_t *self) {
|
||||
// Enable the peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
// Reset the uart
|
||||
MAP_PRCMPeripheralReset(self->peripheral);
|
||||
|
||||
// re-allocate the read buffer after resetting the uart (which automatically disables any irqs)
|
||||
self->read_buf_head = 0;
|
||||
self->read_buf_tail = 0;
|
||||
self->read_buf = MP_OBJ_NULL; // free the read buffer before allocating again
|
||||
self->read_buf = m_new(byte, PYBUART_RX_BUFFER_LEN);
|
||||
|
||||
// Initialize the UART
|
||||
MAP_UARTConfigSetExpClk(self->reg, MAP_PRCMPeripheralClockGet(self->peripheral),
|
||||
self->baudrate, self->config);
|
||||
|
||||
// Enable the FIFO
|
||||
MAP_UARTFIFOEnable(self->reg);
|
||||
|
||||
// Configure the FIFO interrupt levels
|
||||
MAP_UARTFIFOLevelSet(self->reg, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
|
||||
|
||||
// Configure the flow control mode
|
||||
UARTFlowControlSet(self->reg, self->flowcontrol);
|
||||
}
|
||||
|
||||
// Waits at most timeout microseconds for at least 1 char to become ready for
|
||||
// reading (from buf or for direct reading).
|
||||
// Returns true if something available, false if not.
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self) {
|
||||
int timeout = PYBUART_RX_TIMEOUT_US(self->baudrate);
|
||||
for ( ; ; ) {
|
||||
if (uart_rx_any(self)) {
|
||||
return true; // we have at least 1 char ready for reading
|
||||
}
|
||||
if (timeout > 0) {
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(1));
|
||||
timeout--;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_irq_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_irq_enable (self);
|
||||
return _irq;
|
||||
}
|
||||
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
pyb_uart_obj_t *self;
|
||||
uint32_t status;
|
||||
|
||||
self = &pyb_uart_obj[uart_id];
|
||||
status = MAP_UARTIntStatus(self->reg, true);
|
||||
// receive interrupt
|
||||
if (status & (UART_INT_RX | UART_INT_RT)) {
|
||||
// set the flags
|
||||
self->irq_flags = UART_TRIGGER_RX_ANY;
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
while (UARTCharsAvail(self->reg)) {
|
||||
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
||||
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == user_interrupt_char) {
|
||||
// raise an exception when interrupts are finished
|
||||
mpexception_keyboard_nlr_jump();
|
||||
} else { // there's always a read buffer available
|
||||
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
if (next_head != self->read_buf_tail) {
|
||||
// only store data if room in buf
|
||||
self->read_buf[self->read_buf_head] = data;
|
||||
self->read_buf_head = next_head;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the flags to see if the user handler should be called
|
||||
if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) {
|
||||
// call the user defined handler
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
|
||||
// clear the flags
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self) {
|
||||
// not initialized
|
||||
if (!self->baudrate) {
|
||||
mp_raise_OSError(MP_EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void UART0IntHandler(void) {
|
||||
UARTGenericIntHandler(0);
|
||||
}
|
||||
|
||||
STATIC void UART1IntHandler(void) {
|
||||
UARTGenericIntHandler(1);
|
||||
}
|
||||
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
// check for any of the rx interrupt types
|
||||
if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) {
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
}
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
}
|
||||
|
||||
STATIC int uart_irq_flags (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* MicroPython bindings */
|
||||
|
||||
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=", self->uart_id, self->baudrate);
|
||||
switch (self->config & UART_CONFIG_WLEN_MASK) {
|
||||
case UART_CONFIG_WLEN_5:
|
||||
mp_print_str(print, "5");
|
||||
break;
|
||||
case UART_CONFIG_WLEN_6:
|
||||
mp_print_str(print, "6");
|
||||
break;
|
||||
case UART_CONFIG_WLEN_7:
|
||||
mp_print_str(print, "7");
|
||||
break;
|
||||
case UART_CONFIG_WLEN_8:
|
||||
mp_print_str(print, "8");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_NONE) {
|
||||
mp_print_str(print, ", parity=None");
|
||||
} else {
|
||||
mp_printf(print, ", parity=UART.%q", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? MP_QSTR_EVEN : MP_QSTR_ODD);
|
||||
}
|
||||
mp_printf(print, ", stop=%u)", (self->config & UART_CONFIG_STOP_MASK) == UART_CONFIG_STOP_ONE ? 1 : 2);
|
||||
}
|
||||
else {
|
||||
mp_printf(print, "UART(%u)", self->uart_id);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *args) {
|
||||
// get the baudrate
|
||||
if (args[0].u_int <= 0) {
|
||||
goto error;
|
||||
}
|
||||
uint baudrate = args[0].u_int;
|
||||
uint config;
|
||||
switch (args[1].u_int) {
|
||||
case 5:
|
||||
config = UART_CONFIG_WLEN_5;
|
||||
break;
|
||||
case 6:
|
||||
config = UART_CONFIG_WLEN_6;
|
||||
break;
|
||||
case 7:
|
||||
config = UART_CONFIG_WLEN_7;
|
||||
break;
|
||||
case 8:
|
||||
config = UART_CONFIG_WLEN_8;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
// parity
|
||||
if (args[2].u_obj == mp_const_none) {
|
||||
config |= UART_CONFIG_PAR_NONE;
|
||||
} else {
|
||||
uint parity = mp_obj_get_int(args[2].u_obj);
|
||||
if (parity == 0) {
|
||||
config |= UART_CONFIG_PAR_EVEN;
|
||||
} else if (parity == 1) {
|
||||
config |= UART_CONFIG_PAR_ODD;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
// stop bits
|
||||
config |= (args[3].u_int == 1 ? UART_CONFIG_STOP_ONE : UART_CONFIG_STOP_TWO);
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[4].u_obj;
|
||||
uint flowcontrol = UART_FLOWCONTROL_NONE;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
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];
|
||||
} else {
|
||||
mp_obj_get_array(pins_o, &n_pins, &pins);
|
||||
if (n_pins != 2 && n_pins != 4) {
|
||||
goto error;
|
||||
}
|
||||
if (n_pins == 4) {
|
||||
if (pins[PIN_TYPE_UART_RTS] != mp_const_none && pins[PIN_TYPE_UART_RX] == mp_const_none) {
|
||||
goto error; // RTS pin given in TX only mode
|
||||
} else if (pins[PIN_TYPE_UART_CTS] != mp_const_none && pins[PIN_TYPE_UART_TX] == mp_const_none) {
|
||||
goto error; // CTS pin given in RX only mode
|
||||
} else {
|
||||
if (pins[PIN_TYPE_UART_RTS] != mp_const_none) {
|
||||
flowcontrol |= UART_FLOWCONTROL_RX;
|
||||
}
|
||||
if (pins[PIN_TYPE_UART_CTS] != mp_const_none) {
|
||||
flowcontrol |= UART_FLOWCONTROL_TX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_UART, self->uart_id);
|
||||
}
|
||||
|
||||
self->baudrate = baudrate;
|
||||
self->config = config;
|
||||
self->flowcontrol = flowcontrol;
|
||||
|
||||
// initialize and enable the uart
|
||||
uart_init (self);
|
||||
// register it with the sleep module
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
// enable the callback
|
||||
uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none);
|
||||
// disable the irq (from the user point of view)
|
||||
uart_irq_disable(self);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
error:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t pyb_uart_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} },
|
||||
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *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_uart_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_uart_init_args, args);
|
||||
|
||||
// work out the uart id
|
||||
uint uart_id;
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
if (args[5].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *pins;
|
||||
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) {
|
||||
uart_id = pin_find_peripheral_unit(pins[1], PIN_FN_UART, PIN_TYPE_UART_RX);
|
||||
} else {
|
||||
uart_id = pin_find_peripheral_unit(pins[0], PIN_FN_UART, PIN_TYPE_UART_TX);
|
||||
}
|
||||
} else {
|
||||
// default id
|
||||
uart_id = 0;
|
||||
}
|
||||
} else {
|
||||
uart_id = mp_obj_get_int(args[0].u_obj);
|
||||
}
|
||||
|
||||
if (uart_id > PYB_UART_1) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// get the correct uart instance
|
||||
pyb_uart_obj_t *self = &pyb_uart_obj[uart_id];
|
||||
self->base.type = &pyb_uart_type;
|
||||
self->uart_id = uart_id;
|
||||
|
||||
// start the peripheral
|
||||
pyb_uart_init_helper(self, &args[1]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_uart_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_uart_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_uart_init_args[1], args);
|
||||
return pyb_uart_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
|
||||
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
|
||||
// unregister it with the sleep module
|
||||
pyb_sleep_remove (self);
|
||||
// invalidate the baudrate
|
||||
self->baudrate = 0;
|
||||
// free the read buffer
|
||||
m_del(byte, self->read_buf, PYBUART_RX_BUFFER_LEN);
|
||||
MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTDisable(self->reg);
|
||||
MAP_PRCMPeripheralClkDisable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
uart_check_init(self);
|
||||
return mp_obj_new_int(uart_rx_any(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
|
||||
|
||||
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
uart_check_init(self);
|
||||
// send a break signal for at least 2 complete frames
|
||||
MAP_UARTBreakCtl(self->reg, true);
|
||||
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_2_FRAMES_TIME_US(self->baudrate)));
|
||||
MAP_UARTBreakCtl(self->reg, false);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
pyb_uart_obj_t *self = pos_args[0];
|
||||
uart_check_init(self);
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// check the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (PYB_PWR_MODE_ACTIVE != pwrmode) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// check the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
return uart_irq_new (self, trigger, priority, args[2].u_obj);
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_uart_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_irq_obj },
|
||||
|
||||
/// \method read([nbytes])
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
/// \method readline()
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
|
||||
/// \method readinto(buf[, nbytes])
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
|
||||
/// \method write(buf)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
|
||||
STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
byte *buf = buf_in;
|
||||
uart_check_init(self);
|
||||
|
||||
// make sure we want at least 1 char
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// wait for first char to become available
|
||||
if (!uart_rx_wait(self)) {
|
||||
// return MP_EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
*errcode = MP_EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
// read the data
|
||||
byte *orig_buf = buf;
|
||||
for ( ; ; ) {
|
||||
*buf++ = uart_rx_char(self);
|
||||
if (--size == 0 || !uart_rx_wait(self)) {
|
||||
// return number of bytes read
|
||||
return buf - orig_buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
const char *buf = buf_in;
|
||||
uart_check_init(self);
|
||||
|
||||
// write the data
|
||||
if (!uart_tx_strn(self, buf, size)) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
mp_uint_t ret;
|
||||
uart_check_init(self);
|
||||
|
||||
if (request == MP_STREAM_POLL) {
|
||||
mp_uint_t flags = arg;
|
||||
ret = 0;
|
||||
if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self)) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
if ((flags & MP_STREAM_POLL_WR) && MAP_UARTSpaceAvail(self->reg)) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
} else {
|
||||
*errcode = MP_EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.read = pyb_uart_read,
|
||||
.write = pyb_uart_write,
|
||||
.ioctl = pyb_uart_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
STATIC const mp_irq_methods_t uart_irq_methods = {
|
||||
.init = pyb_uart_irq,
|
||||
.enable = uart_irq_enable,
|
||||
.disable = uart_irq_disable,
|
||||
.flags = uart_irq_flags
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_uart_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_UART,
|
||||
.print = pyb_uart_print,
|
||||
.make_new = pyb_uart_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &uart_stream_p,
|
||||
.locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
|
||||
};
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#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"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "wdt.h"
|
||||
#include "prcm.h"
|
||||
#include "utils.h"
|
||||
#include "pybwdt.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBWDT_MILLISECONDS_TO_TICKS(ms) ((80000000 / 1000) * (ms))
|
||||
#define PYBWDT_MIN_TIMEOUT_MS (1000)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bool servers;
|
||||
bool servers_sleeping;
|
||||
bool simplelink;
|
||||
bool running;
|
||||
} pyb_wdt_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_wdt_obj_t pyb_wdt_obj = {.servers = false, .servers_sleeping = false, .simplelink = false, .running = false};
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
// must be called in main.c just after initializing the hal
|
||||
__attribute__ ((section (".boot")))
|
||||
void pybwdt_init0 (void) {
|
||||
}
|
||||
|
||||
void pybwdt_srv_alive (void) {
|
||||
pyb_wdt_obj.servers = true;
|
||||
}
|
||||
|
||||
void pybwdt_srv_sleeping (bool state) {
|
||||
pyb_wdt_obj.servers_sleeping = state;
|
||||
}
|
||||
|
||||
void pybwdt_sl_alive (void) {
|
||||
pyb_wdt_obj.simplelink = true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
|
||||
STATIC const mp_arg_t pyb_wdt_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} }, // 5 s
|
||||
};
|
||||
STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// check the arguments
|
||||
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_wdt_init_args)];
|
||||
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_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_OSError(MP_EPERM);
|
||||
}
|
||||
|
||||
// Enable the WDT peripheral clock
|
||||
MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
|
||||
// Unlock to be able to configure the registers
|
||||
MAP_WatchdogUnlock(WDT_BASE);
|
||||
|
||||
#ifdef DEBUG
|
||||
// make the WDT stall when the debugger stops on a breakpoint
|
||||
MAP_WatchdogStallEnable (WDT_BASE);
|
||||
#endif
|
||||
|
||||
// set the watchdog timer reload value
|
||||
// the WDT trigger a system reset after the second timeout
|
||||
// so, divide by 2 the timeout value received
|
||||
MAP_WatchdogReloadSet(WDT_BASE, PYBWDT_MILLISECONDS_TO_TICKS(timeout_ms / 2));
|
||||
|
||||
// start the timer. Once it's started, it cannot be disabled.
|
||||
MAP_WatchdogEnable(WDT_BASE);
|
||||
pyb_wdt_obj.base.type = &pyb_wdt_type;
|
||||
pyb_wdt_obj.running = true;
|
||||
|
||||
return (mp_obj_t)&pyb_wdt_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) {
|
||||
pyb_wdt_obj_t *self = self_in;
|
||||
if ((self->servers || self->servers_sleeping) && self->simplelink && self->running) {
|
||||
self->servers = false;
|
||||
self->simplelink = false;
|
||||
MAP_WatchdogIntClear(WDT_BASE);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed);
|
||||
|
||||
STATIC const mp_map_elem_t pybwdt_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&pyb_wdt_feed_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pybwdt_locals_dict, pybwdt_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_wdt_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_WDT,
|
||||
.make_new = pyb_wdt_make_new,
|
||||
.locals_dict = (mp_obj_t)&pybwdt_locals_dict,
|
||||
};
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
// options to control how MicroPython is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (128)
|
||||
#define MICROPY_PERSISTENT_CODE_LOAD (1)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (1)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_ENABLE_FINALISER (1)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_STACK_CHECK (0)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#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_VFS (1)
|
||||
#ifndef DEBUG // we need ram on the launchxl while debugging
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#else
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#endif
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
#define MICROPY_FATFS_ENABLE_LFN (2)
|
||||
#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_REENTRANT (1)
|
||||
#define MICROPY_FATFS_TIMEOUT (2500)
|
||||
#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t
|
||||
|
||||
#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_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)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (1)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
|
||||
#else
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_EXECFILE (0)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
|
||||
#endif
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||
#define MICROPY_PY_SYS_EXIT (1)
|
||||
#define MICROPY_PY_SYS_STDFILES (1)
|
||||
#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)
|
||||
#define MICROPY_PY_UCTYPES (0)
|
||||
#define MICROPY_PY_UZLIB (0)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#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_open), (mp_obj_t)&mp_builtin_open_obj }, \
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t machine_module;
|
||||
extern const struct _mp_obj_module_t wipy_module;
|
||||
extern const struct _mp_obj_module_t mp_module_ure;
|
||||
extern const struct _mp_obj_module_t mp_module_ujson;
|
||||
extern const struct _mp_obj_module_t mp_module_uos;
|
||||
extern const struct _mp_obj_module_t mp_module_utime;
|
||||
extern const struct _mp_obj_module_t mp_module_uselect;
|
||||
extern const struct _mp_obj_module_t mp_module_usocket;
|
||||
extern const struct _mp_obj_module_t mp_module_network;
|
||||
extern const struct _mp_obj_module_t mp_module_ubinascii;
|
||||
extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wipy), (mp_obj_t)&wipy_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uselect), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ 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 }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
|
||||
// extra constants
|
||||
#define MICROPY_PORT_CONSTANTS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
|
||||
// vm state and root pointers for the gc
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
mp_obj_t mp_const_user_interrupt; \
|
||||
mp_obj_t machine_config_main; \
|
||||
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; \
|
||||
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 MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
#define MP_SSIZE_MAX (0x7FFFFFFF)
|
||||
|
||||
#define UINT_FMT "%u"
|
||||
#define INT_FMT "%d"
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef unsigned int mp_uint_t; // must be pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
|
||||
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
|
||||
#define MICROPY_EVENT_POLL_HOOK __WFI();
|
||||
|
||||
// assembly functions to handle critical sections, interrupt
|
||||
// disabling/enabling and sleep mode enter/exit
|
||||
#include "cc3200_asm.h"
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
// Include board specific configuration
|
||||
#include "mpconfigboard.h"
|
||||
|
||||
#define MICROPY_MPHALPORT_H "cc3200_hal.h"
|
||||
#define MICROPY_PORT_HAS_TELNET (1)
|
||||
#define MICROPY_PORT_HAS_FTP (1)
|
||||
#define MICROPY_PY_SYS_PLATFORM "WiPy"
|
||||
|
||||
#define MICROPY_PORT_WLAN_AP_SSID "wipy-wlan"
|
||||
#define MICROPY_PORT_WLAN_AP_KEY "www.wipy.io"
|
||||
#define MICROPY_PORT_WLAN_AP_SECURITY SL_SEC_TYPE_WPA_WPA2
|
||||
#define MICROPY_PORT_WLAN_AP_CHANNEL 5
|
398
cc3200/mptask.c
398
cc3200/mptask.c
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/obj.h"
|
||||
#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"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "pin.h"
|
||||
#include "prcm.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "gccollect.h"
|
||||
#include "gchelper.h"
|
||||
#include "mperror.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modusocket.h"
|
||||
#include "modwlan.h"
|
||||
#include "serverstask.h"
|
||||
#include "telnet.h"
|
||||
#include "debug.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"
|
||||
#include "mpirq.h"
|
||||
#include "updater.h"
|
||||
#include "moduos.h"
|
||||
#include "antenna.h"
|
||||
#include "task.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void mptask_pre_init (void);
|
||||
STATIC void mptask_init_sflash_filesystem (void);
|
||||
STATIC void mptask_enter_ap_mode (void);
|
||||
STATIC void mptask_create_main_py (void);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
#ifdef DEBUG
|
||||
OsiTaskHandle svTaskHandle;
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
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"
|
||||
"# can run arbitrary Python, but best to keep it minimal\r\n"
|
||||
#if MICROPY_STDIO_UART
|
||||
"import os, machine\r\n"
|
||||
"os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n"
|
||||
#endif
|
||||
;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void TASK_MicroPython (void *pvParameters) {
|
||||
// get the top of the stack to initialize the garbage collector
|
||||
uint32_t sp = gc_helper_get_sp();
|
||||
|
||||
bool safeboot = false;
|
||||
mptask_pre_init();
|
||||
|
||||
#ifndef DEBUG
|
||||
safeboot = PRCMGetSpecialBit(PRCM_SAFE_BOOT_BIT);
|
||||
#endif
|
||||
|
||||
soft_reset:
|
||||
|
||||
// Thread init
|
||||
#if MICROPY_PY_THREAD
|
||||
mp_thread_init();
|
||||
#endif
|
||||
|
||||
// initialise the stack pointer for the main thread (must be done after mp_thread_init)
|
||||
mp_stack_set_top((void*)sp);
|
||||
|
||||
// GC init
|
||||
gc_init(&_boot, &_eheap);
|
||||
|
||||
// MicroPython init
|
||||
mp_init();
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
||||
|
||||
// execute all basic initializations
|
||||
mpexception_init0();
|
||||
mp_irq_init0();
|
||||
pyb_sleep_init0();
|
||||
pin_init0();
|
||||
mperror_init0();
|
||||
uart_init0();
|
||||
timer_init0();
|
||||
readline_init0();
|
||||
mod_network_init0();
|
||||
rng_init0();
|
||||
|
||||
pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause();
|
||||
if (rstcause < PYB_SLP_SOFT_RESET) {
|
||||
if (rstcause == PYB_SLP_HIB_RESET) {
|
||||
// when waking up from hibernate we just want
|
||||
// to enable simplelink and leave it as is
|
||||
wlan_first_start();
|
||||
}
|
||||
else {
|
||||
// only if not comming out of hibernate or a soft reset
|
||||
mptask_enter_ap_mode();
|
||||
}
|
||||
|
||||
// enable telnet and ftp
|
||||
servers_start();
|
||||
}
|
||||
|
||||
// initialize the serial flash file system
|
||||
mptask_init_sflash_filesystem();
|
||||
|
||||
// append the flash paths to the system path
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib));
|
||||
|
||||
// reset config variables; they should be set by boot.py
|
||||
MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL;
|
||||
|
||||
if (!safeboot) {
|
||||
// run boot.py
|
||||
int ret = pyexec_file("boot.py");
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
goto soft_reset_exit;
|
||||
}
|
||||
if (!ret) {
|
||||
// flash the system led
|
||||
mperror_signal_error();
|
||||
}
|
||||
}
|
||||
|
||||
// now we initialise sub-systems that need configuration from boot.py,
|
||||
// or whose initialisation can be safely deferred until after running
|
||||
// boot.py.
|
||||
|
||||
// at this point everything is fully configured and initialised.
|
||||
|
||||
if (!safeboot) {
|
||||
// run the main script from the current directory.
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
const char *main_py;
|
||||
if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) {
|
||||
main_py = "main.py";
|
||||
} else {
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main));
|
||||
}
|
||||
int ret = pyexec_file(main_py);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
goto soft_reset_exit;
|
||||
}
|
||||
if (!ret) {
|
||||
// flash the system led
|
||||
mperror_signal_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// main script is finished, so now go into REPL mode.
|
||||
// the REPL mode can change, or it can request a soft reset.
|
||||
for ( ; ; ) {
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
if (pyexec_raw_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (pyexec_friendly_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
soft_reset_exit:
|
||||
|
||||
// soft reset
|
||||
pyb_sleep_signal_soft_reset();
|
||||
mp_printf(&mp_plat_print, "PYB: soft reboot\n");
|
||||
|
||||
// disable all callbacks to avoid undefined behaviour
|
||||
// when coming out of a soft reset
|
||||
mp_irq_disable_all();
|
||||
|
||||
// cancel the RTC alarm which might be running independent of the irq state
|
||||
pyb_rtc_disable_alarm();
|
||||
|
||||
// flush the serial flash buffer
|
||||
sflash_disk_flush();
|
||||
|
||||
// clean-up the user socket space
|
||||
modusocket_close_all_user_sockets();
|
||||
|
||||
// unmount all user file systems
|
||||
osmount_unmount_all();
|
||||
|
||||
// wait for pending transactions to complete
|
||||
mp_hal_delay_ms(20);
|
||||
|
||||
goto soft_reset;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
STATIC void mptask_pre_init (void) {
|
||||
// this one only makes sense after a poweron reset
|
||||
pyb_rtc_pre_init();
|
||||
|
||||
// Create the simple link spawn task
|
||||
ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY));
|
||||
|
||||
// Allocate memory for the flash file system
|
||||
ASSERT ((sflash_vfs_fat = mem_Malloc(sizeof(*sflash_vfs_fat))) != NULL);
|
||||
|
||||
// this one allocates memory for the nvic vault
|
||||
pyb_sleep_pre_init();
|
||||
|
||||
// this one allocates memory for the WLAN semaphore
|
||||
wlan_pre_init();
|
||||
|
||||
// this one allocates memory for the updater semaphore
|
||||
updater_pre_init();
|
||||
|
||||
// this one allocates memory for the socket semaphore
|
||||
modusocket_pre_init();
|
||||
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
#ifndef DEBUG
|
||||
OsiTaskHandle svTaskHandle;
|
||||
#endif
|
||||
svTaskHandle = xTaskCreateStatic(TASK_Servers, "Servers",
|
||||
SERVERS_STACK_LEN, NULL, SERVERS_PRIORITY, svTaskStack, &svTaskTCB);
|
||||
ASSERT(svTaskHandle != NULL);
|
||||
}
|
||||
|
||||
STATIC void mptask_init_sflash_filesystem (void) {
|
||||
FILINFO fno;
|
||||
|
||||
// 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(&vfs_fat->fatfs);
|
||||
if (res == FR_NO_FILESYSTEM) {
|
||||
// no filesystem, so create a fresh one
|
||||
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 {
|
||||
__fatal_error("failed to create /flash");
|
||||
}
|
||||
// create empty main.py
|
||||
mptask_create_main_py();
|
||||
} else if (res == FR_OK) {
|
||||
// mount sucessful
|
||||
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.
|
||||
MP_STATE_PORT(vfs_cur) = vfs;
|
||||
|
||||
// create /flash/sys, /flash/lib and /flash/cert if they don't exist
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/sys")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/sys");
|
||||
}
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/lib")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/lib");
|
||||
}
|
||||
if (FR_OK != f_chdir(&vfs_fat->fatfs, "/cert")) {
|
||||
f_mkdir(&vfs_fat->fatfs, "/cert");
|
||||
}
|
||||
|
||||
f_chdir(&vfs_fat->fatfs, "/");
|
||||
|
||||
// make sure we have a /flash/boot.py. Create it if needed.
|
||||
res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno);
|
||||
if (res == FR_OK) {
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
// exists as a directory
|
||||
// TODO handle this case
|
||||
// see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation
|
||||
} else {
|
||||
// exists as a file, good!
|
||||
}
|
||||
} else {
|
||||
// doesn't exist, create fresh file
|
||||
FIL fp;
|
||||
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
|
||||
f_close(&fp);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void mptask_enter_ap_mode (void) {
|
||||
// append the mac only if it's not the first boot
|
||||
bool add_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
// enable simplelink in ap mode (use the MAC address to make the ssid unique)
|
||||
wlan_sl_init (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID),
|
||||
MICROPY_PORT_WLAN_AP_SECURITY, MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY),
|
||||
MICROPY_PORT_WLAN_AP_CHANNEL, ANTENNA_TYPE_INTERNAL, add_mac);
|
||||
}
|
||||
|
||||
STATIC void mptask_create_main_py (void) {
|
||||
// create empty main.py
|
||||
FIL fp;
|
||||
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);
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mpthread.h"
|
||||
#include "py/mphal.h"
|
||||
#include "mptask.h"
|
||||
#include "task.h"
|
||||
#include "irq.h"
|
||||
|
||||
#if MICROPY_PY_THREAD
|
||||
|
||||
// this structure forms a linked list, one node per active thread
|
||||
typedef struct _thread_t {
|
||||
TaskHandle_t id; // system id of thread
|
||||
int ready; // whether the thread is ready and running
|
||||
void *arg; // thread Python args, a GC root pointer
|
||||
void *stack; // pointer to the stack
|
||||
size_t stack_len; // number of words in the stack
|
||||
struct _thread_t *next;
|
||||
} thread_t;
|
||||
|
||||
// the mutex controls access to the linked list
|
||||
STATIC mp_thread_mutex_t thread_mutex;
|
||||
STATIC thread_t thread_entry0;
|
||||
STATIC thread_t *thread; // root pointer, handled bp mp_thread_gc_others
|
||||
|
||||
void mp_thread_init(void) {
|
||||
mp_thread_mutex_init(&thread_mutex);
|
||||
mp_thread_set_state(&mp_state_ctx.thread);
|
||||
|
||||
// create first entry in linked list of all threads
|
||||
thread = &thread_entry0;
|
||||
thread->id = xTaskGetCurrentTaskHandle();
|
||||
thread->ready = 1;
|
||||
thread->arg = NULL;
|
||||
thread->stack = mpTaskStack;
|
||||
thread->stack_len = MICROPY_TASK_STACK_LEN;
|
||||
thread->next = NULL;
|
||||
}
|
||||
|
||||
void mp_thread_gc_others(void) {
|
||||
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||
for (thread_t *th = thread; th != NULL; th = th->next) {
|
||||
gc_collect_root((void**)&th, 1);
|
||||
gc_collect_root(&th->arg, 1); // probably not needed
|
||||
if (th->id == xTaskGetCurrentTaskHandle()) {
|
||||
continue;
|
||||
}
|
||||
if (!th->ready) {
|
||||
continue;
|
||||
}
|
||||
gc_collect_root(th->stack, th->stack_len); // probably not needed
|
||||
}
|
||||
mp_thread_mutex_unlock(&thread_mutex);
|
||||
}
|
||||
|
||||
mp_state_thread_t *mp_thread_get_state(void) {
|
||||
return pvTaskGetThreadLocalStoragePointer(NULL, 0);
|
||||
}
|
||||
|
||||
void mp_thread_set_state(void *state) {
|
||||
vTaskSetThreadLocalStoragePointer(NULL, 0, state);
|
||||
}
|
||||
|
||||
void mp_thread_start(void) {
|
||||
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||
for (thread_t *th = thread; th != NULL; th = th->next) {
|
||||
if (th->id == xTaskGetCurrentTaskHandle()) {
|
||||
th->ready = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mp_thread_mutex_unlock(&thread_mutex);
|
||||
}
|
||||
|
||||
STATIC void *(*ext_thread_entry)(void*) = NULL;
|
||||
|
||||
STATIC void freertos_entry(void *arg) {
|
||||
if (ext_thread_entry) {
|
||||
ext_thread_entry(arg);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
|
||||
// store thread entry function into a global variable so we can access it
|
||||
ext_thread_entry = entry;
|
||||
|
||||
if (*stack_size == 0) {
|
||||
*stack_size = 4096; // default stack size
|
||||
} else if (*stack_size < 2048) {
|
||||
*stack_size = 2048; // minimum stack size
|
||||
}
|
||||
|
||||
// allocate TCB, stack and linked-list node (must be outside thread_mutex lock)
|
||||
StaticTask_t *tcb = m_new(StaticTask_t, 1);
|
||||
StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t));
|
||||
thread_t *th = m_new_obj(thread_t);
|
||||
|
||||
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||
|
||||
// create thread
|
||||
TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", *stack_size / sizeof(void*), arg, 2, stack, tcb);
|
||||
if (id == NULL) {
|
||||
mp_thread_mutex_unlock(&thread_mutex);
|
||||
mp_raise_msg(&mp_type_OSError, "can't create thread");
|
||||
}
|
||||
|
||||
// add thread to linked list of all threads
|
||||
th->id = id;
|
||||
th->ready = 0;
|
||||
th->arg = arg;
|
||||
th->stack = stack;
|
||||
th->stack_len = *stack_size / sizeof(StackType_t);
|
||||
th->next = thread;
|
||||
thread = th;
|
||||
|
||||
mp_thread_mutex_unlock(&thread_mutex);
|
||||
|
||||
// adjust stack_size to provide room to recover from hitting the limit
|
||||
*stack_size -= 512;
|
||||
}
|
||||
|
||||
void mp_thread_finish(void) {
|
||||
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||
// TODO unlink from list
|
||||
for (thread_t *th = thread; th != NULL; th = th->next) {
|
||||
if (th->id == xTaskGetCurrentTaskHandle()) {
|
||||
th->ready = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mp_thread_mutex_unlock(&thread_mutex);
|
||||
}
|
||||
|
||||
void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
|
||||
mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer);
|
||||
}
|
||||
|
||||
// To allow hard interrupts to work with threading we only take/give the semaphore
|
||||
// if we are not within an interrupt context and interrupts are enabled.
|
||||
|
||||
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
|
||||
int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0);
|
||||
return ret == pdTRUE;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
|
||||
if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) {
|
||||
xSemaphoreGive(mutex->handle);
|
||||
// TODO check return value
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_THREAD
|
|
@ -1,497 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "telnet.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "modusocket.h"
|
||||
#include "debug.h"
|
||||
#include "mpexception.h"
|
||||
#include "serverstask.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "irq.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define TELNET_PORT 23
|
||||
// rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256
|
||||
#define TELNET_RX_BUFFER_SIZE 256
|
||||
#define TELNET_MAX_CLIENTS 1
|
||||
#define TELNET_TX_RETRIES_MAX 50
|
||||
#define TELNET_WAIT_TIME_MS 5
|
||||
#define TELNET_LOGIN_RETRIES_MAX 3
|
||||
#define TELNET_CYCLE_TIME_MS (SERVERS_CYCLE_TIME_MS * 2)
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
typedef enum {
|
||||
E_TELNET_RESULT_OK = 0,
|
||||
E_TELNET_RESULT_AGAIN,
|
||||
E_TELNET_RESULT_FAILED
|
||||
} telnet_result_t;
|
||||
|
||||
typedef enum {
|
||||
E_TELNET_STE_DISABLED = 0,
|
||||
E_TELNET_STE_START,
|
||||
E_TELNET_STE_LISTEN,
|
||||
E_TELNET_STE_CONNECTED,
|
||||
E_TELNET_STE_LOGGED_IN
|
||||
} telnet_state_t;
|
||||
|
||||
typedef enum {
|
||||
E_TELNET_STE_SUB_WELCOME,
|
||||
E_TELNET_STE_SUB_SND_USER_OPTIONS,
|
||||
E_TELNET_STE_SUB_REQ_USER,
|
||||
E_TELNET_STE_SUB_GET_USER,
|
||||
E_TELNET_STE_SUB_REQ_PASSWORD,
|
||||
E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS,
|
||||
E_TELNET_STE_SUB_GET_PASSWORD,
|
||||
E_TELNET_STE_SUB_INVALID_LOGGIN,
|
||||
E_TELNET_STE_SUB_SND_REPL_OPTIONS,
|
||||
E_TELNET_STE_SUB_LOGGIN_SUCCESS
|
||||
} telnet_connected_substate_t;
|
||||
|
||||
typedef union {
|
||||
telnet_connected_substate_t connected;
|
||||
} telnet_substate_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *rxBuffer;
|
||||
uint32_t timeout;
|
||||
telnet_state_t state;
|
||||
telnet_substate_t substate;
|
||||
int16_t sd;
|
||||
int16_t n_sd;
|
||||
|
||||
// rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256
|
||||
uint8_t rxWindex;
|
||||
uint8_t rxRindex;
|
||||
|
||||
uint8_t txRetries;
|
||||
uint8_t logginRetries;
|
||||
bool enabled;
|
||||
bool credentialsValid;
|
||||
} telnet_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static telnet_data_t telnet_data;
|
||||
static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
|
||||
static const char* telnet_request_user = "Login as: ";
|
||||
static const char* telnet_request_password = "Password: ";
|
||||
static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n";
|
||||
static const char* telnet_loggin_success = "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n";
|
||||
static const uint8_t telnet_options_user[] = // IAC WONT ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE
|
||||
{ 255, 252, 1, 255, 252, 3, 255, 251, 34 };
|
||||
static const uint8_t telnet_options_pass[] = // IAC WILL ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE
|
||||
{ 255, 251, 1, 255, 252, 3, 255, 251, 34 };
|
||||
static const uint8_t telnet_options_repl[] = // IAC WILL ECHO IAC WILL SUPPRESS_GO_AHEAD IAC WONT LINEMODE
|
||||
{ 255, 251, 1, 255, 251, 3, 255, 252, 34 };
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
static void telnet_wait_for_enabled (void);
|
||||
static bool telnet_create_socket (void);
|
||||
static void telnet_wait_for_connection (void);
|
||||
static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state);
|
||||
static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len);
|
||||
static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen);
|
||||
static void telnet_process (void);
|
||||
static int telnet_process_credential (char *credential, _i16 rxLen);
|
||||
static void telnet_parse_input (uint8_t *str, int16_t *len);
|
||||
static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len);
|
||||
static void telnet_reset_buffer (void);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void telnet_init (void) {
|
||||
// Allocate memory for the receive buffer (from the RTOS heap)
|
||||
ASSERT ((telnet_data.rxBuffer = mem_Malloc(TELNET_RX_BUFFER_SIZE)) != NULL);
|
||||
telnet_data.state = E_TELNET_STE_DISABLED;
|
||||
}
|
||||
|
||||
void telnet_run (void) {
|
||||
_i16 rxLen;
|
||||
switch (telnet_data.state) {
|
||||
case E_TELNET_STE_DISABLED:
|
||||
telnet_wait_for_enabled();
|
||||
break;
|
||||
case E_TELNET_STE_START:
|
||||
if (wlan_is_connected() && telnet_create_socket()) {
|
||||
telnet_data.state = E_TELNET_STE_LISTEN;
|
||||
}
|
||||
break;
|
||||
case E_TELNET_STE_LISTEN:
|
||||
telnet_wait_for_connection();
|
||||
break;
|
||||
case E_TELNET_STE_CONNECTED:
|
||||
switch (telnet_data.substate.connected) {
|
||||
case E_TELNET_STE_SUB_WELCOME:
|
||||
telnet_send_and_proceed((void *)telnet_welcome_msg, strlen(telnet_welcome_msg), E_TELNET_STE_SUB_SND_USER_OPTIONS);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_SND_USER_OPTIONS:
|
||||
telnet_send_and_proceed((void *)telnet_options_user, sizeof(telnet_options_user), E_TELNET_STE_SUB_REQ_USER);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_REQ_USER:
|
||||
// to catch any left over characters from the previous actions
|
||||
telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen);
|
||||
telnet_send_and_proceed((void *)telnet_request_user, strlen(telnet_request_user), E_TELNET_STE_SUB_GET_USER);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_GET_USER:
|
||||
if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex,
|
||||
TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex,
|
||||
&rxLen)) {
|
||||
int result;
|
||||
if ((result = telnet_process_credential (servers_user, rxLen))) {
|
||||
telnet_data.credentialsValid = result > 0 ? true : false;
|
||||
telnet_data.substate.connected = E_TELNET_STE_SUB_REQ_PASSWORD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_TELNET_STE_SUB_REQ_PASSWORD:
|
||||
telnet_send_and_proceed((void *)telnet_request_password, strlen(telnet_request_password), E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS:
|
||||
// to catch any left over characters from the previous actions
|
||||
telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen);
|
||||
telnet_send_and_proceed((void *)telnet_options_pass, sizeof(telnet_options_pass), E_TELNET_STE_SUB_GET_PASSWORD);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_GET_PASSWORD:
|
||||
if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex,
|
||||
TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex,
|
||||
&rxLen)) {
|
||||
int result;
|
||||
if ((result = telnet_process_credential (servers_pass, rxLen))) {
|
||||
if ((telnet_data.credentialsValid = telnet_data.credentialsValid && (result > 0 ? true : false))) {
|
||||
telnet_data.substate.connected = E_TELNET_STE_SUB_SND_REPL_OPTIONS;
|
||||
}
|
||||
else {
|
||||
telnet_data.substate.connected = E_TELNET_STE_SUB_INVALID_LOGGIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_TELNET_STE_SUB_INVALID_LOGGIN:
|
||||
if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_invalid_loggin, strlen(telnet_invalid_loggin))) {
|
||||
telnet_data.credentialsValid = true;
|
||||
if (++telnet_data.logginRetries >= TELNET_LOGIN_RETRIES_MAX) {
|
||||
telnet_reset();
|
||||
}
|
||||
else {
|
||||
telnet_data.substate.connected = E_TELNET_STE_SUB_SND_USER_OPTIONS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_TELNET_STE_SUB_SND_REPL_OPTIONS:
|
||||
telnet_send_and_proceed((void *)telnet_options_repl, sizeof(telnet_options_repl), E_TELNET_STE_SUB_LOGGIN_SUCCESS);
|
||||
break;
|
||||
case E_TELNET_STE_SUB_LOGGIN_SUCCESS:
|
||||
if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_loggin_success, strlen(telnet_loggin_success))) {
|
||||
// clear the current line and force the prompt
|
||||
telnet_reset_buffer();
|
||||
telnet_data.state= E_TELNET_STE_LOGGED_IN;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case E_TELNET_STE_LOGGED_IN:
|
||||
telnet_process();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (telnet_data.state >= E_TELNET_STE_CONNECTED) {
|
||||
if (telnet_data.timeout++ > (servers_get_timeout() / TELNET_CYCLE_TIME_MS)) {
|
||||
telnet_reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void telnet_tx_strn (const char *str, int len) {
|
||||
if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
|
||||
telnet_send_with_retries(telnet_data.n_sd, str, len);
|
||||
}
|
||||
}
|
||||
|
||||
bool telnet_rx_any (void) {
|
||||
return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
|
||||
telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
|
||||
}
|
||||
|
||||
int telnet_rx_char (void) {
|
||||
int rx_char = -1;
|
||||
if (telnet_data.rxRindex != telnet_data.rxWindex) {
|
||||
// rxRindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically
|
||||
rx_char = (int)telnet_data.rxBuffer[telnet_data.rxRindex++];
|
||||
}
|
||||
return rx_char;
|
||||
}
|
||||
|
||||
void telnet_enable (void) {
|
||||
telnet_data.enabled = true;
|
||||
}
|
||||
|
||||
void telnet_disable (void) {
|
||||
telnet_reset();
|
||||
telnet_data.enabled = false;
|
||||
telnet_data.state = E_TELNET_STE_DISABLED;
|
||||
}
|
||||
|
||||
void telnet_reset (void) {
|
||||
// close the connection and start all over again
|
||||
servers_close_socket(&telnet_data.n_sd);
|
||||
servers_close_socket(&telnet_data.sd);
|
||||
telnet_data.state = E_TELNET_STE_START;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
static void telnet_wait_for_enabled (void) {
|
||||
// Init telnet's data
|
||||
telnet_data.n_sd = -1;
|
||||
telnet_data.sd = -1;
|
||||
|
||||
// Check if the telnet service has been enabled
|
||||
if (telnet_data.enabled) {
|
||||
telnet_data.state = E_TELNET_STE_START;
|
||||
}
|
||||
}
|
||||
|
||||
static bool telnet_create_socket (void) {
|
||||
SlSockNonblocking_t nonBlockingOption;
|
||||
SlSockAddrIn_t sServerAddress;
|
||||
_i16 result;
|
||||
|
||||
// Open a socket for telnet
|
||||
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, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK);
|
||||
|
||||
// Bind the socket to a port number
|
||||
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);
|
||||
|
||||
// Start listening
|
||||
ASSERT ((result |= sl_Listen (telnet_data.sd, TELNET_MAX_CLIENTS)) == SL_SOC_OK);
|
||||
|
||||
if (result == SL_SOC_OK) {
|
||||
return true;
|
||||
}
|
||||
servers_close_socket(&telnet_data.sd);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void telnet_wait_for_connection (void) {
|
||||
SlSocklen_t in_addrSize;
|
||||
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);
|
||||
if (telnet_data.n_sd == SL_EAGAIN) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (telnet_data.n_sd <= 0) {
|
||||
// error
|
||||
telnet_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// close the listening socket, we don't need it anymore
|
||||
servers_close_socket(&telnet_data.sd);
|
||||
|
||||
// add the new socket to the network administration
|
||||
modusocket_socket_add(telnet_data.n_sd, false);
|
||||
|
||||
// client connected, so go on
|
||||
telnet_data.rxWindex = 0;
|
||||
telnet_data.rxRindex = 0;
|
||||
telnet_data.txRetries = 0;
|
||||
|
||||
telnet_data.state = E_TELNET_STE_CONNECTED;
|
||||
telnet_data.substate.connected = E_TELNET_STE_SUB_WELCOME;
|
||||
telnet_data.credentialsValid = true;
|
||||
telnet_data.logginRetries = 0;
|
||||
telnet_data.timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state) {
|
||||
if (E_TELNET_RESULT_OK == telnet_send_non_blocking(data, Len)) {
|
||||
telnet_data.substate.connected = next_state;
|
||||
}
|
||||
}
|
||||
|
||||
static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len) {
|
||||
int16_t result = sl_Send(telnet_data.n_sd, data, Len, 0);
|
||||
|
||||
if (result > 0) {
|
||||
telnet_data.txRetries = 0;
|
||||
return E_TELNET_RESULT_OK;
|
||||
}
|
||||
else if ((TELNET_TX_RETRIES_MAX >= ++telnet_data.txRetries) && (result == SL_EAGAIN)) {
|
||||
return E_TELNET_RESULT_AGAIN;
|
||||
}
|
||||
else {
|
||||
// error
|
||||
telnet_reset();
|
||||
return E_TELNET_RESULT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen) {
|
||||
*rxLen = sl_Recv(telnet_data.n_sd, buff, Maxlen, 0);
|
||||
// if there's data received, parse it
|
||||
if (*rxLen > 0) {
|
||||
telnet_data.timeout = 0;
|
||||
telnet_parse_input (buff, rxLen);
|
||||
if (*rxLen > 0) {
|
||||
return E_TELNET_RESULT_OK;
|
||||
}
|
||||
}
|
||||
else if (*rxLen != SL_EAGAIN) {
|
||||
// error
|
||||
telnet_reset();
|
||||
return E_TELNET_RESULT_FAILED;
|
||||
}
|
||||
return E_TELNET_RESULT_AGAIN;
|
||||
}
|
||||
|
||||
static void telnet_process (void) {
|
||||
_i16 rxLen;
|
||||
_i16 maxLen = (telnet_data.rxWindex >= telnet_data.rxRindex) ? (TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex) :
|
||||
((telnet_data.rxRindex - telnet_data.rxWindex) - 1);
|
||||
// to avoid an overrrun
|
||||
maxLen = (telnet_data.rxRindex == 0) ? (maxLen - 1) : maxLen;
|
||||
|
||||
if (maxLen > 0) {
|
||||
if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(&telnet_data.rxBuffer[telnet_data.rxWindex], maxLen, &rxLen)) {
|
||||
// rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically
|
||||
telnet_data.rxWindex = telnet_data.rxWindex + rxLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int telnet_process_credential (char *credential, _i16 rxLen) {
|
||||
telnet_data.rxWindex += rxLen;
|
||||
if (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX) {
|
||||
telnet_data.rxWindex = SERVERS_USER_PASS_LEN_MAX;
|
||||
}
|
||||
|
||||
uint8_t *p = telnet_data.rxBuffer + SERVERS_USER_PASS_LEN_MAX;
|
||||
// if a '\r' is found, or the length exceeds the max username length
|
||||
if ((p = memchr(telnet_data.rxBuffer, '\r', telnet_data.rxWindex)) || (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX)) {
|
||||
uint8_t len = p - telnet_data.rxBuffer;
|
||||
|
||||
telnet_data.rxWindex = 0;
|
||||
if ((len > 0) && (memcmp(credential, telnet_data.rxBuffer, MAX(len, strlen(credential))) == 0)) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void telnet_parse_input (uint8_t *str, int16_t *len) {
|
||||
int16_t b_len = *len;
|
||||
uint8_t *b_str = str;
|
||||
|
||||
for (uint8_t *_str = b_str; _str < b_str + b_len; ) {
|
||||
if (*_str <= 127) {
|
||||
if (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == user_interrupt_char) {
|
||||
// raise a keyboard exception
|
||||
mpexception_keyboard_nlr_jump();
|
||||
(*len)--;
|
||||
_str++;
|
||||
}
|
||||
else if (*_str > 0) {
|
||||
*str++ = *_str++;
|
||||
}
|
||||
else {
|
||||
_str++;
|
||||
*len -= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in case we have received an incomplete telnet option, unlikely, but possible
|
||||
_str += MIN(3, *len);
|
||||
*len -= MIN(3, *len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) {
|
||||
int32_t retries = 0;
|
||||
uint32_t delay = TELNET_WAIT_TIME_MS;
|
||||
// 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) {
|
||||
do {
|
||||
_i16 result = sl_Send(sd, pBuf, len, 0);
|
||||
if (result > 0) {
|
||||
return true;
|
||||
}
|
||||
else if (SL_EAGAIN != result) {
|
||||
return false;
|
||||
}
|
||||
// start with the default delay and increment it on each retry
|
||||
mp_hal_delay_ms(delay++);
|
||||
} while (++retries <= TELNET_TX_RETRIES_MAX);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void telnet_reset_buffer (void) {
|
||||
// erase any characters present in the current line
|
||||
memset (telnet_data.rxBuffer, '\b', TELNET_RX_BUFFER_SIZE / 2);
|
||||
telnet_data.rxWindex = TELNET_RX_BUFFER_SIZE / 2;
|
||||
// fake an "enter" key pressed to display the prompt
|
||||
telnet_data.rxBuffer[telnet_data.rxWindex++] = '\r';
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mpthread.h"
|
||||
#include "gccollect.h"
|
||||
#include "gchelper.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void gc_collect(void) {
|
||||
// start the GC
|
||||
gc_collect_start();
|
||||
|
||||
// get the registers and the sp
|
||||
mp_uint_t regs[10];
|
||||
mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
|
||||
|
||||
// trace the stack, including the registers (since they live on the stack in this function)
|
||||
gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
|
||||
|
||||
// trace root pointers from any threads
|
||||
#if MICROPY_PY_THREAD
|
||||
mp_thread_gc_others();
|
||||
#endif
|
||||
|
||||
// end the GC
|
||||
gc_collect_end();
|
||||
}
|
|
@ -98,7 +98,7 @@ copyright = '2014-2017, Damien P. George, Paul Sokolovsky, and contributors'
|
|||
#
|
||||
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
|
||||
# breakdown, so use the same version identifier for both to avoid confusion.
|
||||
version = release = '1.9.1'
|
||||
version = release = '1.9.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
@ -20,6 +20,20 @@ To set the colour of pixels use::
|
|||
>>> np[1] = (0, 128, 0) # set to green, half brightness
|
||||
>>> np[2] = (0, 0, 64) # set to blue, quarter brightness
|
||||
|
||||
For LEDs with more than 3 colours, such as RGBW pixels or RGBY pixels, the
|
||||
NeoPixel class takes a ``bpp`` parameter. To setup a NeoPixel object for an
|
||||
RGBW Pixel, do the following::
|
||||
|
||||
>>> import machine, neopixel
|
||||
>>> np = neopixel.NeoPixel(machine.Pin(4), 8, bpp=4)
|
||||
|
||||
In a 4-bpp mode, remember to use 4-tuples instead of 3-tuples to set the colour.
|
||||
For example to set the first three pixels use::
|
||||
|
||||
>>> np[0] = (255, 0, 0, 128) # Orange in an RGBY Setup
|
||||
>>> np[1] = (0, 255, 0, 128) # Yellow-green in an RGBY Setup
|
||||
>>> np[2] = (0, 0, 255, 128) # Green-blue in an RGBY Setup
|
||||
|
||||
Then use the ``write()`` method to output the colours to the LEDs::
|
||||
|
||||
>>> np.write()
|
||||
|
|
|
@ -76,20 +76,24 @@ Example::
|
|||
Functions
|
||||
---------
|
||||
|
||||
.. function:: open(stream, \*, flags=0, cachesize=0, pagesize=0, minkeypage=0)
|
||||
.. function:: open(stream, \*, flags=0, pagesize=0, cachesize=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).
|
||||
is 512-65536. If 0, a port-specific default will be used, optimized for
|
||||
port's memory usage and/or performance.
|
||||
* *cachesize* - Suggested memory cache size in bytes. For a
|
||||
board with enough memory using larger values may improve performance.
|
||||
Cache policy is as follows: entire cache is not allocated at once;
|
||||
instead, accessing a new page in database will allocate a memory buffer
|
||||
for it, until value specified by *cachesize* is reached. Then, these
|
||||
buffers will be managed using LRU (least recently used) policy. More
|
||||
buffers may still be allocated if needed (e.g., if a database contains
|
||||
big keys and/or values). Allocated cache buffers aren't reclaimed.
|
||||
* *minkeypage* - Minimum number of keys to store per page. Default value
|
||||
of 0 equivalent to 2.
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ Constructors
|
|||
- *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.
|
||||
permissible values are listed under Constants below. These set the
|
||||
number of bits used to encode a color value and the layout of these
|
||||
bits in *buffer*.
|
||||
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
|
||||
|
@ -110,8 +110,9 @@ Other methods
|
|||
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.
|
||||
This method works between FrameBuffer instances utilising different formats,
|
||||
but the resulting colors may be unexpected due to the mismatch in color
|
||||
formats.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
|
|
@ -40,8 +40,7 @@ information pertaining to a specific port.
|
|||
|
||||
Beyond the built-in libraries described in this documentation, many more
|
||||
modules from the Python standard library, as well as further MicroPython
|
||||
extensions to it, can be found in the `micropython-lib repository
|
||||
<https://github.com/micropython/micropython-lib>`_.
|
||||
extensions to it, can be found in `micropython-lib`.
|
||||
|
||||
Python standard libraries and micro-libraries
|
||||
---------------------------------------------
|
||||
|
@ -54,7 +53,7 @@ e.g. ``ujson`` instead of ``json``. This is to signify that such a module is
|
|||
micro-library, i.e. implements only a subset of CPython module functionality.
|
||||
By naming them differently, a user has a choice to write a Python-level module
|
||||
to extend functionality for better compatibility with CPython (indeed, this is
|
||||
what done by micropython-lib project mentioned above).
|
||||
what done by the `micropython-lib` project mentioned above).
|
||||
|
||||
On some embedded platforms, where it may be cumbersome to add Python-level
|
||||
wrapper modules to achieve naming compatibility with CPython, micro-modules
|
||||
|
|
|
@ -38,7 +38,7 @@ Methods
|
|||
|
||||
Resets the RTC to the time of January 1, 2015 and starts running it again.
|
||||
|
||||
.. method:: RTC.alarm(id, time, /*, repeat=False)
|
||||
.. method:: RTC.alarm(id, time, \*, repeat=False)
|
||||
|
||||
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
|
||||
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
|
||||
|
|
|
@ -4,17 +4,44 @@
|
|||
class Signal -- control and sense external I/O devices
|
||||
======================================================
|
||||
|
||||
The Signal class is a simple extension of Pin class. Unlike Pin, which
|
||||
The Signal class is a simple extension of the `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.
|
||||
not. In other words, 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
|
||||
of whether different users have an active-high or active-low LED, a normally
|
||||
open or normally closed relay - you can develop a 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.
|
||||
configuration differences in few lines in the config file of your app.
|
||||
|
||||
Example::
|
||||
|
||||
from machine import Pin, Signal
|
||||
|
||||
# Suppose you have an active-high LED on pin 0
|
||||
led1_pin = Pin(0, Pin.OUT)
|
||||
# ... and active-low LED on pin 1
|
||||
led2_pin = Pin(1, Pin.OUT)
|
||||
|
||||
# Now to light up both of them using Pin class, you'll need to set
|
||||
# them to different values
|
||||
led1_pin.value(1)
|
||||
led2_pin.value(0)
|
||||
|
||||
# Signal class allows to abstract away active-high/active-low
|
||||
# difference
|
||||
led1 = Signal(led1_pin, invert=False)
|
||||
led2 = Signal(led2_pin, invert=True)
|
||||
|
||||
# Now lighting up them looks the same
|
||||
led1.value(1)
|
||||
led2.value(1)
|
||||
|
||||
# Even better:
|
||||
led1.on()
|
||||
led2.on()
|
||||
|
||||
Following is the guide when Signal vs Pin should be used:
|
||||
|
||||
|
@ -33,11 +60,11 @@ 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
|
||||
Python manually!). Also, Pin is a 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
|
||||
If in doubt, give the Signal a try! Once again, it is offered 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
|
||||
|
|
|
@ -46,7 +46,7 @@ Functions
|
|||
|
||||
.. function:: mem_info([verbose])
|
||||
|
||||
Print information about currently used memory. If the *verbose`* argument
|
||||
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
|
||||
|
|
|
@ -9,7 +9,7 @@ This module provides network drivers and routing configuration. To use this
|
|||
module, a MicroPython variant/build with network capabilities must be installed.
|
||||
Network drivers for specific hardware are available within this module and are
|
||||
used to configure hardware network interface(s). Network services provided
|
||||
by configured interfaces are then available for use via the :mod:`socket`
|
||||
by configured interfaces are then available for use via the :mod:`usocket`
|
||||
module.
|
||||
|
||||
For example::
|
||||
|
@ -39,9 +39,9 @@ Common network adapter interface
|
|||
================================
|
||||
|
||||
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
|
||||
interface classes implemented by `MicroPython ports <MicroPython port>`
|
||||
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:: AbstractNIC(id=None, ...)
|
||||
|
@ -411,7 +411,7 @@ parameter should be `id`.
|
|||
print(ap.config('channel'))
|
||||
|
||||
Following are commonly supported parameters (availability of a specific parameter
|
||||
depends on network technology type, driver, and MicroPython port).
|
||||
depends on network technology type, driver, and `MicroPython port`).
|
||||
|
||||
========= ===========
|
||||
Parameter Description
|
||||
|
|
|
@ -28,7 +28,7 @@ Functions
|
|||
this function takes just exception value instead of exception type,
|
||||
exception value, and traceback object; *file* argument should be
|
||||
positional; further arguments are not supported. CPython-compatible
|
||||
``traceback`` module can be found in micropython-lib.
|
||||
``traceback`` module can be found in `micropython-lib`.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
|
|
@ -29,8 +29,12 @@ Functions
|
|||
|
||||
.. function:: a2b_base64(data)
|
||||
|
||||
Convert Base64-encoded data to binary representation. Returns bytes string.
|
||||
Decode base64-encoded data, ignoring invalid characters in the input.
|
||||
Conforms to `RFC 2045 s.6.8 <https://tools.ietf.org/html/rfc2045#section-6.8>`_.
|
||||
Returns a bytes object.
|
||||
|
||||
.. function:: b2a_base64(data)
|
||||
|
||||
Encode binary data in Base64 format. Returns string.
|
||||
Encode binary data in base64 format, as in `RFC 3548
|
||||
<https://tools.ietf.org/html/rfc3548.html>`_. Returns the encoded data
|
||||
followed by a newline character, as a bytes object.
|
||||
|
|
|
@ -89,8 +89,22 @@ Functions
|
|||
Return a bytes object with n random bytes. Whenever possible, it is
|
||||
generated by the hardware random number generator.
|
||||
|
||||
.. function:: dupterm(stream_object)
|
||||
.. function:: dupterm(stream_object, index=0)
|
||||
|
||||
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.
|
||||
Duplicate or switch the MicroPython terminal (the REPL) on the given stream-like
|
||||
object. The *stream_object* argument must implement the ``readinto()`` and
|
||||
``write()`` methods. The stream should be in non-blocking mode and
|
||||
``readinto()`` should return ``None`` if there is no data available for reading.
|
||||
|
||||
After calling this function all terminal output is repeated on this stream,
|
||||
and any input that is available on the stream is passed on to the terminal input.
|
||||
|
||||
The *index* parameter should be a non-negative integer and specifies which
|
||||
duplication slot is set. A given port may implement more than one slot (slot 0
|
||||
will always be available) and in that case terminal input and output is
|
||||
duplicated on all the slots that are set.
|
||||
|
||||
If ``None`` is passed as the *stream_object* then duplication is cancelled on
|
||||
the slot given by *index*.
|
||||
|
||||
The function returns the previous stream-like object in the given slot.
|
||||
|
|
|
@ -9,12 +9,6 @@
|
|||
|
||||
This module provides access to the BSD socket interface.
|
||||
|
||||
.. 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
|
||||
|
||||
|
@ -27,11 +21,47 @@ This module provides access to the BSD socket interface.
|
|||
Socket address format(s)
|
||||
------------------------
|
||||
|
||||
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
|
||||
resolved first using `usocket.getaddrinfo()`.
|
||||
The native socket address format of the ``usocket`` module is an opaque data type
|
||||
returned by `getaddrinfo` function, which must be used to resolve textual address
|
||||
(including numeric addresses)::
|
||||
|
||||
sockaddr = usocket.getaddrinfo('www.micropython.org', 80)[0][-1]
|
||||
# You must use getaddrinfo() even for numeric addresses
|
||||
sockaddr = usocket.getaddrinfo('127.0.0.1', 80)[0][-1]
|
||||
# Now you can use that address
|
||||
sock.connect(addr)
|
||||
|
||||
Using `getaddrinfo` is the most efficient (both in terms of memory and processing
|
||||
power) and portable way to work with addresses.
|
||||
|
||||
However, ``socket`` module (note the difference with native MicroPython
|
||||
``usocket`` module described here) provides CPython-compatible way to specify
|
||||
addresses using tuples, as described below. Note that depending on a
|
||||
`MicroPython port`, ``socket`` module can be builtin or need to be
|
||||
installed from `micropython-lib` (as in the case of `MicroPython Unix port`),
|
||||
and some ports still accept only numeric addresses in the tuple format,
|
||||
and require to use `getaddrinfo` function to resolve domain names.
|
||||
|
||||
Summing up:
|
||||
|
||||
* Always use `getaddrinfo` when writing portable applications.
|
||||
* Tuple addresses described below can be used as a shortcut for
|
||||
quick hacks and interactive use, if your port supports them.
|
||||
|
||||
Tuple address format for ``socket`` module:
|
||||
|
||||
* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with
|
||||
dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and
|
||||
integer port number in the range 1-65535. Note the domain names are not
|
||||
accepted as *ipv4_address*, they should be resolved first using
|
||||
`usocket.getaddrinfo()`.
|
||||
* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address*
|
||||
is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``,
|
||||
and *port* is an integer port number in the range 1-65535. *flowinfo*
|
||||
must be 0. *scopeid* is the interface scope identifier for link-local
|
||||
addresses. Note the domain names are not accepted as *ipv6_address*,
|
||||
they should be resolved first using `usocket.getaddrinfo()`. Availability
|
||||
of IPv6 support depends on a `MicroPython port`.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
@ -87,12 +117,12 @@ Constants
|
|||
.. data:: usocket.SOL_*
|
||||
|
||||
Socket option levels (an argument to `setsockopt()`). The exact
|
||||
inventory depends on a MicroPython port.
|
||||
inventory depends on a `MicroPython port`.
|
||||
|
||||
.. data:: usocket.SO_*
|
||||
|
||||
Socket options (an argument to `setsockopt()`). The exact
|
||||
inventory depends on a MicroPython port.
|
||||
inventory depends on a `MicroPython port`.
|
||||
|
||||
Constants specific to WiPy:
|
||||
|
||||
|
@ -250,3 +280,13 @@ Methods
|
|||
the length of *buf*.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
.. exception:: socket.error
|
||||
|
||||
MicroPython does NOT have this exception.
|
||||
|
||||
.. 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.
|
||||
|
|
|
@ -15,4 +15,4 @@ It's as simple as::
|
|||
if uart.any():
|
||||
usb.write(uart.read(256))
|
||||
|
||||
pass_through(pyb.USB_VCP(), pyb.UART(1, 9600))
|
||||
pass_through(pyb.USB_VCP(), pyb.UART(1, 9600, timeout=0))
|
||||
|
|
|
@ -279,7 +279,7 @@ After importing the modules, execute:
|
|||
|
||||
Then copy and paste all the Q(xxx) lines into a text editor. Check for and
|
||||
remove lines which are obviously invalid. Open the file qstrdefsport.h which
|
||||
will be found in stmhal (or the equivalent directory for the architecture in
|
||||
will be found in ports/stm32 (or the equivalent directory for the architecture in
|
||||
use). Copy and paste the corrected lines at the end of the file. Save the file,
|
||||
rebuild and flash the firmware. The outcome can be checked by importing the
|
||||
modules and again issuing:
|
||||
|
|
|
@ -54,11 +54,11 @@ Glossary
|
|||
separate project
|
||||
`micropython-lib <https://github.com/micropython/micropython-lib>`_
|
||||
which provides implementations for many modules from CPython's
|
||||
standard library. However, large subset of these modules required
|
||||
standard library. However, large subset of these modules require
|
||||
POSIX-like environment (Linux, MacOS, Windows may be partially
|
||||
supported), and thus would work or make sense only with MicroPython
|
||||
Unix port. Some subset of modules however usable for baremetal ports
|
||||
too.
|
||||
supported), and thus would work or make sense only with
|
||||
`MicroPython Unix port`. Some subset of modules is however usable
|
||||
for `baremetal` ports too.
|
||||
|
||||
Unlike monolithic :term:`CPython` stdlib, micropython-lib modules
|
||||
are intended to be installed individually - either using manual
|
||||
|
@ -68,7 +68,13 @@ Glossary
|
|||
MicroPython supports different :term:`boards <board>`, RTOSes,
|
||||
and OSes, and can be relatively easily adapted to new systems.
|
||||
MicroPython with support for a particular system is called a
|
||||
"port" to that system.
|
||||
"port" to that system. Different ports may have widely different
|
||||
functionality. This documentation is intended to be a reference
|
||||
of the generic APIs available across different ports ("MicroPython
|
||||
core"). Note that some ports may still omit some APIs described
|
||||
here (e.g. due to resource constraints). Any such differences,
|
||||
and port-specific extensions beyond MicroPython core functionality,
|
||||
would be described in the separate port-specific documentation.
|
||||
|
||||
MicroPython Unix port
|
||||
Unix port is one of the major :term:`MicroPython ports <MicroPython port>`.
|
||||
|
|
|
@ -21,6 +21,7 @@ This summarises the points detailed below and lists the principal recommendation
|
|||
|
||||
* Keep the code as short and simple as possible.
|
||||
* Avoid memory allocation: no appending to lists or insertion into dictionaries, no floating point.
|
||||
* Consider using ``micropython.schedule`` to work around the above constraint.
|
||||
* Where an ISR returns multiple bytes use a pre-allocated ``bytearray``. If multiple integers are to be
|
||||
shared between an ISR and the main program consider an array (``array.array``).
|
||||
* Where data is shared between the main program and an ISR, consider disabling interrupts prior to accessing
|
||||
|
@ -158,6 +159,26 @@ On platforms with hardware floating point (such as the Pyboard) the inline ARM T
|
|||
round this limitation. This is because the processor stores float values in a machine word; values can be shared
|
||||
between the ISR and main program code via an array of floats.
|
||||
|
||||
Using micropython.schedule
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This function enables an ISR to schedule a callback for execution "very soon". The callback is queued for
|
||||
execution which will take place at a time when the heap is not locked. Hence it can create Python objects
|
||||
and use floats. The callback is also guaranteed to run at a time when the main program has completed any
|
||||
update of Python objects, so the callback will not encounter partially updated objects.
|
||||
|
||||
Typical usage is to handle sensor hardware. The ISR acquires data from the hardware and enables it to
|
||||
issue a further interrupt. It then schedules a callback to process the data.
|
||||
|
||||
Scheduled callbacks should comply with the principles of interrupt handler design outlined below. This is to
|
||||
avoid problems resulting from I/O activity and the modification of shared data which can arise in any code
|
||||
which pre-empts the main program loop.
|
||||
|
||||
Execution time needs to be considered in relation to the frequency with which interrupts can occur. If an
|
||||
interrupt occurs while the previous callback is executing, a further instance of the callback will be queued
|
||||
for execution; this will run after the current instance has completed. A sustained high interrupt repetition
|
||||
rate therefore carries a risk of unconstrained queue growth and eventual failure with a ``RuntimeError``.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "pin.h"
|
||||
#include "led.h"
|
||||
|
|
|
@ -40,7 +40,7 @@ STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) {
|
|||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
if (bufinfo.len < 5) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small"));
|
||||
mp_raise_ValueError("buffer too small");
|
||||
}
|
||||
|
||||
// issue start command
|
||||
|
|
|
@ -32,7 +32,21 @@ class SSD1306:
|
|||
self.external_vcc = external_vcc
|
||||
self.pages = self.height // 8
|
||||
self.buffer = bytearray(self.pages * self.width)
|
||||
self.framebuf = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MVLSB)
|
||||
fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
|
||||
self.framebuf = fb
|
||||
# Provide methods for accessing FrameBuffer graphics primitives. This is a
|
||||
# workround because inheritance from a native class is currently unsupported.
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
self.fill = fb.fill
|
||||
self.pixel = fb.pixel
|
||||
self.hline = fb.hline
|
||||
self.vline = fb.vline
|
||||
self.line = fb.line
|
||||
self.rect = fb.rect
|
||||
self.fill_rect = fb.fill_rect
|
||||
self.text = fb.text
|
||||
self.scroll = fb.scroll
|
||||
self.blit = fb.blit
|
||||
self.poweron()
|
||||
self.init_display()
|
||||
|
||||
|
@ -88,18 +102,6 @@ class SSD1306:
|
|||
self.write_cmd(self.pages - 1)
|
||||
self.write_data(self.buffer)
|
||||
|
||||
def fill(self, col):
|
||||
self.framebuf.fill(col)
|
||||
|
||||
def pixel(self, x, y, col):
|
||||
self.framebuf.pixel(x, y, col)
|
||||
|
||||
def scroll(self, dx, dy):
|
||||
self.framebuf.scroll(dx, dy)
|
||||
|
||||
def text(self, string, x, y, col=1):
|
||||
self.framebuf.text(string, x, y, col)
|
||||
|
||||
|
||||
class SSD1306_I2C(SSD1306):
|
||||
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
|
||||
|
|
|
@ -49,10 +49,8 @@ STATIC uint8_t buf[SECTOR_SIZE];
|
|||
void mp_spiflash_init(mp_spiflash_t *self) {
|
||||
mp_hal_pin_write(self->cs, 1);
|
||||
mp_hal_pin_output(self->cs);
|
||||
mp_hal_pin_write(self->spi.sck, 0);
|
||||
mp_hal_pin_output(self->spi.sck);
|
||||
mp_hal_pin_output(self->spi.mosi);
|
||||
mp_hal_pin_input(self->spi.miso);
|
||||
const mp_machine_spi_p_t *protocol = self->spi->type->protocol;
|
||||
protocol->init(self->spi, 0, NULL, (mp_map_t*)&mp_const_empty_map);
|
||||
}
|
||||
|
||||
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
|
||||
|
@ -66,7 +64,8 @@ STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
|
|||
}
|
||||
|
||||
STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
mp_machine_soft_spi_transfer(&self->spi.base, len, src, dest);
|
||||
const mp_machine_spi_p_t *protocol = self->spi->type->protocol;
|
||||
protocol->transfer(self->spi, len, src, dest);
|
||||
}
|
||||
|
||||
STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
|
||||
typedef struct _mp_spiflash_t {
|
||||
mp_hal_pin_obj_t cs;
|
||||
// TODO replace with generic SPI object
|
||||
mp_machine_soft_spi_obj_t spi;
|
||||
mp_obj_base_t *spi; // object must have protocol pointing to mp_machine_spi_p_t struct
|
||||
} mp_spiflash_t;
|
||||
|
||||
void mp_spiflash_init(mp_spiflash_t *self);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""Test for nrf24l01 module."""
|
||||
|
||||
import struct
|
||||
import pyb
|
||||
from pyb import Pin, SPI
|
||||
import utime
|
||||
from machine import Pin, SPI
|
||||
from nrf24l01 import NRF24L01
|
||||
|
||||
pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2')
|
||||
|
@ -24,7 +24,7 @@ def master():
|
|||
while num_successes < num_needed and num_failures < num_needed:
|
||||
# stop listening and send packet
|
||||
nrf.stop_listening()
|
||||
millis = pyb.millis()
|
||||
millis = utime.ticks_ms()
|
||||
led_state = max(1, (led_state << 1) & 0x0f)
|
||||
print('sending:', millis, led_state)
|
||||
try:
|
||||
|
@ -36,10 +36,10 @@ def master():
|
|||
nrf.start_listening()
|
||||
|
||||
# wait for response, with 250ms timeout
|
||||
start_time = pyb.millis()
|
||||
start_time = utime.ticks_ms()
|
||||
timeout = False
|
||||
while not nrf.any() and not timeout:
|
||||
if pyb.elapsed_millis(start_time) > 250:
|
||||
if utime.ticks_diff(utime.ticks_ms(), start_time) > 250:
|
||||
timeout = True
|
||||
|
||||
if timeout:
|
||||
|
@ -51,11 +51,11 @@ def master():
|
|||
got_millis, = struct.unpack('i', nrf.recv())
|
||||
|
||||
# print response and round-trip delay
|
||||
print('got response:', got_millis, '(delay', pyb.millis() - got_millis, 'ms)')
|
||||
print('got response:', got_millis, '(delay', utime.ticks_diff(utime.ticks_ms(), got_millis), 'ms)')
|
||||
num_successes += 1
|
||||
|
||||
# delay then loop
|
||||
pyb.delay(250)
|
||||
utime.sleep_ms(250)
|
||||
|
||||
print('master finished sending; successes=%d, failures=%d' % (num_successes, num_failures))
|
||||
|
||||
|
@ -69,18 +69,19 @@ def slave():
|
|||
print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)')
|
||||
|
||||
while True:
|
||||
pyb.wfi()
|
||||
machine.idle()
|
||||
if nrf.any():
|
||||
while nrf.any():
|
||||
buf = nrf.recv()
|
||||
millis, led_state = struct.unpack('ii', buf)
|
||||
print('received:', millis, led_state)
|
||||
for i in range(4):
|
||||
if led_state & (1 << i):
|
||||
pyb.LED(i + 1).on()
|
||||
for led in leds:
|
||||
if led_state & 1:
|
||||
led.on()
|
||||
else:
|
||||
pyb.LED(i + 1).off()
|
||||
pyb.delay(15)
|
||||
led.off()
|
||||
led_state >>= 1
|
||||
utime.sleep_ms(15)
|
||||
|
||||
nrf.stop_listening()
|
||||
try:
|
||||
|
@ -90,6 +91,12 @@ def slave():
|
|||
print('sent response')
|
||||
nrf.start_listening()
|
||||
|
||||
try:
|
||||
import pyb
|
||||
leds = [pyb.LED(i + 1) for i in range(4)]
|
||||
except:
|
||||
leds = []
|
||||
|
||||
print('NRF24L01 test module loaded')
|
||||
print('NRF24L01 pinout for test:')
|
||||
print(' CE on Y4')
|
||||
|
|
237
esp8266/Makefile
237
esp8266/Makefile
|
@ -1,237 +0,0 @@
|
|||
include ../py/mkenv.mk
|
||||
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h
|
||||
|
||||
MICROPY_PY_USSL = 1
|
||||
MICROPY_SSL_AXTLS = 1
|
||||
MICROPY_FATFS = 1
|
||||
MICROPY_PY_BTREE = 1
|
||||
|
||||
FROZEN_DIR ?= scripts
|
||||
FROZEN_MPY_DIR ?= modules
|
||||
|
||||
# include py core make definitions
|
||||
include ../py/py.mk
|
||||
|
||||
FWBIN = $(BUILD)/firmware-combined.bin
|
||||
PORT ?= /dev/ttyACM0
|
||||
BAUD ?= 115200
|
||||
FLASH_MODE ?= qio
|
||||
FLASH_SIZE ?= detect
|
||||
CROSS_COMPILE = xtensa-lx106-elf-
|
||||
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
|
||||
|
||||
INC += -I.
|
||||
INC += -I..
|
||||
INC += -I../stmhal
|
||||
INC += -I$(BUILD)
|
||||
INC += -I$(ESP_SDK)/include
|
||||
|
||||
# UART for "os" messages. 0 is normal UART as used by MicroPython REPL,
|
||||
# 1 is debug UART (tx only), -1 to disable.
|
||||
UART_OS = 0
|
||||
|
||||
CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \
|
||||
-D__ets__ -DICACHE_FLASH \
|
||||
-fno-inline-functions \
|
||||
-Wl,-EL -mlongcalls -mtext-section-literals -mforce-l32 \
|
||||
-DLWIP_OPEN_SRC
|
||||
|
||||
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \
|
||||
$(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
|
||||
|
||||
LDSCRIPT = esp8266.ld
|
||||
LDFLAGS = -nostdlib -T $(LDSCRIPT) -Map=$(@:.elf=.map) --cref
|
||||
LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211 $(LDFLAGS_MOD)
|
||||
|
||||
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
|
||||
|
||||
# Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g
|
||||
COPT = -O0
|
||||
else
|
||||
CFLAGS += -fdata-sections -ffunction-sections
|
||||
COPT += -Os -DNDEBUG
|
||||
LDFLAGS += --gc-sections
|
||||
endif
|
||||
|
||||
SRC_C = \
|
||||
strtoll.c \
|
||||
main.c \
|
||||
help.c \
|
||||
esp_mphal.c \
|
||||
esp_init_data.c \
|
||||
gccollect.c \
|
||||
lexerstr32.c \
|
||||
uart.c \
|
||||
esppwm.c \
|
||||
espneopixel.c \
|
||||
espapa102.c \
|
||||
intr.c \
|
||||
modpyb.c \
|
||||
modmachine.c \
|
||||
machine_pin.c \
|
||||
machine_pwm.c \
|
||||
machine_rtc.c \
|
||||
machine_adc.c \
|
||||
machine_uart.c \
|
||||
machine_wdt.c \
|
||||
machine_hspi.c \
|
||||
modesp.c \
|
||||
modnetwork.c \
|
||||
modutime.c \
|
||||
moduos.c \
|
||||
ets_alt_task.c \
|
||||
fatfs_port.c \
|
||||
axtls_helpers.c \
|
||||
hspi.c \
|
||||
$(SRC_MOD)
|
||||
|
||||
EXTMOD_SRC_C = $(addprefix extmod/,\
|
||||
modlwip.c \
|
||||
modonewire.c \
|
||||
)
|
||||
|
||||
LIB_SRC_C = $(addprefix lib/,\
|
||||
libc/string0.c \
|
||||
libm/math.c \
|
||||
libm/fmodf.c \
|
||||
libm/nearbyintf.c \
|
||||
libm/ef_sqrt.c \
|
||||
libm/kf_rem_pio2.c \
|
||||
libm/kf_sin.c \
|
||||
libm/kf_cos.c \
|
||||
libm/kf_tan.c \
|
||||
libm/ef_rem_pio2.c \
|
||||
libm/sf_sin.c \
|
||||
libm/sf_cos.c \
|
||||
libm/sf_tan.c \
|
||||
libm/sf_frexp.c \
|
||||
libm/sf_modf.c \
|
||||
libm/sf_ldexp.c \
|
||||
libm/asinfacosf.c \
|
||||
libm/atanf.c \
|
||||
libm/atan2f.c \
|
||||
mp-readline/readline.c \
|
||||
netutils/netutils.c \
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/interrupt_char.c \
|
||||
utils/sys_stdio_mphal.c \
|
||||
)
|
||||
|
||||
ifeq ($(MICROPY_FATFS), 1)
|
||||
LIB_SRC_C += \
|
||||
lib/oofatfs/ff.c \
|
||||
lib/oofatfs/option/unicode.c
|
||||
endif
|
||||
|
||||
DRIVERS_SRC_C = $(addprefix drivers/,\
|
||||
dht/dht.c \
|
||||
)
|
||||
|
||||
SRC_S = \
|
||||
gchelper.s \
|
||||
|
||||
OBJ =
|
||||
OBJ += $(PY_O)
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
|
||||
#OBJ += $(BUILD)/pins_$(BOARD).o
|
||||
|
||||
# List of sources for qstr extraction
|
||||
SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
|
||||
# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
|
||||
SRC_QSTR_AUTO_DEPS +=
|
||||
|
||||
all: $(BUILD)/libaxtls.a $(FWBIN)
|
||||
|
||||
CONFVARS_FILE = $(BUILD)/confvars
|
||||
|
||||
ifeq ($(wildcard $(CONFVARS_FILE)),)
|
||||
$(shell $(MKDIR) -p $(BUILD))
|
||||
$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_DIR) $(UART_OS))
|
||||
$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
endif
|
||||
|
||||
$(BUILD)/uart.o: $(CONFVARS_FILE)
|
||||
|
||||
FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
|
||||
|
||||
.PHONY: deploy
|
||||
|
||||
deploy: $(BUILD)/firmware-combined.bin
|
||||
$(ECHO) "Writing $< to the board"
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $<
|
||||
|
||||
erase:
|
||||
$(ECHO) "Erase flash"
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) erase_flash
|
||||
|
||||
reset:
|
||||
echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT)
|
||||
|
||||
$(FWBIN): $(BUILD)/firmware.elf
|
||||
$(ECHO) "Create $@"
|
||||
$(Q)esptool.py elf2image $^
|
||||
$(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $@
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
512k:
|
||||
$(MAKE) LDSCRIPT=esp8266_512k.ld CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_512k.h>"' MICROPY_FATFS=0 MICROPY_PY_BTREE=0
|
||||
|
||||
ota:
|
||||
rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin
|
||||
$(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin
|
||||
|
||||
#MAKE_PINS = boards/make-pins.py
|
||||
#BOARD_PINS = boards/$(BOARD)/pins.csv
|
||||
#AF_FILE = boards/stm32f4xx_af.csv
|
||||
#PREFIX_FILE = boards/stm32f4xx_prefix.c
|
||||
#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
|
||||
#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
|
||||
#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
|
||||
#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
|
||||
#GEN_PINS_AF_PY = $(BUILD)/pins_af.py
|
||||
|
||||
# Making OBJ use an order-only depenedency on the generated pins.h file
|
||||
# has the side effect of making the pins.h file before we actually compile
|
||||
# any of the objects. The normal dependency generation will deal with the
|
||||
# case when pins.h is modified. But when it doesn't exist, we don't know
|
||||
# which source files might need it.
|
||||
#$(OBJ): | $(HEADER_BUILD)/pins.h
|
||||
|
||||
# Use a pattern rule here so that make will only call make-pins.py once to make
|
||||
# both pins_$(BOARD).c and pins.h
|
||||
#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
|
||||
# $(ECHO) "Create $@"
|
||||
# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
|
||||
#
|
||||
#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
|
||||
# $(call compile_c)
|
||||
|
||||
include ../py/mkrules.mk
|
||||
|
||||
axtls: $(BUILD)/libaxtls.a
|
||||
|
||||
$(BUILD)/libaxtls.a:
|
||||
cd ../lib/axtls; cp config/upyconfig config/.config
|
||||
cd ../lib/axtls; $(MAKE) oldconfig -B
|
||||
cd ../lib/axtls; $(MAKE) clean
|
||||
cd ../lib/axtls; $(MAKE) all CC="$(CC)" LD="$(LD)" AR="$(AR)" CFLAGS_EXTRA="$(CFLAGS_XTENSA) -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096"
|
||||
cp ../lib/axtls/_stage/libaxtls.a $@
|
||||
|
||||
clean-modules:
|
||||
git clean -f -d modules
|
||||
rm -f build/frozen*.c
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Paul Sokolovsky
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include "py/mphal.h"
|
||||
#include "py/gc.h"
|
||||
|
||||
// Functions for axTLS
|
||||
|
||||
void *malloc(size_t size) {
|
||||
return gc_alloc(size, false);
|
||||
}
|
||||
void free(void *ptr) {
|
||||
gc_free(ptr);
|
||||
}
|
||||
void *calloc(size_t nmemb, size_t size) {
|
||||
return m_malloc0(nmemb * size);
|
||||
}
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
return gc_realloc(ptr, size, true);
|
||||
}
|
||||
|
||||
#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
|
||||
#undef htonl
|
||||
#undef ntohl
|
||||
uint32_t ntohl(uint32_t netlong) {
|
||||
return PLATFORM_HTONL(netlong);
|
||||
}
|
||||
uint32_t htonl(uint32_t netlong) {
|
||||
return PLATFORM_HTONL(netlong);
|
||||
}
|
||||
|
||||
time_t time(time_t *t) {
|
||||
return mp_hal_ticks_ms() / 1000;
|
||||
}
|
||||
|
||||
time_t mktime(void *tm) {
|
||||
return 0;
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 <stdio.h>
|
||||
#include "ets_sys.h"
|
||||
#include "etshal.h"
|
||||
#include "uart.h"
|
||||
#include "esp_mphal.h"
|
||||
#include "user_interface.h"
|
||||
#include "ets_alt_task.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/misc.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
|
||||
STATIC byte input_buf_array[256];
|
||||
ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
|
||||
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
|
||||
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
|
||||
|
||||
void mp_hal_init(void) {
|
||||
//ets_wdt_disable(); // it's a pain while developing
|
||||
mp_hal_rtc_init();
|
||||
uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200);
|
||||
}
|
||||
|
||||
void mp_hal_delay_us(uint32_t us) {
|
||||
uint32_t start = system_get_time();
|
||||
while (system_get_time() - start < us) {
|
||||
ets_event_poll();
|
||||
}
|
||||
}
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
for (;;) {
|
||||
int c = ringbuf_get(&input_buf);
|
||||
if (c != -1) {
|
||||
return c;
|
||||
}
|
||||
#if 0
|
||||
// Idles CPU but need more testing before enabling
|
||||
if (!ets_loop_iter()) {
|
||||
asm("waiti 0");
|
||||
}
|
||||
#else
|
||||
mp_hal_delay_us(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_char(char c) {
|
||||
uart_tx_one_char(UART0, c);
|
||||
mp_uos_dupterm_tx_strn(&c, 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void mp_hal_debug_str(const char *str) {
|
||||
while (*str) {
|
||||
uart_tx_one_char(UART0, *str++);
|
||||
}
|
||||
uart_flush(UART0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mp_hal_stdout_tx_str(const char *str) {
|
||||
while (*str) {
|
||||
mp_hal_stdout_tx_char(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
|
||||
while (len--) {
|
||||
mp_hal_stdout_tx_char(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
|
||||
while (len--) {
|
||||
if (*str == '\n') {
|
||||
mp_hal_stdout_tx_char('\r');
|
||||
}
|
||||
mp_hal_stdout_tx_char(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
|
||||
(void)env;
|
||||
while (len--) {
|
||||
if (*str == '\n') {
|
||||
uart_tx_one_char(UART0, '\r');
|
||||
}
|
||||
uart_tx_one_char(UART0, *str++);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_ms(void) {
|
||||
return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_get_time()) / 1000;
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_us(void) {
|
||||
return system_get_time();
|
||||
}
|
||||
|
||||
void mp_hal_delay_ms(uint32_t delay) {
|
||||
mp_hal_delay_us(delay * 1000);
|
||||
}
|
||||
|
||||
void ets_event_poll(void) {
|
||||
ets_loop_iter();
|
||||
mp_handle_pending();
|
||||
}
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||
printf("assert:%s:%d:%s: %s\n", file, line, func, expr);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError,
|
||||
"C-level assert"));
|
||||
}
|
||||
|
||||
void mp_hal_signal_input(void) {
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
system_os_post(UART_TASK_ID, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int call_dupterm_read(void) {
|
||||
if (MP_STATE_PORT(term_obj) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_obj_t readinto_m[3];
|
||||
mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_readinto, readinto_m);
|
||||
readinto_m[2] = MP_STATE_PORT(dupterm_arr_obj);
|
||||
mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
|
||||
if (res == mp_const_none) {
|
||||
nlr_pop();
|
||||
return -2;
|
||||
}
|
||||
if (res == MP_OBJ_NEW_SMALL_INT(0)) {
|
||||
mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
|
||||
nlr_pop();
|
||||
return -1;
|
||||
}
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
|
||||
nlr_pop();
|
||||
if (*(byte*)bufinfo.buf == mp_interrupt_char) {
|
||||
mp_keyboard_interrupt();
|
||||
return -2;
|
||||
}
|
||||
return *(byte*)bufinfo.buf;
|
||||
} else {
|
||||
mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
STATIC void dupterm_task_handler(os_event_t *evt) {
|
||||
static byte lock;
|
||||
if (lock) {
|
||||
return;
|
||||
}
|
||||
lock = 1;
|
||||
while (1) {
|
||||
int c = call_dupterm_read();
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
ringbuf_put(&input_buf, c);
|
||||
}
|
||||
mp_hal_signal_input();
|
||||
lock = 0;
|
||||
}
|
||||
|
||||
STATIC os_event_t dupterm_evt_queue[4];
|
||||
|
||||
void dupterm_task_init() {
|
||||
system_os_task(dupterm_task_handler, DUPTERM_TASK_ID, dupterm_evt_queue, MP_ARRAY_SIZE(dupterm_evt_queue));
|
||||
}
|
||||
|
||||
void mp_hal_signal_dupterm_input(void) {
|
||||
system_os_post(DUPTERM_TASK_ID, 0, 0);
|
||||
}
|
||||
|
||||
// Get pointer to esf_buf bookkeeping structure
|
||||
void *ets_get_esf_buf_ctlblk(void) {
|
||||
// Get literal ptr before start of esf_rx_buf_alloc func
|
||||
extern void *esf_rx_buf_alloc();
|
||||
return ((void**)esf_rx_buf_alloc)[-1];
|
||||
}
|
||||
|
||||
// Get number of esf_buf free buffers of given type, as encoded by index
|
||||
// idx 0 corresponds to buf types 1, 2; 1 - 4; 2 - 5; 3 - 7; 4 - 8
|
||||
// Only following buf types appear to be used:
|
||||
// 1 - tx buffer, 5 - management frame tx buffer; 8 - rx buffer
|
||||
int ets_esf_free_bufs(int idx) {
|
||||
uint32_t *p = ets_get_esf_buf_ctlblk();
|
||||
uint32_t *b = (uint32_t*)p[idx];
|
||||
int cnt = 0;
|
||||
while (b) {
|
||||
b = (uint32_t*)b[0x20 / 4];
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
extern int mp_stream_errno;
|
||||
int *__errno() {
|
||||
return &mp_stream_errno;
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 "py/ringbuf.h"
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "xtirq.h"
|
||||
|
||||
void mp_keyboard_interrupt(void);
|
||||
|
||||
struct _mp_print_t;
|
||||
// Structure for UART-only output via mp_printf()
|
||||
extern const struct _mp_print_t mp_debug_print;
|
||||
|
||||
extern ringbuf_t input_buf;
|
||||
// Call this after putting data to input_buf
|
||||
void mp_hal_signal_input(void);
|
||||
// Call this when data is available in dupterm object
|
||||
void mp_hal_signal_dupterm_input(void);
|
||||
|
||||
void mp_hal_init(void);
|
||||
void mp_hal_rtc_init(void);
|
||||
|
||||
uint32_t mp_hal_ticks_us(void);
|
||||
__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void mp_hal_delay_us(uint32_t);
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
uint32_t mp_hal_get_cpu_freq(void);
|
||||
|
||||
#define UART_TASK_ID 0
|
||||
#define DUPTERM_TASK_ID 1
|
||||
void uart_task_init();
|
||||
void dupterm_task_init();
|
||||
|
||||
void ets_event_poll(void);
|
||||
#define ETS_POLL_WHILE(cond) { while (cond) ets_event_poll(); }
|
||||
|
||||
// needed for machine.I2C
|
||||
#include "osapi.h"
|
||||
#define mp_hal_delay_us_fast(us) os_delay_us(us)
|
||||
|
||||
#define mp_hal_quiet_timing_enter() disable_irq()
|
||||
#define mp_hal_quiet_timing_exit(irq_state) enable_irq(irq_state)
|
||||
|
||||
// C-level pin HAL
|
||||
#include "etshal.h"
|
||||
#include "gpio.h"
|
||||
#include "esp8266/modmachine.h"
|
||||
#define MP_HAL_PIN_FMT "%u"
|
||||
#define mp_hal_pin_obj_t uint32_t
|
||||
#define mp_hal_get_pin_obj(o) mp_obj_get_pin(o)
|
||||
#define mp_hal_pin_name(p) (p)
|
||||
void mp_hal_pin_input(mp_hal_pin_obj_t pin);
|
||||
void mp_hal_pin_output(mp_hal_pin_obj_t pin);
|
||||
void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin);
|
||||
#define mp_hal_pin_od_low(p) do { \
|
||||
if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); } \
|
||||
else { gpio_output_set(0, 1 << (p), 1 << (p), 0); } \
|
||||
} while (0)
|
||||
#define mp_hal_pin_od_high(p) do { \
|
||||
if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \
|
||||
else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \
|
||||
} while (0)
|
||||
#define mp_hal_pin_read(p) pin_get(p)
|
||||
#define mp_hal_pin_write(p, v) pin_set((p), (v))
|
||||
|
||||
void *ets_get_esf_buf_ctlblk(void);
|
||||
int ets_esf_free_bufs(int idx);
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2016 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 "py/builtin.h"
|
||||
|
||||
const char *esp_help_text =
|
||||
"Welcome to MicroPython!\n"
|
||||
"\n"
|
||||
"For online docs please visit http://docs.micropython.org/en/latest/esp8266/ .\n"
|
||||
"For diagnostic information to include in bug reports execute 'import port_diag'.\n"
|
||||
"\n"
|
||||
"Basic WiFi configuration:\n"
|
||||
"\n"
|
||||
"import network\n"
|
||||
"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
|
||||
"sta_if.scan() # Scan for available access points\n"
|
||||
"sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n"
|
||||
"sta_if.isconnected() # Check for successful connection\n"
|
||||
"# Change name/password of ESP8266's AP:\n"
|
||||
"ap_if = network.WLAN(network.AP_IF)\n"
|
||||
"ap_if.config(essid=\"<AP_NAME>\", authmode=network.AUTH_WPA_WPA2_PSK, password=\"<password>\")\n"
|
||||
"\n"
|
||||
"Control commands:\n"
|
||||
" CTRL-A -- on a blank line, enter raw REPL mode\n"
|
||||
" CTRL-B -- on a blank line, enter normal REPL mode\n"
|
||||
" CTRL-C -- interrupt a running program\n"
|
||||
" CTRL-D -- on a blank line, do a soft reset of the board\n"
|
||||
" CTRL-E -- on a blank line, enter paste mode\n"
|
||||
"\n"
|
||||
"For further help on a specific object, type help(obj)\n"
|
||||
;
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Josef Gajdusek
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
const mp_obj_type_t pyb_adc_type;
|
||||
|
||||
typedef struct _pyb_adc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
bool isvdd;
|
||||
} pyb_adc_obj_t;
|
||||
|
||||
STATIC pyb_adc_obj_t pyb_adc_vdd3 = {{&pyb_adc_type}, true};
|
||||
STATIC pyb_adc_obj_t pyb_adc_adc = {{&pyb_adc_type}, false};
|
||||
|
||||
STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw,
|
||||
const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
mp_int_t chn = mp_obj_get_int(args[0]);
|
||||
|
||||
switch (chn) {
|
||||
case 0:
|
||||
return &pyb_adc_adc;
|
||||
case 1:
|
||||
return &pyb_adc_vdd3;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"not a valid ADC Channel: %d", chn));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *adc = self_in;
|
||||
|
||||
if (adc->isvdd) {
|
||||
return mp_obj_new_int(system_get_vdd33());
|
||||
} else {
|
||||
return mp_obj_new_int(system_adc_read());
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_adc_read_obj, pyb_adc_read);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_adc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_adc_read_obj) }
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_adc_locals_dict, pyb_adc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_adc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.make_new = pyb_adc_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_adc_locals_dict,
|
||||
};
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "etshal.h"
|
||||
#include "ets_alt_task.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "modmachine.h"
|
||||
#include "hspi.h"
|
||||
|
||||
typedef struct _machine_hspi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t baudrate;
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
} machine_hspi_obj_t;
|
||||
|
||||
STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
(void)self_in;
|
||||
|
||||
if (dest == NULL) {
|
||||
// fast case when we only need to write data
|
||||
size_t chunk_size = 1024;
|
||||
size_t count = len / chunk_size;
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
for (size_t k = 0; k < chunk_size; ++k) {
|
||||
spi_tx8fast(HSPI, src[i]);
|
||||
++i;
|
||||
}
|
||||
ets_loop_iter();
|
||||
}
|
||||
while (i < len) {
|
||||
spi_tx8fast(HSPI, src[i]);
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
// we need to read and write data
|
||||
|
||||
// Process data in chunks, let the pending tasks run in between
|
||||
size_t chunk_size = 1024; // TODO this should depend on baudrate
|
||||
size_t count = len / chunk_size;
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
for (size_t k = 0; k < chunk_size; ++k) {
|
||||
dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
|
||||
++i;
|
||||
}
|
||||
ets_loop_iter();
|
||||
}
|
||||
while (i < len) {
|
||||
dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for HSPI
|
||||
|
||||
STATIC void machine_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
machine_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "HSPI(id=1, baudrate=%u, polarity=%u, phase=%u)",
|
||||
self->baudrate, self->polarity, self->phase);
|
||||
}
|
||||
|
||||
STATIC void machine_hspi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
machine_hspi_obj_t *self = (machine_hspi_obj_t*)self_in;
|
||||
|
||||
enum { ARG_baudrate, ARG_polarity, ARG_phase };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
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);
|
||||
|
||||
if (args[ARG_baudrate].u_int != -1) {
|
||||
self->baudrate = args[ARG_baudrate].u_int;
|
||||
}
|
||||
if (args[ARG_polarity].u_int != -1) {
|
||||
self->polarity = args[ARG_polarity].u_int;
|
||||
}
|
||||
if (args[ARG_phase].u_int != -1) {
|
||||
self->phase = args[ARG_phase].u_int;
|
||||
}
|
||||
if (self->baudrate == 80000000L) {
|
||||
// Special case for full speed.
|
||||
spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV);
|
||||
spi_clock(HSPI, 0, 0);
|
||||
} else if (self->baudrate > 40000000L) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"impossible baudrate"));
|
||||
} else {
|
||||
uint32_t divider = 40000000L / self->baudrate;
|
||||
uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1);
|
||||
uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even
|
||||
if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"impossible baudrate"));
|
||||
}
|
||||
self->baudrate = 80000000L / (prediv * cntdiv);
|
||||
spi_init_gpio(HSPI, SPI_CLK_USE_DIV);
|
||||
spi_clock(HSPI, prediv, cntdiv);
|
||||
}
|
||||
// TODO: Make the byte order configurable too (discuss param names)
|
||||
spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE | SPI_USR_MISO |
|
||||
SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY);
|
||||
// Clear Dual or Quad lines transmission mode
|
||||
CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_QIO_MODE | SPI_DIO_MODE |
|
||||
SPI_DOUT_MODE | SPI_QOUT_MODE);
|
||||
spi_mode(HSPI, self->phase, self->polarity);
|
||||
}
|
||||
|
||||
mp_obj_t machine_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// args[0] holds the id of the peripheral
|
||||
if (args[0] != MP_OBJ_NEW_SMALL_INT(1)) {
|
||||
// FlashROM is on SPI0, so far we don't support its usage
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
|
||||
machine_hspi_obj_t *self = m_new_obj(machine_hspi_obj_t);
|
||||
self->base.type = &machine_hspi_type;
|
||||
// set defaults
|
||||
self->baudrate = 80000000L;
|
||||
self->polarity = 0;
|
||||
self->phase = 0;
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
machine_hspi_init((mp_obj_base_t*)self, n_args - 1, args + 1, &kw_args);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC const mp_machine_spi_p_t machine_hspi_p = {
|
||||
.init = machine_hspi_init,
|
||||
.transfer = machine_hspi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t machine_hspi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HSPI,
|
||||
.print = machine_hspi_print,
|
||||
.make_new = mp_machine_spi_make_new, // delegate to master constructor
|
||||
.protocol = &machine_hspi_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict,
|
||||
};
|
|
@ -1,519 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2015 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "etshal.h"
|
||||
#include "c_types.h"
|
||||
#include "user_interface.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/virtpin.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
#define GET_TRIGGER(phys_port) \
|
||||
GPIO_PIN_INT_TYPE_GET(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)))
|
||||
#define SET_TRIGGER(phys_port, trig) \
|
||||
(GPIO_REG_WRITE(GPIO_PIN_ADDR(phys_port), \
|
||||
(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)) & ~GPIO_PIN_INT_TYPE_MASK) \
|
||||
| GPIO_PIN_INT_TYPE_SET(trig))) \
|
||||
|
||||
#define GPIO_MODE_INPUT (0)
|
||||
#define GPIO_MODE_OUTPUT (1)
|
||||
#define GPIO_MODE_OPEN_DRAIN (2) // synthesised
|
||||
#define GPIO_PULL_NONE (0)
|
||||
#define GPIO_PULL_UP (1)
|
||||
// Removed in SDK 1.1.0
|
||||
//#define GPIO_PULL_DOWN (2)
|
||||
|
||||
typedef struct _pin_irq_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint16_t phys_port;
|
||||
} pin_irq_obj_t;
|
||||
|
||||
const pyb_pin_obj_t pyb_pin_obj[16 + 1] = {
|
||||
{{&pyb_pin_type}, 0, FUNC_GPIO0, PERIPHS_IO_MUX_GPIO0_U},
|
||||
{{&pyb_pin_type}, 1, FUNC_GPIO1, PERIPHS_IO_MUX_U0TXD_U},
|
||||
{{&pyb_pin_type}, 2, FUNC_GPIO2, PERIPHS_IO_MUX_GPIO2_U},
|
||||
{{&pyb_pin_type}, 3, FUNC_GPIO3, PERIPHS_IO_MUX_U0RXD_U},
|
||||
{{&pyb_pin_type}, 4, FUNC_GPIO4, PERIPHS_IO_MUX_GPIO4_U},
|
||||
{{&pyb_pin_type}, 5, FUNC_GPIO5, PERIPHS_IO_MUX_GPIO5_U},
|
||||
{{NULL}, 0, 0, 0},
|
||||
{{NULL}, 0, 0, 0},
|
||||
{{NULL}, 0, 0, 0},
|
||||
{{&pyb_pin_type}, 9, FUNC_GPIO9, PERIPHS_IO_MUX_SD_DATA2_U},
|
||||
{{&pyb_pin_type}, 10, FUNC_GPIO10, PERIPHS_IO_MUX_SD_DATA3_U},
|
||||
{{NULL}, 0, 0, 0},
|
||||
{{&pyb_pin_type}, 12, FUNC_GPIO12, PERIPHS_IO_MUX_MTDI_U},
|
||||
{{&pyb_pin_type}, 13, FUNC_GPIO13, PERIPHS_IO_MUX_MTCK_U},
|
||||
{{&pyb_pin_type}, 14, FUNC_GPIO14, PERIPHS_IO_MUX_MTMS_U},
|
||||
{{&pyb_pin_type}, 15, FUNC_GPIO15, PERIPHS_IO_MUX_MTDO_U},
|
||||
// GPIO16 is special, belongs to different register set, and
|
||||
// otherwise handled specially.
|
||||
{{&pyb_pin_type}, 16, -1, -1},
|
||||
};
|
||||
|
||||
STATIC uint8_t pin_mode[16 + 1];
|
||||
|
||||
// forward declaration
|
||||
STATIC const pin_irq_obj_t pin_irq_obj[16];
|
||||
|
||||
// whether the irq is hard or soft
|
||||
STATIC bool pin_irq_is_hard[16];
|
||||
|
||||
void pin_init0(void) {
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
ETS_GPIO_INTR_ATTACH(pin_intr_handler_iram, NULL);
|
||||
// disable all interrupts
|
||||
memset(&MP_STATE_PORT(pin_irq_handler)[0], 0, 16 * sizeof(mp_obj_t));
|
||||
memset(pin_irq_is_hard, 0, sizeof(pin_irq_is_hard));
|
||||
for (int p = 0; p < 16; ++p) {
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << p);
|
||||
SET_TRIGGER(p, 0);
|
||||
}
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void pin_intr_handler(uint32_t status) {
|
||||
mp_sched_lock();
|
||||
gc_lock();
|
||||
status &= 0xffff;
|
||||
for (int p = 0; status; ++p, status >>= 1) {
|
||||
if (status & 1) {
|
||||
mp_obj_t handler = MP_STATE_PORT(pin_irq_handler)[p];
|
||||
if (handler != MP_OBJ_NULL) {
|
||||
if (pin_irq_is_hard[p]) {
|
||||
mp_call_function_1_protected(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
|
||||
} else {
|
||||
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gc_unlock();
|
||||
mp_sched_unlock();
|
||||
}
|
||||
|
||||
pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) {
|
||||
if (mp_obj_get_type(pin_in) != &pyb_pin_type) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting a pin"));
|
||||
}
|
||||
pyb_pin_obj_t *self = pin_in;
|
||||
return self;
|
||||
}
|
||||
|
||||
uint mp_obj_get_pin(mp_obj_t pin_in) {
|
||||
return mp_obj_get_pin_obj(pin_in)->phys_port;
|
||||
}
|
||||
|
||||
void mp_hal_pin_input(mp_hal_pin_obj_t pin_id) {
|
||||
pin_mode[pin_id] = GPIO_MODE_INPUT;
|
||||
if (pin_id == 16) {
|
||||
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
|
||||
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
|
||||
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input
|
||||
} else {
|
||||
const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
|
||||
PIN_FUNC_SELECT(self->periph, self->func);
|
||||
PIN_PULLUP_DIS(self->periph);
|
||||
gpio_output_set(0, 0, 0, 1 << self->phys_port);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_pin_output(mp_hal_pin_obj_t pin_id) {
|
||||
pin_mode[pin_id] = GPIO_MODE_OUTPUT;
|
||||
if (pin_id == 16) {
|
||||
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
|
||||
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
|
||||
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); // output
|
||||
} else {
|
||||
const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
|
||||
PIN_FUNC_SELECT(self->periph, self->func);
|
||||
PIN_PULLUP_DIS(self->periph);
|
||||
gpio_output_set(0, 0, 1 << self->phys_port, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) {
|
||||
const pyb_pin_obj_t *pin = &pyb_pin_obj[pin_id];
|
||||
|
||||
if (pin->phys_port == 16) {
|
||||
// configure GPIO16 as input with output register holding 0
|
||||
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
|
||||
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
|
||||
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1)); // out=0
|
||||
return;
|
||||
}
|
||||
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
PIN_FUNC_SELECT(pin->periph, pin->func);
|
||||
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)),
|
||||
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)))
|
||||
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain
|
||||
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,
|
||||
GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << pin->phys_port));
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
}
|
||||
|
||||
int pin_get(uint pin) {
|
||||
if (pin == 16) {
|
||||
return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1;
|
||||
}
|
||||
return GPIO_INPUT_GET(pin);
|
||||
}
|
||||
|
||||
void pin_set(uint pin, int value) {
|
||||
if (pin == 16) {
|
||||
int out_en = (pin_mode[pin] == GPIO_MODE_OUTPUT);
|
||||
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
|
||||
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
|
||||
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | out_en);
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1) | value);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t enable = 0;
|
||||
uint32_t disable = 0;
|
||||
switch (pin_mode[pin]) {
|
||||
case GPIO_MODE_INPUT:
|
||||
value = -1;
|
||||
disable = 1;
|
||||
break;
|
||||
|
||||
case GPIO_MODE_OUTPUT:
|
||||
enable = 1;
|
||||
break;
|
||||
|
||||
case GPIO_MODE_OPEN_DRAIN:
|
||||
if (value == -1) {
|
||||
return;
|
||||
} else if (value == 0) {
|
||||
enable = 1;
|
||||
} else {
|
||||
value = -1;
|
||||
disable = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
enable <<= pin;
|
||||
disable <<= pin;
|
||||
if (value == -1) {
|
||||
gpio_output_set(0, 0, enable, disable);
|
||||
} else {
|
||||
gpio_output_set(value << pin, (1 - value) << pin, enable, disable);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
|
||||
// pin name
|
||||
mp_printf(print, "Pin(%u)", self->phys_port);
|
||||
}
|
||||
|
||||
// pin.init(mode, pull=None, *, value)
|
||||
STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_mode, ARG_pull, ARG_value };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
};
|
||||
|
||||
// parse args
|
||||
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);
|
||||
|
||||
// get io mode
|
||||
uint mode = args[ARG_mode].u_int;
|
||||
|
||||
// get pull mode
|
||||
uint pull = GPIO_PULL_NONE;
|
||||
if (args[ARG_pull].u_obj != mp_const_none) {
|
||||
pull = mp_obj_get_int(args[ARG_pull].u_obj);
|
||||
}
|
||||
|
||||
// get initial value
|
||||
int value;
|
||||
if (args[ARG_value].u_obj == MP_OBJ_NULL) {
|
||||
value = -1;
|
||||
} else {
|
||||
value = mp_obj_is_true(args[ARG_value].u_obj);
|
||||
}
|
||||
|
||||
// save the mode
|
||||
pin_mode[self->phys_port] = mode;
|
||||
|
||||
// configure the GPIO as requested
|
||||
if (self->phys_port == 16) {
|
||||
// only pull-down seems to be supported by the hardware, and
|
||||
// we only expose pull-up behaviour in software
|
||||
if (pull != GPIO_PULL_NONE) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin(16) doesn't support pull"));
|
||||
}
|
||||
} else {
|
||||
PIN_FUNC_SELECT(self->periph, self->func);
|
||||
#if 0
|
||||
// Removed in SDK 1.1.0
|
||||
if ((pull & GPIO_PULL_DOWN) == 0) {
|
||||
PIN_PULLDWN_DIS(self->periph);
|
||||
}
|
||||
#endif
|
||||
if ((pull & GPIO_PULL_UP) == 0) {
|
||||
PIN_PULLUP_DIS(self->periph);
|
||||
}
|
||||
#if 0
|
||||
if ((pull & GPIO_PULL_DOWN) != 0) {
|
||||
PIN_PULLDWN_EN(self->periph);
|
||||
}
|
||||
#endif
|
||||
if ((pull & GPIO_PULL_UP) != 0) {
|
||||
PIN_PULLUP_EN(self->periph);
|
||||
}
|
||||
}
|
||||
|
||||
pin_set(self->phys_port, value);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// constructor(id, ...)
|
||||
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// get the wanted pin object
|
||||
int wanted_pin = mp_obj_get_int(args[0]);
|
||||
pyb_pin_obj_t *pin = NULL;
|
||||
if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
|
||||
pin = (pyb_pin_obj_t*)&pyb_pin_obj[wanted_pin];
|
||||
}
|
||||
if (pin == NULL || pin->base.type == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
|
||||
}
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// pin mode given, so configure this GPIO
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
|
||||
return (mp_obj_t)pin;
|
||||
}
|
||||
|
||||
// fast method for getting/setting pin value
|
||||
STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
if (n_args == 0) {
|
||||
// get pin
|
||||
return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port));
|
||||
} else {
|
||||
// set pin
|
||||
pin_set(self->phys_port, mp_obj_is_true(args[0]));
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// pin.init(mode, pull)
|
||||
STATIC mp_obj_t pyb_pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return pyb_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_init_obj, 1, pyb_pin_obj_init);
|
||||
|
||||
// pin.value([value])
|
||||
STATIC mp_obj_t pyb_pin_value(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
return pyb_pin_call(args[0], n_args - 1, 0, args + 1);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pin_value_obj, 1, 2, pyb_pin_value);
|
||||
|
||||
STATIC mp_obj_t pyb_pin_off(mp_obj_t self_in) {
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
pin_set(self->phys_port, 0);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_off_obj, pyb_pin_off);
|
||||
|
||||
STATIC mp_obj_t pyb_pin_on(mp_obj_t self_in) {
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
pin_set(self->phys_port, 1);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_on_obj, pyb_pin_on);
|
||||
|
||||
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
|
||||
STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_handler, ARG_trigger, ARG_hard };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
|
||||
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
pyb_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
if (self->phys_port >= 16) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities"));
|
||||
}
|
||||
|
||||
if (n_args > 1 || kw_args->used != 0) {
|
||||
// configure irq
|
||||
mp_obj_t handler = args[ARG_handler].u_obj;
|
||||
uint32_t trigger = args[ARG_trigger].u_int;
|
||||
if (handler == mp_const_none) {
|
||||
handler = MP_OBJ_NULL;
|
||||
trigger = 0;
|
||||
}
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler;
|
||||
pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool;
|
||||
SET_TRIGGER(self->phys_port, trigger);
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port);
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
}
|
||||
|
||||
// return the irq object
|
||||
return MP_OBJ_FROM_PTR(&pin_irq_obj[self->phys_port]);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_irq_obj, 1, pyb_pin_irq);
|
||||
|
||||
STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||
STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
(void)errcode;
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
|
||||
switch (request) {
|
||||
case MP_PIN_READ: {
|
||||
return pin_get(self->phys_port);
|
||||
}
|
||||
case MP_PIN_WRITE: {
|
||||
pin_set(self->phys_port, arg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_pin_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pin_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_pin_value_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pyb_pin_off_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pyb_pin_on_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_pin_irq_obj) },
|
||||
|
||||
// class constants
|
||||
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUTPUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OPEN_DRAIN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
|
||||
//{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
|
||||
|
||||
// IRQ triggers, can be or'd together
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_pin_locals_dict, pyb_pin_locals_dict_table);
|
||||
|
||||
STATIC const mp_pin_p_t pin_pin_p = {
|
||||
.ioctl = pin_ioctl,
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_pin_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Pin,
|
||||
.print = pyb_pin_print,
|
||||
.make_new = mp_pin_make_new,
|
||||
.call = pyb_pin_call,
|
||||
.protocol = &pin_pin_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_pin_locals_dict,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// Pin IRQ object
|
||||
|
||||
STATIC const mp_obj_type_t pin_irq_type;
|
||||
|
||||
STATIC const pin_irq_obj_t pin_irq_obj[16] = {
|
||||
{{&pin_irq_type}, 0},
|
||||
{{&pin_irq_type}, 1},
|
||||
{{&pin_irq_type}, 2},
|
||||
{{&pin_irq_type}, 3},
|
||||
{{&pin_irq_type}, 4},
|
||||
{{&pin_irq_type}, 5},
|
||||
{{&pin_irq_type}, 6},
|
||||
{{&pin_irq_type}, 7},
|
||||
{{&pin_irq_type}, 8},
|
||||
{{&pin_irq_type}, 9},
|
||||
{{&pin_irq_type}, 10},
|
||||
{{&pin_irq_type}, 11},
|
||||
{{&pin_irq_type}, 12},
|
||||
{{&pin_irq_type}, 13},
|
||||
{{&pin_irq_type}, 14},
|
||||
{{&pin_irq_type}, 15},
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
pin_irq_obj_t *self = self_in;
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
pin_intr_handler(1 << self->phys_port);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
|
||||
pin_irq_obj_t *self = args[0];
|
||||
uint32_t orig_trig = GET_TRIGGER(self->phys_port);
|
||||
if (n_args == 2) {
|
||||
// set trigger
|
||||
SET_TRIGGER(self->phys_port, mp_obj_get_int(args[1]));
|
||||
}
|
||||
// return original trigger value
|
||||
return MP_OBJ_NEW_SMALL_INT(orig_trig);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pin_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_IRQ,
|
||||
.call = pin_irq_call,
|
||||
.locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict,
|
||||
};
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esppwm.h"
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
typedef struct _pyb_pwm_obj_t {
|
||||
mp_obj_base_t base;
|
||||
pyb_pin_obj_t *pin;
|
||||
uint8_t active;
|
||||
uint8_t channel;
|
||||
} pyb_pwm_obj_t;
|
||||
|
||||
STATIC bool pwm_inited = false;
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for PWM
|
||||
|
||||
STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "PWM(%u", self->pin->phys_port);
|
||||
if (self->active) {
|
||||
mp_printf(print, ", freq=%u, duty=%u",
|
||||
pwm_get_freq(self->channel), pwm_get_duty(self->channel));
|
||||
}
|
||||
mp_printf(print, ")");
|
||||
}
|
||||
|
||||
STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_freq, ARG_duty };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
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);
|
||||
|
||||
int channel = pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
|
||||
if (channel == -1) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"PWM not supported on pin %d", self->pin->phys_port));
|
||||
}
|
||||
|
||||
self->channel = channel;
|
||||
self->active = 1;
|
||||
if (args[ARG_freq].u_int != -1) {
|
||||
pwm_set_freq(args[ARG_freq].u_int, self->channel);
|
||||
}
|
||||
if (args[ARG_duty].u_int != -1) {
|
||||
pwm_set_duty(args[ARG_duty].u_int, self->channel);
|
||||
}
|
||||
|
||||
pwm_start();
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]);
|
||||
|
||||
// create PWM object from the given pin
|
||||
pyb_pwm_obj_t *self = m_new_obj(pyb_pwm_obj_t);
|
||||
self->base.type = &pyb_pwm_type;
|
||||
self->pin = pin;
|
||||
self->active = 0;
|
||||
self->channel = -1;
|
||||
|
||||
// start the PWM subsystem if it's not already running
|
||||
if (!pwm_inited) {
|
||||
pwm_init();
|
||||
pwm_inited = true;
|
||||
}
|
||||
|
||||
// start the PWM running for this channel
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
pyb_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pwm_init_obj, 1, pyb_pwm_init);
|
||||
|
||||
STATIC mp_obj_t pyb_pwm_deinit(mp_obj_t self_in) {
|
||||
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
pwm_delete(self->channel);
|
||||
self->active = 0;
|
||||
pwm_start();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pwm_deinit_obj, pyb_pwm_deinit);
|
||||
|
||||
STATIC mp_obj_t pyb_pwm_freq(size_t n_args, const mp_obj_t *args) {
|
||||
//pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0));
|
||||
} else {
|
||||
// set
|
||||
pwm_set_freq(mp_obj_get_int(args[1]), 0);
|
||||
pwm_start();
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_freq_obj, 1, 2, pyb_pwm_freq);
|
||||
|
||||
STATIC mp_obj_t pyb_pwm_duty(size_t n_args, const mp_obj_t *args) {
|
||||
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
if (!self->active) {
|
||||
pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
|
||||
self->active = 1;
|
||||
}
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel));
|
||||
} else {
|
||||
// set
|
||||
pwm_set_duty(mp_obj_get_int(args[1]), self->channel);
|
||||
pwm_start();
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_duty_obj, 1, 2, pyb_pwm_duty);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_pwm_locals_dict, pyb_pwm_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_pwm_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_PWM,
|
||||
.print = pyb_pwm_print,
|
||||
.make_new = pyb_pwm_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_pwm_locals_dict,
|
||||
};
|
|
@ -1,273 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Josef Gajdusek
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "user_interface.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
#define MEM_MAGIC 0x75507921
|
||||
#define MEM_DELTA_ADDR 64
|
||||
#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2)
|
||||
#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1)
|
||||
#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1)
|
||||
#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1)
|
||||
#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4)
|
||||
|
||||
// singleton RTC object
|
||||
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
|
||||
|
||||
// ALARM0 state
|
||||
uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants
|
||||
uint64_t pyb_rtc_alarm0_expiry; // in microseconds
|
||||
|
||||
// RTC overflow checking
|
||||
STATIC uint32_t rtc_last_ticks;
|
||||
|
||||
void mp_hal_rtc_init(void) {
|
||||
uint32_t magic;
|
||||
|
||||
system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
|
||||
if (magic != MEM_MAGIC) {
|
||||
magic = MEM_MAGIC;
|
||||
system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
|
||||
uint32_t cal = system_rtc_clock_cali_proc();
|
||||
int64_t delta = 0;
|
||||
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
|
||||
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
|
||||
uint32_t len = 0;
|
||||
system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));
|
||||
}
|
||||
// system_get_rtc_time() is always 0 after reset/deepsleep
|
||||
rtc_last_ticks = system_get_rtc_time();
|
||||
|
||||
// reset ALARM0 state
|
||||
pyb_rtc_alarm0_wake = 0;
|
||||
pyb_rtc_alarm0_expiry = 0;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_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 constant object
|
||||
return (mp_obj_t)&pyb_rtc_obj;
|
||||
}
|
||||
|
||||
void pyb_rtc_set_us_since_2000(uint64_t nowus) {
|
||||
uint32_t cal = system_rtc_clock_cali_proc();
|
||||
// Save RTC ticks for overflow detection.
|
||||
rtc_last_ticks = system_get_rtc_time();
|
||||
int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12);
|
||||
|
||||
// As the calibration value jitters quite a bit, to make the
|
||||
// clock at least somewhat practically usable, we need to store it
|
||||
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
|
||||
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
|
||||
};
|
||||
|
||||
uint64_t pyb_rtc_get_us_since_2000() {
|
||||
uint32_t cal;
|
||||
int64_t delta;
|
||||
uint32_t rtc_ticks;
|
||||
|
||||
system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal));
|
||||
system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta));
|
||||
|
||||
// ESP-SDK system_get_rtc_time() only returns uint32 and therefore
|
||||
// overflow about every 7:45h. Thus, we have to check for
|
||||
// overflow and handle it.
|
||||
rtc_ticks = system_get_rtc_time();
|
||||
if (rtc_ticks < rtc_last_ticks) {
|
||||
// Adjust delta because of RTC overflow.
|
||||
delta += (uint64_t)cal << 20;
|
||||
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
|
||||
}
|
||||
rtc_last_ticks = rtc_ticks;
|
||||
|
||||
return (((uint64_t)rtc_ticks * cal) >> 12) + delta;
|
||||
};
|
||||
|
||||
void rtc_prepare_deepsleep(uint64_t sleep_us) {
|
||||
// RTC time will reset at wake up. Let's be preared for this.
|
||||
int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us;
|
||||
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
// Get time
|
||||
uint64_t msecs = pyb_rtc_get_us_since_2000() / 1000;
|
||||
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_2000_to_struct_time(msecs / 1000, &tm);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
mp_obj_new_int(tm.tm_mday),
|
||||
mp_obj_new_int(tm.tm_wday),
|
||||
mp_obj_new_int(tm.tm_hour),
|
||||
mp_obj_new_int(tm.tm_min),
|
||||
mp_obj_new_int(tm.tm_sec),
|
||||
mp_obj_new_int(msecs % 1000)
|
||||
};
|
||||
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
// Set time
|
||||
mp_obj_t *items;
|
||||
mp_obj_get_array_fixed_n(args[1], 8, &items);
|
||||
|
||||
pyb_rtc_set_us_since_2000(
|
||||
((uint64_t)timeutils_seconds_since_2000(
|
||||
mp_obj_get_int(items[0]),
|
||||
mp_obj_get_int(items[1]),
|
||||
mp_obj_get_int(items[2]),
|
||||
mp_obj_get_int(items[4]),
|
||||
mp_obj_get_int(items[5]),
|
||||
mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
uint8_t rtcram[MEM_USER_MAXLEN];
|
||||
uint32_t len;
|
||||
|
||||
if (n_args == 1) {
|
||||
// read RTC memory
|
||||
|
||||
system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len));
|
||||
system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3);
|
||||
|
||||
return mp_obj_new_bytes(rtcram, len);
|
||||
} else {
|
||||
// write RTC memory
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
if (bufinfo.len > MEM_USER_MAXLEN) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"buffer too long"));
|
||||
}
|
||||
|
||||
len = bufinfo.len;
|
||||
system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));
|
||||
|
||||
int i = 0;
|
||||
for (; i < bufinfo.len; i++) {
|
||||
rtcram[i] = ((uint8_t *)bufinfo.buf)[i];
|
||||
}
|
||||
|
||||
system_rtc_mem_write(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) {
|
||||
(void)self_in; // unused
|
||||
|
||||
// check we want alarm0
|
||||
if (mp_obj_get_int(alarm_id) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
|
||||
}
|
||||
|
||||
// set expiry time (in microseconds)
|
||||
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000;
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) {
|
||||
// check we want alarm0
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
mp_raise_ValueError("invalid alarm");
|
||||
}
|
||||
|
||||
uint64_t now = pyb_rtc_get_us_since_2000();
|
||||
if (pyb_rtc_alarm0_expiry <= now) {
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
} else {
|
||||
return mp_obj_new_int((pyb_rtc_alarm0_expiry - now) / 1000);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_trigger, ARG_wake };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// check we want alarm0
|
||||
if (args[ARG_trigger].u_int != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid alarm"));
|
||||
}
|
||||
|
||||
// set the wake value
|
||||
pyb_rtc_alarm0_wake = args[ARG_wake].u_int;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&pyb_rtc_datetime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&pyb_rtc_memory_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_alarm), MP_ROM_PTR(&pyb_rtc_alarm_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_alarm_left), MP_ROM_PTR(&pyb_rtc_alarm_left_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_rtc_irq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ALARM0), MP_ROM_INT(0) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_rtc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_RTC,
|
||||
.make_new = pyb_rtc_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_rtc_locals_dict,
|
||||
};
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Paul Sokolovsky
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "user_interface.h"
|
||||
#include "etshal.h"
|
||||
|
||||
const mp_obj_type_t esp_wdt_type;
|
||||
|
||||
typedef struct _machine_wdt_obj_t {
|
||||
mp_obj_base_t base;
|
||||
} machine_wdt_obj_t;
|
||||
|
||||
STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}};
|
||||
|
||||
STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
||||
mp_int_t id = 0;
|
||||
if (n_args > 0) {
|
||||
id = mp_obj_get_int(args[0]);
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
return &wdt_default;
|
||||
default:
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
|
||||
(void)self_in;
|
||||
system_soft_wdt_feed();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
|
||||
|
||||
STATIC mp_obj_t machine_wdt_deinit(mp_obj_t self_in) {
|
||||
(void)self_in;
|
||||
ets_wdt_disable();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_deinit_obj, machine_wdt_deinit);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_wdt_deinit_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t esp_wdt_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_WDT,
|
||||
.make_new = machine_wdt_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&machine_wdt_locals_dict,
|
||||
};
|
143
esp8266/main.c
143
esp8266/main.c
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/gc.h"
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "gccollect.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
STATIC char heap[36 * 1024];
|
||||
|
||||
STATIC void mp_reset(void) {
|
||||
mp_stack_set_top((void*)0x40000000);
|
||||
mp_stack_set_limit(8192);
|
||||
mp_hal_init();
|
||||
gc_init(heap, heap + sizeof(heap));
|
||||
mp_init();
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL;
|
||||
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
|
||||
extern void esp_native_code_init(void);
|
||||
esp_native_code_init();
|
||||
#endif
|
||||
pin_init0();
|
||||
readline_init0();
|
||||
dupterm_task_init();
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
pyexec_frozen_module("_boot.py");
|
||||
pyexec_file("boot.py");
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
pyexec_file("main.py");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void soft_reset(void) {
|
||||
mp_hal_stdout_tx_str("PYB: soft reboot\r\n");
|
||||
mp_hal_delay_us(10000); // allow UART to flush output
|
||||
mp_reset();
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_event_repl_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void init_done(void) {
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
uart_task_init();
|
||||
#endif
|
||||
mp_reset();
|
||||
mp_hal_stdout_tx_str("\r\n");
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_event_repl_init();
|
||||
#endif
|
||||
|
||||
#if !MICROPY_REPL_EVENT_DRIVEN
|
||||
soft_reset:
|
||||
for (;;) {
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
if (pyexec_raw_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (pyexec_friendly_repl() != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
soft_reset();
|
||||
goto soft_reset;
|
||||
#endif
|
||||
}
|
||||
|
||||
void user_init(void) {
|
||||
system_init_done_cb(init_done);
|
||||
}
|
||||
|
||||
#if !MICROPY_VFS
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
(void)path;
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
#endif
|
||||
|
||||
void MP_FASTCODE(nlr_jump_fail)(void *val) {
|
||||
printf("NLR jump failed\n");
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
|
||||
//void __assert(const char *file, int line, const char *func, const char *expr) {
|
||||
void __assert(const char *file, int line, const char *expr) {
|
||||
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||
for (;;) {
|
||||
}
|
||||
}
|
392
esp8266/modesp.c
392
esp8266/modesp.c
|
@ -1,392 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Paul Sokolovsky
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "drivers/dht/dht.h"
|
||||
#include "uart.h"
|
||||
#include "user_interface.h"
|
||||
#include "mem.h"
|
||||
#include "espneopixel.h"
|
||||
#include "espapa102.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
#define MODESP_INCLUDE_CONSTANTS (1)
|
||||
|
||||
void error_check(bool status, const char *msg) {
|
||||
if (!status) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_osdebug(mp_obj_t val) {
|
||||
if (val == mp_const_none) {
|
||||
uart_os_config(-1);
|
||||
} else {
|
||||
uart_os_config(mp_obj_get_int(val));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_osdebug_obj, esp_osdebug);
|
||||
|
||||
STATIC mp_obj_t esp_sleep_type(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
return mp_obj_new_int(wifi_get_sleep_type());
|
||||
} else {
|
||||
wifi_set_sleep_type(mp_obj_get_int(args[0]));
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_sleep_type_obj, 0, 1, esp_sleep_type);
|
||||
|
||||
STATIC mp_obj_t esp_deepsleep(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
uint32_t sleep_us = n_args > 0 ? mp_obj_get_int(args[0]) : 0;
|
||||
// prepare for RTC reset at wake up
|
||||
rtc_prepare_deepsleep(sleep_us);
|
||||
system_deep_sleep_set_option(n_args > 1 ? mp_obj_get_int(args[1]) : 0);
|
||||
system_deep_sleep(sleep_us);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_deepsleep_obj, 0, 2, esp_deepsleep);
|
||||
|
||||
STATIC mp_obj_t esp_flash_id() {
|
||||
return mp_obj_new_int(spi_flash_get_id());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_id_obj, esp_flash_id);
|
||||
|
||||
STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) {
|
||||
mp_int_t offset = mp_obj_get_int(offset_in);
|
||||
|
||||
mp_int_t len;
|
||||
byte *buf;
|
||||
bool alloc_buf = MP_OBJ_IS_INT(len_or_buf_in);
|
||||
|
||||
if (alloc_buf) {
|
||||
len = mp_obj_get_int(len_or_buf_in);
|
||||
buf = m_new(byte, len);
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(len_or_buf_in, &bufinfo, MP_BUFFER_WRITE);
|
||||
len = bufinfo.len;
|
||||
buf = bufinfo.buf;
|
||||
}
|
||||
|
||||
// We know that allocation will be 4-byte aligned for sure
|
||||
SpiFlashOpResult res = spi_flash_read(offset, (uint32_t*)buf, len);
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
if (alloc_buf) {
|
||||
return mp_obj_new_bytes(buf, len);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
if (alloc_buf) {
|
||||
m_del(byte, buf, len);
|
||||
}
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
|
||||
|
||||
STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) {
|
||||
mp_int_t offset = mp_obj_get_int(offset_in);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
if (bufinfo.len & 0x3) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "len must be multiple of 4"));
|
||||
}
|
||||
SpiFlashOpResult res = spi_flash_write(offset, bufinfo.buf, bufinfo.len);
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
|
||||
|
||||
STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
|
||||
mp_int_t sector = mp_obj_get_int(sector_in);
|
||||
SpiFlashOpResult res = spi_flash_erase_sector(sector);
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
|
||||
|
||||
STATIC mp_obj_t esp_flash_size(void) {
|
||||
extern char flashchip;
|
||||
// For SDK 1.5.2, either address has shifted and not mirrored in
|
||||
// eagle.rom.addr.v6.ld, or extra initial member was added.
|
||||
SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4);
|
||||
#if 0
|
||||
printf("deviceId: %x\n", flash->deviceId);
|
||||
printf("chip_size: %u\n", flash->chip_size);
|
||||
printf("block_size: %u\n", flash->block_size);
|
||||
printf("sector_size: %u\n", flash->sector_size);
|
||||
printf("page_size: %u\n", flash->page_size);
|
||||
printf("status_mask: %u\n", flash->status_mask);
|
||||
#endif
|
||||
return mp_obj_new_int_from_uint(flash->chip_size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
|
||||
|
||||
// If there's just 1 loadable segment at the start of flash,
|
||||
// we assume there's a yaota8266 bootloader.
|
||||
#define IS_OTA_FIRMWARE() ((*(uint32_t*)0x40200000 & 0xff00) == 0x100)
|
||||
|
||||
extern byte _firmware_size[];
|
||||
|
||||
STATIC mp_obj_t esp_flash_user_start(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
|
||||
|
||||
STATIC mp_obj_t esp_check_fw(void) {
|
||||
MD5_CTX ctx;
|
||||
char *fw_start = (char*)0x40200000;
|
||||
if (IS_OTA_FIRMWARE()) {
|
||||
// Skip yaota8266 bootloader
|
||||
fw_start += 0x3c000;
|
||||
}
|
||||
|
||||
uint32_t size = *(uint32_t*)(fw_start + 0x8ffc);
|
||||
printf("size: %d\n", size);
|
||||
if (size > 1024 * 1024) {
|
||||
printf("Invalid size\n");
|
||||
return mp_const_false;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, fw_start + 4, size - 4);
|
||||
unsigned char digest[16];
|
||||
MD5Final(digest, &ctx);
|
||||
printf("md5: ");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x", digest[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return mp_obj_new_bool(memcmp(digest, fw_start + size, sizeof(digest)) == 0);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw);
|
||||
|
||||
|
||||
STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
esp_neopixel_write(mp_obj_get_pin_obj(pin)->phys_port,
|
||||
(uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_is_true(is800k));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
|
||||
|
||||
#if MICROPY_ESP8266_APA102
|
||||
STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
esp_apa102_write(mp_obj_get_pin_obj(clockPin)->phys_port,
|
||||
mp_obj_get_pin_obj(dataPin)->phys_port,
|
||||
(uint8_t*)bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_apa102_write_obj, esp_apa102_write_);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t esp_freemem() {
|
||||
return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_freemem_obj, esp_freemem);
|
||||
|
||||
STATIC mp_obj_t esp_meminfo() {
|
||||
system_print_meminfo();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_meminfo_obj, esp_meminfo);
|
||||
|
||||
STATIC mp_obj_t esp_malloc(mp_obj_t size_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)os_malloc(mp_obj_get_int(size_in)));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_malloc_obj, esp_malloc);
|
||||
|
||||
STATIC mp_obj_t esp_free(mp_obj_t addr_in) {
|
||||
os_free((void*)mp_obj_get_int(addr_in));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_free_obj, esp_free);
|
||||
|
||||
STATIC mp_obj_t esp_esf_free_bufs(mp_obj_t idx_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT(ets_esf_free_bufs(mp_obj_get_int(idx_in)));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_esf_free_bufs_obj, esp_esf_free_bufs);
|
||||
|
||||
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
|
||||
|
||||
// We provide here a way of committing executable data to a region from
|
||||
// which it can be executed by the CPU. There are 2 such writable regions:
|
||||
// - iram1, which may have some space left at the end of it
|
||||
// - memory-mapped flash rom
|
||||
//
|
||||
// By default the iram1 region (the space at the end of it) is used. The
|
||||
// user can select iram1 or a section of flash by calling the
|
||||
// esp.set_native_code_location() function; see below. If flash is selected
|
||||
// then it is erased as needed.
|
||||
|
||||
#include "gccollect.h"
|
||||
|
||||
#define IRAM1_END (0x40108000)
|
||||
#define FLASH_START (0x40200000)
|
||||
#define FLASH_END (0x40300000)
|
||||
#define FLASH_SEC_SIZE (4096)
|
||||
|
||||
#define ESP_NATIVE_CODE_IRAM1 (0)
|
||||
#define ESP_NATIVE_CODE_FLASH (1)
|
||||
|
||||
extern uint32_t _lit4_end;
|
||||
STATIC uint32_t esp_native_code_location;
|
||||
STATIC uint32_t esp_native_code_start;
|
||||
STATIC uint32_t esp_native_code_end;
|
||||
STATIC uint32_t esp_native_code_cur;
|
||||
STATIC uint32_t esp_native_code_erased;
|
||||
|
||||
void esp_native_code_init(void) {
|
||||
esp_native_code_location = ESP_NATIVE_CODE_IRAM1;
|
||||
esp_native_code_start = (uint32_t)&_lit4_end;
|
||||
esp_native_code_end = IRAM1_END;
|
||||
esp_native_code_cur = esp_native_code_start;
|
||||
esp_native_code_erased = 0;
|
||||
}
|
||||
|
||||
void esp_native_code_gc_collect(void) {
|
||||
void *src;
|
||||
if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) {
|
||||
src = (void*)esp_native_code_start;
|
||||
} else {
|
||||
src = (void*)(FLASH_START + esp_native_code_start);
|
||||
}
|
||||
gc_collect_root(src, (esp_native_code_end - esp_native_code_start) / sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void *esp_native_code_commit(void *buf, size_t len) {
|
||||
//printf("COMMIT(buf=%p, len=%u, start=%08x, cur=%08x, end=%08x, erased=%08x)\n", buf, len, esp_native_code_start, esp_native_code_cur, esp_native_code_end, esp_native_code_erased);
|
||||
|
||||
len = (len + 3) & ~3;
|
||||
if (esp_native_code_cur + len > esp_native_code_end) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError,
|
||||
"memory allocation failed, allocating %u bytes for native code", (uint)len));
|
||||
}
|
||||
|
||||
void *dest;
|
||||
if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) {
|
||||
dest = (void*)esp_native_code_cur;
|
||||
memcpy(dest, buf, len);
|
||||
} else {
|
||||
SpiFlashOpResult res;
|
||||
while (esp_native_code_erased < esp_native_code_cur + len) {
|
||||
res = spi_flash_erase_sector(esp_native_code_erased / FLASH_SEC_SIZE);
|
||||
if (res != SPI_FLASH_RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
esp_native_code_erased += FLASH_SEC_SIZE;
|
||||
}
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
res = spi_flash_write(esp_native_code_cur, buf, len);
|
||||
}
|
||||
if (res != SPI_FLASH_RESULT_OK) {
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
dest = (void*)(FLASH_START + esp_native_code_cur);
|
||||
}
|
||||
|
||||
esp_native_code_cur += len;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_set_native_code_location(mp_obj_t start_in, mp_obj_t len_in) {
|
||||
if (start_in == mp_const_none && len_in == mp_const_none) {
|
||||
// use end of iram1 region
|
||||
esp_native_code_init();
|
||||
} else {
|
||||
// use flash; input params are byte offsets from start of flash
|
||||
esp_native_code_location = ESP_NATIVE_CODE_FLASH;
|
||||
esp_native_code_start = mp_obj_get_int(start_in);
|
||||
esp_native_code_end = esp_native_code_start + mp_obj_get_int(len_in);
|
||||
esp_native_code_cur = esp_native_code_start;
|
||||
esp_native_code_erased = esp_native_code_start;
|
||||
// memory-mapped flash is limited in extents to 1MByte
|
||||
if (esp_native_code_end > FLASH_END - FLASH_START) {
|
||||
mp_raise_ValueError("flash location must be below 1MByte");
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_set_native_code_location_obj, esp_set_native_code_location);
|
||||
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep_type), MP_ROM_PTR(&esp_sleep_type_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&esp_deepsleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_id), MP_ROM_PTR(&esp_flash_id_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) },
|
||||
#if MICROPY_ESP8266_NEOPIXEL
|
||||
{ MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
|
||||
#endif
|
||||
#if MICROPY_ESP8266_APA102
|
||||
{ MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_freemem), MP_ROM_PTR(&esp_freemem_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_meminfo), MP_ROM_PTR(&esp_meminfo_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_check_fw), MP_ROM_PTR(&esp_check_fw_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_info_obj) }, // TODO delete/rename/move elsewhere
|
||||
{ MP_ROM_QSTR(MP_QSTR_malloc), MP_ROM_PTR(&esp_malloc_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&esp_free_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_esf_free_bufs), MP_ROM_PTR(&esp_esf_free_bufs_obj) },
|
||||
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_native_code_location), MP_ROM_PTR(&esp_set_native_code_location_obj) },
|
||||
#endif
|
||||
|
||||
#if MODESP_INCLUDE_CONSTANTS
|
||||
{ MP_ROM_QSTR(MP_QSTR_SLEEP_NONE), MP_ROM_INT(NONE_SLEEP_T) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SLEEP_LIGHT), MP_ROM_INT(LIGHT_SLEEP_T) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SLEEP_MODEM), MP_ROM_INT(MODEM_SLEEP_T) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);
|
||||
|
||||
const mp_obj_module_t esp_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&esp_module_globals,
|
||||
};
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2015 Damien P. George
|
||||
* Copyright (c) 2016 Paul Sokolovsky
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_mem.h"
|
||||
#include "extmod/machine_signal.h"
|
||||
#include "extmod/machine_pulse.h"
|
||||
#include "extmod/machine_i2c.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
#include "xtirq.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "etshal.h"
|
||||
#include "ets_alt_task.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
//#define MACHINE_WAKE_IDLE (0x01)
|
||||
//#define MACHINE_WAKE_SLEEP (0x02)
|
||||
#define MACHINE_WAKE_DEEPSLEEP (0x04)
|
||||
|
||||
extern const mp_obj_type_t esp_wdt_type;
|
||||
|
||||
STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
// get
|
||||
return mp_obj_new_int(system_get_cpu_freq() * 1000000);
|
||||
} else {
|
||||
// set
|
||||
mp_int_t freq = mp_obj_get_int(args[0]) / 1000000;
|
||||
if (freq != 80 && freq != 160) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"frequency can only be either 80Mhz or 160MHz"));
|
||||
}
|
||||
system_update_cpu_freq(freq);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq);
|
||||
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
system_restart();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
||||
STATIC mp_obj_t machine_reset_cause(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(system_get_rst_info()->reason);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC mp_obj_t machine_unique_id(void) {
|
||||
uint32_t id = system_get_chip_id();
|
||||
return mp_obj_new_bytes((byte*)&id, sizeof(id));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
uint32_t t = mp_hal_ticks_cpu();
|
||||
asm("waiti 0");
|
||||
t = mp_hal_ticks_cpu() - t;
|
||||
return MP_OBJ_NEW_SMALL_INT(t);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC mp_obj_t machine_sleep(void) {
|
||||
printf("Warning: not yet implemented\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
|
||||
|
||||
STATIC mp_obj_t machine_deepsleep(void) {
|
||||
// default to sleep forever
|
||||
uint32_t sleep_us = 0;
|
||||
|
||||
// see if RTC.ALARM0 should wake the device
|
||||
if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) {
|
||||
uint64_t t = pyb_rtc_get_us_since_2000();
|
||||
if (pyb_rtc_alarm0_expiry <= t) {
|
||||
sleep_us = 1; // alarm already expired so wake immediately
|
||||
} else {
|
||||
uint64_t delta = pyb_rtc_alarm0_expiry - t;
|
||||
if (delta <= 0xffffffff) {
|
||||
// sleep for the desired time
|
||||
sleep_us = delta;
|
||||
} else {
|
||||
// overflow, just set to maximum sleep time
|
||||
sleep_us = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prepare for RTC reset at wake up
|
||||
rtc_prepare_deepsleep(sleep_us);
|
||||
// put the device in a deep-sleep state
|
||||
system_deep_sleep_set_option(0); // default power down mode; TODO check this
|
||||
system_deep_sleep(sleep_us);
|
||||
|
||||
for (;;) {
|
||||
// we must not return
|
||||
ets_loop_iter();
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
|
||||
|
||||
typedef struct _esp_timer_obj_t {
|
||||
mp_obj_base_t base;
|
||||
os_timer_t timer;
|
||||
mp_obj_t callback;
|
||||
} esp_timer_obj_t;
|
||||
|
||||
const mp_obj_type_t esp_timer_type;
|
||||
|
||||
STATIC void esp_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
esp_timer_obj_t *self = self_in;
|
||||
mp_printf(print, "Timer(%p)", &self->timer);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
esp_timer_obj_t *tim = m_new_obj(esp_timer_obj_t);
|
||||
tim->base.type = &esp_timer_type;
|
||||
return tim;
|
||||
}
|
||||
|
||||
STATIC void esp_timer_cb(void *arg) {
|
||||
esp_timer_obj_t *self = arg;
|
||||
mp_sched_schedule(self->callback, self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
// { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
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);
|
||||
|
||||
self->callback = args[2].u_obj;
|
||||
// Be sure to disarm timer before making any changes
|
||||
os_timer_disarm(&self->timer);
|
||||
os_timer_setfn(&self->timer, esp_timer_cb, self);
|
||||
os_timer_arm(&self->timer, args[0].u_int, args[1].u_int);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return esp_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_timer_init_obj, 1, esp_timer_init);
|
||||
|
||||
STATIC mp_obj_t esp_timer_deinit(mp_obj_t self_in) {
|
||||
esp_timer_obj_t *self = self_in;
|
||||
os_timer_disarm(&self->timer);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_timer_deinit_obj, esp_timer_deinit);
|
||||
|
||||
STATIC const mp_rom_map_elem_t esp_timer_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp_timer_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp_timer_init_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&esp_timer_callback_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(esp_timer_locals_dict, esp_timer_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t esp_timer_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Timer,
|
||||
.print = esp_timer_print,
|
||||
.make_new = esp_timer_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&esp_timer_locals_dict,
|
||||
};
|
||||
|
||||
// this bit is unused in the Xtensa PS register
|
||||
#define ETS_LOOP_ITER_BIT (12)
|
||||
|
||||
STATIC mp_obj_t machine_disable_irq(void) {
|
||||
uint32_t state = disable_irq();
|
||||
state = (state & ~(1 << ETS_LOOP_ITER_BIT)) | (ets_loop_iter_disable << ETS_LOOP_ITER_BIT);
|
||||
ets_loop_iter_disable = 1;
|
||||
return mp_obj_new_int(state);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
|
||||
|
||||
STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
|
||||
uint32_t state = mp_obj_get_int(state_in);
|
||||
ets_loop_iter_disable = (state >> ETS_LOOP_ITER_BIT) & 1;
|
||||
enable_irq(state & ~(1 << ETS_LOOP_ITER_BIT));
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) },
|
||||
|
||||
// wake abilities
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
|
||||
|
||||
// reset causes
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(REASON_SOFT_RESTART) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_machine = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_MACHINE
|
|
@ -1,492 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Paul Sokolovsky
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/netutils/netutils.h"
|
||||
#include "queue.h"
|
||||
#include "user_interface.h"
|
||||
#include "espconn.h"
|
||||
#include "spi_flash.h"
|
||||
#include "ets_alt_task.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#define MODNETWORK_INCLUDE_CONSTANTS (1)
|
||||
|
||||
typedef struct _wlan_if_obj_t {
|
||||
mp_obj_base_t base;
|
||||
int if_id;
|
||||
} wlan_if_obj_t;
|
||||
|
||||
void error_check(bool status, const char *msg);
|
||||
const mp_obj_type_t wlan_if_type;
|
||||
|
||||
STATIC const wlan_if_obj_t wlan_objs[] = {
|
||||
{{&wlan_if_type}, STATION_IF},
|
||||
{{&wlan_if_type}, SOFTAP_IF},
|
||||
};
|
||||
|
||||
STATIC void require_if(mp_obj_t wlan_if, int if_no) {
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
|
||||
if (self->if_id != if_no) {
|
||||
error_check(false, if_no == STATION_IF ? "STA required" : "AP required");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t get_wlan(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
int idx = 0;
|
||||
if (n_args > 0) {
|
||||
idx = mp_obj_get_int(args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
|
||||
|
||||
STATIC mp_obj_t esp_active(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
uint32_t mode = wifi_get_opmode();
|
||||
if (n_args > 1) {
|
||||
int mask = self->if_id == STATION_IF ? STATION_MODE : SOFTAP_MODE;
|
||||
if (mp_obj_get_int(args[1]) != 0) {
|
||||
mode |= mask;
|
||||
} else {
|
||||
mode &= ~mask;
|
||||
}
|
||||
error_check(wifi_set_opmode(mode), "Cannot update i/f status");
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// Get active status
|
||||
if (self->if_id == STATION_IF) {
|
||||
return mp_obj_new_bool(mode & STATION_MODE);
|
||||
} else {
|
||||
return mp_obj_new_bool(mode & SOFTAP_MODE);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
|
||||
|
||||
STATIC mp_obj_t esp_connect(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
require_if(args[0], STATION_IF);
|
||||
struct station_config config = {{0}};
|
||||
size_t len;
|
||||
const char *p;
|
||||
|
||||
if (n_args > 1) {
|
||||
p = mp_obj_str_get_data(args[1], &len);
|
||||
len = MIN(len, sizeof(config.ssid));
|
||||
memcpy(config.ssid, p, len);
|
||||
if (n_args > 2) {
|
||||
p = mp_obj_str_get_data(args[2], &len);
|
||||
len = MIN(len, sizeof(config.password));
|
||||
memcpy(config.password, p, len);
|
||||
}
|
||||
|
||||
error_check(wifi_station_set_config(&config), "Cannot set STA config");
|
||||
}
|
||||
error_check(wifi_station_connect(), "Cannot connect to AP");
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect);
|
||||
|
||||
STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
|
||||
require_if(self_in, STATION_IF);
|
||||
error_check(wifi_station_disconnect(), "Cannot disconnect from AP");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
|
||||
|
||||
STATIC mp_obj_t esp_status(mp_obj_t self_in) {
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->if_id == STATION_IF) {
|
||||
return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(-1);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status);
|
||||
|
||||
STATIC mp_obj_t *esp_scan_list = NULL;
|
||||
|
||||
STATIC void esp_scan_cb(void *result, STATUS status) {
|
||||
if (esp_scan_list == NULL) {
|
||||
// called unexpectedly
|
||||
return;
|
||||
}
|
||||
if (result && status == 0) {
|
||||
// we need to catch any memory errors
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) {
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
|
||||
#if 1
|
||||
// struct bss_info::ssid_len is not documented in SDK API Guide,
|
||||
// but is present in SDK headers since 1.4.0
|
||||
t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len);
|
||||
#else
|
||||
t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid));
|
||||
#endif
|
||||
t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid));
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel);
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi);
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode);
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden);
|
||||
mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
|
||||
}
|
||||
nlr_pop();
|
||||
} else {
|
||||
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
|
||||
// indicate error
|
||||
*esp_scan_list = MP_OBJ_NULL;
|
||||
}
|
||||
} else {
|
||||
// indicate error
|
||||
*esp_scan_list = MP_OBJ_NULL;
|
||||
}
|
||||
esp_scan_list = NULL;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
|
||||
require_if(self_in, STATION_IF);
|
||||
if ((wifi_get_opmode() & STATION_MODE) == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
|
||||
"STA must be active"));
|
||||
}
|
||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
||||
esp_scan_list = &list;
|
||||
wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb);
|
||||
while (esp_scan_list != NULL) {
|
||||
// our esp_scan_cb is called via ets_loop_iter so it's safe to set the
|
||||
// esp_scan_list variable to NULL without disabling interrupts
|
||||
if (MP_STATE_VM(mp_pending_exception) != NULL) {
|
||||
esp_scan_list = NULL;
|
||||
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
|
||||
nlr_raise(obj);
|
||||
}
|
||||
ets_loop_iter();
|
||||
}
|
||||
if (list == MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed"));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
|
||||
|
||||
/// \method isconnected()
|
||||
/// Return True if connected to an AP and an IP address has been assigned,
|
||||
/// false otherwise.
|
||||
STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->if_id == STATION_IF) {
|
||||
if (wifi_station_get_connect_status() == STATION_GOT_IP) {
|
||||
return mp_const_true;
|
||||
}
|
||||
} else {
|
||||
if (wifi_softap_get_station_num() > 0) {
|
||||
return mp_const_true;
|
||||
}
|
||||
}
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
|
||||
|
||||
STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
struct ip_info info;
|
||||
ip_addr_t dns_addr;
|
||||
wifi_get_ip_info(self->if_id, &info);
|
||||
if (n_args == 1) {
|
||||
// get
|
||||
dns_addr = dns_getserver(0);
|
||||
mp_obj_t tuple[4] = {
|
||||
netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG),
|
||||
netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG),
|
||||
netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG),
|
||||
netutils_format_ipv4_addr((uint8_t*)&dns_addr, NETUTILS_BIG),
|
||||
};
|
||||
return mp_obj_new_tuple(4, tuple);
|
||||
} else {
|
||||
// set
|
||||
mp_obj_t *items;
|
||||
bool restart_dhcp_server = false;
|
||||
mp_obj_get_array_fixed_n(args[1], 4, &items);
|
||||
netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG);
|
||||
if (mp_obj_is_integer(items[1])) {
|
||||
// allow numeric netmask, i.e.:
|
||||
// 24 -> 255.255.255.0
|
||||
// 16 -> 255.255.0.0
|
||||
// etc...
|
||||
uint32_t* m = (uint32_t*)&info.netmask;
|
||||
*m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
|
||||
} else {
|
||||
netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG);
|
||||
}
|
||||
netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG);
|
||||
netutils_parse_ipv4_addr(items[3], (void*)&dns_addr, NETUTILS_BIG);
|
||||
// To set a static IP we have to disable DHCP first
|
||||
if (self->if_id == STATION_IF) {
|
||||
wifi_station_dhcpc_stop();
|
||||
} else {
|
||||
restart_dhcp_server = wifi_softap_dhcps_status();
|
||||
wifi_softap_dhcps_stop();
|
||||
}
|
||||
if (!wifi_set_ip_info(self->if_id, &info)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
|
||||
"wifi_set_ip_info() failed"));
|
||||
}
|
||||
dns_setserver(0, &dns_addr);
|
||||
if (restart_dhcp_server) {
|
||||
wifi_softap_dhcps_start();
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
|
||||
|
||||
STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
if (n_args != 1 && kwargs->used != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"either pos or kw args are allowed"));
|
||||
}
|
||||
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
union {
|
||||
struct station_config sta;
|
||||
struct softap_config ap;
|
||||
} cfg;
|
||||
|
||||
if (self->if_id == STATION_IF) {
|
||||
error_check(wifi_station_get_config(&cfg.sta), "can't get STA config");
|
||||
} else {
|
||||
error_check(wifi_softap_get_config(&cfg.ap), "can't get AP config");
|
||||
}
|
||||
|
||||
int req_if = -1;
|
||||
|
||||
if (kwargs->used != 0) {
|
||||
|
||||
for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
switch ((uintptr_t)kwargs->table[i].key) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
|
||||
if (bufinfo.len != 6) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"invalid buffer length"));
|
||||
}
|
||||
wifi_set_macaddr(self->if_id, bufinfo.buf);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_essid): {
|
||||
req_if = SOFTAP_IF;
|
||||
size_t len;
|
||||
const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
|
||||
len = MIN(len, sizeof(cfg.ap.ssid));
|
||||
memcpy(cfg.ap.ssid, s, len);
|
||||
cfg.ap.ssid_len = len;
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_hidden): {
|
||||
req_if = SOFTAP_IF;
|
||||
cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_authmode): {
|
||||
req_if = SOFTAP_IF;
|
||||
cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_password): {
|
||||
req_if = SOFTAP_IF;
|
||||
size_t len;
|
||||
const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
|
||||
len = MIN(len, sizeof(cfg.ap.password) - 1);
|
||||
memcpy(cfg.ap.password, s, len);
|
||||
cfg.ap.password[len] = 0;
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_channel): {
|
||||
req_if = SOFTAP_IF;
|
||||
cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_dhcp_hostname): {
|
||||
req_if = STATION_IF;
|
||||
if (self->if_id == STATION_IF) {
|
||||
const char *s = mp_obj_str_get_str(kwargs->table[i].value);
|
||||
wifi_station_set_hostname((char*)s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
#undef QS
|
||||
}
|
||||
}
|
||||
|
||||
// We post-check interface requirements to save on code size
|
||||
if (req_if >= 0) {
|
||||
require_if(args[0], req_if);
|
||||
}
|
||||
|
||||
if (self->if_id == STATION_IF) {
|
||||
error_check(wifi_station_set_config(&cfg.sta), "can't set STA config");
|
||||
} else {
|
||||
error_check(wifi_softap_set_config(&cfg.ap), "can't set AP config");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// Get config
|
||||
|
||||
if (n_args != 2) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"can query only one param"));
|
||||
}
|
||||
|
||||
mp_obj_t val;
|
||||
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
switch ((uintptr_t)args[1]) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
uint8_t mac[6];
|
||||
wifi_get_macaddr(self->if_id, mac);
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
}
|
||||
case QS(MP_QSTR_essid):
|
||||
req_if = SOFTAP_IF;
|
||||
val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false);
|
||||
break;
|
||||
case QS(MP_QSTR_hidden):
|
||||
req_if = SOFTAP_IF;
|
||||
val = mp_obj_new_bool(cfg.ap.ssid_hidden);
|
||||
break;
|
||||
case QS(MP_QSTR_authmode):
|
||||
req_if = SOFTAP_IF;
|
||||
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
|
||||
break;
|
||||
case QS(MP_QSTR_channel):
|
||||
req_if = SOFTAP_IF;
|
||||
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
|
||||
break;
|
||||
case QS(MP_QSTR_dhcp_hostname): {
|
||||
req_if = STATION_IF;
|
||||
char* s = wifi_station_get_hostname();
|
||||
val = mp_obj_new_str(s, strlen(s), false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
#undef QS
|
||||
|
||||
// We post-check interface requirements to save on code size
|
||||
if (req_if >= 0) {
|
||||
require_if(args[0], req_if);
|
||||
}
|
||||
|
||||
return val;
|
||||
|
||||
unknown:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"unknown config param"));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
|
||||
|
||||
STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t wlan_if_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_WLAN,
|
||||
.locals_dict = (mp_obj_dict_t*)&wlan_if_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_obj_t esp_phy_mode(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
return mp_obj_new_int(wifi_get_phy_mode());
|
||||
} else {
|
||||
wifi_set_phy_mode(mp_obj_get_int(args[0]));
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
|
||||
|
||||
#if MODNETWORK_INCLUDE_CONSTANTS
|
||||
{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
|
||||
|
||||
const mp_obj_module_t network_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 <stdio.h>
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "gccollect.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
// The pyb module no longer exists since all functionality now appears
|
||||
// elsewhere, in more standard places (eg time, machine modules). The
|
||||
// only remaining function is pyb.info() which has been moved to the
|
||||
// esp module, pending deletion/renaming/moving elsewhere.
|
||||
|
||||
STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// print info about memory
|
||||
{
|
||||
printf("_text_start=%p\n", &_text_start);
|
||||
printf("_text_end=%p\n", &_text_end);
|
||||
printf("_irom0_text_start=%p\n", &_irom0_text_start);
|
||||
printf("_irom0_text_end=%p\n", &_irom0_text_end);
|
||||
printf("_data_start=%p\n", &_data_start);
|
||||
printf("_data_end=%p\n", &_data_end);
|
||||
printf("_rodata_start=%p\n", &_rodata_start);
|
||||
printf("_rodata_end=%p\n", &_rodata_end);
|
||||
printf("_bss_start=%p\n", &_bss_start);
|
||||
printf("_bss_end=%p\n", &_bss_end);
|
||||
printf("_heap_start=%p\n", &_heap_start);
|
||||
printf("_heap_end=%p\n", &_heap_end);
|
||||
}
|
||||
|
||||
// qstr info
|
||||
{
|
||||
mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
|
||||
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
|
||||
printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
|
||||
}
|
||||
|
||||
// GC info
|
||||
{
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
printf("GC:\n");
|
||||
printf(" " UINT_FMT " total\n", info.total);
|
||||
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
|
||||
printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
|
||||
}
|
||||
|
||||
if (n_args == 1) {
|
||||
// arg given means dump gc allocation table
|
||||
gc_dump_alloc_table();
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
|
|
@ -1 +0,0 @@
|
|||
../../drivers/onewire/ds18x20.py
|
|
@ -1 +0,0 @@
|
|||
../../drivers/onewire/onewire.py
|
|
@ -1 +0,0 @@
|
|||
../../tools/upip.py
|
|
@ -1 +0,0 @@
|
|||
../../tools/upip_utarfile.py
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2015 Josef Gajdusek
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/smallint.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "modmachine.h"
|
||||
#include "user_interface.h"
|
||||
#include "extmod/utime_mphal.h"
|
||||
|
||||
/// \module time - time related functions
|
||||
///
|
||||
/// The `time` module provides functions for getting the current time and date,
|
||||
/// and for sleeping.
|
||||
|
||||
/// \function localtime([secs])
|
||||
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
/// If secs is not provided or None, then the current time from the RTC is used.
|
||||
/// year includes the century (for example 2014)
|
||||
/// month is 1-12
|
||||
/// mday is 1-31
|
||||
/// hour is 0-23
|
||||
/// minute is 0-59
|
||||
/// second is 0-59
|
||||
/// weekday is 0-6 for Mon-Sun.
|
||||
/// yearday is 1-366
|
||||
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
timeutils_struct_time_t tm;
|
||||
mp_int_t seconds;
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000;
|
||||
} else {
|
||||
seconds = mp_obj_get_int(args[0]);
|
||||
}
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
tuple[0] = mp_obj_new_int(tm.tm_year),
|
||||
tuple[1] = mp_obj_new_int(tm.tm_mon),
|
||||
tuple[2] = mp_obj_new_int(tm.tm_mday),
|
||||
tuple[3] = mp_obj_new_int(tm.tm_hour),
|
||||
tuple[4] = mp_obj_new_int(tm.tm_min),
|
||||
tuple[5] = mp_obj_new_int(tm.tm_sec),
|
||||
tuple[6] = mp_obj_new_int(tm.tm_wday),
|
||||
tuple[7] = mp_obj_new_int(tm.tm_yday),
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
|
||||
|
||||
/// \function mktime()
|
||||
/// This is inverse function of localtime. It's argument is a full 8-tuple
|
||||
/// which expresses a time as per localtime. It returns an integer which is
|
||||
/// the number of seconds since Jan 1, 2000.
|
||||
STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
size_t len;
|
||||
mp_obj_t *elem;
|
||||
mp_obj_get_array(tuple, &len, &elem);
|
||||
|
||||
// localtime generates a tuple of len 8. CPython uses 9, so we accept both.
|
||||
if (len < 8 || len > 9) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len));
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
|
||||
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
|
||||
|
||||
/// \function time()
|
||||
/// Returns the number of seconds, as an integer, since 1/1/2000.
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
// get date and time
|
||||
return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
|
||||
|
||||
STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
||||
const mp_obj_module_t utime_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&time_module_globals,
|
||||
};
|
|
@ -1,198 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// options to control how MicroPython is built
|
||||
|
||||
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
|
||||
#define MICROPY_ALLOC_PATH_MAX (128)
|
||||
#define MICROPY_ALLOC_LEXER_INDENT_INIT (8)
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INIT (48)
|
||||
#define MICROPY_ALLOC_PARSE_RULE_INC (8)
|
||||
#define MICROPY_ALLOC_PARSE_RESULT_INC (8)
|
||||
#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64)
|
||||
#define MICROPY_PERSISTENT_CODE_LOAD (1)
|
||||
#define MICROPY_EMIT_XTENSA (1)
|
||||
#define MICROPY_EMIT_INLINE_XTENSA (1)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (1)
|
||||
#define MICROPY_DEBUG_PRINTER_DEST mp_debug_print
|
||||
#define MICROPY_READER_VFS (MICROPY_VFS)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_ENABLE_FINALISER (1)
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_KBD_EXCEPTION (1)
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_USE_INTERNAL_ERRNO (1)
|
||||
#define MICROPY_ENABLE_SCHEDULER (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (0)
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#define MICROPY_PY_BUILTINS_INPUT (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text
|
||||
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (1)
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_IO_FILEIO (1)
|
||||
#define MICROPY_PY_STRUCT (1)
|
||||
#define MICROPY_PY_SYS (1)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||
#define MICROPY_PY_SYS_EXIT (1)
|
||||
#define MICROPY_PY_SYS_STDFILES (1)
|
||||
#define MICROPY_PY_SYS_STDIO_BUFFER (1)
|
||||
#define MICROPY_PY_UERRNO (1)
|
||||
#define MICROPY_PY_UBINASCII (1)
|
||||
#define MICROPY_PY_UCTYPES (1)
|
||||
#define MICROPY_PY_UHASHLIB (1)
|
||||
#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS)
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
#define MICROPY_PY_UTIMEQ (1)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#define MICROPY_PY_USELECT (1)
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
#define MICROPY_PY_UZLIB (1)
|
||||
#define MICROPY_PY_LWIP (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
|
||||
#define MICROPY_PY_MACHINE_PULSE (1)
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_SPI (1)
|
||||
#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hspi_make_new
|
||||
#define MICROPY_PY_WEBSOCKET (1)
|
||||
#define MICROPY_PY_WEBREPL (1)
|
||||
#define MICROPY_PY_WEBREPL_DELAY (20)
|
||||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
||||
#define MICROPY_PY_OS_DUPTERM (1)
|
||||
#define MICROPY_CPYTHON_COMPAT (1)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
|
||||
#define MICROPY_WARNINGS (1)
|
||||
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
|
||||
#define MICROPY_STREAMS_NON_BLOCK (1)
|
||||
#define MICROPY_STREAMS_POSIX_API (1)
|
||||
#define MICROPY_MODULE_FROZEN_STR (1)
|
||||
#define MICROPY_MODULE_FROZEN_MPY (1)
|
||||
#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32
|
||||
#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
|
||||
|
||||
#define MICROPY_VFS (1)
|
||||
#define MICROPY_FATFS_ENABLE_LFN (1)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_MAX_SS (4096)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
|
||||
#define MICROPY_VFS_FAT (1)
|
||||
#define MICROPY_ESP8266_APA102 (1)
|
||||
#define MICROPY_ESP8266_NEOPIXEL (1)
|
||||
|
||||
#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();}
|
||||
#define MICROPY_VM_HOOK_COUNT (10)
|
||||
#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT;
|
||||
#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \
|
||||
vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \
|
||||
extern void ets_loop_iter(void); \
|
||||
ets_loop_iter(); \
|
||||
}
|
||||
#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL
|
||||
#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p)))
|
||||
|
||||
#define MP_SSIZE_MAX (0x7fffffff)
|
||||
|
||||
#define UINT_FMT "%u"
|
||||
#define INT_FMT "%d"
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef long mp_off_t;
|
||||
typedef uint32_t sys_prot_t; // for modlwip
|
||||
// ssize_t, off_t as required by POSIX-signatured functions in stream.h
|
||||
#include <sys/types.h>
|
||||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
void *esp_native_code_commit(void*, size_t);
|
||||
#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len)
|
||||
|
||||
#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_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t esp_module;
|
||||
extern const struct _mp_obj_module_t network_module;
|
||||
extern const struct _mp_obj_module_t utime_module;
|
||||
extern const struct _mp_obj_module_t uos_module;
|
||||
extern const struct _mp_obj_module_t mp_module_lwip;
|
||||
extern const struct _mp_obj_module_t mp_module_machine;
|
||||
extern const struct _mp_obj_module_t mp_module_onewire;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_lwip }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&network_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_lwip }, \
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
mp_obj_t pin_irq_handler[16]; \
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
// board specifics
|
||||
|
||||
#define MICROPY_MPHALPORT_H "esp_mphal.h"
|
||||
#define MICROPY_HW_BOARD_NAME "ESP module"
|
||||
#define MICROPY_HW_MCU_NAME "ESP8266"
|
||||
#define MICROPY_PY_SYS_PLATFORM "esp8266"
|
||||
|
||||
#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n
|
||||
|
||||
#define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr))
|
106
esp8266/uart.h
106
esp8266/uart.h
|
@ -1,106 +0,0 @@
|
|||
#ifndef MICROPY_INCLUDED_ESP8266_UART_H
|
||||
#define MICROPY_INCLUDED_ESP8266_UART_H
|
||||
|
||||
#include <eagle_soc.h>
|
||||
|
||||
#define UART0 (0)
|
||||
#define UART1 (1)
|
||||
|
||||
typedef enum {
|
||||
UART_FIVE_BITS = 0x0,
|
||||
UART_SIX_BITS = 0x1,
|
||||
UART_SEVEN_BITS = 0x2,
|
||||
UART_EIGHT_BITS = 0x3
|
||||
} UartBitsNum4Char;
|
||||
|
||||
typedef enum {
|
||||
UART_ONE_STOP_BIT = 0,
|
||||
UART_ONE_HALF_STOP_BIT = BIT2,
|
||||
UART_TWO_STOP_BIT = BIT2
|
||||
} UartStopBitsNum;
|
||||
|
||||
typedef enum {
|
||||
UART_NONE_BITS = 0,
|
||||
UART_ODD_BITS = BIT0,
|
||||
UART_EVEN_BITS = 0
|
||||
} UartParityMode;
|
||||
|
||||
typedef enum {
|
||||
UART_STICK_PARITY_DIS = 0,
|
||||
UART_STICK_PARITY_EN = BIT1
|
||||
} UartExistParity;
|
||||
|
||||
typedef enum {
|
||||
UART_BIT_RATE_9600 = 9600,
|
||||
UART_BIT_RATE_19200 = 19200,
|
||||
UART_BIT_RATE_38400 = 38400,
|
||||
UART_BIT_RATE_57600 = 57600,
|
||||
UART_BIT_RATE_74880 = 74880,
|
||||
UART_BIT_RATE_115200 = 115200,
|
||||
UART_BIT_RATE_230400 = 230400,
|
||||
UART_BIT_RATE_256000 = 256000,
|
||||
UART_BIT_RATE_460800 = 460800,
|
||||
UART_BIT_RATE_921600 = 921600
|
||||
} UartBautRate;
|
||||
|
||||
typedef enum {
|
||||
UART_NONE_CTRL,
|
||||
UART_HARDWARE_CTRL,
|
||||
UART_XON_XOFF_CTRL
|
||||
} UartFlowCtrl;
|
||||
|
||||
typedef enum {
|
||||
UART_EMPTY,
|
||||
UART_UNDER_WRITE,
|
||||
UART_WRITE_OVER
|
||||
} RcvMsgBuffState;
|
||||
|
||||
typedef struct {
|
||||
uint32 RcvBuffSize;
|
||||
uint8 *pRcvMsgBuff;
|
||||
uint8 *pWritePos;
|
||||
uint8 *pReadPos;
|
||||
uint8 TrigLvl; //JLU: may need to pad
|
||||
RcvMsgBuffState BuffState;
|
||||
} RcvMsgBuff;
|
||||
|
||||
typedef struct {
|
||||
uint32 TrxBuffSize;
|
||||
uint8 *pTrxBuff;
|
||||
} TrxMsgBuff;
|
||||
|
||||
typedef enum {
|
||||
UART_BAUD_RATE_DET,
|
||||
UART_WAIT_SYNC_FRM,
|
||||
UART_SRCH_MSG_HEAD,
|
||||
UART_RCV_MSG_BODY,
|
||||
UART_RCV_ESC_CHAR,
|
||||
} RcvMsgState;
|
||||
|
||||
typedef struct {
|
||||
UartBautRate baut_rate;
|
||||
UartBitsNum4Char data_bits;
|
||||
UartExistParity exist_parity;
|
||||
UartParityMode parity; // chip size in byte
|
||||
UartStopBitsNum stop_bits;
|
||||
UartFlowCtrl flow_ctrl;
|
||||
RcvMsgBuff rcv_buff;
|
||||
TrxMsgBuff trx_buff;
|
||||
RcvMsgState rcv_state;
|
||||
int received;
|
||||
int buff_uart_no; //indicate which uart use tx/rx buffer
|
||||
} UartDevice;
|
||||
|
||||
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
|
||||
int uart0_rx(void);
|
||||
bool uart_rx_wait(uint32_t timeout_us);
|
||||
int uart_rx_char(void);
|
||||
void uart_tx_one_char(uint8 uart, uint8 TxChar);
|
||||
void uart_flush(uint8 uart);
|
||||
void uart_os_config(int uart);
|
||||
void uart_setup(uint8 uart);
|
||||
// check status of rx/tx
|
||||
int uart_rx_any(uint8 uart);
|
||||
int uart_tx_any_room(uint8 uart);
|
||||
|
||||
#endif // MICROPY_INCLUDED_ESP8266_UART_H
|
|
@ -89,7 +89,7 @@
|
|||
extern const struct _mp_obj_module_t mp_module_os;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Print a nice list of pins, their current settings, and available afs.
|
||||
# Requires pins_af.py from stmhal/build-PYBV10/ directory.
|
||||
# Requires pins_af.py from ports/stm32/build-PYBV10/ directory.
|
||||
|
||||
import pyb
|
||||
import pins_af
|
||||
|
|
|
@ -269,7 +269,7 @@ int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t
|
|||
/******************************************************************************/
|
||||
// MicroPython bindings for I2C
|
||||
|
||||
STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC void machine_i2c_obj_init_helper(machine_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, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_mem.h"
|
||||
#include "py/nlr.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/virtpin.h"
|
||||
#include "extmod/machine_pinbase.h"
|
||||
|
||||
// PinBase class
|
||||
|
||||
|
@ -40,10 +41,8 @@ typedef struct _mp_pinbase_t {
|
|||
mp_obj_base_t base;
|
||||
} mp_pinbase_t;
|
||||
|
||||
STATIC const mp_obj_type_t pinbase_type;
|
||||
|
||||
STATIC mp_pinbase_t pinbase_singleton = {
|
||||
.base = { &pinbase_type },
|
||||
STATIC const mp_pinbase_t pinbase_singleton = {
|
||||
.base = { &machine_pinbase_type },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t pinbase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
|
|
|
@ -29,9 +29,7 @@
|
|||
#include <errno.h> // for declaration of global errno variable
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_BTREE
|
||||
|
@ -281,7 +279,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
|||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in);
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_IN: {
|
||||
|
|
|
@ -27,13 +27,11 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_FRAMEBUF
|
||||
|
||||
#include "stmhal/font_petme128_8x8.h"
|
||||
#include "ports/stm32/font_petme128_8x8.h"
|
||||
|
||||
typedef struct _mp_obj_framebuf_t {
|
||||
mp_obj_base_t base;
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
@ -129,15 +128,15 @@ STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw,
|
|||
|
||||
ip_addr_t iplocal, ipremote;
|
||||
if (!ipaddr_aton(mp_obj_str_get_str(args[1]), &iplocal)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "not a valid local IP"));
|
||||
mp_raise_ValueError("not a valid local IP");
|
||||
}
|
||||
if (!ipaddr_aton(mp_obj_str_get_str(args[2]), &ipremote)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "not a valid remote IP"));
|
||||
mp_raise_ValueError("not a valid remote IP");
|
||||
}
|
||||
|
||||
struct netif *n = &lwip_slip_obj.lwip_netif;
|
||||
if (netif_add(n, &iplocal, IP_ADDR_BROADCAST, &ipremote, NULL, slipif_init, ip_input) == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "out of memory"));
|
||||
mp_raise_ValueError("out of memory");
|
||||
}
|
||||
netif_set_up(n);
|
||||
netif_set_default(n);
|
||||
|
@ -1033,7 +1032,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
|
|||
break;
|
||||
}
|
||||
case MOD_NETWORK_SOCK_DGRAM:
|
||||
mp_not_implemented("");
|
||||
mp_raise_NotImplementedError("");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1070,7 +1069,7 @@ STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking);
|
||||
|
||||
STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args; // always 4
|
||||
lwip_socket_obj_t *socket = args[0];
|
||||
|
||||
|
@ -1120,7 +1119,7 @@ STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt);
|
||||
|
||||
STATIC mp_obj_t lwip_socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t lwip_socket_makefile(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
return args[0];
|
||||
}
|
||||
|
|
|
@ -28,13 +28,10 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "extmod/modubinascii.h"
|
||||
|
||||
#include "uzlib/tinf.h"
|
||||
|
||||
mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
|
||||
// Second argument is for an extension to allow a separator to be used
|
||||
// between values.
|
||||
|
@ -105,54 +102,64 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
|
||||
|
||||
// If ch is a character in the base64 alphabet, and is not a pad character, then
|
||||
// the corresponding integer between 0 and 63, inclusively, is returned.
|
||||
// Otherwise, -1 is returned.
|
||||
static int mod_binascii_sextet(byte ch) {
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
return ch - 'A';
|
||||
} else if (ch >= 'a' && ch <= 'z') {
|
||||
return ch - 'a' + 26;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
return ch - '0' + 52;
|
||||
} else if (ch == '+') {
|
||||
return 62;
|
||||
} else if (ch == '/') {
|
||||
return 63;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
if (bufinfo.len % 4 != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incorrect padding"));
|
||||
}
|
||||
byte *in = bufinfo.buf;
|
||||
|
||||
vstr_t vstr;
|
||||
byte *in = bufinfo.buf;
|
||||
if (bufinfo.len == 0) {
|
||||
vstr_init_len(&vstr, 0);
|
||||
}
|
||||
else {
|
||||
vstr_init_len(&vstr, ((bufinfo.len / 4) * 3) - ((in[bufinfo.len-1] == '=') ? ((in[bufinfo.len-2] == '=') ? 2 : 1 ) : 0));
|
||||
}
|
||||
byte *out = (byte*)vstr.buf;
|
||||
for (mp_uint_t i = bufinfo.len; i; i -= 4) {
|
||||
char hold[4];
|
||||
for (int j = 4; j--;) {
|
||||
if (in[j] >= 'A' && in[j] <= 'Z') {
|
||||
hold[j] = in[j] - 'A';
|
||||
} else if (in[j] >= 'a' && in[j] <= 'z') {
|
||||
hold[j] = in[j] - 'a' + 26;
|
||||
} else if (in[j] >= '0' && in[j] <= '9') {
|
||||
hold[j] = in[j] - '0' + 52;
|
||||
} else if (in[j] == '+') {
|
||||
hold[j] = 62;
|
||||
} else if (in[j] == '/') {
|
||||
hold[j] = 63;
|
||||
} else if (in[j] == '=') {
|
||||
if (j < 2 || i > 4) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incorrect padding"));
|
||||
}
|
||||
hold[j] = 64;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid character"));
|
||||
}
|
||||
}
|
||||
in += 4;
|
||||
vstr_init(&vstr, (bufinfo.len / 4) * 3 + 1); // Potentially over-allocate
|
||||
byte *out = (byte *)vstr.buf;
|
||||
|
||||
*out++ = (hold[0]) << 2 | (hold[1]) >> 4;
|
||||
if (hold[2] != 64) {
|
||||
*out++ = (hold[1] & 0x0F) << 4 | hold[2] >> 2;
|
||||
if (hold[3] != 64) {
|
||||
*out++ = (hold[2] & 0x03) << 6 | hold[3];
|
||||
uint shift = 0;
|
||||
int nbits = 0; // Number of meaningful bits in shift
|
||||
bool hadpad = false; // Had a pad character since last valid character
|
||||
for (size_t i = 0; i < bufinfo.len; i++) {
|
||||
if (in[i] == '=') {
|
||||
if ((nbits == 2) || ((nbits == 4) && hadpad)) {
|
||||
nbits = 0;
|
||||
break;
|
||||
}
|
||||
hadpad = true;
|
||||
}
|
||||
|
||||
int sextet = mod_binascii_sextet(in[i]);
|
||||
if (sextet == -1) {
|
||||
continue;
|
||||
}
|
||||
hadpad = false;
|
||||
shift = (shift << 6) | sextet;
|
||||
nbits += 6;
|
||||
|
||||
if (nbits >= 8) {
|
||||
nbits -= 8;
|
||||
out[vstr.len++] = (shift >> nbits) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbits) {
|
||||
mp_raise_ValueError("incorrect padding");
|
||||
}
|
||||
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
|
||||
|
@ -184,7 +191,7 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
|
|||
*out++ = (in[0] & 0x03) << 4;
|
||||
*out++ = 64;
|
||||
}
|
||||
*out++ = 64;
|
||||
*out = 64;
|
||||
}
|
||||
|
||||
// Second pass, we convert number base 64 values to actual base64 ascii encoding
|
||||
|
@ -211,6 +218,8 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
|
|||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);
|
||||
|
||||
#if MICROPY_PY_UBINASCII_CRC32
|
||||
#include "uzlib/tinf.h"
|
||||
|
||||
mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/binary.h"
|
||||
|
@ -118,7 +117,7 @@ typedef struct _mp_obj_uctypes_struct_t {
|
|||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
STATIC NORETURN void syntax_error(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
|
||||
mp_raise_TypeError("syntax error in uctypes descriptor");
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
|
@ -215,7 +214,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_
|
|||
// but scalar structure field is lowered into native Python int, so all
|
||||
// type info is lost. So, we cannot say if it's scalar type description,
|
||||
// or such lowered scalar.
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Cannot unambiguously get sizeof scalar"));
|
||||
mp_raise_TypeError("Cannot unambiguously get sizeof scalar");
|
||||
}
|
||||
syntax_error();
|
||||
}
|
||||
|
@ -393,7 +392,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||
|
||||
// TODO: Support at least OrderedDict in addition
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: no fields"));
|
||||
mp_raise_TypeError("struct: no fields");
|
||||
}
|
||||
|
||||
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
||||
|
@ -526,7 +525,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob
|
|||
} else {
|
||||
// load / store
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: cannot index"));
|
||||
mp_raise_TypeError("struct: cannot index");
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue