mirror of
https://github.com/micropython/micropython.git
synced 2025-12-28 15:50:14 +01:00
Compare commits
347 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8d31585a0 | ||
|
|
1e3a7c4ac5 | ||
|
|
48feb8ac6e | ||
|
|
57226a2b7f | ||
|
|
ad3724e0bc | ||
|
|
7d0d7215d2 | ||
|
|
6caca3259f | ||
|
|
2750a7b38e | ||
|
|
a3edeb9ea5 | ||
|
|
e9404e5f5f | ||
|
|
453c2e8f55 | ||
|
|
799ccdc789 | ||
|
|
06234a6115 | ||
|
|
36f97f19b4 | ||
|
|
f059563507 | ||
|
|
a97284423e | ||
|
|
824f5c5a32 | ||
|
|
ed878275b0 | ||
|
|
34d0b3f85c | ||
|
|
6a4c6fc023 | ||
|
|
b0a15aa735 | ||
|
|
8298251215 | ||
|
|
e42186d356 | ||
|
|
f2f8ae110b | ||
|
|
11ab807d76 | ||
|
|
e93c1ca5da | ||
|
|
f17f3314d0 | ||
|
|
1a01ed0d2a | ||
|
|
b6a544b917 | ||
|
|
06ee5e947f | ||
|
|
998578a2b8 | ||
|
|
cdbeee0c50 | ||
|
|
4021b1e1b8 | ||
|
|
af8d791bd0 | ||
|
|
11fc6553e8 | ||
|
|
31101d91ce | ||
|
|
deaa57acf3 | ||
|
|
db4e009217 | ||
|
|
f274561e16 | ||
|
|
d02f3a57f4 | ||
|
|
eaef6b5324 | ||
|
|
9e1dec1818 | ||
|
|
39968aaaff | ||
|
|
6dff3df501 | ||
|
|
8bb7d958f1 | ||
|
|
df3e5d2b2f | ||
|
|
48874942f0 | ||
|
|
5e22afce41 | ||
|
|
e49153fb98 | ||
|
|
7f0e563de3 | ||
|
|
7dc2345715 | ||
|
|
93c76d2b06 | ||
|
|
1b76f88e7a | ||
|
|
aa7828f822 | ||
|
|
7e3b21ec54 | ||
|
|
b3a65791b1 | ||
|
|
ac70119779 | ||
|
|
a181340ad8 | ||
|
|
5a699a7017 | ||
|
|
244b02f744 | ||
|
|
cbc0bf6fec | ||
|
|
2ea52cb045 | ||
|
|
7df9f313c6 | ||
|
|
9ad5032164 | ||
|
|
9d9efc0c5a | ||
|
|
cff9f02cd7 | ||
|
|
fa5ac678fc | ||
|
|
3dabaae47d | ||
|
|
d22a04d9c4 | ||
|
|
49e140488d | ||
|
|
3b3612c65b | ||
|
|
dc43508cc2 | ||
|
|
016dba0e98 | ||
|
|
503089ea9d | ||
|
|
23a568240d | ||
|
|
a2bfcbe029 | ||
|
|
e3d29996b3 | ||
|
|
75af908c0e | ||
|
|
06d0083468 | ||
|
|
620c4c32bf | ||
|
|
3a0a771730 | ||
|
|
0363e1d7b5 | ||
|
|
00c1fc6d77 | ||
|
|
82af4d6749 | ||
|
|
dffa383b06 | ||
|
|
9fdba0e09c | ||
|
|
056da75a8a | ||
|
|
0bb3c7d3b7 | ||
|
|
c08f50bcf7 | ||
|
|
7f19b1c3eb | ||
|
|
b89ac9db78 | ||
|
|
b1537a5752 | ||
|
|
bcf60b43ee | ||
|
|
7a9c183c20 | ||
|
|
cecf6bee97 | ||
|
|
161e9f4115 | ||
|
|
52784bf595 | ||
|
|
addd1d3db1 | ||
|
|
99d62c4def | ||
|
|
8f3cf6e6a8 | ||
|
|
eb239b8398 | ||
|
|
03de5a13cf | ||
|
|
cd20027f56 | ||
|
|
1f433c719b | ||
|
|
bd925b59c3 | ||
|
|
b0eb0d6153 | ||
|
|
b932b2dd1f | ||
|
|
9f1e395c16 | ||
|
|
bd87375202 | ||
|
|
5deedd6685 | ||
|
|
d4a5ca5056 | ||
|
|
077dbf4a86 | ||
|
|
d434ce3fca | ||
|
|
a22a67661a | ||
|
|
5bb28c7f10 | ||
|
|
a0d97fe408 | ||
|
|
8de270b4fc | ||
|
|
eca1408f16 | ||
|
|
3be4f886ce | ||
|
|
9f72a14920 | ||
|
|
b04d4a5b13 | ||
|
|
fa6f774b2c | ||
|
|
6aea34ad89 | ||
|
|
17b4509564 | ||
|
|
3c582bc7cb | ||
|
|
216a711cd4 | ||
|
|
6cf2a3966e | ||
|
|
0d10517a45 | ||
|
|
d5495966ce | ||
|
|
3dea8c9e92 | ||
|
|
6ab2c5e6cc | ||
|
|
53bfcc9e84 | ||
|
|
219245e10f | ||
|
|
7165fbd8f4 | ||
|
|
b32c01b748 | ||
|
|
443cc0114d | ||
|
|
2c7716fed0 | ||
|
|
dd4135aeaf | ||
|
|
0c595fa094 | ||
|
|
c71edaed73 | ||
|
|
88ca7ff565 | ||
|
|
7385b018ed | ||
|
|
897129a7ff | ||
|
|
290daa15d9 | ||
|
|
4fb72fe624 | ||
|
|
670376c5cb | ||
|
|
dcf14c1b18 | ||
|
|
791b65f4b2 | ||
|
|
f65e4f0b8f | ||
|
|
71fec076dc | ||
|
|
38b54b65d4 | ||
|
|
3f0c1c2452 | ||
|
|
f040685b0c | ||
|
|
67d52d8cb9 | ||
|
|
d46de80162 | ||
|
|
7b901d6fb7 | ||
|
|
d8a4d9d67c | ||
|
|
4c63986101 | ||
|
|
9cc8ec843e | ||
|
|
6d310a5552 | ||
|
|
eeb9d99333 | ||
|
|
7df9291b6c | ||
|
|
e97df97600 | ||
|
|
46ab042230 | ||
|
|
ec078af985 | ||
|
|
1f69b16d3f | ||
|
|
9310dad15d | ||
|
|
c4a69c75a5 | ||
|
|
6c79980b0e | ||
|
|
79ec869f95 | ||
|
|
c528489eee | ||
|
|
080e4d44f3 | ||
|
|
5f0ecb72c2 | ||
|
|
7f5a541b84 | ||
|
|
b84e1231c9 | ||
|
|
9ea2882317 | ||
|
|
93c4a6a3f7 | ||
|
|
b0a46900de | ||
|
|
7ea3fa2641 | ||
|
|
21c719bd0a | ||
|
|
34e0198436 | ||
|
|
cc7c311b5e | ||
|
|
3f5fe6269e | ||
|
|
bb954d80a4 | ||
|
|
fbddea929d | ||
|
|
60592fd23c | ||
|
|
b85bcd671c | ||
|
|
e60835bac5 | ||
|
|
4874bde104 | ||
|
|
8dd5960ac0 | ||
|
|
5da0d29d3c | ||
|
|
adaf0d865c | ||
|
|
a5624bf381 | ||
|
|
4b3f1d712b | ||
|
|
3fe047f08f | ||
|
|
4ab3eef8d7 | ||
|
|
a2391b5a74 | ||
|
|
5bf1b4e9d9 | ||
|
|
d08c9d342f | ||
|
|
f28efa1971 | ||
|
|
8ae885a0c6 | ||
|
|
ee324c501e | ||
|
|
b9672bcbe8 | ||
|
|
2b7c4a1878 | ||
|
|
67a4813601 | ||
|
|
f84b341618 | ||
|
|
3fea1f014c | ||
|
|
0fd3d8d19f | ||
|
|
081c0648ec | ||
|
|
dd0e6ddfeb | ||
|
|
d14d4cdb8b | ||
|
|
a50b26e4b0 | ||
|
|
b236b1974b | ||
|
|
2f02960607 | ||
|
|
1ba516f475 | ||
|
|
06a1194300 | ||
|
|
d89de18f40 | ||
|
|
f3b19ef634 | ||
|
|
3611dcc260 | ||
|
|
763e04bba5 | ||
|
|
f3b5480be7 | ||
|
|
dab0f316d2 | ||
|
|
742d8bdbe4 | ||
|
|
b4be5a8f34 | ||
|
|
4a9542c0c0 | ||
|
|
9103cbe366 | ||
|
|
b88bf6c76b | ||
|
|
69768c97c0 | ||
|
|
e4d6a10dc9 | ||
|
|
2b882e9aca | ||
|
|
ef47a67cf4 | ||
|
|
9526e24234 | ||
|
|
e2ac8bb3f1 | ||
|
|
cac8dc3414 | ||
|
|
778729c597 | ||
|
|
b4df3e74e1 | ||
|
|
20da9064d7 | ||
|
|
dba40afa70 | ||
|
|
7ddd1a58f6 | ||
|
|
1708fe3cc7 | ||
|
|
61e2dfd97d | ||
|
|
1bc5cb4312 | ||
|
|
fedab995ee | ||
|
|
2d8740a4d1 | ||
|
|
47899a1ab8 | ||
|
|
8c6856d2e7 | ||
|
|
015774a04f | ||
|
|
4a33677c97 | ||
|
|
76c366df56 | ||
|
|
f7c4611523 | ||
|
|
fafd587514 | ||
|
|
a6864a13c7 | ||
|
|
c51c883cc8 | ||
|
|
41ec22632d | ||
|
|
b6bdf18deb | ||
|
|
b4790afdaf | ||
|
|
58f3861358 | ||
|
|
5f3bda422a | ||
|
|
f127bef3e4 | ||
|
|
f98bb2ddcb | ||
|
|
ce1c786297 | ||
|
|
49406b0ac6 | ||
|
|
9b64d1966b | ||
|
|
3be8b688c0 | ||
|
|
5863e15a23 | ||
|
|
0823c1baf8 | ||
|
|
9c04ef2a67 | ||
|
|
1f61fe07a2 | ||
|
|
bae62d9abe | ||
|
|
76dcaddc0f | ||
|
|
efc904c41d | ||
|
|
5c3a2f162e | ||
|
|
d1a366fdd4 | ||
|
|
c777b6950e | ||
|
|
0f8b1ba8a2 | ||
|
|
f2da6467a9 | ||
|
|
57c92d90b0 | ||
|
|
13c5a228c9 | ||
|
|
59a9509703 | ||
|
|
8e9b98e974 | ||
|
|
9fba618356 | ||
|
|
ed0a06a93f | ||
|
|
263aaa7030 | ||
|
|
8f8f699eb7 | ||
|
|
f4ee9f8853 | ||
|
|
581a59a456 | ||
|
|
531217a06b | ||
|
|
fea7fe45ea | ||
|
|
26295e04ff | ||
|
|
fe3cc5bb53 | ||
|
|
3b5affa0d1 | ||
|
|
24df30c133 | ||
|
|
fc73c9b4b2 | ||
|
|
5ffe1d8dc0 | ||
|
|
d29ca28288 | ||
|
|
b0e2106fb8 | ||
|
|
891479e62a | ||
|
|
9897bcaa73 | ||
|
|
a589fa3e0b | ||
|
|
d09b6b9aa1 | ||
|
|
78bc31e294 | ||
|
|
5af6184e72 | ||
|
|
c428367543 | ||
|
|
39799f7564 | ||
|
|
6562076454 | ||
|
|
5a5449d4eb | ||
|
|
253e1a6f67 | ||
|
|
d2d9dfcd40 | ||
|
|
c6983e3ce0 | ||
|
|
f2a21a2489 | ||
|
|
d076fae219 | ||
|
|
8e7dfea803 | ||
|
|
49dd532180 | ||
|
|
64c5a9435c | ||
|
|
567e7fcd12 | ||
|
|
244332df9f | ||
|
|
a6fc90f92a | ||
|
|
ed4ce196ed | ||
|
|
ff1c2b03a9 | ||
|
|
bb19e7b94b | ||
|
|
f003310dee | ||
|
|
ed6a1ada24 | ||
|
|
d2cc7c720b | ||
|
|
095e43a9a5 | ||
|
|
f6a8e84a25 | ||
|
|
675d1c9c60 | ||
|
|
41fceae559 | ||
|
|
b359cf2911 | ||
|
|
d5f42c9daf | ||
|
|
3c82d1d34b | ||
|
|
2196799051 | ||
|
|
1a0d3fd632 | ||
|
|
4aaa5adf9f | ||
|
|
9cf2949356 | ||
|
|
0be4a7712d | ||
|
|
c4a8004933 | ||
|
|
83e0ebabb4 | ||
|
|
8c50f93a41 | ||
|
|
9e1b61dedd | ||
|
|
af9889f99a | ||
|
|
dfb8144037 | ||
|
|
4e36dd570b | ||
|
|
5e01fb01b3 | ||
|
|
72ae3c72c7 | ||
|
|
8a15e0b1c7 | ||
|
|
b203c1774e | ||
|
|
2146cdab5e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,6 +32,7 @@ tests/*.out
|
||||
# Python cache files
|
||||
######################
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Customized Makefile/project overrides
|
||||
######################
|
||||
|
||||
@@ -12,7 +12,7 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo dpkg --add-architecture i386
|
||||
- sudo apt-get update -qq || true
|
||||
- sudo apt-get install -y python3 gcc-multilib pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32
|
||||
- sudo apt-get install -y python3 gcc-multilib pkg-config libffi-dev libffi-dev:i386 qemu-system gcc-mingw-w64
|
||||
- sudo apt-get install -y --force-yes gcc-arm-none-eabi
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
@@ -23,6 +23,7 @@ before_script:
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make -C mpy-cross
|
||||
- make -C minimal test
|
||||
- make -C unix deplibs
|
||||
- make -C unix
|
||||
@@ -35,7 +36,7 @@ script:
|
||||
- make -C teensy
|
||||
- make -C cc3200 BTARGET=application BTYPE=release
|
||||
- make -C cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
|
||||
- make -C windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
|
||||
# run tests without coverage info
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
|
||||
@@ -46,6 +47,7 @@ script:
|
||||
- (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)
|
||||
|
||||
after_success:
|
||||
- (cd unix && coveralls --root .. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
[![Build Status][travis-img]][travis-repo] [![Coverage Status][coveralls-img]][coveralls-repo] [![Issue Stats][istats-pr-img]][istats-pr-repo] [![Issue Stats][istats-issue-img]][istats-issue-repo]
|
||||
[![Build Status][travis-img]][travis-repo] [![Coverage Status][coveralls-img]][coveralls-repo]
|
||||
[travis-img]: https://travis-ci.org/micropython/micropython.png?branch=master
|
||||
[travis-repo]: https://travis-ci.org/micropython/micropython
|
||||
[coveralls-img]: https://coveralls.io/repos/micropython/micropython/badge.png?branch=master
|
||||
[coveralls-repo]: https://coveralls.io/r/micropython/micropython?branch=master
|
||||
[istats-pr-img]: http://issuestats.com/github/micropython/micropython/badge/pr
|
||||
[istats-pr-repo]: http://issuestats.com/github/micropython/micropython
|
||||
[istats-issue-img]: http://issuestats.com/github/micropython/micropython/badge/issue
|
||||
[istats-issue-repo]: http://issuestats.com/github/micropython/micropython
|
||||
|
||||
The MicroPython project
|
||||
=======================
|
||||
@@ -26,7 +22,8 @@ MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
The following core datatypes are provided: str (including basic Unicode
|
||||
support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array,
|
||||
collections.namedtuple, classes and instances. Builtin modules include sys,
|
||||
time, and struct. Note that only subset of Python 3.4 functionality
|
||||
time, and struct, etc. Select ports have support for _thread module
|
||||
(multithreading). Note that only subset of Python 3.4 functionality
|
||||
implemented for the data types and modules.
|
||||
|
||||
See the repository www.github.com/micropython/pyboard for the Micro
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#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
|
||||
|
||||
@@ -54,8 +55,6 @@
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// dummy print
|
||||
|
||||
@@ -154,7 +154,6 @@ APP_LIB_SRC_C = $(addprefix lib/,\
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/pyhelp.c \
|
||||
utils/printf.c \
|
||||
)
|
||||
|
||||
APP_STM_SRC_C = $(addprefix stmhal/,\
|
||||
|
||||
@@ -198,7 +198,8 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = {
|
||||
{ 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) },
|
||||
{ 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) },
|
||||
@@ -212,6 +213,5 @@ STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table
|
||||
|
||||
const mp_obj_module_t machine_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_umachine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
|
||||
@@ -161,7 +161,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals
|
||||
|
||||
const mp_obj_module_t mp_module_network = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +58,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globa
|
||||
|
||||
const mp_obj_module_t mp_module_ubinascii = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ubinascii,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_binascii_globals,
|
||||
};
|
||||
|
||||
@@ -204,7 +204,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals
|
||||
|
||||
const mp_obj_module_t mp_module_uhashlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uhashlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -602,6 +602,5 @@ STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uos = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uos,
|
||||
.globals = (mp_obj_dict_t*)&os_module_globals,
|
||||
};
|
||||
|
||||
@@ -541,6 +541,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals
|
||||
|
||||
const mp_obj_module_t mp_module_usocket = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_usocket,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
|
||||
};
|
||||
|
||||
@@ -78,6 +78,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
{ 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} },
|
||||
};
|
||||
|
||||
@@ -93,17 +94,19 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
// 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[5].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
NULL : &(mp_obj_str_get_str(args[5].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 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
|
||||
_i16 _errno;
|
||||
_u8 method = SL_SO_SEC_METHOD_TLSV1;
|
||||
_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;
|
||||
}
|
||||
@@ -146,13 +149,17 @@ STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
|
||||
{ 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 },
|
||||
.name = MP_QSTR_ussl,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ussl_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -196,6 +196,5 @@ STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_utime = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_utime,
|
||||
.globals = (mp_obj_dict_t*)&time_module_globals,
|
||||
};
|
||||
|
||||
@@ -26,6 +26,5 @@ STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
|
||||
|
||||
const mp_obj_module_t wipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_wipy,
|
||||
.globals = (mp_obj_dict_t*)&wipy_module_globals,
|
||||
};
|
||||
|
||||
@@ -185,8 +185,6 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef unsigned int mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
@@ -99,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors'
|
||||
# The short X.Y version.
|
||||
version = '1.8'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.8.3'
|
||||
release = '1.8.5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -23,14 +23,14 @@ Tab-completion is useful to find out what methods an object has.
|
||||
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
|
||||
the REPL.
|
||||
|
||||
The ``machine`` module::
|
||||
The :mod:`machine` module::
|
||||
|
||||
import machine
|
||||
|
||||
machine.freq() # get the current frequency of the CPU
|
||||
machine.freq(160000000) # set the CPU frequency to 160 MHz
|
||||
|
||||
The ``esp`` module::
|
||||
The :mod:`esp` module::
|
||||
|
||||
import esp
|
||||
|
||||
@@ -40,7 +40,7 @@ The ``esp`` module::
|
||||
Networking
|
||||
----------
|
||||
|
||||
The ``network`` module::
|
||||
The :mod:`network` module::
|
||||
|
||||
import network
|
||||
|
||||
@@ -69,13 +69,13 @@ A useful function for connecting to your local WiFi network is::
|
||||
pass
|
||||
print('network config:', wlan.ifconfig())
|
||||
|
||||
Once the network is established the ``socket`` module can be used
|
||||
Once the network is established the :mod:`socket <usocket>` module can be used
|
||||
to create and use TCP/UDP sockets as usual.
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the ``time`` module::
|
||||
Use the :mod:`time <utime>` module::
|
||||
|
||||
import time
|
||||
|
||||
@@ -162,17 +162,18 @@ Use the ``machine.ADC`` class::
|
||||
adc = ADC(0) # create ADC object on ADC pin
|
||||
adc.read() # read value, 0-1024
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
Software SPI bus
|
||||
----------------
|
||||
|
||||
The SPI driver is implemented in software and works on all pins::
|
||||
There are two SPI drivers. One is implemented in software (bit-banging)
|
||||
and works on all pins::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
# construct an SPI bus on the given pins
|
||||
# polarity is the idle state of SCK
|
||||
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||
spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
@@ -189,6 +190,21 @@ The SPI driver is implemented in software and works on all pins::
|
||||
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
|
||||
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
|
||||
|
||||
|
||||
Hardware SPI bus
|
||||
----------------
|
||||
|
||||
The hardware SPI is faster (up to 80Mhz), but only works on following pins:
|
||||
``MISO`` is GPIO12, ``MOSI`` is GPIO13, and ``SCK`` is GPIO14. It has the same
|
||||
methods as the bitbanging SPI class above, except for the pin parameters for the
|
||||
constructor and init (as those are fixed)::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
hspi = SPI(1, baudrate=80000000, polarity=0, phase=0)
|
||||
|
||||
(``SPI(0)`` is used for FlashROM and not available to users.)
|
||||
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
@@ -239,15 +255,14 @@ The OneWire driver is implemented in software and works on all pins::
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.readbyte() # read a byte
|
||||
ow.read(5) # read 5 bytes
|
||||
ow.writebyte(0x12) # write a byte on the bus
|
||||
ow.write('123') # write bytes on the bus
|
||||
ow.select_rom(b'12345678') # select a specific device by its ROM code
|
||||
|
||||
There is a specific driver for DS18B20 devices::
|
||||
There is a specific driver for DS18S20 and DS18B20 devices::
|
||||
|
||||
import time
|
||||
ds = onewire.DS18B20(ow)
|
||||
import time, ds18x20
|
||||
ds = ds18x20.DS18X20(ow)
|
||||
roms = ds.scan()
|
||||
ds.convert_temp()
|
||||
time.sleep_ms(750)
|
||||
|
||||
@@ -135,6 +135,10 @@ after it, here are troubleshooting recommendations:
|
||||
rate may be too high and lead to errors. Try a more common 115200 baud
|
||||
rate instead in such cases.
|
||||
|
||||
* If lower baud rate didn't help, you may want to try older version of
|
||||
esptool.py, which had a different programming algorithm::
|
||||
pip install esptool==1.0.1
|
||||
|
||||
* The ``--flash_size`` option in the commands above is mandatory. Omitting
|
||||
it will lead to a corrupted firmware.
|
||||
|
||||
|
||||
@@ -6,19 +6,19 @@ The 1-wire bus is a serial bus that uses just a single wire for communication
|
||||
is a very popular 1-wire device, and here we show how to use the onewire module
|
||||
to read from such a device.
|
||||
|
||||
For the following code to work you need to have at least one DS18B20 temperature
|
||||
For the following code to work you need to have at least one DS18S20 or DS18B20 temperature
|
||||
sensor with its data line connected to GPIO12. You must also power the sensors
|
||||
and connect a 4.7k Ohm resistor between the data pin and the power pin. ::
|
||||
|
||||
import time
|
||||
import machine
|
||||
import onewire
|
||||
import onewire, ds18x20
|
||||
|
||||
# the device is on GPIO12
|
||||
dat = machine.Pin(12)
|
||||
|
||||
# create the onewire object
|
||||
ds = onewire.DS18B20(onewire.OneWire(dat))
|
||||
ds = ds18x20.DS18X20(onewire.OneWire(dat))
|
||||
|
||||
# scan for devices on the bus
|
||||
roms = ds.scan()
|
||||
|
||||
@@ -14,7 +14,7 @@ Here, the "0" is the pin that you want to access. Usually you want to
|
||||
configure the pin to be input or output, and you do this when constructing
|
||||
it. To make an input pin use::
|
||||
|
||||
>>> pin = machine.Pin(0, machine.Pin.OUT, machine.Pin.PULL_UP)
|
||||
>>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
|
||||
|
||||
You can either use PULL_UP or None for the input pull-mode. If it's
|
||||
not specified then it defaults to None, which is no pull resistor.
|
||||
|
||||
@@ -170,8 +170,7 @@ methods are convenience functions to communicate with such devices.
|
||||
|
||||
Read `nbytes` from the slave specified by `addr` starting from the memory
|
||||
address specified by `memaddr`.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
The argument `addrsize` specifies the address size in bits.
|
||||
Returns a `bytes` object with the data read.
|
||||
|
||||
.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8)
|
||||
|
||||
@@ -14,6 +14,8 @@ Example usage::
|
||||
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
|
||||
wdt.feed()
|
||||
|
||||
Availability of this class: pyboard, WiPy.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
|
||||
@@ -24,17 +24,15 @@ Interrupt related functions
|
||||
.. function:: disable_irq()
|
||||
|
||||
Disable interrupt requests.
|
||||
Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs
|
||||
respectively. This return value can be passed to enable_irq to restore
|
||||
the IRQ to its original state.
|
||||
Returns the previous IRQ state which should be considered an opaque value.
|
||||
This return value should be passed to the ``enable_irq`` function to restore
|
||||
interrupts to their original state, before ``disable_irq`` was called.
|
||||
|
||||
.. function:: enable_irq(state=True)
|
||||
.. function:: enable_irq(state)
|
||||
|
||||
Enable interrupt requests.
|
||||
If ``state`` is ``True`` (the default value) then IRQs are enabled.
|
||||
If ``state`` is ``False`` then IRQs are disabled. The most common use of
|
||||
this function is to pass it the value returned by ``disable_irq`` to
|
||||
exit a critical section.
|
||||
Re-enable interrupt requests.
|
||||
The ``state`` parameter should be the value that was returned from the most
|
||||
recent call to the ``disable_irq`` function.
|
||||
|
||||
Power related functions
|
||||
-----------------------
|
||||
@@ -125,7 +123,7 @@ Constants
|
||||
|
||||
irq wake values
|
||||
|
||||
.. data:: machine.POWER_ON
|
||||
.. data:: machine.PWRON_RESET
|
||||
.. data:: machine.HARD_RESET
|
||||
.. data:: machine.WDT_RESET
|
||||
.. data:: machine.DEEPSLEEP_RESET
|
||||
|
||||
@@ -68,6 +68,7 @@ Methods
|
||||
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
|
||||
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
|
||||
respectively.
|
||||
- ``bits`` can be 8 or 16, and is the number of bits in each transferred word.
|
||||
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
|
||||
- ``crc`` can be None for no CRC, or a polynomial specifier.
|
||||
|
||||
|
||||
39
docs/library/pyb.USB_HID.rst
Normal file
39
docs/library/pyb.USB_HID.rst
Normal file
@@ -0,0 +1,39 @@
|
||||
.. currentmodule:: pyb
|
||||
|
||||
class USB_HID -- USB Human Interface Device (HID)
|
||||
=================================================
|
||||
|
||||
The USB_HID class allows creation of an object representing the USB
|
||||
Human Interface Device (HID) interface. It can be used to emulate
|
||||
a peripheral such as a mouse or keyboard.
|
||||
|
||||
Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.USB_HID()
|
||||
|
||||
Create a new USB_HID object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: USB_HID.recv(data, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``data`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: if ``data`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the number of bytes read into ``data`` is returned.
|
||||
|
||||
.. method:: USB_HID.send(data)
|
||||
|
||||
Send data over the USB HID interface:
|
||||
|
||||
- ``data`` is the data to send (a tuple/list of integers, or a
|
||||
bytearray).
|
||||
@@ -188,7 +188,7 @@ Miscellaneous functions
|
||||
Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
|
||||
signal a HID mouse-motion event.
|
||||
|
||||
.. note:: This function is deprecated. Use pyb.USB_HID().send(...) instead.
|
||||
.. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead.
|
||||
|
||||
.. function:: info([dump_alloc_table])
|
||||
|
||||
@@ -254,6 +254,33 @@ Miscellaneous functions
|
||||
|
||||
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
|
||||
|
||||
.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse)
|
||||
|
||||
If called with no arguments, return the current USB mode as a string.
|
||||
|
||||
If called with ``modestr`` provided, attempts to set USB mode.
|
||||
This can only be done when called from ``boot.py`` before
|
||||
:meth:`pyb.main()` has been called. The following values of
|
||||
``modestr`` are understood:
|
||||
|
||||
- ``None``: disables USB
|
||||
- ``'VCP'``: enable with VCP (Virtual COM Port) interface
|
||||
- ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class)
|
||||
- ``'VCP+HID'``: enable with VCP and HID (human interface device)
|
||||
|
||||
For backwards compatibility, ``'CDC'`` is understood to mean
|
||||
``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``).
|
||||
|
||||
The ``vid`` and ``pid`` parameters allow you to specify the VID
|
||||
(vendor id) and PID (product id).
|
||||
|
||||
If enabling HID mode, you may also specify the HID details by
|
||||
passing the ``hid`` keyword parameter. It takes a tuple of
|
||||
(subclass, protocol, max packet length, polling interval, report
|
||||
descriptor). By default it will set appropriate values for a USB
|
||||
mouse. There is also a ``pyb.hid_keyboard`` constant, which is an
|
||||
appropriate tuple for a USB keyboard.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
@@ -277,4 +304,5 @@ Classes
|
||||
pyb.Switch.rst
|
||||
pyb.Timer.rst
|
||||
pyb.UART.rst
|
||||
pyb.USB_HID.rst
|
||||
pyb.USB_VCP.rst
|
||||
|
||||
@@ -61,6 +61,29 @@ Functions
|
||||
|
||||
Get the status of a file or directory.
|
||||
|
||||
.. only:: port_unix or port_pyboard or port_esp8266
|
||||
|
||||
.. function:: statvfs(path)
|
||||
|
||||
Get the status of a fileystem.
|
||||
|
||||
Returns a tuple with the filesystem information in the following order:
|
||||
|
||||
* ``f_bsize`` -- file system block size
|
||||
* ``f_frsize`` -- fragment size
|
||||
* ``f_blocks`` -- size of fs in f_frsize units
|
||||
* ``f_bfree`` -- number of free blocks
|
||||
* ``f_bavail`` -- number of free blocks for unpriviliged users
|
||||
* ``f_files`` -- number of inodes
|
||||
* ``f_ffree`` -- number of free inodes
|
||||
* ``f_favail`` -- number of free inodes for unpriviliged users
|
||||
* ``f_flag`` -- mount flags
|
||||
* ``f_namemax`` -- maximum filename length
|
||||
|
||||
Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
|
||||
and the ``f_flags`` parameter may return ``0`` as they can be unavailable
|
||||
in a port-specific implementation.
|
||||
|
||||
.. function:: sync()
|
||||
|
||||
Sync all filesystems.
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
Quick reference for the pyboard
|
||||
===============================
|
||||
|
||||
The below pinout is for PYBv1.0. You can also view pinouts for
|
||||
other versions of the pyboard:
|
||||
`PYBv1.1 <http://micropython.org/resources/pybv11-pinout.jpg>`__
|
||||
or `PYBLITEv1.0-AC <http://micropython.org/resources/pyblitev10ac-pinout.jpg>`__
|
||||
or `PYBLITEv1.0 <http://micropython.org/resources/pyblitev10-pinout.jpg>`__.
|
||||
|
||||
.. image:: http://micropython.org/resources/pybv10-pinout.jpg
|
||||
:alt: PYBv1.0 pinout
|
||||
:width: 700px
|
||||
@@ -14,14 +20,25 @@ See :mod:`pyb`. ::
|
||||
|
||||
import pyb
|
||||
|
||||
pyb.delay(50) # wait 50 milliseconds
|
||||
pyb.millis() # number of milliseconds since bootup
|
||||
pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1)
|
||||
pyb.wfi() # pause CPU, waiting for interrupt
|
||||
pyb.freq() # get CPU and bus frequencies
|
||||
pyb.freq(60000000) # set CPU freq to 60MHz
|
||||
pyb.stop() # stop CPU, waiting for external interrupt
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the :mod:`time <utime>` module::
|
||||
|
||||
import time
|
||||
|
||||
time.sleep(1) # sleep for 1 second
|
||||
time.sleep_ms(500) # sleep for 500 milliseconds
|
||||
time.sleep_us(10) # sleep for 10 microseconds
|
||||
start = time.ticks_ms() # get value of millisecond counter
|
||||
delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference
|
||||
|
||||
LEDs
|
||||
----
|
||||
|
||||
|
||||
@@ -13,23 +13,23 @@ will look something like this::
|
||||
|
||||
import pyb
|
||||
#pyb.main('main.py') # main script to run after this one
|
||||
#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device
|
||||
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device
|
||||
#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
To enable the mouse mode, uncomment the last line of the file, to
|
||||
make it look like::
|
||||
|
||||
pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
If you already changed your ``boot.py`` file, then the minimum code it
|
||||
needs to work is::
|
||||
|
||||
import pyb
|
||||
pyb.usb_mode('CDC+HID')
|
||||
pyb.usb_mode('VCP+HID')
|
||||
|
||||
This tells the pyboard to configure itself as a CDC (serial) and HID
|
||||
(human interface device, in our case a mouse) USB device when it boots
|
||||
up.
|
||||
This tells the pyboard to configure itself as a VCP (Virtual COM Port,
|
||||
ie serial port) and HID (human interface device, in our case a mouse)
|
||||
USB device when it boots up.
|
||||
|
||||
Eject/unmount the pyboard drive and reset it using the RST switch.
|
||||
Your PC should now detect the pyboard as a mouse!
|
||||
@@ -41,7 +41,8 @@ To get the py-mouse to do anything we need to send mouse events to the PC.
|
||||
We will first do this manually using the REPL prompt. Connect to your
|
||||
pyboard using your serial program and type the following::
|
||||
|
||||
>>> pyb.hid((0, 10, 0, 0))
|
||||
>>> hid = pyb.USB_HID()
|
||||
>>> hid.send((0, 10, 0, 0))
|
||||
|
||||
Your mouse should move 10 pixels to the right! In the command above you
|
||||
are sending 4 pieces of information: button status, x, y and scroll. The
|
||||
@@ -52,7 +53,7 @@ Let's make the mouse oscillate left and right::
|
||||
>>> import math
|
||||
>>> def osc(n, d):
|
||||
... for i in range(n):
|
||||
... pyb.hid((0, int(20 * math.sin(i / 10)), 0, 0))
|
||||
... hid.send((0, int(20 * math.sin(i / 10)), 0, 0))
|
||||
... pyb.delay(d)
|
||||
...
|
||||
>>> osc(100, 50)
|
||||
@@ -100,9 +101,10 @@ In ``main.py`` put the following code::
|
||||
|
||||
switch = pyb.Switch()
|
||||
accel = pyb.Accel()
|
||||
hid = pyb.USB_HID()
|
||||
|
||||
while not switch():
|
||||
pyb.hid((0, accel.x(), accel.y(), 0))
|
||||
hid.send((0, accel.x(), accel.y(), 0))
|
||||
pyb.delay(20)
|
||||
|
||||
Save your file, eject/unmount your pyboard drive, and reset it using the RST
|
||||
@@ -112,7 +114,7 @@ the mouse around. Try it out, and see if you can make the mouse stand still!
|
||||
Press the USR switch to stop the mouse motion.
|
||||
|
||||
You'll note that the y-axis is inverted. That's easy to fix: just put a
|
||||
minus sign in front of the y-coordinate in the ``pyb.hid()`` line above.
|
||||
minus sign in front of the y-coordinate in the ``hid.send()`` line above.
|
||||
|
||||
Restoring your pyboard to normal
|
||||
--------------------------------
|
||||
@@ -121,9 +123,9 @@ If you leave your pyboard as-is, it'll behave as a mouse everytime you plug
|
||||
it in. You probably want to change it back to normal. To do this you need
|
||||
to first enter safe mode (see above), and then edit the ``boot.py`` file.
|
||||
In the ``boot.py`` file, comment out (put a # in front of) the line with the
|
||||
``CDC+HID`` setting, so it looks like::
|
||||
``VCP+HID`` setting, so it looks like::
|
||||
|
||||
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
Save your file, eject/unmount the drive, and reset the pyboard. It is now
|
||||
back to normal operating mode.
|
||||
|
||||
456
docs/reference/constrained.rst
Normal file
456
docs/reference/constrained.rst
Normal file
@@ -0,0 +1,456 @@
|
||||
.. _constrained:
|
||||
|
||||
MicroPython on Microcontrollers
|
||||
===============================
|
||||
|
||||
MicroPython is designed to be capable of running on microcontrollers. These
|
||||
have hardware limitations which may be unfamiliar to programmers more familiar
|
||||
with conventional computers. In particular the amount of RAM and nonvolatile
|
||||
"disk" (flash memory) storage is limited. This tutorial offers ways to make
|
||||
the most of the limited resources. Because MicroPython runs on controllers
|
||||
based on a variety of architectures, the methods presented are generic: in some
|
||||
cases it will be necessary to obtain detailed information from platform specific
|
||||
documentation.
|
||||
|
||||
Flash Memory
|
||||
------------
|
||||
|
||||
On the Pyboard the simple way to address the limited capacity is to fit a micro
|
||||
SD card. In some cases this is impractical, either because the device does not
|
||||
have an SD card slot or for reasons of cost or power consumption; hence the
|
||||
on-chip flash must be used. The firmware including the MicroPython subsystem is
|
||||
stored in the onboard flash. The remaining capacity is available for use. For
|
||||
reasons connected with the physical architecture of the flash memory part of
|
||||
this capacity may be inaccessible as a filesystem. In such cases this space may
|
||||
be employed by incorporating user modules into a firmware build which is then
|
||||
flashed to the device.
|
||||
|
||||
There are two ways to achieve this: frozen modules and frozen bytecode. Frozen
|
||||
modules store the Python source with the firmware. Frozen bytecode uses the
|
||||
cross compiler to convert the source to bytecode which is then stored with the
|
||||
firmware. In either case the module may be accessed with an import statement:
|
||||
|
||||
.. code::
|
||||
|
||||
import mymodule
|
||||
|
||||
The procedure for producing frozen modules and bytecode is platform dependent;
|
||||
instructions for building the firmware can be found in the README files in the
|
||||
relevant part of the source tree.
|
||||
|
||||
In general terms the steps are as follows:
|
||||
|
||||
* Clone the MicroPython `repository <https://github.com/micropython/micropython>`_.
|
||||
* Acquire the (platform specific) toolchain to build the firmware.
|
||||
* Build the cross compiler.
|
||||
* Place the modules to be frozen in a specified directory (dependent on whether
|
||||
the module is to be frozen as source or as bytecode).
|
||||
* Build the firmware. A specific command may be required to build frozen
|
||||
code of either type - see the platform documentation.
|
||||
* Flash the firmware to the device.
|
||||
|
||||
RAM
|
||||
---
|
||||
|
||||
When reducing RAM usage there are two phases to consider: compilation and
|
||||
execution. In addition to memory consumption, there is also an issue known as
|
||||
heap fragmentation. In general terms it is best to minimise the repeated
|
||||
creation and destruction of objects. The reason for this is covered in the
|
||||
section covering the `heap`_.
|
||||
|
||||
Compilation Phase
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a module is imported, MicroPython compiles the code to bytecode which is
|
||||
then executed by the MicroPython virtual machine (VM). The bytecode is stored
|
||||
in RAM. The compiler itself requires RAM, but this becomes available for use
|
||||
when the compilation has completed.
|
||||
|
||||
If a number of modules have already been imported the situation can arise where
|
||||
there is insufficient RAM to run the compiler. In this case the import
|
||||
statement will produce a memory exception.
|
||||
|
||||
If a module instantiates global objects on import it will consume RAM at the
|
||||
time of import, which is then unavailable for the compiler to use on subsequent
|
||||
imports. In general it is best to avoid code which runs on import; a better
|
||||
approach is to have initialisation code which is run by the application after
|
||||
all modules have been imported. This maximises the RAM available to the
|
||||
compiler.
|
||||
|
||||
If RAM is still insufficient to compile all modules one solution is to
|
||||
precompile modules. MicroPython has a cross compiler capable of compiling Python
|
||||
modules to bytecode (see the README in the mpy-cross directory). The resulting
|
||||
bytecode file has a .mpy extension; it may be copied to the filesystem and
|
||||
imported in the usual way. Alternatively some or all modules may be implemented
|
||||
as frozen bytecode: on most platforms this saves even more RAM as the bytecode
|
||||
is run directly from flash rather than being stored in RAM.
|
||||
|
||||
Execution Phase
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
There are a number of coding techniques for reducing RAM usage.
|
||||
|
||||
**Constants**
|
||||
|
||||
MicroPython provides a ``const`` keyword which may be used as follows:
|
||||
|
||||
.. code::
|
||||
|
||||
from micropython import const
|
||||
ROWS = const(33)
|
||||
_COLS = const(0x10)
|
||||
a = ROWS
|
||||
b = _COLS
|
||||
|
||||
In both instances where the constant is assigned to a variable the compiler
|
||||
will avoid coding a lookup to the name of the constant by substituting its
|
||||
literal value. This saves bytecode and hence RAM. However the ``ROWS`` value
|
||||
will occupy at least two machine words, one each for the key and value in the
|
||||
globals dictionary. The presence in the dictionary is necessary because another
|
||||
module might import or use it. This RAM can be saved by prepending the name
|
||||
with an underscore as in ``_COLS``: this symbol is not visible outside the
|
||||
module so will not occupy RAM.
|
||||
|
||||
The argument to ``const()`` may be anything which, at compile time, evaluates
|
||||
to an integer e.g. ``0x100`` or ``1 << 8``. It can even include other const
|
||||
symbols that have already been defined, e.g. ``1 << BIT``.
|
||||
|
||||
**Constant data structures**
|
||||
|
||||
Where there is a substantial volume of constant data and the platform supports
|
||||
execution from Flash, RAM may be saved as follows. The data should be located in
|
||||
Python modules and frozen as bytecode. The data must be defined as ``bytes``
|
||||
objects. The compiler 'knows' that ``bytes`` objects are immutable and ensures
|
||||
that the objects remain in flash memory rather than being copied to RAM. The
|
||||
``ustruct`` module can assist in converting between ``bytes`` types and other
|
||||
Python built-in types.
|
||||
|
||||
When considering the implications of frozen bytecode, note that in Python
|
||||
strings, floats, bytes, integers and complex numbers are immutable. Accordingly
|
||||
these will be frozen into flash. Thus, in the line
|
||||
|
||||
.. code::
|
||||
|
||||
mystring = "The quick brown fox"
|
||||
|
||||
the actual string "The quick brown fox" will reside in flash. At runtime a
|
||||
reference to the string is assigned to the *variable* ``mystring``. The reference
|
||||
occupies a single machine word. In principle a long integer could be used to
|
||||
store constant data:
|
||||
|
||||
.. code::
|
||||
|
||||
bar = 0xDEADBEEF0000DEADBEEF
|
||||
|
||||
As in the string example, at runtime a reference to the arbitrarily large
|
||||
integer is assigned to the variable ``bar``. That reference occupies a
|
||||
single machine word.
|
||||
|
||||
It might be expected that tuples of integers could be employed for the purpose
|
||||
of storing constant data with minimal RAM use. With the current compiler this
|
||||
is ineffective (the code works, but RAM is not saved).
|
||||
|
||||
.. code::
|
||||
|
||||
foo = (1, 2, 3, 4, 5, 6, 100000)
|
||||
|
||||
At runtime the tuple will be located in RAM. This may be subject to future
|
||||
improvement.
|
||||
|
||||
**Needless object creation**
|
||||
|
||||
There are a number of situations where objects may unwittingly be created and
|
||||
destroyed. This can reduce the usability of RAM through fragmentation. The
|
||||
following sections discuss instances of this.
|
||||
|
||||
**String concatenation**
|
||||
|
||||
Consider the following code fragments which aim to produce constant strings:
|
||||
|
||||
.. code::
|
||||
|
||||
var = "foo" + "bar"
|
||||
var1 = "foo" "bar"
|
||||
var2 = """\
|
||||
foo\
|
||||
bar"""
|
||||
|
||||
Each produces the same outcome, however the first needlessly creates two string
|
||||
objects at runtime, allocates more RAM for concatenation before producing the
|
||||
third. The others perform the concatenation at compile time which is more
|
||||
efficient, reducing fragmentation.
|
||||
|
||||
Where strings must be dynamically created before being fed to a stream such as
|
||||
a file it will save RAM if this is done in a piecemeal fashion. Rather than
|
||||
creating a large string object, create a substring and feed it to the stream
|
||||
before dealing with the next.
|
||||
|
||||
The best way to create dynamic strings is by means of the string ``format``
|
||||
method:
|
||||
|
||||
.. code::
|
||||
|
||||
var = "Temperature {:5.2f} Pressure {:06d}\n".format(temp, press)
|
||||
|
||||
**Buffers**
|
||||
|
||||
When accessing devices such as instances of UART, I2C and SPI interfaces, using
|
||||
pre-allocated buffers avoids the creation of needless objects. Consider these
|
||||
two loops:
|
||||
|
||||
.. code::
|
||||
|
||||
while True:
|
||||
var = spi.read(100)
|
||||
# process data
|
||||
|
||||
buf = bytearray(100)
|
||||
while True:
|
||||
spi.readinto(buf)
|
||||
# process data in buf
|
||||
|
||||
The first creates a buffer on each pass whereas the second re-uses a pre-allocated
|
||||
buffer; this is both faster and more efficient in terms of memory fragmentation.
|
||||
|
||||
**Bytes are smaller than ints**
|
||||
|
||||
On most platforms an integer consumes four bytes. Consider the two calls to the
|
||||
function ``foo()``:
|
||||
|
||||
.. code::
|
||||
|
||||
def foo(bar):
|
||||
for x in bar:
|
||||
print(x)
|
||||
foo((1, 2, 0xff))
|
||||
foo(b'\1\2\xff')
|
||||
|
||||
In the first call a tuple of integers is created in RAM. The second efficiently
|
||||
creates a ``bytes`` object consuming the minimum amount of RAM. If the module
|
||||
were frozen as bytecode, the ``bytes`` object would reside in flash.
|
||||
|
||||
**Strings Versus Bytes**
|
||||
|
||||
Python3 introduced Unicode support. This introduced a distinction between a
|
||||
string and an array of bytes. MicroPython ensures that Unicode strings take no
|
||||
additional space so long as all characters in the string are ASCII (i.e. have
|
||||
a value < 126). If values in the full 8-bit range are required ``bytes`` and
|
||||
``bytearray`` objects can be used to ensure that no additional space will be
|
||||
required. Note that most string methods (e.g. ``strip()``) apply also to ``bytes``
|
||||
instances so the process of eliminating Unicode can be painless.
|
||||
|
||||
.. code::
|
||||
|
||||
s = 'the quick brown fox' # A string instance
|
||||
b = b'the quick brown fox' # a bytes instance
|
||||
|
||||
Where it is necessary to convert between strings and bytes the string ``encode``
|
||||
and the bytes ``decode`` methods can be used. Note that both strings and bytes
|
||||
are immutable. Any operation which takes as input such an object and produces
|
||||
another implies at least one RAM allocation to produce the result. In the
|
||||
second line below a new bytes object is allocated. This would also occur if ``foo``
|
||||
were a string.
|
||||
|
||||
.. code::
|
||||
|
||||
foo = b' empty whitespace'
|
||||
foo = foo.lstrip()
|
||||
|
||||
**Runtime compiler execution**
|
||||
|
||||
The Python keywords ``eval`` and ``exec`` invoke the compiler at runtime, which
|
||||
requires significant amounts of RAM. Note that the ``pickle`` library employs
|
||||
``exec``. It may be more RAM efficient to use the ``json`` library for object
|
||||
serialisation.
|
||||
|
||||
**Storing strings in flash**
|
||||
|
||||
Python strings are immutable hence have the potential to be stored in read only
|
||||
memory. The compiler can place in flash strings defined in Python code. As with
|
||||
frozen modules it is necessary to have a copy of the source tree on the PC and
|
||||
the toolchain to build the firmware. The procedure will work even if the
|
||||
modules have not been fully debugged, so long as they can be imported and run.
|
||||
|
||||
After importing the modules, execute:
|
||||
|
||||
.. code::
|
||||
|
||||
micropython.qstr_info(1)
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
.. code::
|
||||
|
||||
micropython.qstr_info(1)
|
||||
|
||||
The Q(xxx) lines should be gone.
|
||||
|
||||
.. _heap:
|
||||
|
||||
The Heap
|
||||
--------
|
||||
|
||||
When a running program instantiates an object the necessary RAM is allocated
|
||||
from a fixed size pool known as the heap. When the object goes out of scope (in
|
||||
other words becomes inaccessible to code) the redundant object is known as
|
||||
"garbage". A process known as "garbage collection" (GC) reclaims that memory,
|
||||
returning it to the free heap. This process runs automatically, however it can
|
||||
be invoked directly by issuing ``gc.collect()``.
|
||||
|
||||
The discourse on this is somewhat involved. For a 'quick fix' issue the
|
||||
following periodically:
|
||||
|
||||
.. code::
|
||||
|
||||
gc.collect()
|
||||
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
|
||||
|
||||
Fragmentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Say a program creates an object ``foo``, then an object ``bar``. Subsequently
|
||||
``foo`` goes out of scope but ``bar`` remains. The RAM used by ``foo`` will be
|
||||
reclaimed by GC. However if ``bar`` was allocated to a higher address, the
|
||||
RAM reclaimed from ``foo`` will only be of use for objects no bigger than
|
||||
``foo``. In a complex or long running program the heap can become fragmented:
|
||||
despite there being a substantial amount of RAM available, there is insufficient
|
||||
contiguous space to allocate a particular object, and the program fails with a
|
||||
memory error.
|
||||
|
||||
The techniques outlined above aim to minimise this. Where large permanent buffers
|
||||
or other objects are required it is best to instantiate these early in the
|
||||
process of program execution before fragmentation can occur. Further improvements
|
||||
may be made by monitoring the state of the heap and by controlling GC; these are
|
||||
outlined below.
|
||||
|
||||
Reporting
|
||||
~~~~~~~~~
|
||||
|
||||
A number of library functions are available to report on memory allocation and
|
||||
to control GC. These are to be found in the ``gc`` and ``micropython`` modules.
|
||||
The following example may be pasted at the REPL (``ctrl e`` to enter paste mode,
|
||||
``ctrl d`` to run it).
|
||||
|
||||
.. code::
|
||||
|
||||
import gc
|
||||
import micropython
|
||||
gc.collect()
|
||||
micropython.mem_info()
|
||||
print('-----------------------------')
|
||||
print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
def func():
|
||||
a = bytearray(10000)
|
||||
gc.collect()
|
||||
print('Func definition: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
func()
|
||||
print('Func run free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
gc.collect()
|
||||
print('Garbage collect free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
print('-----------------------------')
|
||||
micropython.mem_info(1)
|
||||
|
||||
Methods employed above:
|
||||
|
||||
* ``gc.collect()`` Force a garbage collection. See footnote.
|
||||
* ``micropython.mem_info()`` Print a summary of RAM utilisation.
|
||||
* ``gc.mem_free()`` Return the free heap size in bytes.
|
||||
* ``gc.mem_alloc()`` Return the number of bytes currently allocated.
|
||||
* ``micropython.mem_info(1)`` Print a table of heap utilisation (detailed below).
|
||||
|
||||
The numbers produced are dependent on the platform, but it can be seen that
|
||||
declaring the function uses a small amount of RAM in the form of bytecode
|
||||
emitted by the compiler (the RAM used by the compiler has been reclaimed).
|
||||
Running the function uses over 10KiB, but on return ``a`` is garbage because it
|
||||
is out of scope and cannot be referenced. The final ``gc.collect()`` recovers
|
||||
that memory.
|
||||
|
||||
The final output produced by ``micropython.mem_info(1)`` will vary in detail but
|
||||
may be interpreted as follows:
|
||||
|
||||
====== =================
|
||||
Symbol Meaning
|
||||
====== =================
|
||||
. free block
|
||||
h head block
|
||||
= tail block
|
||||
m marked head block
|
||||
T tuple
|
||||
L list
|
||||
D dict
|
||||
F float
|
||||
B byte code
|
||||
M module
|
||||
====== =================
|
||||
|
||||
Each letter represents a single block of memory, a block being 16 bytes. So each
|
||||
line of the heap dump represents 0x400 bytes or 1KiB of RAM.
|
||||
|
||||
Control of Garbage Collection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A GC can be demanded at any time by issuing ``gc.collect()``. It is advantageous
|
||||
to do this at intervals, firstly to pre-empt fragmentation and secondly for
|
||||
performance. A GC can take several milliseconds but is quicker when there is
|
||||
little work to do (about 1ms on the Pyboard). An explicit call can minimise that
|
||||
delay while ensuring it occurs at points in the program when it is acceptable.
|
||||
|
||||
Automatic GC is provoked under the following circumstances. When an attempt at
|
||||
allocation fails, a GC is performed and the allocation re-tried. Only if this
|
||||
fails is an exception raised. Secondly an automatic GC will be triggered if the
|
||||
amount of free RAM falls below a threshold. This threshold can be adapted as
|
||||
execution progresses:
|
||||
|
||||
.. code::
|
||||
|
||||
gc.collect()
|
||||
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
|
||||
|
||||
This will provoke a GC when more than 25% of the currently free heap becomes
|
||||
occupied.
|
||||
|
||||
In general modules should instantiate data objects at runtime using constructors
|
||||
or other initialisation functions. The reason is that if this occurs on
|
||||
initialisation the compiler may be starved of RAM when subsequent modules are
|
||||
imported. If modules do instantiate data on import then ``gc.collect()`` issued
|
||||
after the import will ameliorate the problem.
|
||||
|
||||
String Operations
|
||||
-----------------
|
||||
|
||||
MicroPython handles strings in an efficient manner and understanding this can
|
||||
help in designing applications to run on microcontrollers. When a module
|
||||
is compiled, strings which occur multiple times are stored once only, a process
|
||||
known as string interning. In MicroPython an interned string is known as a ``qstr``.
|
||||
In a module imported normally that single instance will be located in RAM, but
|
||||
as described above, in modules frozen as bytecode it will be located in flash.
|
||||
|
||||
String comparisons are also performed efficiently using hashing rather than
|
||||
character by character. The penalty for using strings rather than integers may
|
||||
hence be small both in terms of performance and RAM usage - a fact which may
|
||||
come as a surprise to C programmers.
|
||||
|
||||
Postscript
|
||||
----------
|
||||
|
||||
MicroPython passes, returns and (by default) copies objects by reference. A
|
||||
reference occupies a single machine word so these processes are efficient in
|
||||
RAM usage and speed.
|
||||
|
||||
Where variables are required whose size is neither a byte nor a machine word
|
||||
there are standard libraries which can assist in storing these efficiently and
|
||||
in performing conversions. See the ``array``, ``ustruct`` and ``uctypes``
|
||||
modules.
|
||||
|
||||
Footnote: gc.collect() return value
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
On Unix and Windows platforms the ``gc.collect()`` method returns an integer
|
||||
which signifies the number of distinct memory regions that were reclaimed in the
|
||||
collection (more precisely, the number of heads that were turned into frees). For
|
||||
efficiency reasons bare metal ports do not return this value.
|
||||
@@ -15,6 +15,7 @@ MicroPython are described in the sections here.
|
||||
repl.rst
|
||||
isr_rules.rst
|
||||
speed_python.rst
|
||||
constrained.rst
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
|
||||
@@ -110,6 +110,19 @@ the flag. The memory allocation occurs in the main program code when the object
|
||||
The MicroPython library I/O methods usually provide an option to use a pre-allocated buffer. For
|
||||
example ``pyb.i2c.recv()`` can accept a mutable buffer as its first argument: this enables its use in an ISR.
|
||||
|
||||
A means of creating an object without employing a class or globals is as follows:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def set_volume(t, buf=bytearray(3)):
|
||||
buf[0] = 0xa5
|
||||
buf[1] = t >> 4
|
||||
buf[2] = 0x5a
|
||||
return buf
|
||||
|
||||
The compiler instantiates the default ``buf`` argument when the function is
|
||||
loaded for the first time (usually when the module it's in is imported).
|
||||
|
||||
Use of Python objects
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -300,3 +313,20 @@ that access to the critical variables is denied. A simple example of a mutex may
|
||||
but only for the duration of eight machine instructions: the benefit of this approach is that other interrupts are
|
||||
virtually unaffected.
|
||||
|
||||
Interrupts and the REPL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Interrupt handlers, such as those associated with timers, can continue to run
|
||||
after a program terminates. This may produce unexpected results where you might
|
||||
have expected the object raising the callback to have gone out of scope. For
|
||||
example on the Pyboard:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def bar():
|
||||
foo = pyb.Timer(2, freq=4, callback=lambda t: print('.', end=''))
|
||||
|
||||
bar()
|
||||
|
||||
This continues to run until the timer is explicitly disabled or the board is
|
||||
reset with ``ctrl D``.
|
||||
|
||||
@@ -14,18 +14,18 @@ all divisions must be performed using '//' instead of '/'. Example::
|
||||
Before applying power
|
||||
---------------------
|
||||
|
||||
.. warning::
|
||||
.. warning::
|
||||
|
||||
The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higher
|
||||
than 3.6V will cause irreparable damage to the board. ADC pins, when configured
|
||||
than 3.6V will cause irreparable damage to the board. ADC pins, when configured
|
||||
in analog mode cannot withstand voltages above 1.8V. Keep these considerations in
|
||||
mind when wiring your electronics.
|
||||
|
||||
WLAN default behaviour
|
||||
----------------------
|
||||
|
||||
When the WiPy boots with the default factory configuration starts in Access Point
|
||||
mode with ``ssid`` that starts with: ``wipy-wlan`` and ``key: www.wipy.io``.
|
||||
When the WiPy boots with the default factory configuration starts in Access Point
|
||||
mode with ``ssid`` that starts with: ``wipy-wlan`` and ``key: www.wipy.io``.
|
||||
Connect to this network and the WiPy will be reachable at ``192.168.1.1``. In order
|
||||
to gain access to the interactive prompt, open a telnet session to that IP address on
|
||||
the default port (23). You will be asked for credentials:
|
||||
@@ -98,7 +98,7 @@ the WiPy by pressing the switch on the board, or by typing::
|
||||
>>> import machine
|
||||
>>> machine.reset()
|
||||
|
||||
Software updates can be found in: https://github.com/wipy/wipy/releases (**Binaries.zip**).
|
||||
Software updates can be found in: https://github.com/wipy/wipy/releases (**Binaries.zip**).
|
||||
It's always recommended to update to the latest software, but make sure to
|
||||
read the **release notes** before.
|
||||
|
||||
@@ -122,7 +122,7 @@ Boot modes and safe boot
|
||||
------------------------
|
||||
|
||||
If you power up normally, or press the reset button, the WiPy will boot
|
||||
into standard mode; the ``boot.py`` file will be executed first, then
|
||||
into standard mode; the ``boot.py`` file will be executed first, then
|
||||
``main.py`` will run.
|
||||
|
||||
You can override this boot sequence by pulling ``GP28`` **up** (connect
|
||||
@@ -178,4 +178,4 @@ Details on sleep modes
|
||||
configuration required.
|
||||
* ``machine.sleep()``: 950uA (in WLAN STA mode). Wake sources are ``Pin``, ``RTC``
|
||||
and ``WLAN``
|
||||
* ``machine.deepsleep()``: ~5uA. Wake sources are ``Pin`` and ``RTC``.
|
||||
* ``machine.deepsleep()``: ~350uA. Wake sources are ``Pin`` and ``RTC``.
|
||||
|
||||
@@ -51,11 +51,10 @@ See :ref:`machine.Timer <machine.Timer>` and :ref:`machine.Pin <machine.Pin>`. :
|
||||
|
||||
tim = Timer(0, mode=Timer.PERIODIC)
|
||||
tim_a = tim.channel(Timer.A, freq=1000)
|
||||
tim_a.time() # get the value in microseconds
|
||||
tim_a.freq(5) # 5 Hz
|
||||
|
||||
p_out = Pin('GP2', mode=Pin.OUT)
|
||||
tim_a.irq(handler=lambda t: p_out.toggle())
|
||||
tim_a.irq(trigger=Timer.TIMEOUT, handler=lambda t: p_out.toggle())
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
@@ -135,10 +134,9 @@ Real time clock (RTC)
|
||||
|
||||
See :ref:`machine.RTC <machine.RTC>` ::
|
||||
|
||||
import machine
|
||||
from machine import RTC
|
||||
|
||||
rtc = machine.RTC() # init with default time and date
|
||||
rtc = RTC() # init with default time and date
|
||||
rtc = RTC(datetime=(2015, 8, 29, 9, 0, 0, 0, None)) # init with a specific time and date
|
||||
print(rtc.now())
|
||||
|
||||
|
||||
@@ -84,6 +84,6 @@ STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) {
|
||||
|
||||
timeout:
|
||||
mp_hal_quiet_timing_exit(irq_state);
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto);
|
||||
|
||||
@@ -4,31 +4,41 @@ Micro Python driver for SD cards using SPI bus.
|
||||
Requires an SPI bus and a CS pin. Provides readblocks and writeblocks
|
||||
methods so the device can be mounted as a filesystem.
|
||||
|
||||
Example usage:
|
||||
Example usage on pyboard:
|
||||
|
||||
import pyb, sdcard, os
|
||||
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)
|
||||
pyb.mount(sd, '/sd2')
|
||||
os.listdir('/')
|
||||
|
||||
Example usage on ESP8266:
|
||||
|
||||
import machine, sdcard, os
|
||||
sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15))
|
||||
os.umount()
|
||||
os.VfsFat(sd, "")
|
||||
os.listdir()
|
||||
|
||||
"""
|
||||
|
||||
import pyb
|
||||
import time
|
||||
|
||||
|
||||
_CMD_TIMEOUT = const(100)
|
||||
|
||||
_R1_IDLE_STATE = const(1 << 0)
|
||||
#R1_ERASE_RESET = const(1 << 1)
|
||||
_R1_ILLEGAL_COMMAND = const(1 << 2)
|
||||
#R1_COM_CRC_ERROR = const(1 << 3)
|
||||
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
||||
#R1_ADDRESS_ERROR = const(1 << 5)
|
||||
#R1_PARAMETER_ERROR = const(1 << 6)
|
||||
_TOKEN_CMD25 = const(0xfc)
|
||||
_TOKEN_STOP_TRAN = const(0xfd)
|
||||
_TOKEN_DATA = const(0xfe)
|
||||
|
||||
|
||||
class SDCard:
|
||||
CMD_TIMEOUT = const(100)
|
||||
|
||||
R1_IDLE_STATE = const(1 << 0)
|
||||
#R1_ERASE_RESET = const(1 << 1)
|
||||
R1_ILLEGAL_COMMAND = const(1 << 2)
|
||||
#R1_COM_CRC_ERROR = const(1 << 3)
|
||||
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
||||
#R1_ADDRESS_ERROR = const(1 << 5)
|
||||
#R1_PARAMETER_ERROR = const(1 << 6)
|
||||
TOKEN_CMD25 = const(0xfc)
|
||||
TOKEN_STOP_TRAN = const(0xfd)
|
||||
TOKEN_DATA = const(0xfe)
|
||||
|
||||
def __init__(self, spi, cs):
|
||||
self.spi = spi
|
||||
self.cs = cs
|
||||
@@ -42,30 +52,39 @@ class SDCard:
|
||||
# initialise the card
|
||||
self.init_card()
|
||||
|
||||
def init_spi(self, baudrate):
|
||||
try:
|
||||
master = self.spi.MASTER
|
||||
except AttributeError:
|
||||
# on ESP8266
|
||||
self.spi.init(baudrate=baudrate, phase=0, polarity=0)
|
||||
else:
|
||||
# on pyboard
|
||||
self.spi.init(master, baudrate=baudrate, phase=0, polarity=0)
|
||||
|
||||
def init_card(self):
|
||||
# init CS pin
|
||||
self.cs.high()
|
||||
self.cs.init(self.cs.OUT_PP)
|
||||
self.cs.init(self.cs.OUT, value=1)
|
||||
|
||||
# init SPI bus; use low data rate for initialisation
|
||||
self.spi.init(self.spi.MASTER, baudrate=100000, phase=0, polarity=0)
|
||||
self.init_spi(100000)
|
||||
|
||||
# clock card at least 100 cycles with cs high
|
||||
for i in range(16):
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
# CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts)
|
||||
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
|
||||
for _ in range(5):
|
||||
if self.cmd(0, 0, 0x95) == R1_IDLE_STATE:
|
||||
if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
|
||||
break
|
||||
else:
|
||||
raise OSError("no SD card")
|
||||
|
||||
# CMD8: determine card version
|
||||
r = self.cmd(8, 0x01aa, 0x87, 4)
|
||||
if r == R1_IDLE_STATE:
|
||||
if r == _R1_IDLE_STATE:
|
||||
self.init_card_v2()
|
||||
elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND):
|
||||
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
|
||||
self.init_card_v1()
|
||||
else:
|
||||
raise OSError("couldn't determine SD card version")
|
||||
@@ -86,10 +105,10 @@ class SDCard:
|
||||
raise OSError("can't set 512 block size")
|
||||
|
||||
# set to high data rate now that it's initialised
|
||||
self.spi.init(self.spi.MASTER, baudrate=1320000, phase=0, polarity=0)
|
||||
self.init_spi(1320000)
|
||||
|
||||
def init_card_v1(self):
|
||||
for i in range(CMD_TIMEOUT):
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
self.cmd(55, 0, 0)
|
||||
if self.cmd(41, 0, 0) == 0:
|
||||
self.cdv = 512
|
||||
@@ -98,8 +117,8 @@ class SDCard:
|
||||
raise OSError("timeout waiting for v1 card")
|
||||
|
||||
def init_card_v2(self):
|
||||
for i in range(CMD_TIMEOUT):
|
||||
pyb.delay(50)
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
time.sleep_ms(50)
|
||||
self.cmd(58, 0, 0, 4)
|
||||
self.cmd(55, 0, 0)
|
||||
if self.cmd(41, 0x40000000, 0) == 0:
|
||||
@@ -120,87 +139,87 @@ class SDCard:
|
||||
buf[3] = arg >> 8
|
||||
buf[4] = arg
|
||||
buf[5] = crc
|
||||
self.spi.send(buf)
|
||||
self.spi.write(buf)
|
||||
|
||||
# wait for the repsonse (response[7] == 0)
|
||||
for i in range(CMD_TIMEOUT):
|
||||
response = self.spi.send_recv(0xff)[0]
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
response = self.spi.read(1, 0xff)[0]
|
||||
if not (response & 0x80):
|
||||
# this could be a big-endian integer that we are getting here
|
||||
for j in range(final):
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
if release:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return response
|
||||
|
||||
# timeout
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return -1
|
||||
|
||||
def cmd_nodata(self, cmd):
|
||||
self.spi.send(cmd)
|
||||
self.spi.send_recv(0xff) # ignore stuff byte
|
||||
for _ in range(CMD_TIMEOUT):
|
||||
if self.spi.send_recv(0xff)[0] == 0xff:
|
||||
self.spi.write(cmd)
|
||||
self.spi.read(1, 0xff) # ignore stuff byte
|
||||
for _ in range(_CMD_TIMEOUT):
|
||||
if self.spi.read(1, 0xff)[0] == 0xff:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return 0 # OK
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return 1 # timeout
|
||||
|
||||
def readinto(self, buf):
|
||||
self.cs.low()
|
||||
|
||||
# read until start byte (0xff)
|
||||
while self.spi.send_recv(0xff)[0] != 0xfe:
|
||||
while self.spi.read(1, 0xff)[0] != 0xfe:
|
||||
pass
|
||||
|
||||
# read data
|
||||
mv = self.dummybuf_memoryview[:len(buf)]
|
||||
self.spi.send_recv(mv, recv=buf)
|
||||
self.spi.write_readinto(mv, buf)
|
||||
|
||||
# read checksum
|
||||
self.spi.send(0xff)
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def write(self, token, buf):
|
||||
self.cs.low()
|
||||
|
||||
# send: start of block, data, checksum
|
||||
self.spi.send(token)
|
||||
self.spi.send(buf)
|
||||
self.spi.send(0xff)
|
||||
self.spi.send(0xff)
|
||||
self.spi.read(1, token)
|
||||
self.spi.write(buf)
|
||||
self.spi.write(b'\xff')
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
# check the response
|
||||
if (self.spi.send_recv(0xff)[0] & 0x1f) != 0x05:
|
||||
if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return
|
||||
|
||||
# wait for write to finish
|
||||
while self.spi.send_recv(0xff)[0] == 0:
|
||||
while self.spi.read(1, 0xff)[0] == 0:
|
||||
pass
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def write_token(self, token):
|
||||
self.cs.low()
|
||||
self.spi.send(token)
|
||||
self.spi.send(0xff)
|
||||
self.spi.read(1, token)
|
||||
self.spi.write(b'\xff')
|
||||
# wait for write to finish
|
||||
while self.spi.send_recv(0xff)[0] == 0:
|
||||
while self.spi.read(1, 0xff)[0] == 0x00:
|
||||
pass
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def count(self):
|
||||
return self.sectors
|
||||
@@ -224,7 +243,7 @@ class SDCard:
|
||||
self.readinto(mv[offset : offset + 512])
|
||||
offset += 512
|
||||
nblocks -= 1
|
||||
return self.cmd_nodata(12)
|
||||
return self.cmd_nodata(b'\x0c') # cmd 12
|
||||
return 0
|
||||
|
||||
def writeblocks(self, block_num, buf):
|
||||
@@ -236,7 +255,7 @@ class SDCard:
|
||||
return 1
|
||||
|
||||
# send the data
|
||||
self.write(TOKEN_DATA, buf)
|
||||
self.write(_TOKEN_DATA, buf)
|
||||
else:
|
||||
# CMD25: set write address for first block
|
||||
if self.cmd(25, block_num * self.cdv, 0) != 0:
|
||||
@@ -245,8 +264,8 @@ class SDCard:
|
||||
offset = 0
|
||||
mv = memoryview(buf)
|
||||
while nblocks:
|
||||
self.write(TOKEN_CMD25, mv[offset : offset + 512])
|
||||
self.write(_TOKEN_CMD25, mv[offset : offset + 512])
|
||||
offset += 512
|
||||
nblocks -= 1
|
||||
self.write_token(TOKEN_STOP_TRAN)
|
||||
self.write_token(_TOKEN_STOP_TRAN)
|
||||
return 0
|
||||
|
||||
@@ -12,12 +12,13 @@ include ../py/py.mk
|
||||
|
||||
MPY_CROSS = ../mpy-cross/mpy-cross
|
||||
MPY_TOOL = ../tools/mpy-tool.py
|
||||
MAKE_FROZEN = ../tools/make-frozen.py
|
||||
|
||||
SCRIPTDIR = scripts
|
||||
FROZEN_DIR = scripts
|
||||
FROZEN_MPY_DIR = modules
|
||||
PORT ?= /dev/ttyACM0
|
||||
BAUD ?= 115200
|
||||
FLASH_MODE ?= qio
|
||||
FLASH_SIZE ?= 8m
|
||||
CROSS_COMPILE = xtensa-lx106-elf-
|
||||
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
|
||||
|
||||
@@ -78,7 +79,9 @@ SRC_C = \
|
||||
modpybrtc.c \
|
||||
modpybadc.c \
|
||||
modpybuart.c \
|
||||
modmachinewdt.c \
|
||||
modpybspi.c \
|
||||
modpybhspi.c \
|
||||
modesp.c \
|
||||
modnetwork.c \
|
||||
modutime.c \
|
||||
@@ -89,6 +92,7 @@ SRC_C = \
|
||||
$(BUILD)/frozen.c \
|
||||
fatfs_port.c \
|
||||
axtls_helpers.c \
|
||||
hspi.c \
|
||||
$(SRC_MOD)
|
||||
|
||||
STM_SRC_C = $(addprefix stmhal/,\
|
||||
@@ -125,7 +129,7 @@ LIB_SRC_C = $(addprefix lib/,\
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/pyhelp.c \
|
||||
utils/printf.c \
|
||||
utils/interrupt_char.c \
|
||||
fatfs/ff.c \
|
||||
fatfs/option/ccsbcs.c \
|
||||
)
|
||||
@@ -137,7 +141,7 @@ DRIVERS_SRC_C = $(addprefix drivers/,\
|
||||
SRC_S = \
|
||||
gchelper.s \
|
||||
|
||||
FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py')
|
||||
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py')
|
||||
FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
|
||||
|
||||
OBJ =
|
||||
@@ -162,16 +166,14 @@ CONFVARS_FILE = $(BUILD)/confvars
|
||||
|
||||
ifeq ($(wildcard $(CONFVARS_FILE)),)
|
||||
$(shell $(MKDIR) -p $(BUILD))
|
||||
$(shell echo $(SCRIPTDIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
else ifneq ($(shell cat $(CONFVARS_FILE)), $(SCRIPTDIR) $(UART_OS))
|
||||
$(shell echo $(SCRIPTDIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
$(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)
|
||||
|
||||
$(BUILD)/frozen.c: $(wildcard $(SCRIPTDIR)/*) $(CONFVARS_FILE)
|
||||
$(ECHO) "Generating $@"
|
||||
$(Q)$(MAKE_FROZEN) $(SCRIPTDIR) > $@
|
||||
FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
|
||||
|
||||
# to build .mpy files from .py files
|
||||
$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py
|
||||
@@ -188,7 +190,7 @@ $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generate
|
||||
|
||||
deploy: $(BUILD)/firmware-combined.bin
|
||||
$(ECHO) "Writing $< to the board"
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=8m 0 $<
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $<
|
||||
#$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $(BUILD)/firmware.elf-0x00000.bin 0x9000 $(BUILD)/firmware.elf-0x0[1-f]000.bin
|
||||
|
||||
reset:
|
||||
|
||||
@@ -70,9 +70,10 @@ $ make deploy
|
||||
```
|
||||
This will use the `esptool.py` script to download the images. You must have
|
||||
your ESP module in the bootloader mode, and connected to a serial port on your PC.
|
||||
The default serial port is `/dev/ttyACM0`. To specify another, use, eg:
|
||||
The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is `8m`.
|
||||
To specify other values, use, eg:
|
||||
```bash
|
||||
$ make PORT=/dev/ttyUSB0 deploy
|
||||
$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=8m deploy
|
||||
```
|
||||
|
||||
The image produced is `firmware-combined.bin`, to be flashed at 0x00000.
|
||||
|
||||
@@ -141,7 +141,10 @@ SECTIONS
|
||||
*modpybadc.o(.literal*, .text*)
|
||||
*modpybuart.o(.literal*, .text*)
|
||||
*modpybi2c.o(.literal*, .text*)
|
||||
*modmachinewdt.o(.literal*, .text*)
|
||||
*modpybspi.o(.literal*, .text*)
|
||||
*modpybhspi.o(.literal*, .text*)
|
||||
*hspi.o(.literal*, .text*)
|
||||
*modesp.o(.literal* .text*)
|
||||
*modnetwork.o(.literal* .text*)
|
||||
*moduos.o(.literal* .text*)
|
||||
|
||||
@@ -36,17 +36,13 @@
|
||||
#include "extmod/misc.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
|
||||
extern void ets_wdt_disable(void);
|
||||
extern void wdt_feed(void);
|
||||
extern void ets_delay_us();
|
||||
|
||||
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
|
||||
//ets_wdt_disable(); // it's a pain while developing
|
||||
mp_hal_rtc_init();
|
||||
uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200);
|
||||
}
|
||||
@@ -64,7 +60,14 @@ int mp_hal_stdin_rx_chr(void) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@ void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_ms(void) {
|
||||
return system_get_time() / 1000;
|
||||
return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_get_time()) / 1000;
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_us(void) {
|
||||
@@ -125,14 +128,6 @@ void mp_hal_delay_ms(uint32_t delay) {
|
||||
mp_hal_delay_us(delay * 1000);
|
||||
}
|
||||
|
||||
void mp_hal_set_interrupt_char(int c) {
|
||||
if (c != -1) {
|
||||
mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_kbd_exception));
|
||||
}
|
||||
extern int interrupt_char;
|
||||
interrupt_char = c;
|
||||
}
|
||||
|
||||
void ets_event_poll(void) {
|
||||
ets_loop_iter();
|
||||
if (MP_STATE_VM(mp_pending_exception) != NULL) {
|
||||
@@ -177,7 +172,7 @@ static int call_dupterm_read(void) {
|
||||
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 == interrupt_char) {
|
||||
if (*(byte*)bufinfo.buf == mp_interrupt_char) {
|
||||
mp_keyboard_interrupt();
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
#define _INCLUDED_MPHAL_H_
|
||||
|
||||
#include "py/ringbuf.h"
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "xtirq.h"
|
||||
|
||||
void mp_keyboard_interrupt(void);
|
||||
extern int interrupt_char;
|
||||
|
||||
struct _mp_print_t;
|
||||
// Structure for UART-only output via mp_printf()
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
|
||||
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#if MICROPY_ESP8266_NEOPIXEL
|
||||
|
||||
#include "c_types.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "user_interface.h"
|
||||
@@ -41,6 +44,7 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t irq_state = mp_hal_quiet_timing_enter();
|
||||
for(t = time0;; t = time0) {
|
||||
if(pix & mask) t = time1; // Bit high duration
|
||||
while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
|
||||
@@ -55,4 +59,7 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32
|
||||
}
|
||||
}
|
||||
while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
|
||||
mp_hal_quiet_timing_exit(irq_state);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ESP8266_NEOPIXEL
|
||||
|
||||
@@ -87,7 +87,7 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
|
||||
if (emu_tasks[id].i_put == -1) {
|
||||
// queue is full
|
||||
printf("ets_post: task %d queue full\n", prio);
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
q = &q[emu_tasks[id].i_put++];
|
||||
q->sig = sig;
|
||||
@@ -104,16 +104,28 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
|
||||
|
||||
ets_intr_unlock();
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ets_loop_iter_disable = 0;
|
||||
|
||||
// to implement a 64-bit wide microsecond counter
|
||||
static uint32_t system_time_prev = 0;
|
||||
uint32_t system_time_high_word = 0;
|
||||
|
||||
bool ets_loop_iter(void) {
|
||||
if (ets_loop_iter_disable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle overflow of system microsecond counter
|
||||
uint32_t system_time_cur = system_get_time();
|
||||
if (system_time_cur < system_time_prev) {
|
||||
system_time_high_word += 1; // record overflow of low 32-bits
|
||||
}
|
||||
system_time_prev = system_time_cur;
|
||||
|
||||
//static unsigned cnt;
|
||||
bool progress = false;
|
||||
for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
extern int ets_loop_iter_disable;
|
||||
extern uint32_t system_time_high_word;
|
||||
|
||||
bool ets_loop_iter(void);
|
||||
|
||||
@@ -20,6 +20,9 @@ void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_mi
|
||||
void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data);
|
||||
void ets_timer_disarm(os_timer_t *tim);
|
||||
|
||||
extern void ets_wdt_disable(void);
|
||||
extern void wdt_feed(void);
|
||||
|
||||
// Opaque structure
|
||||
typedef char MD5_CTX[64];
|
||||
|
||||
|
||||
331
esp8266/hspi.c
Normal file
331
esp8266/hspi.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 David Ogilvy (MetalPhreak)
|
||||
* Modified 2016 by Radomir Dopieralski
|
||||
*
|
||||
* 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 "hspi.h"
|
||||
|
||||
/*
|
||||
Wrapper to setup HSPI/SPI GPIO pins and default SPI clock
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
Not used in Micropython.
|
||||
*/
|
||||
void spi_init(uint8_t spi_no) {
|
||||
spi_init_gpio(spi_no, SPI_CLK_USE_DIV);
|
||||
spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
|
||||
spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Configures SPI mode parameters for clock edge and clock polarity.
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
spi_cpha - (0) Data is valid on clock leading edge
|
||||
(1) Data is valid on clock trailing edge
|
||||
spi_cpol - (0) Clock is low when inactive
|
||||
(1) Clock is high when inactive
|
||||
For Micropython this version is different from original.
|
||||
*/
|
||||
void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) {
|
||||
if (spi_cpol) {
|
||||
SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
|
||||
}
|
||||
if (spi_cpha == spi_cpol) {
|
||||
// Mode 3 - MOSI is set on falling edge of clock
|
||||
// Mode 0 - MOSI is set on falling edge of clock
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
|
||||
SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
|
||||
} else {
|
||||
// Mode 2 - MOSI is set on rising edge of clock
|
||||
// Mode 1 - MOSI is set on rising edge of clock
|
||||
SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialise the GPIO pins for use as SPI pins.
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
sysclk_as_spiclk -
|
||||
SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock.
|
||||
SPI_CLK_USE_DIV (0) if using divider for lower speed.
|
||||
*/
|
||||
void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) {
|
||||
uint32_t clock_div_flag = 0;
|
||||
if (sysclk_as_spiclk) {
|
||||
clock_div_flag = 0x0001;
|
||||
}
|
||||
if (spi_no == SPI) {
|
||||
// Set bit 8 if 80MHz sysclock required
|
||||
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8));
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);
|
||||
} else if (spi_no == HSPI) {
|
||||
// Set bit 9 if 80MHz sysclock required
|
||||
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9));
|
||||
// GPIO12 is HSPI MISO pin (Master Data In)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
|
||||
// GPIO13 is HSPI MOSI pin (Master Data Out)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
|
||||
// GPIO14 is HSPI CLK pin (Clock)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
|
||||
// GPIO15 is HSPI CS pin (Chip Select / Slave Select)
|
||||
// In Micropython, we are handling CS ourself in drivers.
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set up the control registers for the SPI clock
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
prediv - predivider value (actual division value)
|
||||
cntdiv - postdivider value (actual division value)
|
||||
Set either divider to 0 to disable all division (80MHz sysclock)
|
||||
*/
|
||||
void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) {
|
||||
if (prediv == 0 || cntdiv == 0) {
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK);
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no),
|
||||
(((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
|
||||
(((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
|
||||
(((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
|
||||
((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Setup the byte order for shifting data out of buffer
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
byte_order -
|
||||
SPI_BYTE_ORDER_HIGH_TO_LOW (1)
|
||||
Data is sent out starting with Bit31 and down to Bit0
|
||||
SPI_BYTE_ORDER_LOW_TO_HIGH (0)
|
||||
Data is sent out starting with the lowest BYTE, from MSB to LSB,
|
||||
followed by the second lowest BYTE, from MSB to LSB, followed by
|
||||
the second highest BYTE, from MSB to LSB, followed by the highest
|
||||
BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB.
|
||||
*/
|
||||
void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) {
|
||||
if (byte_order) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Setup the byte order for shifting data into buffer
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
byte_order -
|
||||
SPI_BYTE_ORDER_HIGH_TO_LOW (1)
|
||||
Data is read in starting with Bit31 and down to Bit0
|
||||
SPI_BYTE_ORDER_LOW_TO_HIGH (0)
|
||||
Data is read in starting with the lowest BYTE, from MSB to LSB,
|
||||
followed by the second lowest BYTE, from MSB to LSB, followed by
|
||||
the second highest BYTE, from MSB to LSB, followed by the highest
|
||||
BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB
|
||||
*/
|
||||
void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) {
|
||||
if (byte_order) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SPI transaction function
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
cmd_bits - actual number of bits to transmit
|
||||
cmd_data - command data
|
||||
addr_bits - actual number of bits to transmit
|
||||
addr_data - address data
|
||||
dout_bits - actual number of bits to transmit
|
||||
dout_data - output data
|
||||
din_bits - actual number of bits to receive
|
||||
Returns: read data - uint32_t containing read in data only if RX was set
|
||||
0 - something went wrong (or actual read data was 0)
|
||||
1 - data sent ok (or actual read data is 1)
|
||||
Note: all data is assumed to be stored in the lower bits of the data variables
|
||||
(for anything <32 bits).
|
||||
*/
|
||||
uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
|
||||
uint32_t addr_bits, uint32_t addr_data,
|
||||
uint32_t dout_bits, uint32_t dout_data,
|
||||
uint32_t din_bits, uint32_t dummy_bits) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
|
||||
|
||||
// Enable SPI Functions
|
||||
// Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
|
||||
SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
|
||||
|
||||
// Enable functions based on number of bits. 0 bits = disabled.
|
||||
// This is rather inefficient but allows for a very generic function.
|
||||
// CMD ADDR and MOSI are set below to save on an extra if statement.
|
||||
if (din_bits) {
|
||||
if (dout_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
|
||||
}
|
||||
}
|
||||
if (dummy_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);
|
||||
}
|
||||
|
||||
// Setup Bitlengths
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no),
|
||||
// Number of bits in Address
|
||||
((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S |
|
||||
// Number of bits to Send
|
||||
((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
|
||||
// Number of bits to receive
|
||||
((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S |
|
||||
// Number of Dummy bits to insert
|
||||
((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S);
|
||||
|
||||
// Setup Command Data
|
||||
if (cmd_bits) {
|
||||
// Enable COMMAND function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);
|
||||
// Align command data to high bits
|
||||
uint16_t command = cmd_data << (16-cmd_bits);
|
||||
// Swap byte order
|
||||
command = ((command>>8)&0xff) | ((command<<8)&0xff00);
|
||||
WRITE_PERI_REG(SPI_USER2(spi_no), (
|
||||
(((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
|
||||
(command & SPI_USR_COMMAND_VALUE)
|
||||
));
|
||||
}
|
||||
|
||||
// Setup Address Data
|
||||
if (addr_bits) {
|
||||
// Enable ADDRess function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);
|
||||
// Align address data to high bits
|
||||
WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits));
|
||||
}
|
||||
|
||||
// Setup DOUT data
|
||||
if (dout_bits) {
|
||||
// Enable MOSI function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
|
||||
// Copy data to W0
|
||||
if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits));
|
||||
} else {
|
||||
uint8_t dout_extra_bits = dout_bits%8;
|
||||
|
||||
if (dout_extra_bits) {
|
||||
// If your data isn't a byte multiple (8/16/24/32 bits) and you
|
||||
// don't have SPI_WR_BYTE_ORDER set, you need this to move the
|
||||
// non-8bit remainder to the MSBs. Not sure if there's even a use
|
||||
// case for this, but it's here if you need it... For example,
|
||||
// 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output
|
||||
// as if it were 0x0DA4, of which 0xA4, and then 0x0 would be
|
||||
// shifted out (first 8 bits of low byte, then 4 MSB bits of high
|
||||
// byte - ie reverse byte order).
|
||||
// The code below shifts it out as 0xA4 followed by 0xD as you
|
||||
// might require.
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), (
|
||||
(0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data)
|
||||
<< (8-dout_extra_bits) |
|
||||
((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits)))
|
||||
& dout_data)
|
||||
));
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Begin SPI Transaction
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
|
||||
// Return DIN data
|
||||
if (din_bits) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete
|
||||
if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) {
|
||||
// Assuming data in is written to MSB. TBC
|
||||
return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits);
|
||||
} else {
|
||||
// Read in the same way as DOUT is sent. Note existing contents of
|
||||
// SPI_W0 remain unless overwritten!
|
||||
return READ_PERI_REG(SPI_W0(spi_no));
|
||||
}
|
||||
return 0; // Something went wrong
|
||||
}
|
||||
|
||||
// Transaction completed
|
||||
return 1; // Success
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Just do minimal work needed to send 8 bits.
|
||||
*/
|
||||
inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
|
||||
|
||||
// Enable SPI Functions
|
||||
// Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
|
||||
SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
|
||||
|
||||
// Setup Bitlengths
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no),
|
||||
// Number of bits to Send
|
||||
((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
|
||||
// Number of bits to receive
|
||||
((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S);
|
||||
|
||||
|
||||
// Setup DOUT data
|
||||
// Enable MOSI function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
|
||||
// Copy data to W0
|
||||
if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8));
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
|
||||
}
|
||||
|
||||
// Begin SPI Transaction
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
}
|
||||
79
esp8266/hspi.h
Normal file
79
esp8266/hspi.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 David Ogilvy (MetalPhreak)
|
||||
* Modified 2016 by Radomir Dopieralski
|
||||
*
|
||||
* 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 SPI_APP_H
|
||||
#define SPI_APP_H
|
||||
|
||||
#include "hspi_register.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "os_type.h"
|
||||
|
||||
// Define SPI hardware modules
|
||||
#define SPI 0
|
||||
#define HSPI 1
|
||||
|
||||
#define SPI_CLK_USE_DIV 0
|
||||
#define SPI_CLK_80MHZ_NODIV 1
|
||||
|
||||
#define SPI_BYTE_ORDER_HIGH_TO_LOW 1
|
||||
#define SPI_BYTE_ORDER_LOW_TO_HIGH 0
|
||||
|
||||
#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h
|
||||
#define CPU_CLK_FREQ (80 * 1000000)
|
||||
#endif
|
||||
|
||||
// Define some default SPI clock settings
|
||||
#define SPI_CLK_PREDIV 10
|
||||
#define SPI_CLK_CNTDIV 2
|
||||
#define SPI_CLK_FREQ (CPU_CLK_FREQ / (SPI_CLK_PREDIV * SPI_CLK_CNTDIV))
|
||||
// 80 / 20 = 4 MHz
|
||||
|
||||
void spi_init(uint8_t spi_no);
|
||||
void spi_mode(uint8_t spi_no, uint8_t spi_cpha,uint8_t spi_cpol);
|
||||
void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk);
|
||||
void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv);
|
||||
void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order);
|
||||
void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order);
|
||||
uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
|
||||
uint32_t addr_bits, uint32_t addr_data,
|
||||
uint32_t dout_bits, uint32_t dout_data,
|
||||
uint32_t din_bits, uint32_t dummy_bits);
|
||||
void spi_tx8fast(uint8_t spi_no, uint8_t dout_data);
|
||||
|
||||
// Expansion Macros
|
||||
#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR
|
||||
|
||||
#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32_t) data, 0, 0)
|
||||
#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32_t) data, 0, 0)
|
||||
#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32_t) data, 0, 0)
|
||||
#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32_t) data, 0, 0)
|
||||
|
||||
#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0)
|
||||
#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0)
|
||||
#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0)
|
||||
#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0)
|
||||
|
||||
#endif
|
||||
278
esp8266/hspi_register.h
Normal file
278
esp8266/hspi_register.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2010 - 2011 Espressif System
|
||||
* Modified by David Ogilvy (MetalPhreak)
|
||||
* Based on original file included in SDK 1.0.0
|
||||
*
|
||||
* Missing defines from previous SDK versions have
|
||||
* been added and are noted with comments. The
|
||||
* names of these defines are likely to change.
|
||||
*/
|
||||
|
||||
#ifndef SPI_REGISTER_H_INCLUDED
|
||||
#define SPI_REGISTER_H_INCLUDED
|
||||
|
||||
#define REG_SPI_BASE(i) (0x60000200-i*0x100)
|
||||
|
||||
#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0)
|
||||
#define SPI_FLASH_READ (BIT(31)) //From previous SDK
|
||||
#define SPI_FLASH_WREN (BIT(30)) //From previous SDK
|
||||
#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK
|
||||
#define SPI_FLASH_RDID (BIT(28)) //From previous SDK
|
||||
#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK
|
||||
#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK
|
||||
#define SPI_FLASH_PP (BIT(25)) //From previous SDK
|
||||
#define SPI_FLASH_SE (BIT(24)) //From previous SDK
|
||||
#define SPI_FLASH_BE (BIT(23)) //From previous SDK
|
||||
#define SPI_FLASH_CE (BIT(22)) //From previous SDK
|
||||
#define SPI_FLASH_DP (BIT(21)) //From previous SDK
|
||||
#define SPI_FLASH_RES (BIT(20)) //From previous SDK
|
||||
#define SPI_FLASH_HPM (BIT(19)) //From previous SDK
|
||||
#define SPI_USR (BIT(18))
|
||||
|
||||
#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4)
|
||||
|
||||
#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8)
|
||||
#define SPI_WR_BIT_ORDER (BIT(26))
|
||||
#define SPI_RD_BIT_ORDER (BIT(25))
|
||||
#define SPI_QIO_MODE (BIT(24))
|
||||
#define SPI_DIO_MODE (BIT(23))
|
||||
#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK
|
||||
#define SPI_WP_REG (BIT(21)) //From previous SDK
|
||||
#define SPI_QOUT_MODE (BIT(20))
|
||||
#define SPI_SHARE_BUS (BIT(19)) //From previous SDK
|
||||
#define SPI_HOLD_MODE (BIT(18)) //From previous SDK
|
||||
#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK
|
||||
#define SPI_SST_AAI (BIT(16)) //From previous SDK
|
||||
#define SPI_RESANDRES (BIT(15)) //From previous SDK
|
||||
#define SPI_DOUT_MODE (BIT(14))
|
||||
#define SPI_FASTRD_MODE (BIT(13))
|
||||
|
||||
#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS
|
||||
#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK
|
||||
#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK
|
||||
|
||||
|
||||
#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10)
|
||||
#define SPI_STATUS_EXT 0x000000FF //From previous SDK
|
||||
#define SPI_STATUS_EXT_S 24 //From previous SDK
|
||||
#define SPI_WB_MODE 0x000000FF //From previous SDK
|
||||
#define SPI_WB_MODE_S 16 //From previous SDK
|
||||
#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK
|
||||
#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK
|
||||
#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK
|
||||
#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK
|
||||
#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK
|
||||
#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK
|
||||
#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK
|
||||
|
||||
#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14)
|
||||
#define SPI_CS_DELAY_NUM 0x0000000F
|
||||
#define SPI_CS_DELAY_NUM_S 28
|
||||
#define SPI_CS_DELAY_MODE 0x00000003
|
||||
#define SPI_CS_DELAY_MODE_S 26
|
||||
#define SPI_MOSI_DELAY_NUM 0x00000007
|
||||
#define SPI_MOSI_DELAY_NUM_S 23
|
||||
#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk
|
||||
//mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk
|
||||
//mode 2 : Do not use this mode.
|
||||
#define SPI_MOSI_DELAY_MODE_S 21
|
||||
#define SPI_MISO_DELAY_NUM 0x00000007
|
||||
#define SPI_MISO_DELAY_NUM_S 18
|
||||
#define SPI_MISO_DELAY_MODE 0x00000003
|
||||
#define SPI_MISO_DELAY_MODE_S 16
|
||||
#define SPI_CK_OUT_HIGH_MODE 0x0000000F
|
||||
#define SPI_CK_OUT_HIGH_MODE_S 12
|
||||
#define SPI_CK_OUT_LOW_MODE 0x0000000F
|
||||
#define SPI_CK_OUT_LOW_MODE_S 8
|
||||
#define SPI_HOLD_TIME 0x0000000F
|
||||
#define SPI_HOLD_TIME_S 4
|
||||
#define SPI_SETUP_TIME 0x0000000F
|
||||
#define SPI_SETUP_TIME_S 0
|
||||
|
||||
#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18)
|
||||
#define SPI_CLK_EQU_SYSCLK (BIT(31))
|
||||
#define SPI_CLKDIV_PRE 0x00001FFF
|
||||
#define SPI_CLKDIV_PRE_S 18
|
||||
#define SPI_CLKCNT_N 0x0000003F
|
||||
#define SPI_CLKCNT_N_S 12
|
||||
#define SPI_CLKCNT_H 0x0000003F
|
||||
#define SPI_CLKCNT_H_S 6
|
||||
#define SPI_CLKCNT_L 0x0000003F
|
||||
#define SPI_CLKCNT_L_S 0
|
||||
|
||||
#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C)
|
||||
#define SPI_USR_COMMAND (BIT(31))
|
||||
#define SPI_USR_ADDR (BIT(30))
|
||||
#define SPI_USR_DUMMY (BIT(29))
|
||||
#define SPI_USR_MISO (BIT(28))
|
||||
#define SPI_USR_MOSI (BIT(27))
|
||||
#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK
|
||||
#define SPI_USR_MOSI_HIGHPART (BIT(25))
|
||||
#define SPI_USR_MISO_HIGHPART (BIT(24))
|
||||
#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK
|
||||
#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK
|
||||
#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK
|
||||
#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK
|
||||
#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK
|
||||
#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK
|
||||
#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK
|
||||
#define SPI_SIO (BIT(16))
|
||||
#define SPI_FWRITE_QIO (BIT(15))
|
||||
#define SPI_FWRITE_DIO (BIT(14))
|
||||
#define SPI_FWRITE_QUAD (BIT(13))
|
||||
#define SPI_FWRITE_DUAL (BIT(12))
|
||||
#define SPI_WR_BYTE_ORDER (BIT(11))
|
||||
#define SPI_RD_BYTE_ORDER (BIT(10))
|
||||
#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK
|
||||
#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK
|
||||
#define SPI_CK_OUT_EDGE (BIT(7))
|
||||
#define SPI_CK_I_EDGE (BIT(6))
|
||||
#define SPI_CS_SETUP (BIT(5))
|
||||
#define SPI_CS_HOLD (BIT(4))
|
||||
#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK
|
||||
#define SPI_FLASH_MODE (BIT(2))
|
||||
#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK
|
||||
#define SPI_DOUTDIN (BIT(0)) //From previous SDK
|
||||
|
||||
//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ?
|
||||
|
||||
|
||||
#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20)
|
||||
#define SPI_USR_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_USR_ADDR_BITLEN_S 26
|
||||
#define SPI_USR_MOSI_BITLEN 0x000001FF
|
||||
#define SPI_USR_MOSI_BITLEN_S 17
|
||||
#define SPI_USR_MISO_BITLEN 0x000001FF
|
||||
#define SPI_USR_MISO_BITLEN_S 8
|
||||
#define SPI_USR_DUMMY_CYCLELEN 0x000000FF
|
||||
#define SPI_USR_DUMMY_CYCLELEN_S 0
|
||||
|
||||
#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24)
|
||||
#define SPI_USR_COMMAND_BITLEN 0x0000000F
|
||||
#define SPI_USR_COMMAND_BITLEN_S 28
|
||||
#define SPI_USR_COMMAND_VALUE 0x0000FFFF
|
||||
#define SPI_USR_COMMAND_VALUE_S 0
|
||||
|
||||
#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28)
|
||||
//previously defined as SPI_FLASH_USER3. No further info available.
|
||||
|
||||
#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C)
|
||||
#define SPI_IDLE_EDGE (BIT(29))
|
||||
#define SPI_CS2_DIS (BIT(2))
|
||||
#define SPI_CS1_DIS (BIT(1))
|
||||
#define SPI_CS0_DIS (BIT(0))
|
||||
|
||||
#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30)
|
||||
#define SPI_SYNC_RESET (BIT(31))
|
||||
#define SPI_SLAVE_MODE (BIT(30))
|
||||
#define SPI_SLV_WR_RD_BUF_EN (BIT(29))
|
||||
#define SPI_SLV_WR_RD_STA_EN (BIT(28))
|
||||
#define SPI_SLV_CMD_DEFINE (BIT(27))
|
||||
#define SPI_TRANS_CNT 0x0000000F
|
||||
#define SPI_TRANS_CNT_S 23
|
||||
#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK
|
||||
#define SPI_SLV_LAST_STATE_S 20 //From previous SDK
|
||||
#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK
|
||||
#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK
|
||||
#define SPI_CS_I_MODE 0x00000003 //From previous SDK
|
||||
#define SPI_CS_I_MODE_S 10 //From previous SDK
|
||||
#define SPI_TRANS_DONE_EN (BIT(9))
|
||||
#define SPI_SLV_WR_STA_DONE_EN (BIT(8))
|
||||
#define SPI_SLV_RD_STA_DONE_EN (BIT(7))
|
||||
#define SPI_SLV_WR_BUF_DONE_EN (BIT(6))
|
||||
#define SPI_SLV_RD_BUF_DONE_EN (BIT(5))
|
||||
#define SLV_SPI_INT_EN 0x0000001f
|
||||
#define SLV_SPI_INT_EN_S 5
|
||||
#define SPI_TRANS_DONE (BIT(4))
|
||||
#define SPI_SLV_WR_STA_DONE (BIT(3))
|
||||
#define SPI_SLV_RD_STA_DONE (BIT(2))
|
||||
#define SPI_SLV_WR_BUF_DONE (BIT(1))
|
||||
#define SPI_SLV_RD_BUF_DONE (BIT(0))
|
||||
|
||||
#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34)
|
||||
#define SPI_SLV_STATUS_BITLEN 0x0000001F
|
||||
#define SPI_SLV_STATUS_BITLEN_S 27
|
||||
#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK
|
||||
#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK
|
||||
#define SPI_SLV_BUF_BITLEN 0x000001FF
|
||||
#define SPI_SLV_BUF_BITLEN_S 16
|
||||
#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_SLV_RD_ADDR_BITLEN_S 10
|
||||
#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_SLV_WR_ADDR_BITLEN_S 4
|
||||
#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3))
|
||||
#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2))
|
||||
#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1))
|
||||
#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0))
|
||||
|
||||
|
||||
|
||||
#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38)
|
||||
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24
|
||||
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16
|
||||
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8
|
||||
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF
|
||||
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0
|
||||
|
||||
#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C)
|
||||
#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_WRSTA_CMD_VALUE_S 24
|
||||
#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_RDSTA_CMD_VALUE_S 16
|
||||
#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_WRBUF_CMD_VALUE_S 8
|
||||
#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_RDBUF_CMD_VALUE_S 0
|
||||
|
||||
//Previous SDKs referred to these following registers as SPI_C0 etc.
|
||||
|
||||
#define SPI_W0(i) (REG_SPI_BASE(i) +0x40)
|
||||
#define SPI_W1(i) (REG_SPI_BASE(i) +0x44)
|
||||
#define SPI_W2(i) (REG_SPI_BASE(i) +0x48)
|
||||
#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C)
|
||||
#define SPI_W4(i) (REG_SPI_BASE(i) +0x50)
|
||||
#define SPI_W5(i) (REG_SPI_BASE(i) +0x54)
|
||||
#define SPI_W6(i) (REG_SPI_BASE(i) +0x58)
|
||||
#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C)
|
||||
#define SPI_W8(i) (REG_SPI_BASE(i) +0x60)
|
||||
#define SPI_W9(i) (REG_SPI_BASE(i) +0x64)
|
||||
#define SPI_W10(i) (REG_SPI_BASE(i) +0x68)
|
||||
#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C)
|
||||
#define SPI_W12(i) (REG_SPI_BASE(i) +0x70)
|
||||
#define SPI_W13(i) (REG_SPI_BASE(i) +0x74)
|
||||
#define SPI_W14(i) (REG_SPI_BASE(i) +0x78)
|
||||
#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C)
|
||||
|
||||
// +0x80 to +0xBC could be SPI_W16 through SPI_W31?
|
||||
|
||||
// +0xC0 to +0xEC not currently defined.
|
||||
|
||||
#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_T_PP_ENA (BIT(31)) //From previous SDK
|
||||
#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK
|
||||
#define SPI_T_PP_SHIFT_S 16 //From previous SDK
|
||||
#define SPI_T_PP_TIME 0x00000FFF //From previous SDK
|
||||
#define SPI_T_PP_TIME_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK
|
||||
#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK
|
||||
#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK
|
||||
#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK
|
||||
#define SPI_T_ERASE_TIME_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_ST 0x00000007 //From previous SDK
|
||||
#define SPI_ST_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
|
||||
#define SPI_INT_HOLD_ENA 0x00000003
|
||||
#define SPI_INT_HOLD_ENA_S 0
|
||||
#endif // SPI_REGISTER_H_INCLUDED
|
||||
@@ -49,8 +49,8 @@ STATIC void mp_reset(void) {
|
||||
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_));
|
||||
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);
|
||||
#if MICROPY_VFS_FAT
|
||||
memset(MP_STATE_PORT(fs_user_mount), 0, sizeof(MP_STATE_PORT(fs_user_mount)));
|
||||
@@ -141,10 +141,6 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void mp_keyboard_interrupt(void) {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
|
||||
}
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
printf("NLR jump failed\n");
|
||||
for (;;) {
|
||||
|
||||
@@ -583,7 +583,7 @@ STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) {
|
||||
if (alloc_buf) {
|
||||
m_del(byte, buf, len);
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
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);
|
||||
|
||||
@@ -598,9 +598,7 @@ STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) {
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(
|
||||
&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
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);
|
||||
|
||||
@@ -610,9 +608,7 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(
|
||||
&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
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);
|
||||
|
||||
@@ -714,7 +710,9 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj },
|
||||
#endif
|
||||
#if MICROPY_ESP8266_NEOPIXEL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&esp_neopixel_write_obj },
|
||||
#endif
|
||||
#if MICROPY_ESP8266_APA102
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_apa102_write), (mp_obj_t)&esp_apa102_write_obj },
|
||||
#endif
|
||||
@@ -748,6 +746,5 @@ STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);
|
||||
|
||||
const mp_obj_module_t esp_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_esp,
|
||||
.globals = (mp_obj_dict_t*)&esp_module_globals,
|
||||
};
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
//#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
|
||||
@@ -84,8 +86,10 @@ STATIC mp_obj_t machine_unique_id(void) {
|
||||
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");
|
||||
return mp_const_none;
|
||||
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);
|
||||
|
||||
@@ -246,27 +250,29 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
|
||||
{ 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_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(&pyb_spi_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_hspi_type) },
|
||||
|
||||
// wake abilities
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
|
||||
|
||||
// reset causes
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
|
||||
{ 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 },
|
||||
.name = MP_QSTR_umachine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
|
||||
|
||||
85
esp8266/modmachinewdt.c
Normal file
85
esp8266/modmachinewdt.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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, mp_uint_t n_args, mp_uint_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_map_elem_t machine_wdt_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&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_t)&machine_wdt_locals_dict,
|
||||
};
|
||||
@@ -130,17 +130,16 @@ 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(scaninfo *si, STATUS status) {
|
||||
STATIC void esp_scan_cb(void *result, STATUS status) {
|
||||
if (esp_scan_list == NULL) {
|
||||
// called unexpectedly
|
||||
return;
|
||||
}
|
||||
if (si->pbss && status == 0) {
|
||||
if (result && status == 0) {
|
||||
// we need to catch any memory errors
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
struct bss_info *bs;
|
||||
STAILQ_FOREACH(bs, si->pbss, next) {
|
||||
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,
|
||||
@@ -485,6 +484,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals
|
||||
|
||||
const mp_obj_module_t network_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
@@ -117,6 +117,5 @@ STATIC MP_DEFINE_CONST_DICT(onewire_module_globals, onewire_module_globals_table
|
||||
|
||||
const mp_obj_module_t onewire_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_onewire,
|
||||
.globals = (mp_obj_dict_t*)&onewire_module_globals,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@ extern const mp_obj_type_t pyb_rtc_type;
|
||||
extern const mp_obj_type_t pyb_uart_type;
|
||||
extern const mp_obj_type_t pyb_i2c_type;
|
||||
extern const mp_obj_type_t pyb_spi_type;
|
||||
extern const mp_obj_type_t pyb_hspi_type;
|
||||
extern const mp_obj_type_t machine_spi_type;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_info_obj);
|
||||
|
||||
|
||||
212
esp8266/modpybhspi.c
Normal file
212
esp8266/modpybhspi.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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 "hspi.h"
|
||||
|
||||
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 *args);
|
||||
|
||||
typedef struct _pyb_hspi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t baudrate;
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
} pyb_hspi_obj_t;
|
||||
|
||||
|
||||
STATIC void 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 pyb_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_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 pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
|
||||
{ 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 pyb_hspi_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, 1, true);
|
||||
mp_int_t id = -1;
|
||||
if (n_args > 0) {
|
||||
id = mp_obj_get_int(args[0]);
|
||||
}
|
||||
|
||||
if (id == -1) {
|
||||
// Multiplex to bitbanging SPI
|
||||
if (n_args > 0) {
|
||||
args++;
|
||||
}
|
||||
return pyb_spi_make_new(type, 0, n_kw, args);
|
||||
}
|
||||
|
||||
if (id != 1) {
|
||||
// FlashROM is on SPI0, so far we don't support its usage
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
|
||||
pyb_hspi_obj_t *self = m_new_obj(pyb_hspi_obj_t);
|
||||
self->base.type = &pyb_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);
|
||||
pyb_hspi_init_helper(self, n_args, args, &kw_args);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_hspi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
pyb_hspi_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_hspi_init_obj, 1, pyb_hspi_init);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_hspi_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_hspi_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_hspi_locals_dict, pyb_hspi_locals_dict_table);
|
||||
|
||||
STATIC const mp_machine_spi_p_t pyb_hspi_p = {
|
||||
.transfer = hspi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_hspi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HSPI,
|
||||
.print = pyb_hspi_print,
|
||||
.make_new = pyb_hspi_make_new,
|
||||
.protocol = &pyb_hspi_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_hspi_locals_dict,
|
||||
};
|
||||
@@ -244,7 +244,11 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c
|
||||
|
||||
// configure the GPIO as requested
|
||||
if (self->phys_port == 16) {
|
||||
// TODO: Set pull up/pull down
|
||||
// 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
|
||||
@@ -301,7 +305,7 @@ STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
if (n_args == 0) {
|
||||
// get pin
|
||||
return MP_OBJ_NEW_SMALL_INT(GPIO_INPUT_GET(self->phys_port));
|
||||
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]));
|
||||
|
||||
@@ -212,13 +212,28 @@ STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time
|
||||
}
|
||||
|
||||
// set expiry time (in microseconds)
|
||||
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000;
|
||||
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[] = {
|
||||
@@ -244,6 +259,7 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_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_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(0) },
|
||||
};
|
||||
|
||||
@@ -28,71 +28,35 @@
|
||||
#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"
|
||||
|
||||
typedef struct _pyb_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t baudrate;
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
mp_hal_pin_obj_t sck;
|
||||
mp_hal_pin_obj_t mosi;
|
||||
mp_hal_pin_obj_t miso;
|
||||
} pyb_spi_obj_t;
|
||||
|
||||
STATIC void mp_hal_spi_transfer(pyb_spi_obj_t *self, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) {
|
||||
// only MSB transfer is implemented
|
||||
uint32_t delay_half = 500000 / self->baudrate + 1;
|
||||
for (size_t i = 0; i < src_len || i < dest_len; ++i) {
|
||||
uint8_t data_out;
|
||||
if (src_len == 1) {
|
||||
data_out = src_buf[0];
|
||||
} else {
|
||||
data_out = src_buf[i];
|
||||
}
|
||||
uint8_t data_in = 0;
|
||||
for (int j = 0; j < 8; ++j, data_out <<= 1) {
|
||||
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
|
||||
if (self->phase == 0) {
|
||||
ets_delay_us(delay_half);
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
ets_delay_us(delay_half);
|
||||
}
|
||||
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
|
||||
if (self->phase == 0) {
|
||||
ets_delay_us(delay_half);
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
ets_delay_us(delay_half);
|
||||
}
|
||||
}
|
||||
if (dest_len != 0) {
|
||||
dest_buf[i] = data_in;
|
||||
}
|
||||
// make sure pending tasks have a chance to run
|
||||
ets_loop_iter();
|
||||
}
|
||||
}
|
||||
#include "extmod/machine_spi.h"
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for SPI
|
||||
|
||||
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 = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SPI(baudrate=%u, polarity=%u, phase=%u, sck=%u, mosi=%u, miso=%u)",
|
||||
self->baudrate, self->polarity, self->phase, self->sck, self->mosi, self->miso);
|
||||
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
|
||||
return 500000 / delay_half;
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
|
||||
uint32_t delay_half = 500000 / baudrate;
|
||||
// round delay_half up so that: actual_baudrate <= requested_baudrate
|
||||
if (500000 % baudrate != 0) {
|
||||
delay_half += 1;
|
||||
}
|
||||
return delay_half;
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SPI(baudrate=%u, polarity=%u, phase=%u, sck=%u, mosi=%u, miso=%u)",
|
||||
baudrate_from_delay_half(self->delay_half),
|
||||
self->polarity, self->phase, self->sck, self->mosi, self->miso);
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_init_helper(mp_machine_soft_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
|
||||
@@ -106,7 +70,7 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj
|
||||
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;
|
||||
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
||||
}
|
||||
if (args[ARG_polarity].u_int != -1) {
|
||||
self->polarity = args[ARG_polarity].u_int;
|
||||
@@ -131,12 +95,12 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj
|
||||
mp_hal_pin_input(self->miso);
|
||||
}
|
||||
|
||||
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 *args) {
|
||||
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 *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
pyb_spi_obj_t *self = m_new_obj(pyb_spi_obj_t);
|
||||
mp_machine_soft_spi_obj_t *self = m_new_obj(mp_machine_soft_spi_obj_t);
|
||||
self->base.type = &pyb_spi_type;
|
||||
// set defaults
|
||||
self->baudrate = 500000;
|
||||
self->delay_half = baudrate_to_delay_half(500000);
|
||||
self->polarity = 0;
|
||||
self->phase = 0;
|
||||
self->sck = 14;
|
||||
@@ -154,69 +118,25 @@ STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_a
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *args) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
uint8_t write_byte = 0;
|
||||
if (n_args == 3) {
|
||||
write_byte = mp_obj_get_int(args[2]);
|
||||
}
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
|
||||
mp_hal_spi_transfer(self, 1, &write_byte, vstr.len, (uint8_t*)vstr.buf);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_read_obj, 2, 3, pyb_spi_read);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *args) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
||||
uint8_t write_byte = 0;
|
||||
if (n_args == 3) {
|
||||
write_byte = mp_obj_get_int(args[2]);
|
||||
}
|
||||
mp_hal_spi_transfer(self, 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_readinto_obj, 2, 3, pyb_spi_readinto);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t src_buf;
|
||||
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
|
||||
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, 0, NULL);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t src_buf;
|
||||
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
|
||||
mp_buffer_info_t dest_buf;
|
||||
mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE);
|
||||
if (src_buf.len != dest_buf.len) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length"));
|
||||
}
|
||||
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, dest_buf.len, (uint8_t*)dest_buf.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
|
||||
|
||||
STATIC const mp_machine_spi_p_t pyb_spi_p = {
|
||||
.transfer = mp_machine_soft_spi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_spi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SPI,
|
||||
.name = MP_QSTR_SoftSPI,
|
||||
.print = pyb_spi_print,
|
||||
.make_new = pyb_spi_make_new,
|
||||
.protocol = &pyb_spi_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict,
|
||||
};
|
||||
|
||||
46
esp8266/modules/ds18x20.py
Normal file
46
esp8266/modules/ds18x20.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# DS18x20 temperature sensor driver for MicroPython.
|
||||
# MIT license; Copyright (c) 2016 Damien P. George
|
||||
|
||||
_CONVERT = const(0x44)
|
||||
_RD_SCRATCH = const(0xbe)
|
||||
_WR_SCRATCH = const(0x4e)
|
||||
|
||||
class DS18X20:
|
||||
def __init__(self, onewire):
|
||||
self.ow = onewire
|
||||
self.buf = bytearray(9)
|
||||
|
||||
def scan(self):
|
||||
return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28]
|
||||
|
||||
def convert_temp(self):
|
||||
self.ow.reset(True)
|
||||
self.ow.writebyte(self.ow.SKIP_ROM)
|
||||
self.ow.writebyte(_CONVERT)
|
||||
|
||||
def read_scratch(self, rom):
|
||||
self.ow.reset(True)
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(_RD_SCRATCH)
|
||||
self.ow.readinto(self.buf)
|
||||
if self.ow.crc8(self.buf):
|
||||
raise Exception('CRC error')
|
||||
return self.buf
|
||||
|
||||
def write_scratch(self, rom, buf):
|
||||
self.ow.reset(True)
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(_WR_SCRATCH)
|
||||
self.ow.write(buf)
|
||||
|
||||
def read_temp(self, rom):
|
||||
buf = self.read_scratch(rom)
|
||||
if rom[0] == 0x10:
|
||||
if buf[1]:
|
||||
t = buf[0] >> 1 | 0x80
|
||||
t = -((~t + 1) & 0xff)
|
||||
else:
|
||||
t = buf[0] >> 1
|
||||
return t - 0.25 + (buf[7] - buf[6]) / buf[7]
|
||||
else:
|
||||
return (buf[1] << 8 | buf[0]) / 16
|
||||
@@ -15,8 +15,11 @@ class OneWire:
|
||||
self.pin = pin
|
||||
self.pin.init(pin.OPEN_DRAIN)
|
||||
|
||||
def reset(self):
|
||||
return _ow.reset(self.pin)
|
||||
def reset(self, required=False):
|
||||
reset = _ow.reset(self.pin)
|
||||
if required and not reset:
|
||||
raise OneWireError
|
||||
return reset
|
||||
|
||||
def readbit(self):
|
||||
return _ow.readbit(self.pin)
|
||||
@@ -24,11 +27,9 @@ class OneWire:
|
||||
def readbyte(self):
|
||||
return _ow.readbyte(self.pin)
|
||||
|
||||
def read(self, count):
|
||||
buf = bytearray(count)
|
||||
for i in range(count):
|
||||
def readinto(self, buf):
|
||||
for i in range(len(buf)):
|
||||
buf[i] = _ow.readbyte(self.pin)
|
||||
return buf
|
||||
|
||||
def writebit(self, value):
|
||||
return _ow.writebit(self.pin, value)
|
||||
@@ -87,41 +88,3 @@ class OneWire:
|
||||
|
||||
def crc8(self, data):
|
||||
return _ow.crc8(data)
|
||||
|
||||
class DS18B20:
|
||||
CONVERT = const(0x44)
|
||||
RD_SCRATCH = const(0xbe)
|
||||
WR_SCRATCH = const(0x4e)
|
||||
|
||||
def __init__(self, onewire):
|
||||
self.ow = onewire
|
||||
|
||||
def scan(self):
|
||||
return [rom for rom in self.ow.scan() if rom[0] == 0x28]
|
||||
|
||||
def convert_temp(self):
|
||||
if not self.ow.reset():
|
||||
raise OneWireError
|
||||
self.ow.writebyte(SKIP_ROM)
|
||||
self.ow.writebyte(CONVERT)
|
||||
|
||||
def read_scratch(self, rom):
|
||||
if not self.ow.reset():
|
||||
raise OneWireError
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(RD_SCRATCH)
|
||||
buf = self.ow.read(9)
|
||||
if self.ow.crc8(buf):
|
||||
raise OneWireError
|
||||
return buf
|
||||
|
||||
def write_scratch(self, rom, buf):
|
||||
if not self.ow.reset():
|
||||
raise OneWireError
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(WR_SCRATCH)
|
||||
self.ow.write(buf)
|
||||
|
||||
def read_temp(self, rom):
|
||||
buf = self.read_scratch(rom)
|
||||
return (buf[1] << 8 | buf[0]) / 16
|
||||
@@ -74,7 +74,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
#if MICROPY_VFS_FAT
|
||||
mp_obj_t vfs_proxy_call(qstr method_name, mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (MP_STATE_PORT(fs_user_mount)[0] == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENODEV)));
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
mp_obj_t meth[n_args + 2];
|
||||
@@ -123,6 +123,20 @@ STATIC mp_obj_t os_rename(mp_obj_t path_old, mp_obj_t path_new) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
|
||||
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
return vfs_proxy_call(MP_QSTR_stat, 1, &path_in);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
STATIC mp_obj_t os_statvfs(mp_obj_t path_in) {
|
||||
return vfs_proxy_call(MP_QSTR_statvfs, 1, &path_in);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_statvfs_obj, os_statvfs);
|
||||
|
||||
STATIC mp_obj_t os_umount(void) {
|
||||
return vfs_proxy_call(MP_QSTR_umount, 0, NULL);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_umount_obj, os_umount);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
@@ -143,11 +157,6 @@ STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
|
||||
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
return vfs_proxy_call(MP_QSTR_stat, 1, &path_in);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
|
||||
@@ -166,6 +175,8 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&os_statvfs_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&os_umount_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -173,6 +184,5 @@ STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
const mp_obj_module_t uos_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uos,
|
||||
.globals = (mp_obj_dict_t*)&os_module_globals,
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "modpybrtc.h"
|
||||
#include "timeutils.h"
|
||||
#include "user_interface.h"
|
||||
#include "extmod/utime_mphal.h"
|
||||
|
||||
/// \module time - time related functions
|
||||
///
|
||||
@@ -99,53 +100,6 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
|
||||
|
||||
/// \function sleep(seconds)
|
||||
/// Sleep for the given number of seconds.
|
||||
STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o));
|
||||
#else
|
||||
mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
|
||||
|
||||
STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
|
||||
mp_hal_delay_ms(mp_obj_get_int(arg));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms);
|
||||
|
||||
STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
|
||||
mp_hal_delay_us(mp_obj_get_int(arg));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_ms(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
|
||||
|
||||
STATIC mp_obj_t time_ticks_us(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_cpu(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
|
||||
|
||||
STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) {
|
||||
// we assume that the arguments come from ticks_xx so are small ints
|
||||
uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
|
||||
uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
|
||||
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff);
|
||||
|
||||
/// \function time()
|
||||
/// Returns the number of seconds, as an integer, since 1/1/2000.
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
@@ -159,13 +113,13 @@ STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
|
||||
{ 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_sleep), (mp_obj_t)&time_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mp_utime_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&mp_utime_ticks_cpu_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
|
||||
};
|
||||
|
||||
@@ -173,6 +127,5 @@ STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
||||
const mp_obj_module_t utime_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_utime,
|
||||
.globals = (mp_obj_dict_t*)&time_module_globals,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#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_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
@@ -17,6 +18,7 @@
|
||||
#define MICROPY_DEBUG_PRINTER_DEST mp_debug_print
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
@@ -25,6 +27,7 @@
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_USE_INTERNAL_ERRNO (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)
|
||||
@@ -32,6 +35,7 @@
|
||||
#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___FILE__ (0)
|
||||
#define MICROPY_PY_GC (1)
|
||||
@@ -48,20 +52,23 @@
|
||||
#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 (1)
|
||||
#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS)
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_URE (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_PULSE (1)
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_SPI (1)
|
||||
#define MICROPY_PY_WEBSOCKET (1)
|
||||
#define MICROPY_PY_WEBREPL (1)
|
||||
#define MICROPY_PY_WEBREPL_DELAY (20)
|
||||
@@ -89,6 +96,7 @@
|
||||
#define MICROPY_FSUSERMOUNT (1)
|
||||
#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)
|
||||
@@ -114,8 +122,6 @@
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of 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
|
||||
|
||||
@@ -39,8 +39,6 @@ static void uart0_rx_intr_handler(void *para);
|
||||
void soft_reset(void);
|
||||
void mp_keyboard_interrupt(void);
|
||||
|
||||
int interrupt_char;
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart_config
|
||||
* Description : Internal used function
|
||||
@@ -172,7 +170,7 @@ static void uart0_rx_intr_handler(void *para) {
|
||||
|
||||
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
||||
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
|
||||
if (RcvChar == interrupt_char) {
|
||||
if (RcvChar == mp_interrupt_char) {
|
||||
mp_keyboard_interrupt();
|
||||
} else {
|
||||
ringbuf_put(&input_buf, RcvChar);
|
||||
|
||||
@@ -16,10 +16,10 @@ pyb.LED(3).off() # indicate that we finished waiting for the swit
|
||||
pyb.LED(4).on() # indicate that we are selecting the mode
|
||||
|
||||
if switch_value:
|
||||
pyb.usb_mode('CDC+MSC')
|
||||
pyb.usb_mode('VCP+MSC')
|
||||
pyb.main('cardreader.py') # if switch was pressed, run this
|
||||
else:
|
||||
pyb.usb_mode('CDC+HID')
|
||||
pyb.usb_mode('VCP+HID')
|
||||
pyb.main('datalogger.py') # if switch wasn't pressed, run this
|
||||
|
||||
pyb.LED(4).off() # indicate that we finished selecting the mode
|
||||
|
||||
@@ -127,9 +127,6 @@ typedef long long mp_off_t;
|
||||
typedef long mp_off_t;
|
||||
#endif
|
||||
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#ifdef __FreeBSD__
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -18,10 +18,10 @@ def main(use_stream=False):
|
||||
# MicroPython socket objects support stream (aka file) interface
|
||||
# directly, but the line below is needed for CPython.
|
||||
s = s.makefile("rwb", 0)
|
||||
s.write(b"GET / HTTP/1.0\n\n")
|
||||
s.write(b"GET / HTTP/1.0\r\n\r\n")
|
||||
print(s.readall())
|
||||
else:
|
||||
s.send(b"GET / HTTP/1.0\n\n")
|
||||
s.send(b"GET / HTTP/1.0\r\n\r\n")
|
||||
print(s.recv(4096))
|
||||
|
||||
s.close()
|
||||
|
||||
@@ -24,12 +24,12 @@ def main(use_stream=True):
|
||||
if use_stream:
|
||||
# Both CPython and MicroPython SSLSocket objects support read() and
|
||||
# write() methods.
|
||||
s.write(b"GET / HTTP/1.0\n\n")
|
||||
s.write(b"GET / HTTP/1.0\r\n\r\n")
|
||||
print(s.read(4096))
|
||||
else:
|
||||
# MicroPython SSLSocket objects implement only stream interface, not
|
||||
# socket interface
|
||||
s.send(b"GET / HTTP/1.0\n\n")
|
||||
s.send(b"GET / HTTP/1.0\r\n\r\n")
|
||||
print(s.recv(4096))
|
||||
|
||||
s.close()
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
@@ -162,7 +163,7 @@ STATIC mp_obj_t fatfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount);
|
||||
|
||||
STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) {
|
||||
mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) {
|
||||
size_t i = 0;
|
||||
if (MP_OBJ_IS_STR(bdev_or_path_in)) {
|
||||
mp_uint_t mnt_len;
|
||||
@@ -183,7 +184,7 @@ STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) {
|
||||
}
|
||||
|
||||
if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL)));
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef struct _fs_user_mount_t {
|
||||
} fs_user_mount_t;
|
||||
|
||||
fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs);
|
||||
mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj);
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C
|
||||
|
||||
// Clock stretching limit, so that we don't get stuck.
|
||||
#define I2C_STRETCH_LIMIT 255
|
||||
|
||||
typedef struct _machine_i2c_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t us_delay;
|
||||
@@ -53,6 +56,11 @@ STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) {
|
||||
|
||||
STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
|
||||
mp_hal_pin_od_high(self->scl);
|
||||
mp_hal_i2c_delay(self);
|
||||
// For clock stretching, wait for the SCL pin to be released, with timeout.
|
||||
for (int count = I2C_STRETCH_LIMIT; mp_hal_pin_read(self->scl) == 0 && count; --count) {
|
||||
mp_hal_delay_us_fast(1);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {
|
||||
@@ -71,7 +79,6 @@ STATIC void mp_hal_i2c_start(machine_i2c_obj_t *self) {
|
||||
mp_hal_i2c_sda_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_sda_low(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
}
|
||||
@@ -81,7 +88,6 @@ STATIC void mp_hal_i2c_stop(machine_i2c_obj_t *self) {
|
||||
mp_hal_i2c_sda_low(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_sda_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
}
|
||||
@@ -108,14 +114,12 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
|
||||
}
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_low(self);
|
||||
}
|
||||
|
||||
mp_hal_i2c_sda_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
|
||||
int ret = mp_hal_i2c_sda_read(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
@@ -124,24 +128,6 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
|
||||
return !ret;
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) {
|
||||
mp_hal_i2c_start(self);
|
||||
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
|
||||
goto er;
|
||||
}
|
||||
while (len--) {
|
||||
if (!mp_hal_i2c_write_byte(self, *data++)) {
|
||||
goto er;
|
||||
}
|
||||
}
|
||||
mp_hal_i2c_stop(self);
|
||||
return;
|
||||
|
||||
er:
|
||||
mp_hal_i2c_stop(self);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
|
||||
}
|
||||
|
||||
STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_low(self);
|
||||
@@ -150,7 +136,6 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
|
||||
uint8_t data = 0;
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
data = (data << 1) | mp_hal_i2c_sda_read(self);
|
||||
mp_hal_i2c_scl_low(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
@@ -163,40 +148,33 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
|
||||
}
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_release(self);
|
||||
mp_hal_i2c_delay(self);
|
||||
mp_hal_i2c_scl_low(self);
|
||||
mp_hal_i2c_sda_release(self);
|
||||
|
||||
return 1; // success
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) {
|
||||
mp_hal_i2c_start(self);
|
||||
if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
|
||||
goto er;
|
||||
// addr is the device address, memaddr is a memory address sent big-endian
|
||||
STATIC int mp_hal_i2c_write_addresses(machine_i2c_obj_t *self, uint8_t addr,
|
||||
uint32_t memaddr, uint8_t addrsize) {
|
||||
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
|
||||
return 0; // error
|
||||
}
|
||||
while (len--) {
|
||||
if (!mp_hal_i2c_read_byte(self, data++, len == 0)) {
|
||||
goto er;
|
||||
for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
|
||||
if (!mp_hal_i2c_write_byte(self, memaddr >> i)) {
|
||||
return 0; // error
|
||||
}
|
||||
}
|
||||
mp_hal_i2c_stop(self);
|
||||
return;
|
||||
|
||||
er:
|
||||
mp_hal_i2c_stop(self);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
|
||||
return 1; // success
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, const uint8_t *src, size_t len) {
|
||||
STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr,
|
||||
uint32_t memaddr, uint8_t addrsize, const uint8_t *src, size_t len) {
|
||||
// start the I2C transaction
|
||||
mp_hal_i2c_start(self);
|
||||
|
||||
// write the slave address and the memory address within the slave
|
||||
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
|
||||
goto er;
|
||||
}
|
||||
if (!mp_hal_i2c_write_byte(self, memaddr)) {
|
||||
if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
|
||||
goto er;
|
||||
}
|
||||
|
||||
@@ -216,20 +194,30 @@ er:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, uint8_t *dest, size_t len) {
|
||||
STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr,
|
||||
uint32_t memaddr, uint8_t addrsize, uint8_t *dest, size_t len) {
|
||||
// start the I2C transaction
|
||||
mp_hal_i2c_start(self);
|
||||
|
||||
// write the slave address and the memory address within the slave
|
||||
if (!mp_hal_i2c_write_byte(self, addr << 1)) {
|
||||
goto er;
|
||||
}
|
||||
if (!mp_hal_i2c_write_byte(self, memaddr)) {
|
||||
goto er;
|
||||
if (addrsize) {
|
||||
// write the slave address and the memory address within the slave
|
||||
if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
|
||||
goto er;
|
||||
}
|
||||
|
||||
// i2c_read will do a repeated start, and then read the I2C memory
|
||||
mp_hal_i2c_start(self);
|
||||
}
|
||||
|
||||
// i2c_read will do a repeated start, and then read the I2C memory
|
||||
mp_hal_i2c_read(self, addr, dest, len);
|
||||
if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
|
||||
goto er;
|
||||
}
|
||||
while (len--) {
|
||||
if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) {
|
||||
goto er;
|
||||
}
|
||||
}
|
||||
mp_hal_i2c_stop(self);
|
||||
return;
|
||||
|
||||
er:
|
||||
@@ -237,6 +225,14 @@ er:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, const uint8_t *src, size_t len) {
|
||||
mp_hal_i2c_write_mem(self, addr, 0, 0, src, len);
|
||||
}
|
||||
|
||||
STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *dest, size_t len) {
|
||||
mp_hal_i2c_read_mem(self, addr, 0, 0, dest, len);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for I2C
|
||||
|
||||
@@ -276,7 +272,7 @@ STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
|
||||
// 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
|
||||
for (int addr = 0x08; addr < 0x78; ++addr) {
|
||||
mp_hal_i2c_start(self);
|
||||
int ack = mp_hal_i2c_write_byte(self, (addr << 1) | 1);
|
||||
int ack = mp_hal_i2c_write_byte(self, (addr << 1));
|
||||
if (ack) {
|
||||
mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
|
||||
}
|
||||
@@ -365,68 +361,64 @@ STATIC mp_obj_t machine_i2c_writeto(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_writeto_obj, machine_i2c_writeto);
|
||||
|
||||
STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_arg, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
|
||||
};
|
||||
|
||||
STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
|
||||
};
|
||||
machine_i2c_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);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
|
||||
|
||||
// create the buffer to store data into
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, args[ARG_n].u_int);
|
||||
vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));
|
||||
|
||||
// do the transfer
|
||||
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, (uint8_t*)vstr.buf, vstr.len);
|
||||
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
|
||||
args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);
|
||||
|
||||
|
||||
STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
|
||||
};
|
||||
machine_i2c_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);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
|
||||
|
||||
// get the buffer to store data into
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
// do the transfer
|
||||
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, bufinfo.buf, bufinfo.len);
|
||||
mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
|
||||
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);
|
||||
|
||||
STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
//{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO
|
||||
};
|
||||
machine_i2c_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);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
|
||||
|
||||
// get the buffer to write the data from
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
// do the transfer
|
||||
mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, bufinfo.buf, bufinfo.len);
|
||||
mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
|
||||
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);
|
||||
|
||||
@@ -58,7 +58,7 @@ STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us);
|
||||
if (us == (mp_uint_t)-1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
return mp_obj_new_int(us);
|
||||
}
|
||||
|
||||
141
extmod/machine_spi.c
Normal file
141
extmod/machine_spi.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_SPI
|
||||
|
||||
void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
|
||||
uint32_t delay_half = self->delay_half;
|
||||
|
||||
// only MSB transfer is implemented
|
||||
|
||||
// If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured
|
||||
// delay_half is equal to this value, then the software SPI implementation
|
||||
// will run as fast as possible, limited only by CPU speed and GPIO time.
|
||||
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
|
||||
if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
uint8_t data_out = src[i];
|
||||
uint8_t data_in = 0;
|
||||
for (int j = 0; j < 8; ++j, data_out <<= 1) {
|
||||
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
}
|
||||
if (dest != NULL) {
|
||||
dest[i] = data_in;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
uint8_t data_out = src[i];
|
||||
uint8_t data_in = 0;
|
||||
for (int j = 0; j < 8; ++j, data_out <<= 1) {
|
||||
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
|
||||
if (self->phase == 0) {
|
||||
mp_hal_delay_us_fast(delay_half);
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
mp_hal_delay_us_fast(delay_half);
|
||||
}
|
||||
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
|
||||
if (self->phase == 0) {
|
||||
mp_hal_delay_us_fast(delay_half);
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
mp_hal_delay_us_fast(delay_half);
|
||||
}
|
||||
}
|
||||
if (dest != NULL) {
|
||||
dest[i] = data_in;
|
||||
}
|
||||
|
||||
// Some ports need a regular callback, but probably we don't need
|
||||
// to do this every byte, or even at all.
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest) {
|
||||
mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self);
|
||||
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;
|
||||
spi_p->transfer(s, len, src, dest);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) {
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
|
||||
memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);
|
||||
mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read);
|
||||
|
||||
STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
||||
memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);
|
||||
mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto);
|
||||
|
||||
STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) {
|
||||
mp_buffer_info_t src;
|
||||
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
||||
mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write);
|
||||
|
||||
STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) {
|
||||
mp_buffer_info_t src;
|
||||
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
||||
mp_buffer_info_t dest;
|
||||
mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE);
|
||||
if (src.len != dest.len) {
|
||||
mp_raise_ValueError("buffers must be the same length");
|
||||
}
|
||||
mp_machine_spi_transfer(self, src.len, src.buf, dest.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_SPI
|
||||
55
extmod/machine_spi.h
Normal file
55
extmod/machine_spi.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
// SPI protocol
|
||||
typedef struct _mp_machine_spi_p_t {
|
||||
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
|
||||
} mp_machine_spi_p_t;
|
||||
|
||||
typedef struct _mp_machine_soft_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t delay_half; // microsecond delay for half SCK period
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
mp_hal_pin_obj_t sck;
|
||||
mp_hal_pin_obj_t mosi;
|
||||
mp_hal_pin_obj_t miso;
|
||||
} mp_machine_soft_spi_obj_t;
|
||||
|
||||
void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_read_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_readinto_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_readinto_obj);
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
||||
@@ -58,7 +58,7 @@ STATIC const mp_obj_type_t btree_type;
|
||||
|
||||
#define CHECK_ERROR(res) \
|
||||
if (res == RET_ERROR) { \
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno))); \
|
||||
mp_raise_OSError(errno); \
|
||||
}
|
||||
|
||||
void __dbpanic(DB *db) {
|
||||
@@ -133,6 +133,7 @@ STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
int res = __bt_seq(self->db, &key, &val, flags);
|
||||
CHECK_ERROR(res);
|
||||
if (res == RET_SPECIAL) {
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -369,7 +370,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
|
||||
DB *db = __bt_open(pos_args[0], &btree_stream_fvtable, &openinfo, /*dflags*/0);
|
||||
if (db == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno)));
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(btree_new(db));
|
||||
}
|
||||
@@ -386,7 +387,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_tab
|
||||
|
||||
const mp_obj_module_t mp_module_btree = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_btree,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_btree_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#if MICROPY_PY_FRAMEBUF
|
||||
|
||||
#include "font_petme128_8x8.h"
|
||||
#include "stmhal/font_petme128_8x8.h"
|
||||
|
||||
// 1-bit frame buffer, each byte is a column of 8 pixels
|
||||
typedef struct _mp_obj_framebuf1_t {
|
||||
@@ -68,7 +68,8 @@ STATIC mp_obj_t framebuf1_fill(mp_obj_t self_in, mp_obj_t col_in) {
|
||||
if (col) {
|
||||
col = 0xff;
|
||||
}
|
||||
for (int y = 0; y < self->height / 8; ++y) {
|
||||
int end = (self->height + 7) >> 3;
|
||||
for (int y = 0; y < end; ++y) {
|
||||
memset(self->buf + y * self->stride, col, self->width);
|
||||
}
|
||||
return mp_const_none;
|
||||
@@ -83,7 +84,7 @@ STATIC mp_obj_t framebuf1_pixel(size_t n_args, const mp_obj_t *args) {
|
||||
int index = (y / 8) * self->stride + x;
|
||||
if (n_args == 3) {
|
||||
// get
|
||||
return MP_OBJ_NEW_SMALL_INT(self->buf[index] >> (y & 7));
|
||||
return MP_OBJ_NEW_SMALL_INT((self->buf[index] >> (y & 7)) & 1);
|
||||
} else {
|
||||
// set
|
||||
if (mp_obj_get_int(args[3])) {
|
||||
@@ -101,8 +102,9 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y
|
||||
mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t xstep = mp_obj_get_int(xstep_in);
|
||||
mp_int_t ystep = mp_obj_get_int(ystep_in);
|
||||
if (xstep == 0 && ystep > 0) {
|
||||
for (int y = self->height / 8; y > 0;) {
|
||||
int end = (self->height + 7) >> 3;
|
||||
if (ystep > 0) {
|
||||
for (int y = end; y > 0;) {
|
||||
--y;
|
||||
for (int x = 0; x < self->width; ++x) {
|
||||
int prev = 0;
|
||||
@@ -112,18 +114,31 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y
|
||||
self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] << ystep) | prev;
|
||||
}
|
||||
}
|
||||
} else if (xstep == 0 && ystep < 0) {
|
||||
for (int y = 0; y < self->height / 8; ++y) {
|
||||
} else if (ystep < 0) {
|
||||
for (int y = 0; y < end; ++y) {
|
||||
for (int x = 0; x < self->width; ++x) {
|
||||
int prev = 0;
|
||||
if (y + 1 < self->height / 8) {
|
||||
if (y + 1 < end) {
|
||||
prev = self->buf[(y + 1) * self->stride + x] << (8 + ystep);
|
||||
}
|
||||
self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] >> -ystep) | prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO xstep!=0
|
||||
if (xstep < 0) {
|
||||
for (int y = 0; y < end; ++y) {
|
||||
for (int x = 0; x < self->width + xstep; ++x) {
|
||||
self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep];
|
||||
}
|
||||
}
|
||||
} else if (xstep > 0) {
|
||||
for (int y = 0; y < end; ++y) {
|
||||
for (int x = self->width - 1; x >= xstep; --x) {
|
||||
self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep];
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Should we clear the margin created by scrolling?
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf1_scroll_obj, framebuf1_scroll);
|
||||
@@ -198,7 +213,6 @@ STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_tab
|
||||
|
||||
const mp_obj_module_t mp_module_framebuf = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_framebuf,
|
||||
.globals = (mp_obj_dict_t*)&framebuf_module_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -598,11 +598,11 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args
|
||||
case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break;
|
||||
case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break;
|
||||
//case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break;
|
||||
default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL)));
|
||||
default: mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM)));
|
||||
mp_raise_OSError(MP_ENOMEM);
|
||||
}
|
||||
|
||||
switch (socket->type) {
|
||||
@@ -686,7 +686,7 @@ STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
}
|
||||
|
||||
if (err != ERR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
|
||||
mp_raise_OSError(error_lookup_table[-err]);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
@@ -698,15 +698,15 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
|
||||
mp_int_t backlog = mp_obj_get_int(backlog_in);
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
|
||||
mp_raise_OSError(MP_EBADF);
|
||||
}
|
||||
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP)));
|
||||
mp_raise_OSError(MP_EOPNOTSUPP);
|
||||
}
|
||||
|
||||
struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
|
||||
if (new_pcb == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM)));
|
||||
mp_raise_OSError(MP_ENOMEM);
|
||||
}
|
||||
socket->pcb.tcp = new_pcb;
|
||||
tcp_accept(new_pcb, _lwip_tcp_accept);
|
||||
@@ -719,15 +719,15 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
||||
lwip_socket_obj_t *socket = self_in;
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
|
||||
mp_raise_OSError(MP_EBADF);
|
||||
}
|
||||
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP)));
|
||||
mp_raise_OSError(MP_EOPNOTSUPP);
|
||||
}
|
||||
// I need to do this because "tcp_accepted", later, is a macro.
|
||||
struct tcp_pcb *listener = socket->pcb.tcp;
|
||||
if (listener->state != LISTEN) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL)));
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
// accept incoming connection
|
||||
@@ -738,7 +738,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
||||
if (socket->incoming.connection != NULL) break;
|
||||
}
|
||||
if (socket->incoming.connection == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
} else {
|
||||
while (socket->incoming.connection == NULL) {
|
||||
@@ -785,7 +785,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
lwip_socket_obj_t *socket = self_in;
|
||||
|
||||
if (socket->pcb.tcp == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
|
||||
mp_raise_OSError(MP_EBADF);
|
||||
}
|
||||
|
||||
// get address
|
||||
@@ -800,9 +800,9 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
case MOD_NETWORK_SOCK_STREAM: {
|
||||
if (socket->state != STATE_NEW) {
|
||||
if (socket->state == STATE_CONNECTED) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EALREADY)));
|
||||
mp_raise_OSError(MP_EALREADY);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINPROGRESS)));
|
||||
mp_raise_OSError(MP_EINPROGRESS);
|
||||
}
|
||||
}
|
||||
// Register our recieve callback.
|
||||
@@ -811,7 +811,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
|
||||
if (err != ERR_OK) {
|
||||
socket->state = STATE_NEW;
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
|
||||
mp_raise_OSError(error_lookup_table[-err]);
|
||||
}
|
||||
socket->peer_port = (mp_uint_t)port;
|
||||
memcpy(socket->peer, &dest, sizeof(socket->peer));
|
||||
@@ -822,7 +822,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
if (socket->state != STATE_CONNECTING) break;
|
||||
}
|
||||
if (socket->state == STATE_CONNECTING) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
} else {
|
||||
while (socket->state == STATE_CONNECTING) {
|
||||
@@ -843,7 +843,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
}
|
||||
|
||||
if (err != ERR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
|
||||
mp_raise_OSError(error_lookup_table[-err]);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
@@ -855,7 +855,7 @@ STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) {
|
||||
// not connected
|
||||
int _errno = error_lookup_table[-socket->state];
|
||||
socket->state = _ERR_BADF;
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,7 +880,7 @@ STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
}
|
||||
}
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(ret);
|
||||
@@ -909,7 +909,7 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
}
|
||||
}
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
@@ -944,7 +944,7 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
|
||||
}
|
||||
}
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(ret);
|
||||
@@ -977,7 +977,7 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
}
|
||||
}
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
mp_obj_t tuple[2];
|
||||
@@ -1010,7 +1010,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
// most useful behavior is: check whether we will be able to send all of input
|
||||
// data without EAGAIN, and if won't be, raise it without sending any.
|
||||
if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EAGAIN)));
|
||||
mp_raise_OSError(MP_EAGAIN);
|
||||
}
|
||||
}
|
||||
// TODO: In CPython3.5, socket timeout should apply to the
|
||||
@@ -1018,7 +1018,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
while (bufinfo.len != 0) {
|
||||
ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
|
||||
if (ret == -1) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
bufinfo.len -= ret;
|
||||
bufinfo.buf = (char*)bufinfo.buf + ret;
|
||||
@@ -1259,7 +1259,7 @@ STATIC mp_obj_t lwip_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
|
||||
if (state.status < 0) {
|
||||
// TODO: CPython raises gaierror, we raise with native lwIP negative error
|
||||
// values, to differentiate from normal errno's at least in such way.
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(state.status)));
|
||||
mp_raise_OSError(state.status);
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
|
||||
@@ -1309,7 +1309,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table
|
||||
|
||||
const mp_obj_module_t mp_module_lwip = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_lwip,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_lwip_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#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
|
||||
@@ -203,6 +204,17 @@ 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
|
||||
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);
|
||||
uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;
|
||||
crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
|
||||
return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UBINASCII
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
|
||||
@@ -211,13 +223,15 @@ STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },
|
||||
#if MICROPY_PY_UBINASCII_CRC32
|
||||
{ MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
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 },
|
||||
.name = MP_QSTR_ubinascii,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_binascii_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -31,10 +31,12 @@ extern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args);
|
||||
extern mp_obj_t mod_binascii_unhexlify(mp_obj_t data);
|
||||
extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data);
|
||||
extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data);
|
||||
extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mod_binascii_hexlify_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mod_binascii_unhexlify_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mod_binascii_a2b_base64_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mod_binascii_b2a_base64_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mod_binascii_crc32_obj);
|
||||
|
||||
#endif /* MICROPY_EXTMOD_MODUBINASCII */
|
||||
|
||||
@@ -125,7 +125,7 @@ STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args
|
||||
mp_arg_check_num(n_args, n_kw, 2, 3, false);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = type;
|
||||
o->addr = (void*)(uintptr_t)mp_obj_get_int(args[0]);
|
||||
o->addr = (void*)(uintptr_t)mp_obj_int_get_truncated(args[0]);
|
||||
o->desc = args[1];
|
||||
o->flags = LAYOUT_NATIVE;
|
||||
if (n_args == 3) {
|
||||
@@ -710,7 +710,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uctypes,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -151,7 +151,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals
|
||||
|
||||
const mp_obj_module_t mp_module_uhashlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uhashlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uheapq_globals, mp_module_uheapq_globals_t
|
||||
|
||||
const mp_obj_module_t mp_module_uheapq = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uheapq,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
* Copyright (c) 2014-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
|
||||
@@ -28,8 +28,10 @@
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/objstringio.h"
|
||||
#include "py/parsenum.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
|
||||
@@ -42,7 +44,7 @@ STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
|
||||
|
||||
// This function implements a simple non-recursive JSON parser.
|
||||
// The function below implements a simple non-recursive JSON parser.
|
||||
//
|
||||
// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt
|
||||
// The parser here will parse any valid JSON and return the correct
|
||||
@@ -52,13 +54,35 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
|
||||
// input is outside it's specs.
|
||||
//
|
||||
// Most of the work is parsing the primitives (null, false, true, numbers,
|
||||
// strings). It does 1 pass over the input string and so is easily extended to
|
||||
// being able to parse from a non-seekable stream. It tries to be fast and
|
||||
// strings). It does 1 pass over the input stream. It tries to be fast and
|
||||
// small in code size, while not using more RAM than necessary.
|
||||
STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
mp_uint_t len;
|
||||
const char *s = mp_obj_str_get_data(obj, &len);
|
||||
const char *top = s + len;
|
||||
|
||||
typedef struct _ujson_stream_t {
|
||||
mp_obj_t stream_obj;
|
||||
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
|
||||
int errcode;
|
||||
byte cur;
|
||||
} ujson_stream_t;
|
||||
|
||||
#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker
|
||||
#define S_END(s) ((s).cur == S_EOF)
|
||||
#define S_CUR(s) ((s).cur)
|
||||
#define S_NEXT(s) (ujson_stream_next(&(s)))
|
||||
|
||||
STATIC byte ujson_stream_next(ujson_stream_t *s) {
|
||||
mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode);
|
||||
if (s->errcode != 0) {
|
||||
mp_raise_OSError(s->errcode);
|
||||
}
|
||||
if (ret == 0) {
|
||||
s->cur = S_EOF;
|
||||
}
|
||||
return s->cur;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
|
||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);
|
||||
ujson_stream_t s = {stream_obj, stream_p->read, 0, 0};
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 8);
|
||||
mp_obj_list_t stack; // we use a list as a simple stack for nested JSON
|
||||
@@ -67,41 +91,43 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
mp_obj_t stack_top = MP_OBJ_NULL;
|
||||
mp_obj_type_t *stack_top_type = NULL;
|
||||
mp_obj_t stack_key = MP_OBJ_NULL;
|
||||
S_NEXT(s);
|
||||
for (;;) {
|
||||
cont:
|
||||
if (s == top) {
|
||||
if (S_END(s)) {
|
||||
break;
|
||||
}
|
||||
mp_obj_t next = MP_OBJ_NULL;
|
||||
bool enter = false;
|
||||
switch (*s) {
|
||||
byte cur = S_CUR(s);
|
||||
S_NEXT(s);
|
||||
switch (cur) {
|
||||
case ',':
|
||||
case ':':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
s += 1;
|
||||
goto cont;
|
||||
case 'n':
|
||||
if (s + 3 < top && s[1] == 'u' && s[2] == 'l' && s[3] == 'l') {
|
||||
s += 4;
|
||||
if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') {
|
||||
S_NEXT(s);
|
||||
next = mp_const_none;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (s + 4 < top && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e') {
|
||||
s += 5;
|
||||
if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') {
|
||||
S_NEXT(s);
|
||||
next = mp_const_false;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (s + 3 < top && s[1] == 'r' && s[2] == 'u' && s[3] == 'e') {
|
||||
s += 4;
|
||||
if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') {
|
||||
S_NEXT(s);
|
||||
next = mp_const_true;
|
||||
} else {
|
||||
goto fail;
|
||||
@@ -109,11 +135,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
break;
|
||||
case '"':
|
||||
vstr_reset(&vstr);
|
||||
for (s++; s < top && *s != '"';) {
|
||||
byte c = *s;
|
||||
for (; !S_END(s) && S_CUR(s) != '"';) {
|
||||
byte c = S_CUR(s);
|
||||
if (c == '\\') {
|
||||
s++;
|
||||
c = *s;
|
||||
c = S_NEXT(s);
|
||||
switch (c) {
|
||||
case 'b': c = 0x08; break;
|
||||
case 'f': c = 0x0c; break;
|
||||
@@ -121,10 +146,9 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
case 'r': c = 0x0d; break;
|
||||
case 't': c = 0x09; break;
|
||||
case 'u': {
|
||||
if (s + 4 >= top) { goto fail; }
|
||||
mp_uint_t num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
c = (*++s | 0x20) - '0';
|
||||
c = (S_NEXT(s) | 0x20) - '0';
|
||||
if (c > 9) {
|
||||
c -= ('a' - ('9' + 1));
|
||||
}
|
||||
@@ -137,27 +161,29 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
}
|
||||
vstr_add_byte(&vstr, c);
|
||||
str_cont:
|
||||
s++;
|
||||
S_NEXT(s);
|
||||
}
|
||||
if (s == top) {
|
||||
if (S_END(s)) {
|
||||
goto fail;
|
||||
}
|
||||
s++;
|
||||
S_NEXT(s);
|
||||
next = mp_obj_new_str(vstr.buf, vstr.len, false);
|
||||
break;
|
||||
case '-':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
|
||||
bool flt = false;
|
||||
vstr_reset(&vstr);
|
||||
for (; s < top; s++) {
|
||||
if (*s == '.' || *s == 'E' || *s == 'e') {
|
||||
for (;;) {
|
||||
vstr_add_byte(&vstr, cur);
|
||||
cur = S_CUR(s);
|
||||
if (cur == '.' || cur == 'E' || cur == 'e') {
|
||||
flt = true;
|
||||
} else if (*s == '-' || unichar_isdigit(*s)) {
|
||||
} else if (cur == '-' || unichar_isdigit(cur)) {
|
||||
// pass
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
vstr_add_byte(&vstr, *s);
|
||||
S_NEXT(s);
|
||||
}
|
||||
if (flt) {
|
||||
next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL);
|
||||
@@ -169,16 +195,13 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
case '[':
|
||||
next = mp_obj_new_list(0, NULL);
|
||||
enter = true;
|
||||
s += 1;
|
||||
break;
|
||||
case '{':
|
||||
next = mp_obj_new_dict(0);
|
||||
enter = true;
|
||||
s += 1;
|
||||
break;
|
||||
case '}':
|
||||
case ']': {
|
||||
s += 1;
|
||||
if (stack_top == MP_OBJ_NULL) {
|
||||
// no object at all
|
||||
goto fail;
|
||||
@@ -231,10 +254,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
}
|
||||
success:
|
||||
// eat trailing whitespace
|
||||
while (s < top && unichar_isspace(*s)) {
|
||||
s++;
|
||||
while (unichar_isspace(S_CUR(s))) {
|
||||
S_NEXT(s);
|
||||
}
|
||||
if (s < top) {
|
||||
if (!S_END(s)) {
|
||||
// unexpected chars
|
||||
goto fail;
|
||||
}
|
||||
@@ -248,11 +271,21 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
fail:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "syntax error in JSON"));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load);
|
||||
|
||||
STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
mp_uint_t len;
|
||||
const char *buf = mp_obj_str_get_data(obj, &len);
|
||||
vstr_t vstr = {len, len, (char*)buf, true};
|
||||
mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0};
|
||||
return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },
|
||||
};
|
||||
|
||||
@@ -260,7 +293,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_ujson_globals, mp_module_ujson_globals_tab
|
||||
|
||||
const mp_obj_module_t mp_module_ujson = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ujson,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ujson_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -215,7 +215,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals
|
||||
|
||||
const mp_obj_module_t mp_module_urandom = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_urandom,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_urandom_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -237,7 +237,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ure = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ure,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_re_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) {
|
||||
|
||||
uint32_t options = SSL_SERVER_VERIFY_LATER;
|
||||
if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL)));
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
if (server_side) {
|
||||
@@ -69,7 +69,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) {
|
||||
if ((res = ssl_handshake_status(o->ssl_sock)) != SSL_OK) {
|
||||
printf("ssl_handshake_status: %d\n", res);
|
||||
ssl_display_error(res);
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EIO)));
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ussl = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ussl,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ssl_globals,
|
||||
};
|
||||
|
||||
|
||||
303
extmod/modussl_mbedtls.c
Normal file
303
extmod/modussl_mbedtls.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Linaro 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 "py/mpconfig.h"
|
||||
#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
// mbedtls_time_t
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/debug.h"
|
||||
|
||||
typedef struct _mp_obj_ssl_socket_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t sock;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_x509_crt cert;
|
||||
mbedtls_pk_context pkey;
|
||||
} mp_obj_ssl_socket_t;
|
||||
|
||||
struct ssl_args {
|
||||
mp_arg_val_t key;
|
||||
mp_arg_val_t cert;
|
||||
mp_arg_val_t server_side;
|
||||
mp_arg_val_t server_hostname;
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t ussl_socket_type;
|
||||
|
||||
static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
|
||||
printf("DBG:%s:%04d: %s\n", file, line, str);
|
||||
}
|
||||
|
||||
// TODO: FIXME!
|
||||
int null_entropy_func(void *data, unsigned char *output, size_t len) {
|
||||
// enjoy random bytes
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
|
||||
mp_obj_t sock = *(mp_obj_t*)ctx;
|
||||
|
||||
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
|
||||
int err;
|
||||
|
||||
int out_sz = sock_stream->write(sock, buf, len, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
return -err;
|
||||
} else {
|
||||
return out_sz;
|
||||
}
|
||||
}
|
||||
|
||||
int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
|
||||
mp_obj_t sock = *(mp_obj_t*)ctx;
|
||||
|
||||
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
|
||||
int err;
|
||||
|
||||
int out_sz = sock_stream->read(sock, buf, len, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
return -err;
|
||||
} else {
|
||||
return out_sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
|
||||
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
|
||||
o->base.type = &ussl_socket_type;
|
||||
|
||||
int ret;
|
||||
mbedtls_ssl_init(&o->ssl);
|
||||
mbedtls_ssl_config_init(&o->conf);
|
||||
mbedtls_x509_crt_init(&o->cacert);
|
||||
mbedtls_x509_crt_init(&o->cert);
|
||||
mbedtls_pk_init(&o->pkey);
|
||||
mbedtls_ctr_drbg_init(&o->ctr_drbg);
|
||||
// Debug level (0-4)
|
||||
mbedtls_debug_set_threshold(0);
|
||||
|
||||
mbedtls_entropy_init(&o->entropy);
|
||||
const byte seed[] = "upy";
|
||||
ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed));
|
||||
if (ret != 0) {
|
||||
printf("ret=%d\n", ret);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_config_defaults(&o->conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (ret != 0) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);
|
||||
mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);
|
||||
|
||||
ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
|
||||
if (ret != 0) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (args->server_hostname.u_obj != mp_const_none) {
|
||||
const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
|
||||
ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
|
||||
if (ret != 0) {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
o->sock = sock;
|
||||
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
|
||||
|
||||
if (args->key.u_obj != MP_OBJ_NULL) {
|
||||
mp_uint_t key_len;
|
||||
const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len);
|
||||
// len should include terminating null
|
||||
ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
|
||||
assert(ret == 0);
|
||||
|
||||
mp_uint_t cert_len;
|
||||
const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
|
||||
// len should include terminating null
|
||||
ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
|
||||
assert(ret == 0);
|
||||
|
||||
ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
if (args->server_side.u_bool) {
|
||||
assert(0);
|
||||
} else {
|
||||
while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
//assert(0);
|
||||
printf("mbedtls_ssl_handshake error: -%x\n", -ret);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<_SSLSocket %p>", self);
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
|
||||
int ret = mbedtls_ssl_read(&o->ssl, buf, size);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
*errcode = ret;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
|
||||
int ret = mbedtls_ssl_write(&o->ssl, buf, size);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
*errcode = ret;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
|
||||
// Currently supports only blocking mode
|
||||
(void)self_in;
|
||||
if (!mp_obj_is_true(flag_in)) {
|
||||
mp_not_implemented("");
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
|
||||
|
||||
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
|
||||
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
mbedtls_x509_crt_free(&self->cacert);
|
||||
mbedtls_ssl_free(&self->ssl);
|
||||
mbedtls_ssl_config_free(&self->conf);
|
||||
mbedtls_ctr_drbg_free(&self->ctr_drbg);
|
||||
mbedtls_entropy_free(&self->entropy);
|
||||
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method(self->sock, MP_QSTR_close, dest);
|
||||
return mp_call_method_n_kw(0, 0, dest);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
|
||||
|
||||
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
|
||||
|
||||
STATIC const mp_stream_p_t ussl_socket_stream_p = {
|
||||
.read = socket_read,
|
||||
.write = socket_write,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t ussl_socket_type = {
|
||||
{ &mp_type_type },
|
||||
// Save on qstr's, reuse same as for module
|
||||
.name = MP_QSTR_ussl,
|
||||
.print = socket_print,
|
||||
.getiter = NULL,
|
||||
.iternext = NULL,
|
||||
.protocol = &ussl_socket_stream_p,
|
||||
.locals_dict = (void*)&ussl_socket_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// TODO: Implement more args
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
// TODO: Check that sock implements stream protocol
|
||||
mp_obj_t sock = pos_args[0];
|
||||
|
||||
struct ssl_args args;
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(socket_new(sock, &args));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ussl = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ssl_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_USSL
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
* Copyright (c) 2014-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
|
||||
@@ -25,9 +25,12 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
#if MICROPY_PY_UZLIB
|
||||
|
||||
@@ -39,16 +42,107 @@
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) {
|
||||
if (alloc_req < 256) {
|
||||
alloc_req = 256;
|
||||
typedef struct _mp_obj_decompio_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t src_stream;
|
||||
TINF_DATA decomp;
|
||||
bool eof;
|
||||
} mp_obj_decompio_t;
|
||||
|
||||
STATIC unsigned char read_src_stream(TINF_DATA *data) {
|
||||
byte *p = (void*)data;
|
||||
p -= offsetof(mp_obj_decompio_t, decomp);
|
||||
mp_obj_decompio_t *self = (mp_obj_decompio_t*)p;
|
||||
|
||||
const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ);
|
||||
int err;
|
||||
byte c;
|
||||
mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
mp_raise_OSError(err);
|
||||
}
|
||||
DEBUG_printf("uzlib: Resizing buffer to " UINT_FMT " bytes\n", d->destSize + alloc_req);
|
||||
d->destStart = m_renew(byte, d->destStart, d->destSize, d->destSize + alloc_req);
|
||||
d->destSize += alloc_req;
|
||||
return 0;
|
||||
if (out_sz == 0) {
|
||||
nlr_raise(mp_obj_new_exception(&mp_type_EOFError));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t decompio_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, 2, false);
|
||||
mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t);
|
||||
o->base.type = type;
|
||||
memset(&o->decomp, 0, sizeof(o->decomp));
|
||||
o->decomp.readSource = read_src_stream;
|
||||
o->src_stream = args[0];
|
||||
o->eof = false;
|
||||
|
||||
mp_int_t dict_opt = 0;
|
||||
int dict_sz;
|
||||
if (n_args > 1) {
|
||||
dict_opt = mp_obj_get_int(args[1]);
|
||||
}
|
||||
|
||||
if (dict_opt >= 16) {
|
||||
int st = uzlib_gzip_parse_header(&o->decomp);
|
||||
if (st != TINF_OK) {
|
||||
goto header_error;
|
||||
}
|
||||
dict_sz = 1 << (dict_opt - 16);
|
||||
} else if (dict_opt >= 0) {
|
||||
dict_opt = uzlib_zlib_parse_header(&o->decomp);
|
||||
if (dict_opt < 0) {
|
||||
header_error:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "compression header"));
|
||||
}
|
||||
dict_sz = 1 << dict_opt;
|
||||
} else {
|
||||
dict_sz = 1 << -dict_opt;
|
||||
}
|
||||
|
||||
uzlib_uncompress_init(&o->decomp, m_new(byte, dict_sz), dict_sz);
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
if (o->eof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
o->decomp.dest = buf;
|
||||
o->decomp.destSize = size;
|
||||
int st = uzlib_uncompress_chksum(&o->decomp);
|
||||
if (st == TINF_DONE) {
|
||||
o->eof = true;
|
||||
}
|
||||
if (st < 0) {
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return o->decomp.dest - (byte*)buf;
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
|
||||
|
||||
STATIC const mp_stream_p_t decompio_stream_p = {
|
||||
.read = decompio_read,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t decompio_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_DecompIO,
|
||||
.make_new = decompio_make_new,
|
||||
.protocol = &decompio_stream_p,
|
||||
.locals_dict = (void*)&decompio_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_t data = args[0];
|
||||
@@ -56,43 +150,68 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
TINF_DATA *decomp = m_new_obj(TINF_DATA);
|
||||
memset(decomp, 0, sizeof(*decomp));
|
||||
DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp));
|
||||
uzlib_uncompress_init(decomp, NULL, 0);
|
||||
mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15;
|
||||
byte *dest_buf = m_new(byte, dest_buf_size);
|
||||
|
||||
decomp->destSize = (bufinfo.len + 15) & ~15;
|
||||
decomp->destStart = m_new(byte, decomp->destSize);
|
||||
decomp->dest = dest_buf;
|
||||
decomp->destSize = dest_buf_size;
|
||||
DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", decomp->destSize);
|
||||
decomp->destGrow = mod_uzlib_grow_buf;
|
||||
decomp->source = bufinfo.buf;
|
||||
|
||||
int st;
|
||||
bool is_zlib = true;
|
||||
|
||||
if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) {
|
||||
st = tinf_uncompress_dyn(decomp);
|
||||
} else {
|
||||
st = tinf_zlib_uncompress_dyn(decomp, bufinfo.len);
|
||||
}
|
||||
if (st != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
|
||||
is_zlib = false;
|
||||
}
|
||||
|
||||
mp_uint_t final_sz = decomp->dest - decomp->destStart;
|
||||
DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", decomp->destSize, final_sz);
|
||||
decomp->destStart = (byte*)m_renew(byte, decomp->destStart, decomp->destSize, final_sz);
|
||||
mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, decomp->destStart);
|
||||
if (is_zlib) {
|
||||
st = uzlib_zlib_parse_header(decomp);
|
||||
if (st < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
st = uzlib_uncompress_chksum(decomp);
|
||||
if (st < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (st == TINF_DONE) {
|
||||
break;
|
||||
}
|
||||
size_t offset = decomp->dest - dest_buf;
|
||||
dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256);
|
||||
dest_buf_size += 256;
|
||||
decomp->dest = dest_buf + offset;
|
||||
decomp->destSize = 256;
|
||||
}
|
||||
|
||||
mp_uint_t final_sz = decomp->dest - dest_buf;
|
||||
DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", dest_buf_size, final_sz);
|
||||
dest_buf = (byte*)m_renew(byte, dest_buf, dest_buf_size, final_sz);
|
||||
mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf);
|
||||
m_del_obj(TINF_DATA, decomp);
|
||||
return res;
|
||||
|
||||
error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uzlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uzlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,
|
||||
};
|
||||
|
||||
@@ -101,6 +220,8 @@ const mp_obj_module_t mp_module_uzlib = {
|
||||
|
||||
#include "uzlib/tinflate.c"
|
||||
#include "uzlib/tinfzlib.c"
|
||||
#include "uzlib/tinfgzip.c"
|
||||
#include "uzlib/adler32.c"
|
||||
#include "uzlib/crc32.c"
|
||||
|
||||
#endif // MICROPY_PY_UZLIB
|
||||
|
||||
@@ -310,9 +310,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close);
|
||||
STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) {
|
||||
mp_uint_t len;
|
||||
const char *passwd = mp_obj_str_get_data(passwd_in, &len);
|
||||
len = MIN(len, sizeof(webrepl_passwd) - 1);
|
||||
memcpy(webrepl_passwd, passwd, len);
|
||||
webrepl_passwd[len] = 0;
|
||||
if (len > sizeof(webrepl_passwd) - 1) {
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
strcpy(webrepl_passwd, passwd);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password);
|
||||
@@ -339,7 +340,7 @@ STATIC const mp_obj_type_t webrepl_type = {
|
||||
};
|
||||
|
||||
STATIC const mp_map_elem_t webrepl_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_websocket) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__webrepl) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__webrepl), (mp_obj_t)&webrepl_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_password), (mp_obj_t)&webrepl_set_password_obj },
|
||||
};
|
||||
@@ -348,7 +349,6 @@ STATIC MP_DEFINE_CONST_DICT(webrepl_module_globals, webrepl_module_globals_table
|
||||
|
||||
const mp_obj_module_t mp_module_webrepl = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR__webrepl,
|
||||
.globals = (mp_obj_dict_t*)&webrepl_module_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -313,7 +313,6 @@ STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_t
|
||||
|
||||
const mp_obj_module_t mp_module_websocket = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_websocket,
|
||||
.globals = (mp_obj_dict_t*)&websocket_module_globals,
|
||||
};
|
||||
|
||||
|
||||
89
extmod/utime_mphal.c
Normal file
89
extmod/utime_mphal.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2016 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 "py/mpconfig.h"
|
||||
#if MICROPY_PY_UTIME_MP_HAL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/smallint.h"
|
||||
#include "extmod/utime_mphal.h"
|
||||
|
||||
STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o));
|
||||
#else
|
||||
mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep);
|
||||
|
||||
STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
|
||||
mp_int_t ms = mp_obj_get_int(arg);
|
||||
if (ms > 0) {
|
||||
mp_hal_delay_ms(ms);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms);
|
||||
|
||||
STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
|
||||
mp_int_t us = mp_obj_get_int(arg);
|
||||
if (us > 0) {
|
||||
mp_hal_delay_us(us);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_ms(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms);
|
||||
|
||||
STATIC mp_obj_t time_ticks_us(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_cpu(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu);
|
||||
|
||||
STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) {
|
||||
// we assume that the arguments come from ticks_xx so are small ints
|
||||
uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
|
||||
uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
|
||||
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff);
|
||||
|
||||
#endif // MICROPY_PY_UTIME_MP_HAL
|
||||
36
extmod/utime_mphal.h
Normal file
36
extmod/utime_mphal.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013-2016 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 "py/obj.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_ms_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_us_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_ms_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_us_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_cpu_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_diff_obj);
|
||||
@@ -41,12 +41,12 @@
|
||||
#define A32_BASE 65521
|
||||
#define A32_NMAX 5552
|
||||
|
||||
unsigned int tinf_adler32(const void *data, unsigned int length)
|
||||
uint32_t uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum /* 1 */)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
|
||||
unsigned int s1 = 1;
|
||||
unsigned int s2 = 0;
|
||||
unsigned int s1 = prev_sum & 0xffff;
|
||||
unsigned int s2 = prev_sum >> 16;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
|
||||
63
extmod/uzlib/crc32.c
Normal file
63
extmod/uzlib/crc32.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* CRC32 checksum
|
||||
*
|
||||
* Copyright (c) 1998-2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CRC32 algorithm taken from the zlib source, which is
|
||||
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
static const unsigned int tinf_crc32tab[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
|
||||
0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344,
|
||||
0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278,
|
||||
0xbdbdf21c
|
||||
};
|
||||
|
||||
/* crc is previous value for incremental computation, 0xffffffff initially */
|
||||
uint32_t uzlib_crc32(const void *data, unsigned int length, uint32_t crc)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
crc ^= buf[i];
|
||||
crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);
|
||||
crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);
|
||||
}
|
||||
|
||||
// return value suitable for passing in next time, for final value invert it
|
||||
return crc/* ^ 0xffffffff*/;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||
*/
|
||||
|
||||
#ifndef TINF_H_INCLUDED
|
||||
@@ -26,9 +26,18 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ok status, more data produced */
|
||||
#define TINF_OK 0
|
||||
/* end of compressed stream reached */
|
||||
#define TINF_DONE 1
|
||||
#define TINF_DATA_ERROR (-3)
|
||||
#define TINF_DEST_OVERFLOW (-4)
|
||||
#define TINF_CHKSUM_ERROR (-4)
|
||||
#define TINF_DICT_ERROR (-5)
|
||||
|
||||
/* checksum types */
|
||||
#define TINF_CHKSUM_NONE 0
|
||||
#define TINF_CHKSUM_ADLER 1
|
||||
#define TINF_CHKSUM_CRC 2
|
||||
|
||||
/* data structures */
|
||||
|
||||
@@ -40,6 +49,10 @@ typedef struct {
|
||||
struct TINF_DATA;
|
||||
typedef struct TINF_DATA {
|
||||
const unsigned char *source;
|
||||
/* If source above is NULL, this function will be used to read
|
||||
next byte from source stream */
|
||||
unsigned char (*readSource)(struct TINF_DATA *data);
|
||||
|
||||
unsigned int tag;
|
||||
unsigned int bitcount;
|
||||
|
||||
@@ -51,49 +64,51 @@ typedef struct TINF_DATA {
|
||||
unsigned char *dest;
|
||||
/* Remaining bytes in buffer */
|
||||
unsigned int destRemaining;
|
||||
/* Argument is the allocation size which didn't fit into buffer. Note that
|
||||
exact mimumum size to grow buffer by is lastAlloc - destRemaining. But
|
||||
growing by this exact size is ineficient, as the next allocation will
|
||||
fail again. */
|
||||
int (*destGrow)(struct TINF_DATA *data, unsigned int lastAlloc);
|
||||
|
||||
/* Accumulating checksum */
|
||||
unsigned int checksum;
|
||||
char checksum_type;
|
||||
|
||||
int btype;
|
||||
int bfinal;
|
||||
unsigned int curlen;
|
||||
int lzOff;
|
||||
unsigned char *dict_ring;
|
||||
unsigned int dict_size;
|
||||
unsigned int dict_idx;
|
||||
|
||||
TINF_TREE ltree; /* dynamic length/symbol tree */
|
||||
TINF_TREE dtree; /* dynamic distance tree */
|
||||
} TINF_DATA;
|
||||
|
||||
#define TINF_PUT(d, c) \
|
||||
{ \
|
||||
*d->dest++ = c; \
|
||||
if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \
|
||||
}
|
||||
|
||||
/* low-level API */
|
||||
unsigned char TINFCC uzlib_get_byte(TINF_DATA *d);
|
||||
|
||||
/* Step 1: Allocate TINF_DATA structure */
|
||||
/* Step 2: Set destStart, destSize, and destGrow fields */
|
||||
/* Step 3: Set source field */
|
||||
/* Step 4: Call tinf_uncompress_dyn() */
|
||||
/* Step 5: In response to destGrow callback, update destStart and destSize fields */
|
||||
/* Step 6: When tinf_uncompress_dyn() returns, buf.dest points to a byte past last uncompressed byte */
|
||||
/* Decompression API */
|
||||
|
||||
int TINFCC tinf_uncompress_dyn(TINF_DATA *d);
|
||||
int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen);
|
||||
void TINFCC uzlib_init(void);
|
||||
void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);
|
||||
int TINFCC uzlib_uncompress(TINF_DATA *d);
|
||||
int TINFCC uzlib_uncompress_chksum(TINF_DATA *d);
|
||||
|
||||
/* high-level API */
|
||||
int TINFCC uzlib_zlib_parse_header(TINF_DATA *d);
|
||||
int TINFCC uzlib_gzip_parse_header(TINF_DATA *d);
|
||||
|
||||
void TINFCC tinf_init(void);
|
||||
/* Compression API */
|
||||
|
||||
int TINFCC tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen);
|
||||
|
||||
int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
/* Checksum API */
|
||||
|
||||
int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
unsigned int TINFCC tinf_adler32(const void *data, unsigned int length);
|
||||
|
||||
unsigned int TINFCC tinf_crc32(const void *data, unsigned int length);
|
||||
|
||||
/* compression API */
|
||||
|
||||
void TINFCC tinf_compress(void *data, const uint8_t *src, unsigned slen);
|
||||
/* prev_sum is previous value for incremental computation, 1 initially */
|
||||
uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
|
||||
/* crc is previous value for incremental computation, 0xffffffff initially */
|
||||
uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
110
extmod/uzlib/tinfgzip.c
Normal file
110
extmod/uzlib/tinfgzip.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* tinfgzip - tiny gzip decompressor
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
#define FTEXT 1
|
||||
#define FHCRC 2
|
||||
#define FEXTRA 4
|
||||
#define FNAME 8
|
||||
#define FCOMMENT 16
|
||||
|
||||
void tinf_skip_bytes(TINF_DATA *d, int num);
|
||||
uint16_t tinf_get_uint16(TINF_DATA *d);
|
||||
|
||||
void tinf_skip_bytes(TINF_DATA *d, int num)
|
||||
{
|
||||
while (num--) uzlib_get_byte(d);
|
||||
}
|
||||
|
||||
uint16_t tinf_get_uint16(TINF_DATA *d)
|
||||
{
|
||||
unsigned int v = uzlib_get_byte(d);
|
||||
v = (uzlib_get_byte(d) << 8) | v;
|
||||
return v;
|
||||
}
|
||||
|
||||
int uzlib_gzip_parse_header(TINF_DATA *d)
|
||||
{
|
||||
unsigned char flg;
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
/* check id bytes */
|
||||
if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR;
|
||||
|
||||
/* check method is deflate */
|
||||
if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR;
|
||||
|
||||
/* get flag byte */
|
||||
flg = uzlib_get_byte(d);
|
||||
|
||||
/* check that reserved bits are zero */
|
||||
if (flg & 0xe0) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- find start of compressed data -- */
|
||||
|
||||
/* skip rest of base header of 10 bytes */
|
||||
tinf_skip_bytes(d, 6);
|
||||
|
||||
/* skip extra data if present */
|
||||
if (flg & FEXTRA)
|
||||
{
|
||||
unsigned int xlen = tinf_get_uint16(d);
|
||||
tinf_skip_bytes(d, xlen);
|
||||
}
|
||||
|
||||
/* skip file name if present */
|
||||
if (flg & FNAME) { while (uzlib_get_byte(d)); }
|
||||
|
||||
/* skip file comment if present */
|
||||
if (flg & FCOMMENT) { while (uzlib_get_byte(d)); }
|
||||
|
||||
/* check header crc if present */
|
||||
if (flg & FHCRC)
|
||||
{
|
||||
/*unsigned int hcrc =*/ tinf_get_uint16(d);
|
||||
|
||||
// TODO: Check!
|
||||
// if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff))
|
||||
// return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* initialize for crc32 checksum */
|
||||
d->checksum_type = TINF_CHKSUM_CRC;
|
||||
d->checksum = ~0;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
@@ -32,8 +32,12 @@
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "tinf.h"
|
||||
|
||||
uint32_t tinf_get_le_uint32(TINF_DATA *d);
|
||||
uint32_t tinf_get_be_uint32(TINF_DATA *d);
|
||||
|
||||
/* --------------------------------------------------- *
|
||||
* -- uninitialized global data (static structures) -- *
|
||||
* --------------------------------------------------- */
|
||||
@@ -89,21 +93,6 @@ const unsigned char clcidx[] = {
|
||||
* -- utility functions -- *
|
||||
* ----------------------- */
|
||||
|
||||
/* Execute callback to grow destination buffer */
|
||||
static int tinf_grow_dest_buf(TINF_DATA *d, unsigned int lastAlloc)
|
||||
{
|
||||
unsigned int oldsize = d->dest - d->destStart;
|
||||
/* This will update only destStart and destSize */
|
||||
if (!d->destGrow)
|
||||
{
|
||||
return TINF_DEST_OVERFLOW;
|
||||
}
|
||||
d->destGrow(d, lastAlloc);
|
||||
d->dest = d->destStart + oldsize;
|
||||
d->destRemaining = d->destSize - oldsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
|
||||
@@ -180,6 +169,34 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned
|
||||
* -- decode functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
unsigned char uzlib_get_byte(TINF_DATA *d)
|
||||
{
|
||||
if (d->source) {
|
||||
return *d->source++;
|
||||
}
|
||||
return d->readSource(d);
|
||||
}
|
||||
|
||||
uint32_t tinf_get_le_uint32(TINF_DATA *d)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
int i;
|
||||
for (i = 4; i--;) {
|
||||
val = val >> 8 | uzlib_get_byte(d) << 24;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t tinf_get_be_uint32(TINF_DATA *d)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
int i;
|
||||
for (i = 4; i--;) {
|
||||
val = val << 8 | uzlib_get_byte(d);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* get one bit from source stream */
|
||||
static int tinf_getbit(TINF_DATA *d)
|
||||
{
|
||||
@@ -189,7 +206,7 @@ static int tinf_getbit(TINF_DATA *d)
|
||||
if (!d->bitcount--)
|
||||
{
|
||||
/* load next tag */
|
||||
d->tag = *d->source++;
|
||||
d->tag = uzlib_get_byte(d);
|
||||
d->bitcount = 7;
|
||||
}
|
||||
|
||||
@@ -318,113 +335,86 @@ static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
/* given a stream and two trees, inflate a block of data */
|
||||
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
if (d->curlen == 0) {
|
||||
unsigned int offs;
|
||||
int dist;
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
//printf("huff sym: %02x\n", sym);
|
||||
|
||||
/* check for end of block */
|
||||
if (sym == 256)
|
||||
{
|
||||
return TINF_OK;
|
||||
}
|
||||
/* literal byte */
|
||||
if (sym < 256) {
|
||||
TINF_PUT(d, sym);
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
if (sym < 256)
|
||||
{
|
||||
if (d->destRemaining == 0)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, 1);
|
||||
if (res) return res;
|
||||
}
|
||||
/* end of block */
|
||||
if (sym == 256) {
|
||||
return TINF_DONE;
|
||||
}
|
||||
|
||||
*d->dest++ = sym;
|
||||
d->destRemaining--;
|
||||
/* substring from sliding dictionary */
|
||||
sym -= 257;
|
||||
/* possibly get more bits from length code */
|
||||
d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||
|
||||
} else {
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||
if (d->dict_ring) {
|
||||
if (offs > d->dict_size) {
|
||||
return TINF_DICT_ERROR;
|
||||
}
|
||||
d->lzOff = d->dict_idx - offs;
|
||||
if (d->lzOff < 0) {
|
||||
d->lzOff += d->dict_size;
|
||||
}
|
||||
} else {
|
||||
d->lzOff = -offs;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int length, offs, i;
|
||||
int dist;
|
||||
|
||||
sym -= 257;
|
||||
|
||||
/* possibly get more bits from length code */
|
||||
length = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
/* copy match */
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
d->dest[i] = d->dest[(int)(i - offs)];
|
||||
}
|
||||
|
||||
d->dest += length;
|
||||
d->destRemaining -= length;
|
||||
}
|
||||
}
|
||||
/* copy next byte from dict substring */
|
||||
if (d->dict_ring) {
|
||||
TINF_PUT(d, d->dict_ring[d->lzOff]);
|
||||
if ((unsigned)++d->lzOff == d->dict_size) {
|
||||
d->lzOff = 0;
|
||||
}
|
||||
} else {
|
||||
d->dest[0] = d->dest[d->lzOff];
|
||||
d->dest++;
|
||||
}
|
||||
d->curlen--;
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* inflate an uncompressed block of data */
|
||||
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
|
||||
{
|
||||
unsigned int length, invlength;
|
||||
unsigned int i;
|
||||
if (d->curlen == 0) {
|
||||
unsigned int length, invlength;
|
||||
|
||||
/* get length */
|
||||
length = d->source[1];
|
||||
length = 256*length + d->source[0];
|
||||
/* get length */
|
||||
length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
|
||||
/* get one's complement of length */
|
||||
invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d);
|
||||
/* check length */
|
||||
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||
|
||||
/* get one's complement of length */
|
||||
invlength = d->source[3];
|
||||
invlength = 256*invlength + d->source[2];
|
||||
/* increment length to properly return TINF_DONE below, without
|
||||
producing data at the same time */
|
||||
d->curlen = length + 1;
|
||||
|
||||
/* check length */
|
||||
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
}
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
if (--d->curlen == 0) {
|
||||
return TINF_DONE;
|
||||
}
|
||||
|
||||
d->source += 4;
|
||||
|
||||
/* copy block */
|
||||
for (i = length; i; --i) *d->dest++ = *d->source++;
|
||||
d->destRemaining -= length;
|
||||
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with fixed huffman trees */
|
||||
static int tinf_inflate_fixed_block(TINF_DATA *d)
|
||||
{
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using fixed trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with dynamic huffman trees */
|
||||
static int tinf_inflate_dynamic_block(TINF_DATA *d)
|
||||
{
|
||||
/* decode trees from stream */
|
||||
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using decoded trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
unsigned char c = uzlib_get_byte(d);
|
||||
TINF_PUT(d, c);
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
@@ -432,7 +422,7 @@ static int tinf_inflate_dynamic_block(TINF_DATA *d)
|
||||
* ---------------------- */
|
||||
|
||||
/* initialize global (static) data */
|
||||
void tinf_init(void)
|
||||
void uzlib_init(void)
|
||||
{
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
@@ -445,72 +435,117 @@ void tinf_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
/* initialize decompression structure */
|
||||
void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen)
|
||||
{
|
||||
(void)sourceLen;
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
d.destSize = *destLen;
|
||||
|
||||
res = tinf_uncompress_dyn(&d);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress_dyn(TINF_DATA *d)
|
||||
{
|
||||
int bfinal;
|
||||
|
||||
/* initialise data */
|
||||
d->bitcount = 0;
|
||||
|
||||
d->dest = d->destStart;
|
||||
d->destRemaining = d->destSize;
|
||||
|
||||
do {
|
||||
|
||||
unsigned int btype;
|
||||
int res;
|
||||
|
||||
/* read final block flag */
|
||||
bfinal = tinf_getbit(d);
|
||||
|
||||
/* read block type (2 bits) */
|
||||
btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
/* decompress block */
|
||||
switch (btype)
|
||||
{
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
/* decompress block with fixed huffman trees */
|
||||
res = tinf_inflate_fixed_block(d);
|
||||
break;
|
||||
case 2:
|
||||
/* decompress block with dynamic huffman trees */
|
||||
res = tinf_inflate_dynamic_block(d);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) return TINF_DATA_ERROR;
|
||||
|
||||
} while (!bfinal);
|
||||
|
||||
return TINF_OK;
|
||||
d->bfinal = 0;
|
||||
d->btype = -1;
|
||||
d->dict_size = dictLen;
|
||||
d->dict_ring = dict;
|
||||
d->dict_idx = 0;
|
||||
d->curlen = 0;
|
||||
}
|
||||
|
||||
/* inflate next byte of compressed stream */
|
||||
int uzlib_uncompress(TINF_DATA *d)
|
||||
{
|
||||
do {
|
||||
int res;
|
||||
|
||||
/* start a new block */
|
||||
if (d->btype == -1) {
|
||||
next_blk:
|
||||
/* read final block flag */
|
||||
d->bfinal = tinf_getbit(d);
|
||||
/* read block type (2 bits) */
|
||||
d->btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
//printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal);
|
||||
|
||||
if (d->btype == 1) {
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
} else if (d->btype == 2) {
|
||||
/* decode trees from stream */
|
||||
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
}
|
||||
|
||||
/* process current block */
|
||||
switch (d->btype)
|
||||
{
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
/* decompress block with fixed/dyanamic huffman trees */
|
||||
/* trees were decoded previously, so it's the same routine for both */
|
||||
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res == TINF_DONE && !d->bfinal) {
|
||||
/* the block has ended (without producing more data), but we
|
||||
can't return without data, so start procesing next block */
|
||||
goto next_blk;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
} while (--d->destSize);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
int uzlib_uncompress_chksum(TINF_DATA *d)
|
||||
{
|
||||
int res;
|
||||
unsigned char *data = d->dest;
|
||||
|
||||
res = uzlib_uncompress(d);
|
||||
|
||||
if (res < 0) return res;
|
||||
|
||||
switch (d->checksum_type) {
|
||||
|
||||
case TINF_CHKSUM_ADLER:
|
||||
d->checksum = uzlib_adler32(data, d->dest - data, d->checksum);
|
||||
break;
|
||||
|
||||
case TINF_CHKSUM_CRC:
|
||||
d->checksum = uzlib_crc32(data, d->dest - data, d->checksum);
|
||||
break;
|
||||
}
|
||||
|
||||
if (res == TINF_DONE) {
|
||||
unsigned int val;
|
||||
|
||||
switch (d->checksum_type) {
|
||||
|
||||
case TINF_CHKSUM_ADLER:
|
||||
val = tinf_get_be_uint32(d);
|
||||
if (d->checksum != val) {
|
||||
return TINF_CHKSUM_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case TINF_CHKSUM_CRC:
|
||||
val = tinf_get_le_uint32(d);
|
||||
if (~d->checksum != val) {
|
||||
return TINF_CHKSUM_ERROR;
|
||||
}
|
||||
// Uncompressed size. TODO: Check
|
||||
val = tinf_get_le_uint32(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014-2016 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
@@ -33,35 +35,14 @@
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
int tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
int uzlib_zlib_parse_header(TINF_DATA *d)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_zlib_uncompress_dyn(&d, sourceLen);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen)
|
||||
{
|
||||
unsigned int a32;
|
||||
int res;
|
||||
unsigned char cmf, flg;
|
||||
|
||||
/* -- get header bytes -- */
|
||||
|
||||
cmf = d->source[0];
|
||||
flg = d->source[1];
|
||||
cmf = uzlib_get_byte(d);
|
||||
flg = uzlib_get_byte(d);
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
@@ -77,25 +58,9 @@ int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen)
|
||||
/* check there is no preset dictionary */
|
||||
if (flg & 0x20) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- get adler32 checksum -- */
|
||||
/* initialize for adler32 checksum */
|
||||
d->checksum_type = TINF_CHKSUM_ADLER;
|
||||
d->checksum = 1;
|
||||
|
||||
a32 = d->source[sourceLen - 4];
|
||||
a32 = 256*a32 + d->source[sourceLen - 3];
|
||||
a32 = 256*a32 + d->source[sourceLen - 2];
|
||||
a32 = 256*a32 + d->source[sourceLen - 1];
|
||||
|
||||
d->source += 2;
|
||||
|
||||
/* -- inflate -- */
|
||||
|
||||
res = tinf_uncompress_dyn(d);
|
||||
|
||||
if (res != TINF_OK) return res;
|
||||
|
||||
/* -- check adler32 checksum -- */
|
||||
|
||||
if (a32 != tinf_adler32(d->destStart, d->dest - d->destStart)) return TINF_DATA_ERROR;
|
||||
|
||||
return TINF_OK;
|
||||
return cmf >> 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <string.h>
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
@@ -76,25 +77,42 @@ STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_listdir_obj, 1, 2, fat_vfs_listdir_func);
|
||||
|
||||
STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
(void)vfs_in;
|
||||
STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
// TODO check that path is actually a file before trying to unlink it
|
||||
FRESULT res = f_unlink(path);
|
||||
if (res == FR_OK) {
|
||||
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
FRESULT res = f_stat(path, &fno);
|
||||
|
||||
if (res != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
// check if path is a file or directory
|
||||
if ((fno.fattrib & AM_DIR) == attr) {
|
||||
res = f_unlink(path);
|
||||
|
||||
if (res != FR_OK) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
return mp_const_none;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
(void)vfs_in;
|
||||
return fat_vfs_remove_internal(path_in, 0); // 0 == file attribute
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove);
|
||||
|
||||
STATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
// TODO: Currently just redirects to fat_vfs_remove(), which are
|
||||
// backed by the same underlying FatFs function. Should at least
|
||||
// check that path is actually a dir.
|
||||
return fat_vfs_remove(vfs_in, path_in);
|
||||
(void) vfs_in;
|
||||
return fat_vfs_remove_internal(path_in, AM_DIR);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir);
|
||||
|
||||
@@ -106,8 +124,7 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_
|
||||
if (res == FR_OK) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,8 +137,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
|
||||
if (res == FR_OK) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
|
||||
@@ -139,8 +155,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
@@ -154,7 +169,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||
FRESULT res = f_getcwd(buf, sizeof buf);
|
||||
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
return mp_obj_new_str(buf, strlen(buf), false);
|
||||
@@ -215,8 +230,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
res = f_stat(path, &fno);
|
||||
}
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +264,42 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat);
|
||||
|
||||
// Get the status of a VFS.
|
||||
STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
(void)vfs_in;
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FATFS *fatfs;
|
||||
DWORD nclst;
|
||||
FRESULT res = f_getfree(path, &nclst, &fatfs);
|
||||
if (FR_OK != res) {
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * fatfs->ssize); // f_bsize
|
||||
t->items[1] = t->items[0]; // f_frsize
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT((fatfs->n_fatent - 2) * fatfs->csize); // f_blocks
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree
|
||||
t->items[4] = t->items[3]; // f_bavail
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax
|
||||
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs);
|
||||
|
||||
// Unmount the filesystem
|
||||
STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) {
|
||||
fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount);
|
||||
|
||||
STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },
|
||||
@@ -261,6 +311,8 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user