Compare commits

..

160 Commits
v1.4.6 ... v1.5

Author SHA1 Message Date
Damien George
fe08e3a54f docs: Bump version to 1.5. 2015-10-21 16:58:52 +01:00
danicampora
8fd8bb36b3 cc3200: Bump version to 1.1.0
Incluides several improvements and a few API changes to comply
with the new hardware API.
2015-10-21 16:42:14 +02:00
danicampora
3b24e83731 docs/wipy: Fix formatting indentation. 2015-10-21 15:43:02 +02:00
danicampora
bb489066e8 docs/wipy: Remove incorrect references to usb configuration. 2015-10-21 15:41:36 +02:00
danicampora
109b363ddc docs/wipy: Add more tutorials and examples. 2015-10-21 15:30:57 +02:00
danicampora
075ca64521 cc3200: Fix UART tests after correcting uart.read() behaviour. 2015-10-21 15:30:57 +02:00
danicampora
be2879ce89 cc3200: Enable "all special methods" configuration option. 2015-10-21 15:30:57 +02:00
danicampora
ee0058d174 docs: Remove remaining references to 'af', which is now 'alt'. 2015-10-21 15:30:57 +02:00
danicampora
1f2daf4304 cc3200: Correct ticks_cpu and ticks_us functions in time module. 2015-10-21 15:30:57 +02:00
danicampora
1c7f9b16f0 cc3200: Remove UART info on README.md.
The UART REPL it's not enabled by default anymore.
2015-10-21 15:30:56 +02:00
danicampora
ceb169008d docs: Several corrections to the classes in the machine module. 2015-10-21 15:30:56 +02:00
danicampora
04db848dc7 docs: Add usocket and ussl modules' documentation. 2015-10-21 15:30:56 +02:00
danicampora
4b630c452d cc3200: Make socket.listen([backlog]) compliant with Python 3.5. 2015-10-21 15:30:56 +02:00
danicampora
719dca2515 cc3200: Clean-up socket constants. 2015-10-21 15:30:56 +02:00
danicampora
d67ea6b29f cc3200: Add comment about micropython extensions to standard modules. 2015-10-21 15:30:56 +02:00
danicampora
7ff585333e cc3200: uart.read() returns EGAIN if no chars available. 2015-10-21 15:30:56 +02:00
danicampora
9a507c67ad cc3200: Enable REPL autoindent. 2015-10-21 15:30:56 +02:00
Paul Sokolovsky
9d7ef05caf README: Document how to enable/build external dependencies. 2015-10-21 02:56:42 +03:00
Damien George
e693e52442 tests: Disable some tests for pyboard that do not run correctly. 2015-10-20 23:55:50 +01:00
Damien George
9d0192de4a stmhal: Enable "all special methods" configuration option. 2015-10-20 23:55:27 +01:00
Damien George
f09f8097d5 esp8266: Put more code in irom0 section, to get it building again. 2015-10-20 22:59:31 +01:00
Paul Sokolovsky
d19e4f0ba4 extmod/modussl: Remove unused header. 2015-10-20 17:41:59 +03:00
Damien George
f961456b29 lib/mp-readline: Add n_chars argument to mp_hal_erase_line_from_cursor.
If VT100 support is not available then a given implementation of
mp_hal_erase_line_from_cursor might need to know the number of characters
to erase.

This patch does not change generated code when VT100 is supported, since
compiler can optimise away the argument.
2015-10-20 13:27:14 +01:00
Damien George
22521ea9e2 py/nlrthumb: Make compatible with Cortex-M0 (ARMv6M instr set). 2015-10-20 13:26:34 +01:00
Damien George
04353cc85e py: With obj repr "C", change raw str accessor from macro to function.
This saves around 1000 bytes (Thumb2 arch) because in repr "C" it is
costly to check and extract a qstr.  So making such check/extract a
function instead of a macro saves lots of code space.
2015-10-20 12:38:54 +01:00
Damien George
183edefddd py: Add object repr "C", where 30-bit floats are stuffed in obj word.
This new object representation puts floats into the object word instead
of on the heap, at the expense of reducing their precision to 30 bits.
It only makes sense when the word size is 32-bits.
2015-10-20 12:38:54 +01:00
Damien George
aedb859177 py: Make float representation configurable with object representation. 2015-10-20 12:35:40 +01:00
Damien George
7e359c648b py: Move float e/pi consts to objfloat and make mp_obj_float_t private. 2015-10-20 12:35:17 +01:00
Damien George
aaef1851a7 py: Add mp_obj_is_float function (macro) and use it where appropriate. 2015-10-20 12:35:17 +01:00
Damien George
60401d461a stmhal/rtc: Fix indentation to use spaces rather than tabs. 2015-10-20 12:05:27 +01:00
Peter Hinch
b106532b32 stmhal/rtc: Init uses YMD rather than backup register to detect powerup. 2015-10-20 12:05:16 +01:00
Paul Sokolovsky
8e6e9eaea5 unix: Use "Ctrl" as a name of the key, not "CTRL". 2015-10-20 12:30:36 +03:00
Paul Sokolovsky
acea9352a9 tests/extmod: Add tests for sleep_ms/us(), ticks_ms/us/diff().
Simple smoke tests, mostly for coverage. Added to extmod based on the fact
that they're extensions to standard modules.
2015-10-20 01:54:20 +03:00
Paul Sokolovsky
9058a7031f travis: Build "deplibs" in unix port. 2015-10-20 01:50:27 +03:00
Tom Soulanille
a787467569 tools/pyboard: Add -c argument to run a program passed as a string. 2015-10-19 23:20:59 +01:00
Damien George
4078336d38 teensy: Update to compile with latest changes to stmhal Pin class. 2015-10-19 23:11:48 +01:00
Damien George
2f96b1982a stmhal: Bring Pin class close to new machine module specification.
Looks like we can use the same Pin class for legacy pyb module and new
machine module.
2015-10-19 22:50:59 +01:00
Paul Sokolovsky
bedab235f9 stmhal/uart: If char is not received within timeout, return EAGAIN error.
Instead of return 0, which means EOF. There's no good way to detect EOF on
continuously active bus like UART, and treat timeout as just temporary
unvailability of data. .read() method of UART object will return None in
this case (instead of 0, which again measn EOF). This is fully compliant
with unix port.
2015-10-20 00:27:07 +03:00
Damien George
83158e0e7f stmhal: Implement os.dupterm (was pyb.repl_uart).
pyb.repl_uart still exists but points to os.dupterm.
2015-10-19 21:57:41 +01:00
Damien George
d8066e999d stmhal: Add sleep_{ms,us} and ticks_{ms,us,cpu,diff} to time module.
pyb module still has pyb.delay and pyb.udelay, but these now point to
time.sleep_ms and time.sleep_us respectively.
2015-10-19 21:45:51 +01:00
Dave Hylands
504420c51d stmhal: Early version of machine module for stmhal. 2015-10-19 21:12:42 +01:00
Paul Sokolovsky
2c040edef8 libffi: Skip building docs.
This requires makeinfo installed and wastes time (especially in CI).
2015-10-19 22:30:03 +03:00
danicampora
9c72c71c05 cc3200: WLAN class can retrieve the existing instance. 2015-10-19 21:17:15 +02:00
danicampora
f4c50f1cfc tests/wipy: Make WLAN test more stable. 2015-10-19 21:17:15 +02:00
danicampora
ae70e98ed4 cc3200: Fix time.ticks_* functions. 2015-10-19 21:17:15 +02:00
danicampora
8faf2dc75b docs/wipy: Add wipy tutorials section. 2015-10-19 21:17:15 +02:00
danicampora
36ae417c9f docs: Add wipy and network.server documentation. 2015-10-19 21:17:15 +02:00
danicampora
2e0cd20a1d cc3200: Refactor network module to make the server a propper object. 2015-10-19 21:17:15 +02:00
danicampora
65f6324573 cc3200: Increase stack sizes a bit. 2015-10-19 21:17:15 +02:00
danicampora
d8137178bb cc3200: Create wipy module, remove HeartBeat class.
The heartbeat is now controllable via a single function within the
wipy module.
2015-10-19 21:17:15 +02:00
Paul Sokolovsky
39a380b621 unix/modos: Android Bionic lacks statvfs(), has BSD statfs(). 2015-10-19 21:43:20 +03:00
Paul Sokolovsky
e0f5df579b all: Make netutils.h available to all ports by default.
Generally, ports should inherit INC from py.mk, append to it, not
overwrite it. TODO: Likely should do the same for other vars too.
2015-10-19 18:32:42 +03:00
Paul Sokolovsky
8ee153f234 unix/modtime: Implement ticks_ms(), ticks_us() and ticks_diff().
All of these functions return positive small int, thus range is 2 bits less
than word size (30 bit on 32-bit systems, 62 bit on 64-bit systems).
2015-10-19 17:48:27 +03:00
Paul Sokolovsky
fd379db286 unix/modtime: Implement sleep_ms(), sleep_us(). 2015-10-19 17:48:27 +03:00
Damien George
096d1e4512 py: Add lsl/lsr/asr opcode support to inline Thumb2 assembler. 2015-10-19 14:26:19 +01:00
Paul Sokolovsky
949c5c9180 unix/unix_mphal: Implement HAL_Delay() and HAL_GetTick(). 2015-10-19 00:31:37 +03:00
Paul Sokolovsky
7799410950 py/stream: Allow to reuse is_nonblocking_error(). 2015-10-18 15:39:33 +03:00
Paul Sokolovsky
2ca7b05552 unix/modos: Checking config macros requires mpconfig.h. 2015-10-18 03:05:47 +03:00
Paul Sokolovsky
f8e9ef5cd0 unix/modos: Guard sys/statvfs.h include with MICROPY_PY_OS_STATVFS check.
E.g. Windows lacks this header.
2015-10-18 02:54:20 +03:00
danicampora
020386b61c docs: In top index fix machine module link for the WiPy. 2015-10-18 00:31:12 +02:00
Paul Sokolovsky
c3000b6f69 unix/modos: Add statvfs() function.
Another function (like stat) which is problematic to deal with on ABI level
(FFI), as struct statvfs layout may differ unpredictably between OSes and
even different versions of a same OS. So, implement it in C, returning a
10-element tuple of f_bsize, f_frsize, f_blocks, f_bfree, f_bavail, f_files,
f_ffree, f_favail, f_flag, f_namemax. This is exactly the order described
in Python3 docs, https://docs.python.org/3/library/os.html#os.statvfs
(but note that os.statvfs() should make these values available as
attributes).
2015-10-18 01:21:23 +03:00
Paul Sokolovsky
6ec6f51326 unix: Build libffi in a directory which is gitgnored.
To avoid "-dirty" version previous and spurious "modified" output from
git status, etc.
2015-10-18 00:44:45 +03:00
danicampora
4542643025 docs: Update all WiPy docs to reflect the new API. 2015-10-17 23:29:04 +02:00
danicampora
fca3308cc3 cc3200: Improvements to terminal duplication. 2015-10-17 23:21:44 +02:00
danicampora
e19dfe1c32 cc3200: In scan results rename 'auth' field to 'sec'.
As defined by the new API, since 'auth' is actually a  tuple
composed by the security type and the key.
2015-10-17 23:21:44 +02:00
Dave Hylands
affcbe4139 stmhal: Make USB serial number actually be unique. 2015-10-17 22:02:57 +01:00
Paul Sokolovsky
6a515b95a8 tools/upip: Update to 0.5.9.
MICROPYPATH environment variable is now honored, package are installed to
first path specified in it.
2015-10-17 20:16:41 +03:00
Paul Sokolovsky
c13be69a8e lib/libffi: Add libffi as a submodule.
This allows to build libffi from source together with micropython, and is
useful for cross-compilation. Support for this was already merged
previously, to use:

make libffi
make MICROPY_STANDALONE=1

(To both commands appropriate cross-compilition flags can be added).
2015-10-17 15:52:35 +03:00
Damien George
035a0a2b6e py: Add support for _ in REPL to hold last computed value.
Only available when MICROPY_CAN_OVERRIDE_BUILTINS is enabled.
2015-10-17 12:55:25 +01:00
Damien George
e813541e3f py: Add option for inline assembler to support ARMv7-M instructions.
Cortex-M0, M0+ and M1 only have ARMv6-M Thumb/Thumb2 instructions.  M3,
M4 and M7 have a superset of these, named ARMv7-M.  This patch adds a
config option to enable support of the superset of instructions.
2015-10-16 22:08:57 +01:00
Damien George
4bf3f2d3c0 py: Fix with+for+return bug by popping for-iter when unwinding exc stack.
Addresses issue #1182.
2015-10-15 17:48:28 +01:00
Damien George
556c8a9a4f unix: Fix coverage build now that mp_plat_print uses write. 2015-10-15 00:23:03 +01:00
Damien George
4300c7dba2 py: Remove dependency on printf/fwrite in mp_plat_print.
See issue #1500.
2015-10-15 00:05:55 +01:00
Paul Sokolovsky
74d0df7324 unix: Allow to build against Android down to 1.5.
Bionic libc in Android 1.5 missed log2() and nan() functions.
2015-10-15 00:11:09 +03:00
Damien George
d7e3b36a09 py/compile: Remove unnecessary label in compilation of for statement. 2015-10-14 15:51:12 +01:00
Damien George
fcce1483fa py: Fix build of ARM native emitter due to recent viper changes.
Addresses #1510.
2015-10-14 12:40:54 +01:00
Paul Sokolovsky
2430dfac31 tests/jni: Start adding modjni tests.
These are currently not intended to run with the rest of testsuite, as
they require dependencies and special environment setup anyway (drafted
in tests/jni/README).
2015-10-14 00:56:01 +03:00
Paul Sokolovsky
fe29cc192d unix/modjni: Add iteration support for Java List objects.
Using generic iteration-via-subscription support (TODO: factor it out for
reuse).
2015-10-14 00:36:03 +03:00
Paul Sokolovsky
41eb705477 unix/modjni: call_method: Check for Java exception after method return. 2015-10-14 00:25:10 +03:00
Damien George
2ec835f572 tests: Add more tests for viper 16/32-bit load/store, and ellipsis. 2015-10-13 18:24:36 +01:00
Damien George
59a41e8fcd py/qstr: Fix calc of qstr memory usage, due to new qstr chunk allocation. 2015-10-13 15:52:06 +01:00
Damien George
d6442407f5 docs: Fix formatting of DAC code examples. 2015-10-13 14:44:00 +01:00
Damien George
b5c43be135 stmhal: Allow to set bits resolution for DAC; 8 is default, can have 12.
This patch allows to configure the DAC resolution in the constructor and
in the init function, eg:

dac = DAC(1, bits=12).

The default resolution is 8 bits for backwards compatibility.  The bits
sets the maximum value accepted by write and write_timed methods, being
2**bits - 1.

When using write_timed with 12-bit resolution, the input buffer is
treated as an unsigned half-word array, typecode 'H'.

See PR #1130 for discussion.
2015-10-13 14:33:04 +01:00
Damien George
b8f9ac5411 py: Implement ptr32 load and store in viper emitter. 2015-10-13 00:50:17 +01:00
Paul Sokolovsky
21f43ba9b0 unix/modtermios: tcsetattr: If 0 passed for "when" param, treat as TCSANOW.
As we dn't export constants for TCSANOW, etc., zero makes a good "don't
care" param, and now it will work also under Android Bionic and any other
libc.
2015-10-13 00:37:55 +03:00
Damien George
3c9c3687d6 py: Add support to call __init__ from a builtin module on first import. 2015-10-12 13:46:01 +01:00
Paul Sokolovsky
408b74d74c py: Allow to to build MicroPython as a static library.
The whole current port gets slurped into a static lib named
"libmicropython.a". Maybe that's not ideal, but at least something
to start with.
2015-10-12 15:32:06 +03:00
Damien George
fdfcee7b1e py/parse: Make parser error handling cleaner, less spaghetti-like. 2015-10-12 12:59:18 +01:00
Damien George
64f2b213bb py: Move constant folding from compiler to parser.
It makes much more sense to do constant folding in the parser while the
parse tree is being built.  This eliminates the need to create parse
nodes that will just be folded away.  The code is slightly simpler and a
bit smaller as well.

Constant folding now has a configuration option,
MICROPY_COMP_CONST_FOLDING, which is enabled by default.
2015-10-12 12:58:45 +01:00
Paul Sokolovsky
91fc075a33 py/objarray: Allow to create array of void pointers, as extension to CPython.
Using 'P' format specifier (matches struct module). This is another shortcut
for FFI, just as previously introduced "array of objects" ('O').
2015-10-12 10:13:51 +03:00
Damien George
3aa7dd23c9 unix: Add exit and paste-mode hints to shell startup banner.
Thanks to @nyov for the initial patch.
2015-10-12 00:19:00 +01:00
nyov
fccbe9aa4d README.md: Document "Ctrl+D" shell exit. 2015-10-12 00:15:41 +01:00
Damien George
0334058fa4 Rename "Micro Python" to "MicroPython" in REPL, help, readme's and misc. 2015-10-12 00:06:25 +01:00
Damien George
6206f431cf stmhal: Enable REPL auto indent; document paste mode in help(). 2015-10-11 23:33:46 +01:00
Damien George
46a1102852 repl: Add paste mode to friendly REPL, entered via CTRL-E.
Use CTRL-E to enter paste mode.  Prompt starts with "===" and accepts
all characters verbatim, echoing them back.  Only control characters are
CTRL-C which cancels the input and returns to normal REPL, and CTRL-D
which ends the input and executes it.  The input is executed as though
it were a file.  The input is not added to the prompt history.
2015-10-11 23:30:22 +01:00
Paul Sokolovsky
1b586f3a73 py: Rename MP_BOOL() to mp_obj_new_bool() for consistency in naming. 2015-10-11 15:18:15 +03:00
Paul Sokolovsky
53ca6ae1f3 py/makeqstrdata.py: Catch and report case of empty input file.
The usual cause would be that a cross-compiler for a port is not in PATH.
2015-10-11 11:09:57 +03:00
Anmol Sarma
95b352064e unix/modsocket: Fix usage of pointers to locals outside scope 2015-10-10 17:29:26 +05:30
Damien George
24652228af drivers/sdcard: Allow up to 5 retries to initialise SD card.
Apparently some cards need more than 2 retries.  See issue #1482.
2015-10-10 00:07:40 +01:00
Damien George
845b5a2a58 docs: Describe properly how MCU can be woken from pyb.standby() state. 2015-10-10 00:03:14 +01:00
Paul Sokolovsky
7381b7ac71 unix/modjni: py2jvalue: Support bool and None values. 2015-10-10 01:20:48 +03:00
Peter Hinch
0e87bc7be6 tests: In pyb RTC tests, check wakeup register values. 2015-10-09 23:06:05 +01:00
Dave Hylands
01d64914c5 stmhal: Fix USB CDC-only mode under Windows.
This fix adds PIDs 9801 and 9802 to the pybcdc.inf file.

When in CDC only mode, it presents itself as a Communcations
device rather than as a composite device. Presenting as a
composite device with only the CDC interface seems to confuse
windows.

To test and make sure that the correct pybcdc.inf was being used,
I used USBDeview from http://www.nirsoft.net/utils/usb_devices_view.html
to uninstall any old pyboard drivers (Use Control-F and search
for pyboard). I found running USBDeview as administrator worked best.

Installing the driver in CDC+MSC mode first is recommended (since the
pybcdc.inf file in on the internal flash drive). Then when you switch
modes everything seems to work properly.

I used https://github.com/dhylands/upy-examples/blob/master/boot_switch.py
to easily switch the pyboard between the various USB modes for testing.
2015-10-09 00:18:01 +01:00
Damien George
366239b8b9 py/parse: Factor logic when creating parse node from and-rule. 2015-10-08 23:13:18 +01:00
Paul Sokolovsky
02041bf2e0 unix/modjni: jvalue2py() is currently not used.
Not remove so far, may be needed later.
2015-10-09 00:27:27 +03:00
Paul Sokolovsky
216b6a494e unix/modjni: Allow to access fields of objects. 2015-10-08 16:57:02 +03:00
Damien George
b948de36fb py: Don't generate unnecessary parse nodes for assignment or kwargs.
This patch eliminates the need for a nested parse node for assignments
and keyword arguments.  It saves a little bit of RAM when parsing.
2015-10-08 14:26:01 +01:00
Damien George
4fb5ff86ee tests: Add test for evaluation order of dictionary key/value pairs.
In Python 3.4 the value is evaluated before the key.  In Python 3.5 it's
key then value.
2015-10-08 13:15:07 +01:00
Damien George
9f5f156b9d py/emitnative: Raise ViperTypeError for unsupported unary ops. 2015-10-08 13:08:59 +01:00
Damien George
7e12a601b8 py/compile: Fix edge case when constant-folding negation of integer.
Also adds tests specifically for testing constant folding.
2015-10-08 13:02:00 +01:00
Damien George
2a8d7ee0f8 stmhal: Fix RTC.wakeup so it correctly calculates WUT for large periods.
Thanks to Peter Hinch.  Addresses issue #1488.
2015-10-08 12:41:12 +01:00
Paul Sokolovsky
fd38799049 unix/modjni: After Call*Method(), Java exception should always be checked.
OpenJDK seemed to return NULL in case of exception, but Dalvik returns
arbitrary value, so skip such "optimizations".
2015-10-07 07:40:29 +03:00
Damien George
fa391eed9d stmhal: In RTC.wakeup, fix setting of wucksel to get correct period.
Thanks to Peter Hinch.  See issue #1490.
2015-10-06 23:39:57 +01:00
Radomir Dopieralski
37ab061f4d docs: Update esp8266 documentation to match the code.
* Move the esp.status() to network module.
* Describe the wifi.isconnected() method.
* Describe esp.mac(), esp.wifi_mode(), esp.phy_mode(), esp.sleep_type(),
  esp.deepsleep(), and esp.flash_id() functions.
2015-10-06 23:25:35 +01:00
Paul Sokolovsky
aaa8867d4a modussl: SSL socket wrapper module based on axTLS. 2015-10-06 18:10:39 +03:00
Paul Sokolovsky
062bd81814 tests/basics/builtin_range: PEP8 fixes. 2015-10-05 20:02:52 +03:00
Paul Sokolovsky
f4d55c91fe lib/axtls: Update submodule, adds .gitignore . 2015-10-04 15:55:37 +03:00
Paul Sokolovsky
326ff54649 unix: Add support for building axtls dependency lib. 2015-10-04 02:39:01 +03:00
Paul Sokolovsky
90a36942b4 lib/axtls: Add axtls git submodule, dependency of modussl.
From https://github.com/pfalcon/axtls , branch micropython.
2015-10-04 02:39:00 +03:00
Paul Sokolovsky
1ea4b77a9a unix/modjni: jclass.__str__/__repr__: Return Java .toString() value. 2015-10-04 01:57:07 +03:00
Damien George
0496de26d3 py: Allow to enable inline assembler without native emitter. 2015-10-03 17:07:54 +01:00
Paul Sokolovsky
f22be4ebd9 unix/modjni: jobject.__str__/__repr__: Return Java .toString() value. 2015-10-03 08:58:46 -07:00
Damien George
34f26ea862 tests: Allow tests to pass against CPython 3.5.
All breaking changes going from 3.4 to 3.5 are contained in
basics/python34.py.
2015-10-02 13:01:47 +01:00
Paul Sokolovsky
9e0a3d46b6 unix/modjni: Convert Java's IndexOutOfBoundsException to Python's IndexError. 2015-10-02 00:22:09 -07:00
Damien George
90b1cc5103 minimal: Tune parser chunk allocation policy for very small heap. 2015-10-02 00:33:26 +01:00
Damien George
58e0f4ac50 py: Allocate parse nodes in chunks to reduce fragmentation and RAM use.
With this patch parse nodes are allocated sequentially in chunks.  This
reduces fragmentation of the heap and prevents waste at the end of
individually allocated parse nodes.

Saves roughly 20% of RAM during parse stage.
2015-10-02 00:11:11 +01:00
Damien George
e5635f4ab3 py: Catch all cases of integer (big and small) division by zero. 2015-10-01 22:48:48 +01:00
Damien George
2065373f67 py/mpz: Fix bignum anding of large negative with smaller positive int. 2015-10-01 22:35:06 +01:00
Damien George
a81539db25 tests: Add further tests for mpz code. 2015-10-01 18:49:37 +01:00
Damien George
2f4e8511cd py/mpz: Force rhs of mpz_shl_inpl/mpz_shr_inpl to be unsigned.
Python semantics are that rhs of shift must be non-negative, so there's
no need to handle negative values in the underlying mpz implementation.
2015-10-01 18:01:37 +01:00
Damien George
4c02e54298 py/mpz: Raise NotImplError instead of failing assertion. 2015-10-01 17:57:36 +01:00
Damien George
5f3c3ec5e6 py/parsenum: Provide detailed error for int parsing with escaped bytes.
This patch adds more fine grained error message control for errors when
parsing integers (now has terse, normal and detailed).  When detailed is
enabled, the error now escapes bytes when printing them so they can be
more easily seen.
2015-10-01 17:18:12 +01:00
Paul Sokolovsky
c4489a0543 unix/modjni: Propagate Java exceptions on list access. 2015-10-01 01:20:56 -07:00
Paul Sokolovsky
0eba162ab5 unix/modjni: Fix method argument matching. 2015-09-30 00:55:09 -07:00
Paul Sokolovsky
f3ca8623f7 unix/modjni: Implement len() for objects with java.util.List interface. 2015-09-29 10:06:07 -07:00
Paul Sokolovsky
77020281ae unix/modjni: call_method: Delete done local references in loop.
To avoid local ref table overflow.
2015-09-28 08:37:34 -07:00
Tom Soulanille
f1a9923308 py/objrange: Bugfix for range_subscr() when index is a slice object. 2015-09-28 14:01:28 +00:00
Tom Soulanille
2a8a564fbd tests: Test slicing a range that does not start at zero. 2015-09-28 14:01:20 +00:00
Paul Sokolovsky
0d28a3edb9 unix/modjni: call_method: Better resource release. 2015-09-27 22:32:54 -07:00
Daniel Campora
ff736d6f6f cc3200: WiPy SW v1.0.0 release. 2015-09-28 00:14:25 +02:00
Daniel Campora
d88d3b0b3a tests/wipy: Skip the rtc_irq test. 2015-09-27 21:36:38 +02:00
Daniel Campora
b6bdb0dbda cc3200: Always reset WLAN after setting the mode. 2015-09-27 20:12:42 +02:00
Daniel Campora
ed6a5b78ad cc3200: Make auth param positional in wlan.connect. 2015-09-27 19:10:09 +02:00
Daniel Campora
d5de1bf853 tests: Skip uheapq1 test if target is WiPy. 2015-09-27 18:47:35 +02:00
Daniel Campora
eb9a3ec654 cc3200: Disable uheapq and uhashlib.
Those two are rarely used features and better to have the extra heap.
2015-09-27 18:04:11 +02:00
Daniel Campora
6143f63560 tests/wipy: Fix error in wlan test. 2015-09-27 18:00:36 +02:00
Daniel Campora
37a2015cc5 tests/wipy: Add machine module tests. 2015-09-27 17:35:58 +02:00
Daniel Campora
958e273336 tests: Skip extmod machine tests when target is WiPy. 2015-09-27 17:35:45 +02:00
Daniel Campora
c92e6a45eb cc3200: Rename pyb module to machine. 2015-09-27 16:50:27 +02:00
Daniel Campora
0a7e4fa5ce tests/wipy: Improve robustness of rtc_irq test. 2015-09-27 14:20:38 +02:00
Daniel Campora
8192310dad tests/wipy: Improve robustness of time test. 2015-09-27 12:32:02 +02:00
Daniel Campora
ef369249cb cc3200: Implement support for os.dupterm(). 2015-09-27 11:27:24 +02:00
Daniel Campora
a7261ae059 cc3200/mods: Use mp_obj_get_array_fixed_n() where applicable. 2015-09-27 09:28:27 +02:00
Daniel Campora
635ef16432 cc3200/tools: Improve update script robustness. 2015-09-27 02:00:46 +02:00
Daniel Campora
57fa14b5be cc3200: New WLAN API including test. 2015-09-27 01:50:52 +02:00
Daniel Campora
dbdcb58d64 cc3200: New irq API, affects all classes that provide the irq method. 2015-09-27 01:48:20 +02:00
Paul Sokolovsky
81d64ab939 unix/modjni: call_method(): If name doesn't match, cleanup via goto next_method. 2015-09-26 08:51:22 -07:00
Paul Sokolovsky
c0a79cc919 unix/modjni: Need to really use per-rettype Call*Method functions. 2015-09-26 08:49:12 -07:00
Paul Sokolovsky
7e18d3b6ff unix/modjni: new_jobject(): Handle null reference. 2015-09-24 15:29:57 -07:00
Damien George
9d5e5c08ab py/compile: Put compiler state on the C stack.
It's relatively small (between 44 and 56 bytes) and helps to reduce heap
pressure and fragmentation during compilation.
2015-09-24 13:15:57 +01:00
294 changed files with 8348 additions and 4168 deletions

7
.gitmodules vendored Normal file
View File

@@ -0,0 +1,7 @@
[submodule "lib/axtls"]
path = lib/axtls
url = https://github.com/pfalcon/axtls
branch = micropython
[submodule "lib/libffi"]
path = lib/libffi
url = https://github.com/atgreen/libffi

View File

@@ -15,6 +15,7 @@ before_script:
script:
- make -C minimal test
- make -C unix deplibs CC=gcc-4.7
- make -C unix CC=gcc-4.7
- make -C bare-arm
- make -C qemu-arm test

View File

@@ -1,4 +1,4 @@
The Micro Python project was proudly and successfully crowdfunded
The MicroPython project was proudly and successfully crowdfunded
via a Kickstarter campaign which ended on 13th December 2013. The
project was supported by 1923 very generous backers, who pledged
for a total of 2320 pyboards.

View File

@@ -41,12 +41,12 @@ Names:
- Use CAPS_WITH_UNDERSCORE for enums and macros.
- When defining a type use underscore_case and put '_t' after it.
Integer types: Micro Python runs on 16, 32, and 64 bit machines, so it's
Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's
important to use the correctly-sized (and signed) integer types. The
general guidelines are:
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
integer values. These are guaranteed to be machine-word sized and
therefore big enough to hold the value from a Micro Python small-int
therefore big enough to hold the value from a MicroPython small-int
object.
- Use size_t for things that count bytes / sizes of objects.
- You can use int/uint, but remember that they may be 16-bits wide.

View File

@@ -8,19 +8,19 @@
[istats-issue-img]: http://issuestats.com/github/micropython/micropython/badge/issue
[istats-issue-repo]: http://issuestats.com/github/micropython/micropython
The Micro Python project
========================
The MicroPython project
=======================
<p align="center">
<img src="https://raw.githubusercontent.com/micropython/micropython/master/logo/upython-with-micro.jpg" alt="MicroPython Logo"/>
</p>
This is the Micro Python project, which aims to put an implementation
This is the MicroPython project, which aims to put an implementation
of Python 3.x on microcontrollers and small embedded systems.
WARNING: this project is in beta stage and is subject to changes of the
code-base, including project-wide name changes and API changes.
Micro Python implements the entire Python 3.4 syntax (including exceptions,
MicroPython implements the entire Python 3.4 syntax (including exceptions,
"with", "yield from", etc.). 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.
@@ -33,19 +33,19 @@ Python board, the officially supported reference electronic circuit board.
Major components in this repository:
- py/ -- the core Python implementation, including compiler, runtime, and
core library.
- unix/ -- a version of Micro Python that runs on Unix.
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
- unix/ -- a version of MicroPython that runs on Unix.
- stmhal/ -- a version of MicroPython that runs on the MicroPython board
with an STM32F405RG (using ST's Cube HAL drivers).
- minimal/ -- a minimal Micro Python port. Start with this if you want
to port Micro Python to another microcontroller.
- minimal/ -- a minimal MicroPython port. Start with this if you want
to port MicroPython to another microcontroller.
Additional components:
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Used
- bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
mostly to control code size.
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
- teensy/ -- a version of MicroPython that runs on the Teensy 3.1
(preliminary but functional).
- pic16bit/ -- a version of Micro Python for 16-bit PIC microcontrollers.
- cc3200/ -- a version of Micro Python that runs on the CC3200 from TI.
- pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
- cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
- esp8266/ -- an experimental port for ESP8266 WiFi modules.
- tests/ -- test framework and test scripts.
- tools/ -- various tools, including the pyboard.py module.
@@ -74,6 +74,7 @@ Then to give it a try:
$ ./micropython
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])
Use `CTRL-D` (i.e. EOF) to exit the shell.
Learn about command-line options (in particular, how to increase heap size
which may be needed for larger applications):
@@ -93,9 +94,35 @@ Browse available modules on
Standard library modules come from
[micropython-lib](https://github.com/micropython/micropython-lib) project.
(*) Debian/Ubuntu/Mint derivative Linux distros will require build-essentials,
libffi-dev and pkg-config packages installed. If you have problems with some
dependencies, they can be disabled in unix/mpconfigport.mk .
External dependencies
---------------------
Building Unix version requires some dependencies installed. For
Debian/Ubuntu/Mint derivative Linux distros, install `build-essentials`
(includes toolchain and make), `libffi-dev`, and `pkg-config` packages.
Other dependencies can be built together with MicroPython. Oftentimes,
you need to do this to enable extra features or capabilities. To build
these additional dependencies, first fetch git submodules for them:
$ git submodule update --init
Use this same command to get the latest versions of dependencies, as
they are updated from time to time. After that, in `unix/` dir, execute:
$ make deplibs
This will build all available dependencies (regardless whether they
are used or not). If you intend to build MicroPython with additional
options (like cross-compiling), the same set of options should be passed
to `make deplibs`. To actually enabled use of dependencies, edit
`unix/mpconfigport.mk` file, which has inline descriptions of the options.
For example, to build SSL module (required for `upip` tool described above),
set `MICROPY_PY_USSL` to 1.
In `unix/mpconfigport.mk`, you can also disable some dependencies enabled
by default, like FFI support, which requires libffi development files to
be installed.
The STM version
---------------

View File

@@ -8,7 +8,7 @@ include ../py/py.mk
CROSS_COMPILE = arm-none-eabi-
INC = -I.
INC += -I.
INC += -I..
INC += -I$(BUILD)

View File

@@ -16,8 +16,8 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
qstr source_name = lex->source_name;
mp_parse_node_t pn = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
mp_call_function_0(module_fun);
nlr_pop();
} else {

View File

@@ -57,6 +57,9 @@ 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
#define MP_PLAT_PRINT_STRN(str, len) (void)0
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \

View File

@@ -83,7 +83,7 @@
#define configUSE_TICK_HOOK 1
#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 64 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) )
#define configMAX_TASK_NAME_LEN ( 8 )
#define configUSE_TRACE_FACILITY 0

View File

@@ -1,6 +1,6 @@
# Build Instructions for the CC3200
Currently the CC3200 port of Micro Python builds under Linux and OSX **but not under Windows**.
Currently the CC3200 port of MicroPython builds under Linux and OSX **but not under Windows**.
The tool chain required for the build can be found at <https://launchpad.net/gcc-arm-embedded>.
@@ -25,7 +25,7 @@ make BTARGET=bootloader BTYPE=release BOARD=LAUNCHXL
```
## Regarding old revisions of the CC3200-LAUNCHXL
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and Micro Python cannot run
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and MicroPython cannot run
there. Make sure to use a **v4.1 (or higer) LAUNCHXL board** when trying this port, otherwise it won't work.
## Flashing the CC3200
@@ -53,8 +53,6 @@ If `WIPY_IP`, `WIPY_USER` or `WIPY_PWD` are omitted the default values (the ones
Once the software is running, you have two options to access the MicroPython REPL:
- Through the UART.
**Connect to PORT 22, baud rate = 115200, parity = none, stop bits = 1**
- Through telnet.
* Connect to the network created by the board (as boots up in AP mode), **ssid = "wipy-wlan", key = "www.wipy.io"**.
* You can also reinitialize the WLAN in station mode and connect to another AP, or in AP mode but with a

View File

@@ -78,21 +78,21 @@ APP_MISC_SRC_C = $(addprefix misc/,\
antenna.c \
FreeRTOSHooks.c \
help.c \
mpcallback.c \
mpirq.c \
mperror.c \
mpexception.c \
mpsystick.c \
)
APP_MODS_SRC_C = $(addprefix mods/,\
modmachine.c \
modnetwork.c \
moduhashlib.c \
modubinascii.c \
modpyb.c \
moduos.c \
modusocket.c \
modussl.c \
modutime.c \
modwipy.c \
modwlan.c \
pybadc.c \
pybpin.c \

View File

@@ -52,16 +52,18 @@
#define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \
{ \
{ &pin_type }, \
.name = MP_QSTR_ ## p_pin_name, \
.port = PORT_A ## p_port, \
.af_list = (p_af_list), \
.pull = PIN_TYPE_STD, \
.bit = (p_bit), \
.pin_num = (p_pin_num), \
.af = PIN_MODE_0, \
.strength = PIN_STRENGTH_4MA, \
.mode = GPIO_DIR_MODE_IN, \
.num_afs = (p_num_afs), \
.value = 0, \
.used = false, \
.name = MP_QSTR_ ## p_pin_name, \
.port = PORT_A ## p_port, \
.af_list = (p_af_list), \
.pull = PIN_TYPE_STD, \
.bit = (p_bit), \
.pin_num = (p_pin_num), \
.af = PIN_MODE_0, \
.strength = PIN_STRENGTH_4MA, \
.mode = GPIO_DIR_MODE_IN, \
.num_afs = (p_num_afs), \
.value = 0, \
.used = false, \
.irq_trigger = 0, \
.irq_flags = 0, \
}

View File

@@ -31,12 +31,16 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "py/mpstate.h"
#include MICROPY_HAL_H
#include "py/runtime.h"
#include "py/objstr.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_nvic.h"
#include "hw_memmap.h"
#include "py/mpstate.h"
#include MICROPY_HAL_H
#include "rom_map.h"
#include "interrupt.h"
#include "systick.h"
@@ -47,6 +51,7 @@
#include "pybuart.h"
#include "utils.h"
#include "irq.h"
#include "moduos.h"
#ifdef USE_FREERTOS
#include "FreeRTOS.h"
@@ -67,11 +72,6 @@ static void hal_TickInit (void);
******************************************************************************/
static volatile uint32_t HAL_tickCount;
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
struct _pyb_uart_obj_t *pyb_stdio_uart;
/******************************************************************************
DECLARE IMPORTED DATA
******************************************************************************/
@@ -141,34 +141,57 @@ void mp_hal_stdout_tx_str(const char *str) {
}
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
// send stdout to UART
if (pyb_stdio_uart != NULL) {
uart_tx_strn(pyb_stdio_uart, str, len);
if (MP_STATE_PORT(os_term_dup_obj)) {
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len);
} else {
MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len);
mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write);
}
}
// and also to telnet
if (telnet_is_active()) {
telnet_tx_strn(str, len);
}
telnet_tx_strn(str, len);
}
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
// send stdout to UART
if (pyb_stdio_uart != NULL) {
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
void mp_hal_stdout_tx_strn_cooked (const char *str, uint32_t len) {
int32_t nslen = 0;
const char *_str = str;
for (int i = 0; i < len; i++) {
if (str[i] == '\n') {
mp_hal_stdout_tx_strn(_str, nslen);
mp_hal_stdout_tx_strn("\r\n", 2);
_str += nslen + 1;
nslen = 0;
} else {
nslen++;
}
}
// and also to telnet
if (telnet_is_active()) {
telnet_tx_strn_cooked(str, len);
if (_str < str + len) {
mp_hal_stdout_tx_strn(_str, nslen);
}
}
int mp_hal_stdin_rx_chr(void) {
for ( ;; ) {
// read telnet first
if (telnet_rx_any()) {
return telnet_rx_char();
}
else if (pyb_stdio_uart != NULL && uart_rx_any(pyb_stdio_uart)) {
return uart_rx_char(pyb_stdio_uart);
} else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) {
return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o);
}
} else {
MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1);
mp_obj_t data = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read);
// data len is > 0
if (mp_obj_is_true(data)) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
return ((int *)(bufinfo.buf))[0];
}
}
}
HAL_Delay(1);
}

View File

@@ -55,11 +55,6 @@
" isb \n"); \
}
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
extern struct _pyb_uart_obj_t *pyb_stdio_uart;
/******************************************************************************
DECLARE PUBLIC FUNCTIONS
******************************************************************************/

View File

@@ -112,17 +112,17 @@
// following wrapper can be used to convert the value from cycles to
// millisecond:
//
// CYCLES_U16MS(cycles) ((cycles *1000)/ 1024),
// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024),
//
// Similarly, before setting the value, it must be first converted (from ms to
// cycles).
//
// U16MS_CYCLES(msec) ((msec *1024)/1000)
// U16MS_CYCLES(msec) ((msec * 1024) / 1000)
//
// Note: There is a precision loss of 1 ms with the above scheme.
//
//
#define SCC_U64MSEC_GET() (MAP_PRCMSlowClkCtrGet() >> 5)
#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5)
#define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5))
#define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5)
@@ -208,6 +208,39 @@ static void RTCU32SecRegWrite(unsigned long u32Msec)
MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec);
}
//*****************************************************************************
// Fast function to get the most accurate RTC counter value
//*****************************************************************************
static unsigned long long RTCFastDomainCounterGet (void) {
#define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \
itr++; \
break; \
}
unsigned long long rtc_count1, rtc_count2, rtc_count3;
unsigned int itr;
do {
rtc_count1 = PRCMSlowClkCtrFastGet();
rtc_count2 = PRCMSlowClkCtrFastGet();
rtc_count3 = PRCMSlowClkCtrFastGet();
itr = 0;
BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1);
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2);
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1);
// Consistent values in two consecutive reads implies a correct
// value of the counter. Do note, the counter does not give the
// calendar time but a hardware that ticks upwards continuously.
// The 48-bit counter operates at 32,768 HZ.
} while (true);
return (1 == itr) ? rtc_count2 : rtc_count3;
}
//*****************************************************************************
// Macros
//*****************************************************************************
@@ -1245,6 +1278,35 @@ unsigned long long PRCMSlowClkCtrGet(void)
return ullRTCVal;
}
//*****************************************************************************
//
//! Gets the current value of the internal slow clock counter
//!
//! This function is similar to \sa PRCMSlowClkCtrGet() but reads the counter
//! value from a relatively faster interface using an auto-latch mechainsm.
//!
//! \note Due to the nature of implemetation of auto latching, when using this
//! API, the recommendation is to read the value thrice and identify the right
//! value (as 2 out the 3 read values will always be correct and with a max. of
//! 1 LSB change)
//!
//! \return 64-bit current counter vlaue.
//
//*****************************************************************************
unsigned long long PRCMSlowClkCtrFastGet(void)
{
unsigned long long ullRTCVal;
//
// Read as 2 32-bit values
//
ullRTCVal = HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_MSW_1P2);
ullRTCVal = ullRTCVal << 32;
ullRTCVal |= HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_LSW_1P2);
return ullRTCVal;
}
//*****************************************************************************
//

View File

@@ -247,6 +247,7 @@ extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc);
extern void PRCMHibernateIntervalSet(unsigned long long ullTicks);
extern unsigned long long PRCMSlowClkCtrGet(void);
extern unsigned long long PRCMSlowClkCtrFastGet(void);
extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks);
extern unsigned long long PRCMSlowClkCtrMatchGet(void);

View File

@@ -30,7 +30,7 @@
#include "py/mpconfig.h"
#include "py/obj.h"
STATIC const char help_text[] = "Welcome to Micro Python!\n"
STATIC const char help_text[] = "Welcome to MicroPython!\n"
"For online help please visit http://micropython.org/help/.\n"
"For further help on a specific object, type help(obj)\n";

View File

@@ -149,17 +149,13 @@ void mperror_heartbeat_switch_off (void) {
void mperror_heartbeat_signal (void) {
if (mperror_heart_beat.do_disable) {
mperror_heart_beat.do_disable = false;
mperror_heartbeat_switch_off();
mperror_heart_beat.enabled = false;
}
else if (mperror_heart_beat.enabled) {
} else if (mperror_heart_beat.enabled) {
if (!mperror_heart_beat.beating) {
if ((mperror_heart_beat.on_time = HAL_GetTick()) - mperror_heart_beat.off_time > MPERROR_HEARTBEAT_OFF_MS) {
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
mperror_heart_beat.beating = true;
}
}
else {
} else {
if ((mperror_heart_beat.off_time = HAL_GetTick()) - mperror_heart_beat.on_time > MPERROR_HEARTBEAT_ON_MS) {
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
mperror_heart_beat.beating = false;
@@ -199,48 +195,17 @@ void nlr_jump_fail(void *val) {
#endif
}
#ifndef BOOTLOADER
/******************************************************************************/
// Micro Python bindings
/// \classmethod \constructor()
///
/// Return the heart beat object
STATIC mp_obj_t pyb_heartbeat_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
// return constant object
return (mp_obj_t)&pyb_heartbeat_obj;
void mperror_enable_heartbeat (bool enable) {
if (enable) {
mperror_heart_beat.enabled = true;
mperror_heart_beat.do_disable = false;
mperror_heartbeat_switch_off();
} else {
mperror_heart_beat.do_disable = true;
mperror_heart_beat.enabled = false;
}
}
/// \function enable()
/// Enables the heartbeat signal
STATIC mp_obj_t pyb_enable_heartbeat(mp_obj_t self) {
mperror_heart_beat.enabled = true;
return mp_const_none;
bool mperror_is_heartbeat_enabled (void) {
return mperror_heart_beat.enabled;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_enable_heartbeat_obj, pyb_enable_heartbeat);
/// \function disable()
/// Disables the heartbeat signal
STATIC mp_obj_t pyb_disable_heartbeat(mp_obj_t self) {
mperror_heart_beat.do_disable = true;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_disable_heartbeat_obj, pyb_disable_heartbeat);
STATIC const mp_map_elem_t pyb_heartbeat_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&pyb_enable_heartbeat_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&pyb_disable_heartbeat_obj },
};
STATIC MP_DEFINE_CONST_DICT(pyb_heartbeat_locals_dict, pyb_heartbeat_locals_dict_table);
const mp_obj_type_t pyb_heartbeat_type = {
{ &mp_type_type },
.name = MP_QSTR_HeartBeat,
.make_new = pyb_heartbeat_make_new,
.locals_dict = (mp_obj_t)&pyb_heartbeat_locals_dict,
};
#endif

View File

@@ -40,5 +40,7 @@ void mperror_deinit_sfe_pin (void);
void mperror_signal_error (void);
void mperror_heartbeat_switch_off (void);
void mperror_heartbeat_signal (void);
void mperror_enable_heartbeat (bool enable);
bool mperror_is_heartbeat_enabled (void);
#endif // MPERROR_H_

View File

@@ -34,46 +34,51 @@
#include "inc/hw_types.h"
#include "interrupt.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "mpexception.h"
#include "mperror.h"
#include "mpirq.h"
/******************************************************************************
DEFINE PUBLIC DATA
DECLARE PUBLIC DATA
******************************************************************************/
const mp_arg_t mpcallback_init_args[] = {
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
const mp_arg_t mp_irq_init_args[] = {
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority
{ MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_wake_from, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE} },
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4,
INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 };
/******************************************************************************
DEFINE PUBLIC FUNCTIONS
******************************************************************************/
void mpcallback_init0 (void) {
void mp_irq_init0 (void) {
// initialize the callback objects list
mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0);
mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0);
}
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable) {
mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t);
self->base.type = &pyb_callback_type;
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) {
mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t);
self->base.type = &mp_irq_type;
self->handler = handler;
self->parent = parent;
self->methods = (mp_cb_methods_t *)methods;
self->isenabled = enable;
self->methods = (mp_irq_methods_t *)methods;
self->isenabled = true;
// remove it in case it was already registered
mpcallback_remove(parent);
mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self);
mp_irq_remove(parent);
mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self);
return self;
}
mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
mp_irq_obj_t *mp_irq_find (mp_obj_t parent) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
if (callback_obj->parent == parent) {
return callback_obj;
}
@@ -81,58 +86,40 @@ mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
return NULL;
}
void mpcallback_wake_all (void) {
void mp_irq_wake_all (void) {
// re-enable all active callback objects one by one
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
if (callback_obj->isenabled) {
callback_obj->methods->enable(callback_obj->parent);
}
}
}
void mpcallback_disable_all (void) {
void mp_irq_disable_all (void) {
// re-enable all active callback objects one by one
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
callback_obj->methods->disable(callback_obj->parent);
}
}
void mpcallback_remove (const mp_obj_t parent) {
mpcallback_obj_t *callback_obj;
if ((callback_obj = mpcallback_find(parent))) {
mp_obj_list_remove(&MP_STATE_PORT(mpcallback_obj_list), callback_obj);
void mp_irq_remove (const mp_obj_t parent) {
mp_irq_obj_t *callback_obj;
if ((callback_obj = mp_irq_find(parent))) {
mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj);
}
}
uint mpcallback_translate_priority (uint priority) {
if (priority < 1 || priority > 7) {
uint mp_irq_translate_priority (uint priority) {
if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
switch (priority) {
case 1:
return INT_PRIORITY_LVL_7;
case 2:
return INT_PRIORITY_LVL_6;
case 3:
return INT_PRIORITY_LVL_5;
case 4:
return INT_PRIORITY_LVL_4;
case 5:
return INT_PRIORITY_LVL_3;
case 6:
return INT_PRIORITY_LVL_2;
case 7:
return INT_PRIORITY_LVL_1;
default:
return INT_PRIORITY_LVL_7;
}
return mp_irq_priorities[priority - 1];
}
void mpcallback_handler (mp_obj_t self_in) {
mpcallback_obj_t *self = self_in;
void mp_irq_handler (mp_obj_t self_in) {
mp_irq_obj_t *self = self_in;
if (self && self->handler != mp_const_none) {
// when executing code within a handler we must lock the GC to prevent
// any memory allocations.
@@ -159,59 +146,57 @@ void mpcallback_handler (mp_obj_t self_in) {
/******************************************************************************/
// Micro Python bindings
/// \method init()
/// Initializes the interrupt callback. With no parameters passed, everything will default
/// to the values assigned to mpcallback_init_args[].
STATIC mp_obj_t callback_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mpcallback_obj_t *self = pos_args[0];
STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_irq_obj_t *self = pos_args[0];
// this is a bit of a hack, but it let us reuse the callback_create method from our parent
((mp_obj_t *)pos_args)[0] = self->parent;
self->methods->init (n_args, pos_args, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(callback_init_obj, 1, callback_init);
MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init);
/// \method enable()
/// Enables the interrupt callback
STATIC mp_obj_t callback_enable (mp_obj_t self_in) {
mpcallback_obj_t *self = self_in;
STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) {
mp_irq_obj_t *self = self_in;
self->methods->enable(self->parent);
self->isenabled = true;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable);
/// \method disable()
/// Disables the interrupt callback
STATIC mp_obj_t callback_disable (mp_obj_t self_in) {
mpcallback_obj_t *self = self_in;
STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) {
mp_irq_obj_t *self = self_in;
self->methods->disable(self->parent);
self->isenabled = false;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable);
/// \method \call()
/// Triggers the interrupt callback
STATIC mp_obj_t callback_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) {
mp_irq_obj_t *self = self_in;
return mp_obj_new_int(self->methods->flags(self->parent));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);
STATIC mp_obj_t mp_irq_call (mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mpcallback_handler (self_in);
mp_irq_handler (self_in);
return mp_const_none;
}
STATIC const mp_map_elem_t callback_locals_dict_table[] = {
STATIC const mp_map_elem_t mp_irq_locals_dict_table[] = {
// instance methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&callback_init_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&callback_enable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&callback_disable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj },
};
STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table);
STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);
const mp_obj_type_t pyb_callback_type = {
const mp_obj_type_t mp_irq_type = {
{ &mp_type_type },
.name = MP_QSTR_callback,
.call = callback_call,
.locals_dict = (mp_obj_t)&callback_locals_dict,
.name = MP_QSTR_irq,
.call = mp_irq_call,
.locals_dict = (mp_obj_t)&mp_irq_locals_dict,
};

View File

@@ -24,50 +24,52 @@
* THE SOFTWARE.
*/
#ifndef MPCALLBACK_H_
#define MPCALLBACK_H_
#ifndef MPIRQ_H_
#define MPIRQ_H_
/******************************************************************************
DEFINE CONSTANTS
******************************************************************************/
#define mpcallback_INIT_NUM_ARGS 5
#define mp_irq_INIT_NUM_ARGS 4
/******************************************************************************
DEFINE TYPES
******************************************************************************/
typedef void (*mp_cb_method_t) (mp_obj_t self);
typedef mp_obj_t (*mp_cb_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
typedef mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
typedef void (*mp_irq_void_method_t) (mp_obj_t self);
typedef int (*mp_irq_int_method_t) (mp_obj_t self);
typedef struct {
mp_cb_init_t init;
mp_cb_method_t enable;
mp_cb_method_t disable;
} mp_cb_methods_t;
mp_irq_init_t init;
mp_irq_void_method_t enable;
mp_irq_void_method_t disable;
mp_irq_int_method_t flags;
} mp_irq_methods_t;
typedef struct {
mp_obj_base_t base;
mp_obj_t parent;
mp_obj_t handler;
mp_cb_methods_t *methods;
mp_irq_methods_t *methods;
bool isenabled;
} mpcallback_obj_t;
} mp_irq_obj_t;
/******************************************************************************
DECLARE EXPORTED DATA
******************************************************************************/
extern const mp_arg_t mpcallback_init_args[];
extern const mp_obj_type_t pyb_callback_type;
extern const mp_arg_t mp_irq_init_args[];
extern const mp_obj_type_t mp_irq_type;
/******************************************************************************
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
void mpcallback_init0 (void);
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable);
mpcallback_obj_t *mpcallback_find (mp_obj_t parent);
void mpcallback_wake_all (void);
void mpcallback_disable_all (void);
void mpcallback_remove (const mp_obj_t parent);
void mpcallback_handler (mp_obj_t self_in);
uint mpcallback_translate_priority (uint priority);
void mp_irq_init0 (void);
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods);
mp_irq_obj_t *mp_irq_find (mp_obj_t parent);
void mp_irq_wake_all (void);
void mp_irq_disable_all (void);
void mp_irq_remove (const mp_obj_t parent);
void mp_irq_handler (mp_obj_t self_in);
uint mp_irq_translate_priority (uint priority);
#endif /* MPCALLBACK_H_ */
#endif /* MPIRQ_H_ */

View File

@@ -58,32 +58,14 @@ void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge
// to grab a microsecond counter.
//
// We assume that HAL_GetTick returns milliseconds.
uint32_t sys_tick_get_microseconds(void) {
mp_uint_t irq_state = disable_irq();
uint32_t counter = SysTickValueGet();
uint32_t milliseconds = HAL_GetTick();
uint32_t status = (HWREG(NVIC_ST_CTRL));
enable_irq(irq_state);
// It's still possible for the countflag bit to get set if the counter was
// reloaded between reading VAL and reading CTRL. With interrupts disabled
// it definitely takes less than 50 HCLK cycles between reading VAL and
// reading CTRL, so the test (counter > 50) is to cover the case where VAL
// is +ve and very close to zero, and the COUNTFLAG bit is also set.
if ((status & NVIC_ST_CTRL_COUNT) && counter > 50) {
// This means that the HW reloaded VAL between the time we read VAL and the
// time we read CTRL, which implies that there is an interrupt pending
// to increment the tick counter.
milliseconds++;
}
uint32_t load = (HWREG(NVIC_ST_RELOAD));
uint32_t load = SysTickPeriodGet();
counter = load - counter; // Convert from decrementing to incrementing
// ((load + 1) / 1000) is the number of counts per microsecond.
//
// counter / ((load + 1) / 1000) scales from the systick clock to microseconds
// and is the same thing as (counter * 1000) / (load + 1)
return milliseconds * 1000 + (counter * 1000) / (load + 1);
return (milliseconds * 1000) + ((counter * 1000) / load);
}

View File

@@ -40,18 +40,13 @@
#include "rom_map.h"
#include "prcm.h"
#include "pyexec.h"
#include "ff.h"
#include "diskio.h"
#include "sflash_diskio.h"
#include "pybuart.h"
#include "pybpin.h"
#include "pybrtc.h"
#include "mpsystick.h"
#include "simplelink.h"
#include "modnetwork.h"
#include "modwlan.h"
#include "moduos.h"
#include "telnet.h"
#include "FreeRTOS.h"
#include "portable.h"
#include "task.h"
@@ -66,8 +61,6 @@
#include "pybtimer.h"
#include "utils.h"
#include "gccollect.h"
#include "mperror.h"
#include "genhdr/mpversion.h"
#ifdef DEBUG
@@ -77,26 +70,23 @@ extern OsiTaskHandle xSimpleLinkSpawnTaskHndl;
#endif
/// \module pyb - functions related to the pyboard
/// \module machine - functions related to the SoC
///
/// The `pyb` module contains specific functions related to the pyboard.
/// \function reset()
/// Resets the pyboard in a manner similar to pushing the external
/// reset button.
STATIC mp_obj_t pyb_reset(void) {
/******************************************************************************/
// Micro Python bindings;
STATIC mp_obj_t machine_reset(void) {
// disable wlan
wlan_stop(SL_STOP_TIMEOUT_LONG);
// reset the cpu and it's peripherals
MAP_PRCMMCUReset(true);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_reset_obj, pyb_reset);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
#ifdef DEBUG
/// \function info([dump_alloc_table])
/// Print out some run time info which is helpful during development.
STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t machine_info(uint n_args, const mp_obj_t *args) {
// FreeRTOS info
{
printf("---------------------------------------------\n");
@@ -119,69 +109,82 @@ STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);
#endif
/// \function freq()
/// Returns the CPU frequency: (F_CPU).
STATIC mp_obj_t pyb_freq(void) {
STATIC mp_obj_t machine_freq(void) {
mp_obj_t tuple[1] = {
mp_obj_new_int(HAL_FCPU_HZ),
};
return mp_obj_new_tuple(1, tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
/// \function unique_id()
/// Returns a string of 6 bytes (48 bits), which is the unique ID for the MCU.
STATIC mp_obj_t pyb_unique_id(void) {
STATIC mp_obj_t machine_unique_id(void) {
uint8_t mac[SL_BSSID_LENGTH];
wlan_get_mac (mac);
return mp_obj_new_bytes(mac, SL_BSSID_LENGTH);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
/// \function repl_uart(uart)
/// Get or set the UART object that the REPL is repeated on.
STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {
if (n_args == 0) {
if (pyb_stdio_uart == NULL) {
return mp_const_none;
} else {
return pyb_stdio_uart;
}
STATIC mp_obj_t machine_main(mp_obj_t main) {
if (MP_OBJ_IS_STR(main)) {
MP_STATE_PORT(machine_config_main) = main;
} else {
if (args[0] == mp_const_none) {
pyb_stdio_uart = NULL;
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
pyb_stdio_uart = args[0];
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
}
return mp_const_none;
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart);
MP_DEFINE_CONST_FUN_OBJ_1(machine_main_obj, machine_main);
MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
STATIC mp_obj_t machine_idle(void) {
__WFI();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
STATIC mp_obj_t machine_sleep (void) {
pyb_sleep_sleep();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&pyb_reset_obj },
STATIC mp_obj_t machine_deepsleep (void) {
pyb_sleep_deepsleep();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
STATIC mp_obj_t machine_reset_cause (void) {
return mp_obj_new_int(pyb_sleep_get_reset_cause());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
STATIC mp_obj_t machine_wake_reason (void) {
return mp_obj_new_int(pyb_sleep_get_wake_reason());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason);
STATIC const mp_map_elem_t machine_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&machine_reset_obj },
#ifdef DEBUG
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&machine_freq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&machine_unique_id_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&machine_main_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&machine_rng_get_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&machine_idle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&machine_sleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_deepsleep), (mp_obj_t)&machine_deepsleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&machine_reset_cause_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&machine_wake_reason_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&pyb_rng_get_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
@@ -190,15 +193,26 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Sleep), (mp_obj_t)&pyb_sleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HeartBeat), (mp_obj_t)&pyb_heartbeat_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type },
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
const mp_obj_module_t pyb_module = {
const mp_obj_module_t machine_module = {
.base = { &mp_type_module },
.name = MP_QSTR_pyb,
.globals = (mp_obj_dict_t*)&pyb_module_globals,
.name = MP_QSTR_machine,
.globals = (mp_obj_dict_t*)&machine_module_globals,
};

View File

@@ -29,12 +29,28 @@
#include "py/mpstate.h"
#include MICROPY_HAL_H
#include "py/obj.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "modnetwork.h"
#include "mpexception.h"
#include "serverstask.h"
#include "simplelink.h"
/******************************************************************************
DEFINE TYPES
******************************************************************************/
typedef struct {
mp_obj_base_t base;
} network_server_obj_t;
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
STATIC network_server_obj_t network_server_obj;
STATIC const mp_obj_type_t network_server_type;
/// \module network - network configuration
///
/// This module provides network drivers and server configuration.
@@ -43,48 +59,93 @@ void mod_network_init0(void) {
}
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
STATIC mp_obj_t network_server_running(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args > 0) {
// set
if (mp_obj_is_true(args[0])) {
servers_start();
} else {
servers_stop();
}
return mp_const_none;
} else {
// get
return MP_BOOL(servers_are_enabled());
STATIC mp_obj_t network_server_init_helper(mp_obj_t self, const mp_arg_val_t *args) {
const char *user = SERVERS_DEF_USER;
const char *pass = SERVERS_DEF_PASS;
if (args[0].u_obj != MP_OBJ_NULL) {
mp_obj_t *login;
mp_obj_get_array_fixed_n(args[0].u_obj, 2, &login);
user = mp_obj_str_get_str(login[0]);
pass = mp_obj_str_get_str(login[1]);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_running_obj, 0, 1, network_server_running);
STATIC mp_obj_t network_server_login(mp_obj_t user, mp_obj_t pass) {
const char *_user = mp_obj_str_get_str(user);
const char *_pass = mp_obj_str_get_str(pass);
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
uint32_t timeout = SERVERS_DEF_TIMEOUT_MS / 1000;
if (args[1].u_obj != MP_OBJ_NULL) {
timeout = mp_obj_get_int(args[1].u_obj);
}
servers_set_login ((char *)_user, (char *)_pass);
// configure the new login
servers_set_login ((char *)user, (char *)pass);
// configure the timeout
servers_set_timeout(timeout * 1000);
// start the servers
servers_start();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(network_server_login_obj, network_server_login);
STATIC const mp_arg_t network_server_args[] = {
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_login, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
STATIC mp_obj_t network_server_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
// parse args
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args)];
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), network_server_args, args);
// check the server id
if (args[0].u_obj != MP_OBJ_NULL) {
if (mp_obj_get_int(args[0].u_obj) != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
}
}
// setup the object and initialize it
network_server_obj_t *self = &network_server_obj;
self->base.type = &network_server_type;
network_server_init_helper(self, &args[1]);
return (mp_obj_t)self;
}
STATIC mp_obj_t network_server_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// parse args
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args) - 1];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &network_server_args[1], args);
return network_server_init_helper(pos_args[0], args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_server_init_obj, 1, network_server_init);
// timeout value given in seconds
STATIC mp_obj_t network_server_timeout(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args > 0) {
uint32_t _timeout = mp_obj_get_int(args[0]);
if (!servers_set_timeout(_timeout * 1000)) {
// timeout is too low
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
if (n_args > 1) {
uint32_t timeout = mp_obj_get_int(args[1]);
servers_set_timeout(timeout * 1000);
return mp_const_none;
} else {
// get
return mp_obj_new_int(servers_get_timeout() / 1000);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 0, 1, network_server_timeout);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 1, 2, network_server_timeout);
STATIC mp_obj_t network_server_running(mp_obj_t self_in) {
// get
return mp_obj_new_bool(servers_are_enabled());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_running_obj, network_server_running);
STATIC mp_obj_t network_server_deinit(mp_obj_t self_in) {
// simply stop the servers
servers_stop();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_deinit_obj, network_server_deinit);
#endif
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
@@ -92,9 +153,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&mod_network_nic_type_wlan },
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_running), (mp_obj_t)&network_server_running_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_login), (mp_obj_t)&network_server_login_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_timeout), (mp_obj_t)&network_server_timeout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_server), (mp_obj_t)&network_server_type },
#endif
};
@@ -105,3 +164,21 @@ const mp_obj_module_t mp_module_network = {
.name = MP_QSTR_network,
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
};
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
STATIC const mp_map_elem_t network_server_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&network_server_init_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&network_server_deinit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&network_server_timeout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isrunning), (mp_obj_t)&network_server_running_obj },
};
STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_dict_table);
STATIC const mp_obj_type_t network_server_type = {
{ &mp_type_type },
.name = MP_QSTR_server,
.make_new = network_server_make_new,
.locals_dict = (mp_obj_t)&network_server_locals_dict,
};
#endif

View File

@@ -34,7 +34,7 @@
#include "py/objstr.h"
#include "py/runtime.h"
#include "genhdr/mpversion.h"
#include "ff.h"
#include "moduos.h"
#include "diskio.h"
#include "sflash_diskio.h"
#include "file.h"
@@ -42,8 +42,8 @@
#include "mpexception.h"
#include "version.h"
#include "timeutils.h"
#include "moduos.h"
#include "pybsd.h"
#include "pybuart.h"
/// \module os - basic "operating system" services
///
@@ -60,6 +60,7 @@
DECLARE PRIVATE DATA
******************************************************************************/
STATIC uint32_t os_num_mounted_devices;
STATIC os_term_dup_obj_t os_term_dup_obj;
/******************************************************************************
DEFINE PUBLIC FUNCTIONS
@@ -536,6 +537,31 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs);
STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
if (n_args == 0) {
if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
return mp_const_none;
} else {
return MP_STATE_PORT(os_term_dup_obj)->stream_o;
}
} else {
mp_obj_t stream_o = args[0];
if (stream_o == mp_const_none) {
MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
} else {
if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) {
// must be a stream-like object providing at least read and write methods
mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
}
os_term_dup_obj.stream_o = stream_o;
MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
}
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
@@ -551,9 +577,12 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_urandom), (mp_obj_t)&os_urandom_obj },
// MicroPython additions
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dupterm), (mp_obj_t)&os_dupterm_obj },
/// \constant sep - separation character used in paths
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },

View File

@@ -28,6 +28,11 @@
#ifndef MODUOS_H_
#define MODUOS_H_
#include "ff.h"
/******************************************************************************
DEFINE PUBLIC TYPES
******************************************************************************/
typedef struct _os_fs_mount_t {
mp_obj_t device;
const char *path;
@@ -40,6 +45,15 @@ typedef struct _os_fs_mount_t {
uint8_t vol;
} os_fs_mount_t;
typedef struct _os_term_dup_obj_t {
mp_obj_t stream_o;
mp_obj_t read[3];
mp_obj_t write[3];
} os_term_dup_obj_t;
/******************************************************************************
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
void moduos_init0 (void);
os_fs_mount_t *osmount_find_by_path (const char *path);
os_fs_mount_t *osmount_find_by_volume (uint8_t vol);

View File

@@ -185,17 +185,23 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
// method socket.listen(backlog)
STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
mod_network_socket_obj_t *self = self_in;
// method socket.listen([backlog])
STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) {
mod_network_socket_obj_t *self = args[0];
int32_t backlog = 0;
if (n_args > 1) {
backlog = mp_obj_get_int(args[1]);
backlog = (backlog < 0) ? 0 : backlog;
}
int _errno;
if (wlan_socket_listen(self, mp_obj_get_int(backlog), &_errno) != 0) {
if (wlan_socket_listen(self, backlog, &_errno) != 0) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
// method socket.accept()
STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
@@ -391,6 +397,21 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
// TODO: CPython explicitly says that closing the returned object doesn't
// close the original socket (Python2 at all says that fd is dup()ed). But
// we save on the bloat.
mod_network_socket_obj_t *self = args[0];
if (n_args > 1) {
const char *mode = mp_obj_str_get_str(args[1]);
if (strcmp(mode, "rb") && strcmp(mode, "wb")) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
}
return self;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
@@ -406,7 +427,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&mp_identity_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj },
// stream methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
@@ -504,16 +525,13 @@ STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_SEC), MP_OBJ_NEW_SMALL_INT(SL_SEC_SOCKET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);

View File

@@ -61,7 +61,7 @@ STATIC const mp_obj_type_t ssl_socket_type;
/******************************************************************************/
// Micro Python bindings; SSL class
// ssl socket inherits from normal socket, so we take its
// ssl sockets inherit from normal socket, so we take its
// locals and stream methods
STATIC const mp_obj_type_t ssl_socket_type = {
{ &mp_type_type },
@@ -91,7 +91,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
goto arg_error;
}
// retrieve the file paths (with an 6 byte offset because to strip the '/flash' prefix)
// 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) ?
@@ -116,7 +116,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
// create the ssl socket
mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
// ssl socket inherits all properties from the original socket
// ssl sockets inherit all properties from the original socket
memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
ssl_sock->base.type = &ssl_socket_type;
ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
@@ -130,7 +130,7 @@ socket_error:
arg_error:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) },

View File

@@ -32,6 +32,7 @@
#include MICROPY_HAL_H
#include "py/nlr.h"
#include "py/obj.h"
#include "py/smallint.h"
#include "timeutils.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
@@ -56,7 +57,7 @@
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
/// If secs is not provided or None, then the current time from the RTC is used.
/// year includes the century (for example 2014)
/// year includes the century (for example 2015)
/// month is 1-12
/// mday is 1-31
/// hour is 0-23
@@ -67,14 +68,9 @@
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0 || args[0] == mp_const_none) {
timeutils_struct_time_t tm;
uint32_t seconds;
uint16_t mseconds;
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
mseconds = RTC_CYCLES_U16MS(mseconds);
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
// get the seconds from the RTC
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
mp_obj_new_int(tm.tm_mon),
@@ -154,36 +150,28 @@ STATIC mp_obj_t time_sleep_us (mp_obj_t usec_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
STATIC mp_obj_t time_ticks_ms(void) {
// We want to "cast" the 32 bit unsigned into a small-int. This means
// copying the MSB down 1 bit (extending the sign down), which is
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
return MP_OBJ_NEW_SMALL_INT(HAL_GetTick());
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
return MP_OBJ_NEW_SMALL_INT(HAL_GetTick() & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
STATIC mp_obj_t time_ticks_us(void) {
// We want to "cast" the 32 bit unsigned into a small-int. This means
// copying the MSB down 1 bit (extending the sign down), which is
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds());
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds() & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
STATIC mp_obj_t time_ticks_cpu(void) {
// We want to "cast" the 32 bit unsigned into a small-int. This means
// copying the MSB down 1 bit (extending the sign down), which is
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
return MP_OBJ_NEW_SMALL_INT(SysTickValueGet());
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
return MP_OBJ_NEW_SMALL_INT((SysTickPeriodGet() - SysTickValueGet()) & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
STATIC mp_obj_t time_ticks_diff(mp_obj_t t0, mp_obj_t t1) {
// We want to "cast" the 32 bit unsigned into a small-int. This means
// copying the MSB down 1 bit (extending the sign down), which is
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
uint32_t start = mp_obj_get_int(t0);
uint32_t end = mp_obj_get_int(t1);
return MP_OBJ_NEW_SMALL_INT((end > start) ? (end - start) : (start - end));
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);
@@ -194,6 +182,8 @@ STATIC const mp_map_elem_t time_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
// MicroPython additions
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&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 },

32
cc3200/mods/modwipy.c Normal file
View File

@@ -0,0 +1,32 @@
#include "py/mpconfig.h"
#include MICROPY_HAL_H
#include "py/obj.h"
#include "py/runtime.h"
#include "mperror.h"
/******************************************************************************/
// Micro Python bindings
STATIC mp_obj_t mod_wipy_heartbeat (mp_uint_t n_args, const mp_obj_t *args) {
if (n_args) {
mperror_enable_heartbeat (mp_obj_is_true(args[0]));
return mp_const_none;
} else {
return mp_obj_new_bool(mperror_is_heartbeat_enabled());
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_wipy_heartbeat_obj, 0, 1, mod_wipy_heartbeat);
STATIC const mp_map_elem_t wipy_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_wipy) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat), (mp_obj_t)&mod_wipy_heartbeat_obj },
};
STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
const mp_obj_module_t wipy_module = {
.base = { &mp_type_module },
.name = MP_QSTR_wipy,
.globals = (mp_obj_dict_t*)&wipy_module_globals,
};

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,10 @@
#define SL_STOP_TIMEOUT 35
#define SL_STOP_TIMEOUT_LONG 575
#define MODWLAN_WIFI_EVENT_ANY 0x01
#define MODWLAN_SSID_LEN_MAX 32
/******************************************************************************
DEFINE TYPES
******************************************************************************/
@@ -45,6 +49,34 @@ typedef enum {
MODWLAN_ERROR_UNKNOWN = -3,
} modwlan_Status_t;
typedef struct _wlan_obj_t {
mp_obj_base_t base;
mp_obj_t irq_obj;
uint32_t status;
uint32_t ip;
int8_t mode;
uint8_t auth;
uint8_t channel;
uint8_t antenna;
// my own ssid, key and mac
uint8_t ssid[(MODWLAN_SSID_LEN_MAX + 1)];
uint8_t key[65];
uint8_t mac[SL_MAC_ADDR_LEN];
// the sssid (or name) and mac of the other device
uint8_t ssid_o[33];
uint8_t bssid[6];
uint8_t irq_flags;
bool irq_enabled;
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
bool servers_enabled;
#endif
} wlan_obj_t;
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
@@ -54,12 +86,11 @@ extern _SlLockObj_t wlan_LockObj;
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
extern void wlan_pre_init (void);
extern void wlan_sl_enable (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t sec,
const char *key, uint8_t key_len, uint8_t channel, bool append_mac);
extern void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len,
uint8_t channel, uint8_t antenna, bool add_mac);
extern void wlan_first_start (void);
extern void wlan_update(void);
extern void wlan_stop (uint32_t timeout);
extern void wlan_start (void);
extern void wlan_get_mac (uint8_t *macAddress);
extern void wlan_get_ip (uint32_t *ip);
extern bool wlan_is_connected (void);

View File

@@ -164,7 +164,7 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw,
// initialize and register with the sleep module
pyb_adc_init(self);
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
return self;
}
@@ -188,14 +188,14 @@ STATIC mp_obj_t adc_deinit(mp_obj_t self_in) {
MAP_ADCDisable(ADC_BASE);
self->enabled = false;
// unregister it with the sleep module
pybsleep_remove ((const mp_obj_t)self);
pyb_sleep_remove ((const mp_obj_t)self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit);
STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
STATIC const mp_arg_t pyb_adc_channel_args[] = {
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
@@ -204,12 +204,11 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args);
uint ch_id;
if (args[0].u_obj != mp_const_none) {
if (args[0].u_obj != MP_OBJ_NULL) {
ch_id = mp_obj_get_int(args[0].u_obj);
if (ch_id >= PYB_ADC_NUM_CHANNELS) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable));
}
else if (args[1].u_obj != mp_const_none) {
} else if (args[1].u_obj != mp_const_none) {
uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
if (ch_id != pin_ch_id) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
@@ -224,7 +223,7 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t
self->base.type = &pyb_adc_channel_type;
pyb_adc_channel_init (self);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
return self;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel);
@@ -267,7 +266,7 @@ STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) {
MAP_ADCChannelDisable(ADC_BASE, self->channel);
// unregister it with the sleep module
pybsleep_remove ((const mp_obj_t)self);
pyb_sleep_remove ((const mp_obj_t)self);
self->enabled = false;
return mp_const_none;
}

View File

@@ -292,24 +292,20 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg
mp_obj_t pins_o = args[2].u_obj;
if (pins_o != mp_const_none) {
mp_obj_t *pins;
mp_uint_t n_pins = 2;
if (pins_o == MP_OBJ_NULL) {
// use the default pins
pins = (mp_obj_t *)pyb_i2c_def_pin;
} else {
mp_obj_get_array(pins_o, &n_pins, &pins);
if (n_pins != 2) {
goto invalid_args;
}
mp_obj_get_array_fixed_n(pins_o, 2, &pins);
}
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
pin_assign_pins_af (pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
}
// init the I2C bus
i2c_init(self);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
return mp_const_none;
@@ -320,8 +316,8 @@ invalid_args:
STATIC const mp_arg_t pyb_i2c_init_args[] = {
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = PYBI2C_MASTER} },
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
// parse args
@@ -360,7 +356,7 @@ STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
// invalidate the baudrate
pyb_i2c_obj.baudrate = 0;
// unregister it with the sleep module
pybsleep_remove ((const mp_obj_t)self_in);
pyb_sleep_remove ((const mp_obj_t)self_in);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
@@ -414,7 +410,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_into(mp_uint_t n_args, const mp_obj_t *pos_args
// return the number of bytes received
return mp_obj_new_int(vstr.len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 3, pyb_i2c_readfrom_into);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 1, pyb_i2c_readfrom_into);
STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
STATIC const mp_arg_t pyb_i2c_writeto_args[] = {
@@ -442,7 +438,7 @@ STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m
// return the number of bytes written
return mp_obj_new_int(bufinfo.len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 3, pyb_i2c_writeto);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto);
STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
STATIC const mp_arg_t pyb_i2c_readfrom_mem_args[] = {
@@ -460,7 +456,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
pyb_i2c_readmem_into (args, &vstr);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 4, pyb_i2c_readfrom_mem);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 1, pyb_i2c_readfrom_mem);
STATIC const mp_arg_t pyb_i2c_readfrom_mem_into_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
@@ -479,7 +475,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem_into(mp_uint_t n_args, const mp_obj_t *pos_
pyb_i2c_readmem_into (args, &vstr);
return mp_obj_new_int(vstr.len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 4, pyb_i2c_readfrom_mem_into);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// parse args
@@ -507,7 +503,7 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 4, pyb_i2c_writeto_mem);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem);
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
// instance methods

View File

@@ -45,9 +45,9 @@
#include "gpio.h"
#include "interrupt.h"
#include "pybpin.h"
#include "mpirq.h"
#include "pins.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "mpexception.h"
#include "mperror.h"
@@ -66,8 +66,8 @@ STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type);
STATIC void pin_deassign (pin_obj_t* pin);
STATIC void pin_obj_configure (const pin_obj_t *self);
STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx);
STATIC void pin_extint_enable (mp_obj_t self_in);
STATIC void pin_extint_disable (mp_obj_t self_in);
STATIC void pin_irq_enable (mp_obj_t self_in);
STATIC void pin_irq_disable (mp_obj_t self_in);
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority);
STATIC void pin_validate_mode (uint mode);
STATIC void pin_validate_pull (uint pull);
@@ -88,6 +88,11 @@ DEFINE CONSTANTS
#define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module
#define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode
#define PYB_PIN_FALLING_EDGE 0x01
#define PYB_PIN_RISING_EDGE 0x02
#define PYB_PIN_LOW_LEVEL 0x04
#define PYB_PIN_HIGH_LEVEL 0x08
/******************************************************************************
DEFINE TYPES
******************************************************************************/
@@ -100,7 +105,7 @@ typedef struct {
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
STATIC const mp_cb_methods_t pin_cb_methods;
STATIC const mp_irq_methods_t pin_irq_methods;
STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] =
{ {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
@@ -161,7 +166,7 @@ void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint
pin_obj_configure ((const pin_obj_t *)self);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure);
}
void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit) {
@@ -334,7 +339,7 @@ STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin,
}
}
STATIC void pin_extint_enable (mp_obj_t self_in) {
STATIC void pin_irq_enable (mp_obj_t self_in) {
const pin_obj_t *self = self_in;
uint hib_pin, idx;
@@ -366,7 +371,7 @@ STATIC void pin_extint_enable (mp_obj_t self_in) {
}
}
STATIC void pin_extint_disable (mp_obj_t self_in) {
STATIC void pin_irq_disable (mp_obj_t self_in) {
const pin_obj_t *self = self_in;
uint hib_pin, idx;
@@ -385,6 +390,11 @@ STATIC void pin_extint_disable (mp_obj_t self_in) {
MAP_GPIOIntDisable(self->port, self->bit);
}
STATIC int pin_irq_flags (mp_obj_t self_in) {
const pin_obj_t *self = self_in;
return self->irq_flags;
}
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) {
void *handler;
uint32_t intnum;
@@ -467,14 +477,22 @@ STATIC void EXTI_Handler(uint port) {
uint32_t bits = MAP_GPIOIntStatus(port, true);
MAP_GPIOIntClear(port, bits);
// might be that we have more than one Pin interrupt pending
// might be that we have more than one pin interrupt pending
// therefore we must loop through all of the 8 possible bits
for (int i = 0; i < 8; i++) {
uint32_t bit = (1 << i);
if (bit & bits) {
pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit);
mp_obj_t _callback = mpcallback_find(self);
mpcallback_handler(_callback);
if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
// read the pin value (hoping that the pin level has remained stable)
self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE;
} else {
// same as the triggers
self->irq_flags = self->irq_trigger;
}
mp_irq_handler(mp_irq_find(self));
// always clear the flags after leaving the user handler
self->irq_flags = 0;
}
}
}
@@ -484,7 +502,7 @@ STATIC void EXTI_Handler(uint port) {
// Micro Python bindings
STATIC const mp_arg_t pin_init_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} },
@@ -498,8 +516,14 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_
mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args);
// get the io mode
uint mode = args[0].u_int;
pin_validate_mode(mode);
uint mode;
// default is input
if (args[0].u_obj == MP_OBJ_NULL) {
mode = GPIO_DIR_MODE_IN;
} else {
mode = mp_obj_get_int(args[0].u_obj);
pin_validate_mode (mode);
}
// get the pull type
uint pull;
@@ -609,12 +633,9 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
// Run an argument through the mapper and return the result.
pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]);
if (n_args > 1 || n_kw > 0) {
// pin af given, so configure it
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
}
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
return (mp_obj_t)pin;
}
@@ -726,136 +747,147 @@ STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list);
STATIC mp_obj_t pin_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
/// \method irq(trigger, priority, handler, wake)
STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
pin_obj_t *self = pos_args[0];
// check if any parameters were passed
mp_obj_t _callback = mpcallback_find(self);
if (kw_args->used > 0) {
// convert the priority to the correct value
uint priority = mpcallback_translate_priority (args[2].u_int);
// verify the interrupt mode
uint intmode = args[0].u_int;
if (intmode == (GPIO_FALLING_EDGE | GPIO_RISING_EDGE)) {
intmode = GPIO_BOTH_EDGES;
}
else if (intmode != GPIO_FALLING_EDGE && intmode != GPIO_RISING_EDGE &&
intmode != GPIO_LOW_LEVEL && intmode != GPIO_HIGH_LEVEL) {
// convert the priority to the correct value
uint priority = mp_irq_translate_priority (args[1].u_int);
// verify and translate the interrupt mode
uint mp_trigger = mp_obj_get_int(args[0].u_obj);
uint trigger;
if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
trigger = GPIO_BOTH_EDGES;
} else {
switch (mp_trigger) {
case PYB_PIN_FALLING_EDGE:
trigger = GPIO_FALLING_EDGE;
break;
case PYB_PIN_RISING_EDGE:
trigger = GPIO_RISING_EDGE;
break;
case PYB_PIN_LOW_LEVEL:
trigger = GPIO_LOW_LEVEL;
break;
case PYB_PIN_HIGH_LEVEL:
trigger = GPIO_HIGH_LEVEL;
break;
default:
goto invalid_args;
}
uint pwrmode = args[4].u_int;
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
goto invalid_args;
}
// get the wake info from this pin
uint hib_pin, idx;
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
if (pwrmode & PYB_PWR_MODE_LPDS) {
if (idx >= PYBPIN_NUM_WAKE_PINS) {
goto invalid_args;
}
// wake modes are different in LDPS
uint wake_mode;
switch (intmode) {
case GPIO_FALLING_EDGE:
wake_mode = PRCM_LPDS_FALL_EDGE;
break;
case GPIO_RISING_EDGE:
wake_mode = PRCM_LPDS_RISE_EDGE;
break;
case GPIO_LOW_LEVEL:
wake_mode = PRCM_LPDS_LOW_LEVEL;
break;
case GPIO_HIGH_LEVEL:
wake_mode = PRCM_LPDS_HIGH_LEVEL;
break;
default:
goto invalid_args;
break;
}
// first clear the lpds value from all wake-able pins
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
}
// enable this pin as a wake-up source during LPDS
pybpin_wake_pin[idx].lpds = wake_mode;
}
else {
// this pin was the previous LPDS wake source, so disable it completely
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
}
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
}
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
if (idx >= PYBPIN_NUM_WAKE_PINS) {
goto invalid_args;
}
// wake modes are different in hibernate
uint wake_mode;
switch (intmode) {
case GPIO_FALLING_EDGE:
wake_mode = PRCM_HIB_FALL_EDGE;
break;
case GPIO_RISING_EDGE:
wake_mode = PRCM_HIB_RISE_EDGE;
break;
case GPIO_LOW_LEVEL:
wake_mode = PRCM_HIB_LOW_LEVEL;
break;
case GPIO_HIGH_LEVEL:
wake_mode = PRCM_HIB_HIGH_LEVEL;
break;
default:
goto invalid_args;
break;
}
// enable this pin as wake-up source during hibernate
pybpin_wake_pin[idx].hib = wake_mode;
}
else {
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
}
// we need to update the callback atomically, so we disable the
// interrupt before we update anything.
pin_extint_disable(self);
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
// register the interrupt
pin_extint_register((pin_obj_t *)self, intmode, priority);
if (idx < PYBPIN_NUM_WAKE_PINS) {
pybpin_wake_pin[idx].active = true;
}
}
else if (idx < PYBPIN_NUM_WAKE_PINS) {
pybpin_wake_pin[idx].active = false;
}
// all checks have passed, now we can create the callback
_callback = mpcallback_new (self, args[1].u_obj, &pin_cb_methods, true);
if (pwrmode & PYB_PWR_MODE_LPDS) {
pybsleep_set_gpio_lpds_callback (_callback);
}
// enable the interrupt just before leaving
pin_extint_enable(self);
} else if (!_callback) {
_callback = mpcallback_new (self, mp_const_none, &pin_cb_methods, false);
}
return _callback;
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
goto invalid_args;
}
// get the wake info from this pin
uint hib_pin, idx;
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
if (pwrmode & PYB_PWR_MODE_LPDS) {
if (idx >= PYBPIN_NUM_WAKE_PINS) {
goto invalid_args;
}
// wake modes are different in LDPS
uint wake_mode;
switch (trigger) {
case GPIO_FALLING_EDGE:
wake_mode = PRCM_LPDS_FALL_EDGE;
break;
case GPIO_RISING_EDGE:
wake_mode = PRCM_LPDS_RISE_EDGE;
break;
case GPIO_LOW_LEVEL:
wake_mode = PRCM_LPDS_LOW_LEVEL;
break;
case GPIO_HIGH_LEVEL:
wake_mode = PRCM_LPDS_HIGH_LEVEL;
break;
default:
goto invalid_args;
break;
}
// first clear the lpds value from all wake-able pins
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
}
// enable this pin as a wake-up source during LPDS
pybpin_wake_pin[idx].lpds = wake_mode;
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
// this pin was the previous LPDS wake source, so disable it completely
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
}
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
}
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
if (idx >= PYBPIN_NUM_WAKE_PINS) {
goto invalid_args;
}
// wake modes are different in hibernate
uint wake_mode;
switch (trigger) {
case GPIO_FALLING_EDGE:
wake_mode = PRCM_HIB_FALL_EDGE;
break;
case GPIO_RISING_EDGE:
wake_mode = PRCM_HIB_RISE_EDGE;
break;
case GPIO_LOW_LEVEL:
wake_mode = PRCM_HIB_LOW_LEVEL;
break;
case GPIO_HIGH_LEVEL:
wake_mode = PRCM_HIB_HIGH_LEVEL;
break;
default:
goto invalid_args;
break;
}
// enable this pin as wake-up source during hibernate
pybpin_wake_pin[idx].hib = wake_mode;
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
}
// we need to update the callback atomically, so we disable the
// interrupt before we update anything.
pin_irq_disable(self);
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
// register the interrupt
pin_extint_register((pin_obj_t *)self, trigger, priority);
if (idx < PYBPIN_NUM_WAKE_PINS) {
pybpin_wake_pin[idx].active = true;
}
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
pybpin_wake_pin[idx].active = false;
}
// all checks have passed, we can create the irq object
mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods);
if (pwrmode & PYB_PWR_MODE_LPDS) {
pyb_sleep_set_gpio_lpds_callback (_irq);
}
// save the mp_trigge for later
self->irq_trigger = mp_trigger;
// enable the interrupt just before leaving
pin_irq_enable(self);
return _irq;
invalid_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_callback_obj, 1, pin_callback);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
STATIC const mp_map_elem_t pin_locals_dict_table[] = {
// instance methods
@@ -867,7 +899,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_pull), (mp_obj_t)&pin_pull_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_drive), (mp_obj_t)&pin_drive_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_alt_list), (mp_obj_t)&pin_alt_list_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pin_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pin_irq_obj },
// class attributes
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type },
@@ -883,10 +915,10 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_2MA) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MED_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_4MA) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_6MA) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_FALLING_EDGE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_RISING_EDGE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_LOW_LEVEL) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_HIGH_LEVEL) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_FALLING_EDGE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_RISING_EDGE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_LOW_LEVEL) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_HIGH_LEVEL) },
};
STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
@@ -900,10 +932,11 @@ const mp_obj_type_t pin_type = {
.locals_dict = (mp_obj_t)&pin_locals_dict,
};
STATIC const mp_cb_methods_t pin_cb_methods = {
.init = pin_callback,
.enable = pin_extint_enable,
.disable = pin_extint_disable,
STATIC const mp_irq_methods_t pin_irq_methods = {
.init = pin_irq,
.enable = pin_irq_enable,
.disable = pin_irq_disable,
.flags = pin_irq_flags,
};
STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {

View File

@@ -110,9 +110,11 @@ typedef struct {
int8_t af;
uint8_t strength;
uint8_t mode; // this is now a combination of type and mode
uint8_t num_afs: 6; // up to 63 AFs
uint8_t value : 1;
uint8_t used : 1;
const uint8_t num_afs; // 255 AFs
uint8_t value;
uint8_t used;
uint8_t irq_trigger;
uint8_t irq_flags;
} pin_obj_t;
extern const mp_obj_type_t pin_type;

View File

@@ -37,8 +37,8 @@
#include "rom_map.h"
#include "prcm.h"
#include "pybrtc.h"
#include "mpirq.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "timeutils.h"
#include "simplelink.h"
#include "modnetwork.h"
@@ -48,88 +48,148 @@
/// \moduleref pyb
/// \class RTC - real time clock
/******************************************************************************
DEFINE TYPES
******************************************************************************/
typedef struct _pyb_rtc_obj_t {
mp_obj_base_t base;
byte prwmode;
bool alarmset;
bool repeat;
} pyb_rtc_obj_t;
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
STATIC const mp_cb_methods_t pybrtc_cb_methods;
STATIC pyb_rtc_obj_t pyb_rtc_obj = {.prwmode = 0, .alarmset = false, .repeat = false};
STATIC const mp_irq_methods_t pyb_rtc_irq_methods;
STATIC pyb_rtc_obj_t pyb_rtc_obj;
/******************************************************************************
FUNCTION-LIKE MACROS
******************************************************************************/
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in);
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in);
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in);
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs);
STATIC uint32_t pyb_rtc_reset (void);
STATIC void pyb_rtc_disable_interupt (void);
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in);
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in);
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in);
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds);
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime);
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds);
STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
/******************************************************************************
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
__attribute__ ((section (".boot")))
void pyb_rtc_pre_init(void) {
// if the RTC was previously set, leave it alone
// only if comming out of a power-on reset
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
// Mark the RTC in use first
MAP_PRCMRTCInUseSet();
// reset the time and date
pyb_rtc_reset((mp_obj_t)&pyb_rtc_obj);
pyb_rtc_reset();
}
}
void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) {
uint16_t cycles;
MAP_PRCMRTCGet (secs, &cycles);
*msecs = RTC_CYCLES_U16MS(cycles);
}
uint32_t pyb_rtc_get_seconds (void) {
uint32_t seconds;
uint16_t mseconds;
MAP_PRCMRTCGet(&seconds, &mseconds);
pyb_rtc_get_time(&seconds, &mseconds);
return seconds;
}
void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) {
uint32_t c_seconds;
uint16_t c_mseconds;
// get the current time
pyb_rtc_get_time(&c_seconds, &c_mseconds);
// calculate the future seconds
*f_seconds = c_seconds + (a_mseconds / 1000);
// calculate the "remaining" future mseconds
*f_mseconds = a_mseconds % 1000;
// add the current milliseconds
rtc_msec_add (c_mseconds, f_seconds, f_mseconds);
}
void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
if (self->repeat) {
uint32_t f_seconds, c_seconds;
uint16_t f_mseconds, c_mseconds;
pyb_rtc_get_time(&c_seconds, &c_mseconds);
// substract the time elapsed between waking up and setting up the alarm again
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
int32_t next_alarm = self->alarm_ms - wake_ms;
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds);
// now configure the alarm
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
}
}
void pyb_rtc_disable_alarm (void) {
pyb_rtc_obj.alarmset = false;
pyb_rtc_disable_interupt();
}
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in) {
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) {
// add the RTC access time
rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs);
// convert from mseconds to cycles
msecs = RTC_U16MS_CYCLES(msecs);
// now set the time
MAP_PRCMRTCSet(secs, msecs);
}
STATIC uint32_t pyb_rtc_reset (void) {
// fresh reset; configure the RTC Calendar
// set the date to 1st Jan 2015
// set the time to 00:00:00
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
// Now set the RTC calendar seconds
MAP_PRCMRTCSet(seconds, 0);
// disable any running alarm
pyb_rtc_disable_alarm();
// Now set the RTC calendar time
pyb_rtc_set_time(seconds, 0);
return seconds;
}
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
pyb_rtc_obj_t *self = self_in;
// check the wake from param
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
// enable the slow clock interrupt
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
} else {
// just in case it was already enabled before
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
}
pybsleep_configure_timer_wakeup (self->prwmode);
STATIC void pyb_rtc_disable_interupt (void) {
uint primsk = disable_irq();
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
(void)MAP_PRCMIntStatus();
enable_irq(primsk);
}
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) {
pyb_rtc_obj_t *self = self_in;
// check the wake from param
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
// disable the slow clock interrupt
// we always need interrupts if repeat is enabled
if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) {
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
} else { // just in case it was already enabled before
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
}
// disable wake from ldps and hibernate
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
// read the interrupt status to clear any pending interrupt
(void)MAP_PRCMIntStatus();
self->irq_enabled = true;
}
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) {
pyb_rtc_obj_t *self = self_in;
self->irq_enabled = false;
if (!self->repeat) { // we always need interrupts if repeat is enabled
pyb_rtc_disable_interupt();
}
}
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) {
pyb_rtc_obj_t *self = self_in;
return self->irq_flags;
}
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
@@ -177,15 +237,15 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
///
/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None)
///
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) {
uint32_t seconds;
uint32_t useconds;
if (datetime != MP_OBJ_NULL) {
useconds = pyb_rtc_datetime_s_us(datetime, &seconds);
MAP_PRCMRTCSet(seconds, RTC_U16MS_CYCLES(useconds / 1000));
pyb_rtc_set_time (seconds, useconds / 1000);
} else {
seconds = pyb_rtc_reset(self);
seconds = pyb_rtc_reset();
}
// set WLAN time and date, this is needed to verify certificates
@@ -193,6 +253,32 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
return mp_const_none;
}
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) {
// disable the interrupt before updating anything
if (self->irq_enabled) {
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
}
// set the match value
MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds));
self->alarmset = true;
self->alarm_time_s = seconds;
self->alarm_time_ms = mseconds;
// enabled the interrupts again if applicable
if (self->irq_enabled || self->repeat) {
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
}
}
STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) {
if (msecs_1 + *msecs_2 >= 1000) { // larger than one second
*msecs_2 = (msecs_1 + *msecs_2) - 1000;
*secs += 1; // carry flag
} else {
// simply add the mseconds
*msecs_2 = msecs_1 + *msecs_2;
}
}
/******************************************************************************/
// Micro Python bindings
@@ -219,6 +305,9 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
// set the time and date
pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj);
// pass it to the sleep module
pyb_sleep_set_rtc_obj (self);
// return constant object
return (mp_obj_t)&pyb_rtc_obj;
}
@@ -236,9 +325,8 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
uint32_t seconds;
uint16_t mseconds;
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
mseconds = RTC_CYCLES_U16MS(mseconds);
// get the time from the RTC
pyb_rtc_get_time(&seconds, &mseconds);
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
@@ -256,7 +344,7 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now);
STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) {
pyb_rtc_reset (self_in);
pyb_rtc_reset();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
@@ -264,7 +352,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
@@ -278,114 +366,97 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
}
uint32_t a_seconds;
uint16_t a_mseconds;
uint32_t f_seconds;
uint16_t f_mseconds;
bool repeat = args[2].u_bool;
if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given
a_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &a_seconds) / 1000;
} else { // then it must be an integer or MP_OBJ_NULL
uint32_t c_seconds;
uint16_t c_mseconds;
if (MP_OBJ_IS_INT(args[1].u_obj)) {
a_seconds = 0, a_mseconds = mp_obj_get_int(args[1].u_obj);
} else {
a_seconds = 1, a_mseconds = 0;
// repeat cannot be used with a datetime tuple
if (repeat) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
a_mseconds += RTC_CYCLES_U16MS(c_mseconds);
// calculate the future time
a_seconds += c_seconds + (a_mseconds / 1000);
a_mseconds -= ((a_mseconds / 1000) * 1000);
f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000;
} else { // then it must be an integer
self->alarm_ms = mp_obj_get_int(args[1].u_obj);
pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds);
}
// disable the interrupt before updating anything
pyb_rtc_callback_disable((mp_obj_t)self);
// store the repepat flag
self->repeat = repeat;
// set the match value
MAP_PRCMRTCMatchSet(a_seconds, a_mseconds);
// enabled it again (according to the power mode)
pyb_rtc_callback_enable((mp_obj_t)self);
// set the alarmset flag and store the repeat one
self->alarmset = true;
self->repeat = args[2].u_bool;
// now configure the alarm
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm);
STATIC mp_obj_t pyb_rtc_alarm_left (mp_obj_t self_in) {
pyb_rtc_obj_t *self = self_in;
uint32_t a_seconds, c_seconds;
uint16_t a_mseconds, c_mseconds;
STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
pyb_rtc_obj_t *self = args[0];
int32_t ms_left;
uint32_t c_seconds;
uint16_t c_mseconds;
// only alarm id 0 is available
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
}
// get the alarm time
MAP_PRCMRTCMatchGet(&a_seconds, &a_mseconds);
a_mseconds = RTC_CYCLES_U16MS(a_mseconds);
// get the current time
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
c_mseconds = RTC_CYCLES_U16MS(c_mseconds);
pyb_rtc_get_time(&c_seconds, &c_mseconds);
// calculate the ms left
ms_left = ((a_seconds * 1000) + a_mseconds) - ((c_seconds * 1000) + c_mseconds);
ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds);
if (!self->alarmset || ms_left < 0) {
ms_left = 0;
}
return mp_obj_new_int(ms_left);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_alarm_left_obj, pyb_rtc_alarm_left);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
/// \method callback(handler, value, pwrmode)
/// Creates a callback object associated with the real time clock
/// min num of arguments is 1 (value). The value is the alarm time
/// in the future, in msec
/// FIXME
STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) {
// only alarm id 0 is available
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
}
// disable the alarm
pyb_rtc_disable_alarm();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel);
/// \method irq(trigger, priority, handler, wake)
STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
pyb_rtc_obj_t *self = pos_args[0];
// check if any parameters were passed
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
if (kw_args->used > 0) {
uint32_t f_mseconds = MAX(1, mp_obj_get_int(args[3].u_obj));
uint32_t seconds;
uint16_t mseconds;
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
mseconds = RTC_CYCLES_U16MS(mseconds);
// configure the rtc alarm accordingly
seconds += f_mseconds / 1000;
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
// disable the interrupt before updating anything
pyb_rtc_callback_disable((mp_obj_t)&pyb_rtc_obj);
// set the match value
MAP_PRCMRTCMatchSet(seconds, mseconds);
// save the power mode data for later
self->prwmode = args[4].u_int;
// create the callback
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods, true);
// set the lpds callback
pybsleep_set_timer_lpds_callback(_callback);
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
// to make sure that the wakeup callbacks are always called first when resuming from sleep
// enable the interrupt
pyb_rtc_callback_enable((mp_obj_t)&pyb_rtc_obj);
} else if (!_callback) {
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, mp_const_none, &pybrtc_cb_methods, false);
// save the power mode data for later
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
goto invalid_args;
}
return _callback;
// check the trigger
if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) {
self->pwrmode = pwrmode;
pyb_rtc_irq_enable((mp_obj_t)self);
} else {
goto invalid_args;
}
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
// to make sure that the wakeup irqs are always called first when resuming from sleep
// create the callback
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods);
self->irq_obj = _irq;
return _irq;
invalid_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_callback_obj, 1, pyb_rtc_callback);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj },
@@ -393,7 +464,11 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_rtc_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
@@ -404,8 +479,9 @@ const mp_obj_type_t pyb_rtc_type = {
.locals_dict = (mp_obj_t)&pyb_rtc_locals_dict,
};
STATIC const mp_cb_methods_t pybrtc_cb_methods = {
.init = pyb_rtc_callback,
.enable = pyb_rtc_callback_enable,
.disable = pyb_rtc_callback_disable,
STATIC const mp_irq_methods_t pyb_rtc_irq_methods = {
.init = pyb_rtc_irq,
.enable = pyb_rtc_irq_enable,
.disable = pyb_rtc_irq_disable,
.flags = pyb_rtc_irq_flags
};

View File

@@ -28,12 +28,32 @@
#ifndef PYBRTC_H_
#define PYBRTC_H_
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
// RTC triggers
#define PYB_RTC_ALARM0 (0x01)
#define RTC_ACCESS_TIME_MSEC (5)
#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2)
typedef struct _pyb_rtc_obj_t {
mp_obj_base_t base;
mp_obj_t irq_obj;
uint32_t irq_flags;
uint32_t alarm_ms;
uint32_t alarm_time_s;
uint16_t alarm_time_ms;
byte pwrmode;
bool alarmset;
bool repeat;
bool irq_enabled;
} pyb_rtc_obj_t;
extern const mp_obj_type_t pyb_rtc_type;
extern void pyb_rtc_pre_init(void);
extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs);
extern uint32_t pyb_rtc_get_seconds (void);
extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds);
extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self);
extern void pyb_rtc_disable_alarm (void);
#endif // PYBRTC_H_

View File

@@ -54,7 +54,7 @@
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
pybsd_obj_t pybsd_obj = {.pin_clk = MP_OBJ_NULL, .enabled = false};
pybsd_obj_t pybsd_obj;
/******************************************************************************
DECLARE PRIVATE DATA
@@ -95,17 +95,13 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args)
mp_obj_t pins_o = args[0].u_obj;
if (pins_o != mp_const_none) {
mp_obj_t *pins;
mp_uint_t n_pins = MP_ARRAY_SIZE(pyb_sd_def_pin);
if (pins_o == MP_OBJ_NULL) {
// use the default pins
pins = (mp_obj_t *)pyb_sd_def_pin;
} else {
mp_obj_get_array(pins_o, &n_pins, &pins);
if (n_pins != MP_ARRAY_SIZE(pyb_sd_def_pin)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
mp_obj_get_array_fixed_n(pins_o, MP_ARRAY_SIZE(pyb_sd_def_pin), &pins);
}
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SD, 0);
pin_assign_pins_af (pins, MP_ARRAY_SIZE(pyb_sd_def_pin), PIN_TYPE_STD_PU, PIN_FN_SD, 0);
// save the pins clock
self->pin_clk = pin_find(pins[0]);
}
@@ -116,7 +112,7 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args)
}
// register it with the sleep module
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
return mp_const_none;
}
@@ -163,7 +159,7 @@ STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) {
// de-initialze the sd card at diskio level
sd_disk_deinit();
// unregister it from the sleep module
pybsleep_remove (self);
pyb_sleep_remove (self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit);

View File

@@ -43,6 +43,7 @@
#include "spi.h"
#include "pin.h"
#include "pybsleep.h"
#include "mpirq.h"
#include "pybpin.h"
#include "simplelink.h"
#include "modnetwork.h"
@@ -50,12 +51,12 @@
#include "osi.h"
#include "debug.h"
#include "mpexception.h"
#include "mpcallback.h"
#include "mperror.h"
#include "sleeprestore.h"
#include "serverstask.h"
#include "antenna.h"
#include "cryptohash.h"
#include "pybrtc.h"
/******************************************************************************
DECLARE PRIVATE CONSTANTS
@@ -70,7 +71,7 @@
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
#define WAKEUP_TIME_HIB (32768) // 1 s
#define FORCED_TIMER_INTERRUPT_MS (1)
#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
/******************************************************************************
@@ -110,35 +111,37 @@ typedef struct {
mp_obj_base_t base;
mp_obj_t obj;
WakeUpCB_t wakeup;
} pybsleep_obj_t;
} pyb_sleep_obj_t;
typedef struct {
mp_obj_t wlan_lpds_wake_cb;
mp_obj_t timer_lpds_wake_cb;
mp_obj_t gpio_lpds_wake_cb;
uint timer_wake_pwrmode;
mp_obj_t gpio_lpds_wake_cb;
wlan_obj_t *wlan_obj;
pyb_rtc_obj_t *rtc_obj;
} pybsleep_data_t;
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
STATIC const mp_obj_type_t pybsleep_type;
STATIC nvic_reg_store_t *nvic_reg_store;
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL, 0};
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
volatile arm_cm4_core_regs_t vault_arm_registers;
STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
STATIC const mp_obj_type_t pyb_sleep_type = {
{ &mp_type_type },
.name = MP_QSTR_sleep,
};
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj);
STATIC void pybsleep_flash_powerdown (void);
STATIC NORETURN void pybsleep_suspend_enter (void);
void pybsleep_suspend_exit (void);
STATIC void pybsleep_obj_wakeup (void);
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
STATIC void pyb_sleep_flash_powerdown (void);
STATIC NORETURN void pyb_sleep_suspend_enter (void);
void pyb_sleep_suspend_exit (void);
STATIC void pyb_sleep_obj_wakeup (void);
STATIC void PRCMInterruptHandler (void);
STATIC void pybsleep_iopark (bool hibernate);
STATIC void pyb_sleep_iopark (bool hibernate);
STATIC bool setup_timer_lpds_wake (void);
STATIC bool setup_timer_hibernate_wake (void);
@@ -146,14 +149,14 @@ STATIC bool setup_timer_hibernate_wake (void);
DEFINE PUBLIC FUNCTIONS
******************************************************************************/
__attribute__ ((section (".boot")))
void pybsleep_pre_init (void) {
void pyb_sleep_pre_init (void) {
// allocate memory for nvic registers vault
ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
}
void pybsleep_init0 (void) {
void pyb_sleep_init0 (void) {
// initialize the sleep objects list
mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0);
mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
// register and enable the PRCM interrupt
osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
@@ -164,7 +167,7 @@ void pybsleep_init0 (void) {
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
// store the reset casue (if it's soft reset, leave it as it is)
// check the reset casue (if it's soft reset, leave it as it is)
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
switch (MAP_PRCMSysResetCauseGet()) {
case PRCM_POWER_ON:
@@ -188,6 +191,7 @@ void pybsleep_init0 (void) {
switch (MAP_PRCMHibernateWakeupCauseGet()) {
case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
// TODO repeat the alarm
break;
case PRCM_HIB_WAKEUP_CAUSE_GPIO:
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
@@ -203,54 +207,109 @@ void pybsleep_init0 (void) {
}
}
void pybsleep_signal_soft_reset (void) {
void pyb_sleep_signal_soft_reset (void) {
pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
}
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t);
sleep_obj->base.type = &pybsleep_type;
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
sleep_obj->base.type = &pyb_sleep_type;
sleep_obj->obj = obj;
sleep_obj->wakeup = wakeup;
// remove it in case it was already registered
pybsleep_remove (obj);
mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
pyb_sleep_remove (obj);
mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
}
void pybsleep_remove (const mp_obj_t obj) {
pybsleep_obj_t *sleep_obj;
if ((sleep_obj = pybsleep_find(obj))) {
mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
void pyb_sleep_remove (const mp_obj_t obj) {
pyb_sleep_obj_t *sleep_obj;
if ((sleep_obj = pyb_sleep_find(obj))) {
mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
}
}
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj) {
pybsleep_data.wlan_lpds_wake_cb = cb_obj;
}
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
pybsleep_data.gpio_lpds_wake_cb = cb_obj;
}
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
pybsleep_data.timer_lpds_wake_cb = cb_obj;
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
}
void pybsleep_configure_timer_wakeup (uint pwrmode) {
pybsleep_data.timer_wake_pwrmode = pwrmode;
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
}
pybsleep_reset_cause_t pybsleep_get_reset_cause (void) {
void pyb_sleep_sleep (void) {
nlr_buf_t nlr;
// check if we should enable timer wake-up
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
if (!setup_timer_lpds_wake()) {
// lpds entering is not possible, wait for the forced interrupt and return
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return;
}
} else {
// disable the timer as wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
}
// do we need network wake-up?
if (pybsleep_data.wlan_obj->irq_enabled) {
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
server_sleep_sockets();
} else {
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
}
// entering and exiting suspended mode must be an atomic operation
// therefore interrupts need to be disabled
uint primsk = disable_irq();
if (nlr_push(&nlr) == 0) {
pyb_sleep_suspend_enter();
nlr_pop();
}
// an exception is always raised when exiting suspend mode
enable_irq(primsk);
}
void pyb_sleep_deepsleep (void) {
// check if we should enable timer wake-up
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
if (!setup_timer_hibernate_wake()) {
// hibernating is not possible, wait for the forced interrupt and return
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return;
}
} else {
// disable the timer as hibernate wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
}
wlan_stop(SL_STOP_TIMEOUT);
pyb_sleep_flash_powerdown();
// must be done just before entering hibernate mode
pyb_sleep_iopark(true);
MAP_PRCMHibernateEnter();
}
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
return pybsleep_reset_cause;
}
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
return pybsleep_wake_reason;
}
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
// search for the object and then remove it
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)(MP_STATE_PORT(pybsleep_obj_list).items[i]));
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
if (sleep_obj->obj == obj) {
return sleep_obj;
}
@@ -258,7 +317,7 @@ STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
return NULL;
}
STATIC void pybsleep_flash_powerdown (void) {
STATIC void pyb_sleep_flash_powerdown (void) {
uint32_t status;
// Enable clock for SSPI module
@@ -303,7 +362,7 @@ STATIC void pybsleep_flash_powerdown (void) {
MAP_SPICSDisable(SSPI_BASE);
}
STATIC NORETURN void pybsleep_suspend_enter (void) {
STATIC NORETURN void pyb_sleep_suspend_enter (void) {
// enable full RAM retention
MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
@@ -340,7 +399,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
mperror_heartbeat_switch_off();
// park the gpio pins
pybsleep_iopark(false);
pyb_sleep_iopark(false);
// store the cpu registers
sleep_store();
@@ -353,7 +412,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
for ( ; ; );
}
void pybsleep_suspend_exit (void) {
void pyb_sleep_suspend_exit (void) {
// take the I2C semaphore
uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
reg = (reg & ~0x3) | 0x1;
@@ -407,13 +466,13 @@ void pybsleep_suspend_exit (void) {
sl_IfOpen (NULL, 0);
// restore the configuration of all active peripherals
pybsleep_obj_wakeup();
pyb_sleep_obj_wakeup();
// reconfigure all the previously enabled interrupts
mpcallback_wake_all();
mp_irq_wake_all();
// we need to init the crypto hash engine again
CRYPTOHASH_Init();
//CRYPTOHASH_Init();
// trigger a sw interrupt
MAP_IntPendSet(INT_PRCM);
@@ -425,25 +484,35 @@ void pybsleep_suspend_exit (void) {
STATIC void PRCMInterruptHandler (void) {
// reading the interrupt status automatically clears the interrupt
if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
// this interrupt is triggered during active mode
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
}
else {
// reconfigure it again (if repeat is true)
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
// need to check if irq's are enabled from the user point of view
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
}
pybsleep_data.rtc_obj->irq_flags = 0;
} else {
// interrupt has been triggered while waking up from LPDS
switch (MAP_PRCMLPDSWakeupCauseGet()) {
case PRCM_LPDS_HOST_IRQ:
mpcallback_handler(pybsleep_data.wlan_lpds_wake_cb);
pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
pybsleep_data.wlan_obj->irq_flags = 0;
break;
case PRCM_LPDS_GPIO:
mpcallback_handler(pybsleep_data.gpio_lpds_wake_cb);
mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
break;
case PRCM_LPDS_TIMER:
// disable the timer as wake-up source
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
// reconfigure it again if repeat is true
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
// next one clears the wake cause flag
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
pybsleep_data.rtc_obj->irq_flags = 0;
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
break;
default:
@@ -452,14 +521,14 @@ STATIC void PRCMInterruptHandler (void) {
}
}
STATIC void pybsleep_obj_wakeup (void) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]);
STATIC void pyb_sleep_obj_wakeup (void) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
sleep_obj->wakeup(sleep_obj->obj);
}
}
STATIC void pybsleep_iopark (bool hibernate) {
STATIC void pyb_sleep_iopark (bool hibernate) {
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
for (uint i = 0; i < named_map->used; i++) {
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
@@ -473,9 +542,9 @@ STATIC void pybsleep_iopark (bool hibernate) {
break;
#endif
default:
// enable a weak pull-down if the pin is unused
// enable a weak pull-up if the pin is unused
if (!pin->used) {
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD);
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
}
if (hibernate) {
// make it an input
@@ -517,191 +586,72 @@ STATIC void pybsleep_iopark (bool hibernate) {
}
STATIC bool setup_timer_lpds_wake (void) {
uint64_t t_match, t_curr, t_remaining;
uint64_t t_match, t_curr;
int64_t t_remaining;
// get the time remaining for the RTC timer to expire
t_match = MAP_PRCMSlowClkCtrMatchGet();
t_curr = MAP_PRCMSlowClkCtrGet();
if (t_match > t_curr) {
// get the time remaining in terms of slow clocks
t_remaining = (t_match - t_curr);
if (t_remaining > WAKEUP_TIME_LPDS) {
// subtract the time it takes for wakeup from lpds
t_remaining -= WAKEUP_TIME_LPDS;
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
// setup the LPDS wake time
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
// enable the wake source
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
return true;
}
}
else {
// setup a timer interrupt immediately
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
// get the time remaining in terms of slow clocks
t_remaining = (t_match - t_curr);
if (t_remaining > WAKEUP_TIME_LPDS) {
// subtract the time it takes to wakeup from lpds
t_remaining -= WAKEUP_TIME_LPDS;
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
// setup the LPDS wake time
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
// enable the wake source
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
return true;
}
// disable the timer as wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
// LPDS wake by timer was not possible, force
// an interrupt in active mode instead
uint32_t f_seconds;
uint16_t f_mseconds;
// setup a timer interrupt immediately
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
// LPDS wake by timer was not possible, force an interrupt in active mode instead
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
return false;
}
STATIC bool setup_timer_hibernate_wake (void) {
uint64_t t_match, t_curr, t_remaining;
uint64_t t_match, t_curr;
int64_t t_remaining;
// get the time remaining for the RTC timer to expire
t_match = MAP_PRCMSlowClkCtrMatchGet();
t_curr = MAP_PRCMSlowClkCtrGet();
if (t_match > t_curr) {
// get the time remaining in terms of slow clocks
t_remaining = (t_match - t_curr);
if (t_remaining > WAKEUP_TIME_HIB) {
// subtract the time it takes for wakeup from hibernate
t_remaining -= WAKEUP_TIME_HIB;
// setup the LPDS wake time
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
// enable the wake source
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
return true;
}
}
else {
// setup a timer interrupt immediately
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
// get the time remaining in terms of slow clocks
t_remaining = (t_match - t_curr);
if (t_remaining > WAKEUP_TIME_HIB) {
// subtract the time it takes for wakeup from hibernate
t_remaining -= WAKEUP_TIME_HIB;
// setup the LPDS wake time
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
// enable the wake source
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
return true;
}
// disable the timer as wake source
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
// hibernate wake by timer was not possible, force
// an interrupt in active mode instead
uint32_t f_seconds;
uint16_t f_mseconds;
// setup a timer interrupt immediately
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
// LPDS wake by timer was not possible, force an interrupt in active mode instead
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
return false;
}
/******************************************************************************/
// Micro Python bindings; Sleep class
/// \function idle()
/// Gates the processor clock until an interrupt is triggered
STATIC mp_obj_t pyb_sleep_idle (mp_obj_t self_in) {
__WFI();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle);
/// \function suspend(wlan)
/// Enters suspended mode. Wake up sources should have been enable prior to
/// calling this method.
STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
nlr_buf_t nlr;
// check if we should enable timer wake-up
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
if (!setup_timer_lpds_wake()) {
// lpds entering is not possible, wait for the forced interrupt and return
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return mp_const_none;
}
}
// do we need network wake-up?
if (pybsleep_data.wlan_lpds_wake_cb) {
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
server_sleep_sockets();
}
else {
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
}
// entering and exiting suspended mode must be an atomic operation
// therefore interrupts need to be disabled
uint primsk = disable_irq();
if (nlr_push(&nlr) == 0) {
pybsleep_suspend_enter();
nlr_pop();
}
// an exception is always raised when exiting suspend mode
enable_irq(primsk);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
/// \function hibernate()
/// Enters hibernate mode. Wake up sources should have been enable prior to
/// calling this method.
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
// check if we should enable timer wake-up
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
if (!setup_timer_hibernate_wake()) {
// hibernating is not possible, wait for the forced interrupt and return
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
HAL_Delay (FAILED_SLEEP_DELAY_MS);
return mp_const_none;
}
}
wlan_stop(SL_STOP_TIMEOUT);
pybsleep_flash_powerdown();
// must be done just before entering hibernate mode
pybsleep_iopark(true);
MAP_PRCMHibernateEnter();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_hibernate_obj, pyb_sleep_hibernate);
/// \function reset_cause()
/// Returns the last reset casue
STATIC mp_obj_t pyb_sleep_reset_cause (mp_obj_t self_in) {
return MP_OBJ_NEW_SMALL_INT(pybsleep_reset_cause);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_reset_cause_obj, pyb_sleep_reset_cause);
/// \function wake_reason()
/// Returns the wake up reson from ldps or hibernate
STATIC mp_obj_t pyb_sleep_wake_reason (mp_obj_t self_in) {
return MP_OBJ_NEW_SMALL_INT(pybsleep_wake_reason);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_wake_reason_obj, pyb_sleep_wake_reason);
STATIC const mp_map_elem_t pybsleep_locals_dict_table[] = {
// instance methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_sleep_idle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_suspend), (mp_obj_t)&pyb_sleep_suspend_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_hibernate), (mp_obj_t)&pyb_sleep_hibernate_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&pyb_sleep_reset_cause_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&pyb_sleep_wake_reason_obj },
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SUSPENDED), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIBERNATING), 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_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_HIB_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
};
STATIC MP_DEFINE_CONST_DICT(pybsleep_locals_dict, pybsleep_locals_dict_table);
STATIC const mp_obj_type_t pybsleep_type = {
{ &mp_type_type },
.name = MP_QSTR_Sleep,
.locals_dict = (mp_obj_t)&pybsleep_locals_dict,
};
const mp_obj_base_t pyb_sleep_obj = {&pybsleep_type};

View File

@@ -54,23 +54,20 @@ typedef enum {
typedef void (*WakeUpCB_t)(const mp_obj_t self);
/******************************************************************************
DECLARE EXPORTED VARIABLES
******************************************************************************/
extern const mp_obj_base_t pyb_sleep_obj;
/******************************************************************************
DECLARE FUNCTIONS
******************************************************************************/
void pybsleep_pre_init (void);
void pybsleep_init0 (void);
void pybsleep_signal_soft_reset (void);
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
void pybsleep_remove (const mp_obj_t obj);
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
void pybsleep_configure_timer_wakeup (uint pwrmode);
pybsleep_reset_cause_t pybsleep_get_reset_cause (void);
void pyb_sleep_pre_init (void);
void pyb_sleep_init0 (void);
void pyb_sleep_signal_soft_reset (void);
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
void pyb_sleep_remove (const mp_obj_t obj);
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj);
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj);
void pyb_sleep_sleep (void);
void pyb_sleep_deepsleep (void);
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void);
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void);
#endif /* PYBSLEEP_H_ */

View File

@@ -201,24 +201,20 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *arg
mp_obj_t pins_o = args[6].u_obj;
if (pins_o != mp_const_none) {
mp_obj_t *pins;
mp_uint_t n_pins = 3;
if (pins_o == MP_OBJ_NULL) {
// use the default pins
pins = (mp_obj_t *)pyb_spi_def_pin;
} else {
mp_obj_get_array(pins_o, &n_pins, &pins);
if (n_pins != 3) {
goto invalid_args;
}
mp_obj_get_array_fixed_n(pins_o, 3, &pins);
}
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
pin_assign_pins_af (pins, 3, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
}
// init the bus
pybspi_init((const pyb_spi_obj_t *)self);
// register it with the sleep module
pybsleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
pyb_sleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
return mp_const_none;
@@ -275,7 +271,7 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
// invalidate the baudrate
pyb_spi_obj.baudrate = 0;
// unregister it with the sleep module
pybsleep_remove((const mp_obj_t)self_in);
pyb_sleep_remove((const mp_obj_t)self_in);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);

View File

@@ -44,8 +44,8 @@
#include "prcm.h"
#include "timer.h"
#include "pybtimer.h"
#include "mpirq.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "mpexception.h"
@@ -96,7 +96,8 @@ typedef struct _pyb_timer_obj_t {
mp_obj_base_t base;
uint32_t timer;
uint32_t config;
uint16_t intflags;
uint16_t irq_trigger;
uint16_t irq_flags;
uint8_t peripheral;
uint8_t id;
} pyb_timer_obj_t;
@@ -114,7 +115,7 @@ typedef struct _pyb_timer_channel_obj_t {
/******************************************************************************
DEFINE PRIVATE DATA
******************************************************************************/
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods;
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods;
STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0},
{.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1},
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
@@ -124,7 +125,7 @@ STATIC const mp_obj_type_t pyb_timer_channel_type;
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
STATIC void timer_disable (pyb_timer_obj_t *tim);
STATIC void TIMER0AIntHandler(void);
STATIC void TIMER0BIntHandler(void);
@@ -142,18 +143,26 @@ void timer_init0 (void) {
mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0);
}
void pyb_timer_channel_callback_enable (mp_obj_t self_in) {
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) {
pyb_timer_channel_obj_t *self = self_in;
MAP_TimerIntClear(self->timer->timer, self->timer->intflags & self->channel);
MAP_TimerIntEnable(self->timer->timer, self->timer->intflags & self->channel);
MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel);
MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel);
}
void pyb_timer_channel_callback_disable (mp_obj_t self_in) {
STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) {
pyb_timer_channel_obj_t *self = self_in;
MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel);
MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel);
}
pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) {
pyb_timer_channel_obj_t *self = self_in;
return self->timer->irq_flags;
}
STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) {
pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i]));
// any 32-bit timer must be matched by any of its 16-bit versions
@@ -164,14 +173,14 @@ pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channe
return MP_OBJ_NULL;
}
void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
pyb_timer_channel_obj_t *channel;
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
}
}
void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
// remove it in case it already exists
pyb_timer_channel_remove(ch);
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
@@ -180,8 +189,8 @@ void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
STATIC void timer_disable (pyb_timer_obj_t *tim) {
// disable all timers and it's interrupts
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
MAP_TimerIntDisable(tim->timer, tim->intflags);
MAP_TimerIntClear(tim->timer, tim->intflags);
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
}
@@ -335,7 +344,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
timer_init(tim);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
pyb_sleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
return mp_const_none;
@@ -470,7 +479,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
timer_channel_init(ch);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
pyb_sleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
// add the timer to the list
pyb_timer_channel_add(ch);
@@ -509,10 +518,11 @@ const mp_obj_type_t pyb_timer_type = {
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
};
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods = {
.init = pyb_timer_channel_callback,
.enable = pyb_timer_channel_callback_enable,
.disable = pyb_timer_channel_callback_disable,
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
.init = pyb_timer_channel_irq,
.enable = pyb_timer_channel_irq_enable,
.disable = pyb_timer_channel_irq_disable,
.flags = pyb_timer_channel_irq_flags,
};
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
@@ -522,8 +532,7 @@ STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
if ((self = pyb_timer_channel_find(timer, channel))) {
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
MAP_TimerIntClear(self->timer->timer, status);
mp_obj_t _callback = mpcallback_find(self);
mpcallback_handler(_callback);
mp_irq_handler(mp_irq_find(self));
}
}
@@ -716,130 +725,107 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
/// \method callback(handler, priority, value)
/// create a callback object associated with the timer channel
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
/// \method irq(trigger, priority, handler, wake)
/// FIXME triggers!!
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
pyb_timer_channel_obj_t *ch = pos_args[0];
mp_obj_t _callback = mpcallback_find(ch);
if (kw_args->used > 0) {
// convert the priority to the correct value
uint priority = mpcallback_translate_priority (args[2].u_int);
// validate the power mode
uint pwrmode = args[4].u_int;
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
goto invalid_args;
}
// convert the priority to the correct value
uint priority = mp_irq_translate_priority (args[1].u_int);
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
uint32_t c_value = mp_obj_get_int(args[3].u_obj);
// validate and set the value if we are in edge count mode
if (_config == TIMER_CFG_A_CAP_COUNT) {
if (!c_value || c_value > 0xFFFF) {
// zero or exceeds the maximum value of a 16-bit timer
goto invalid_args;
}
MAP_TimerMatchSet(ch->timer->timer, ch->channel, c_value);
}
// disable the callback first
pyb_timer_channel_callback_disable(ch);
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
switch (_config) {
case TIMER_CFG_A_ONE_SHOT:
case TIMER_CFG_A_PERIODIC:
ch->timer->intflags |= TIMER_TIMA_TIMEOUT << shift;
break;
case TIMER_CFG_A_CAP_COUNT:
ch->timer->intflags |= TIMER_CAPA_MATCH << shift;
// set the match value and make 1 the minimum
MAP_TimerMatchSet(ch->timer->timer, ch->channel, MAX(1, c_value));
break;
case TIMER_CFG_A_CAP_TIME:
ch->timer->intflags |= TIMER_CAPA_EVENT << shift;
break;
case TIMER_CFG_A_PWM:
// special case for the PWM match interrupt
ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
break;
default:
break;
}
// special case for a 32-bit timer
if (ch->channel == (TIMER_A | TIMER_B)) {
ch->timer->intflags |= (ch->timer->intflags << 8);
}
void (*pfnHandler)(void);
uint32_t intregister;
switch (ch->timer->timer) {
case TIMERA0_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER0BIntHandler;
intregister = INT_TIMERA0B;
} else {
pfnHandler = &TIMER0AIntHandler;
intregister = INT_TIMERA0A;
}
break;
case TIMERA1_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER1BIntHandler;
intregister = INT_TIMERA1B;
} else {
pfnHandler = &TIMER1AIntHandler;
intregister = INT_TIMERA1A;
}
break;
case TIMERA2_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER2BIntHandler;
intregister = INT_TIMERA2B;
} else {
pfnHandler = &TIMER2AIntHandler;
intregister = INT_TIMERA2A;
}
break;
default:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER3BIntHandler;
intregister = INT_TIMERA3B;
} else {
pfnHandler = &TIMER3AIntHandler;
intregister = INT_TIMERA3A;
}
break;
}
// register the interrupt and configure the priority
MAP_IntPrioritySet(intregister, priority);
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
// create the callback
_callback = mpcallback_new (ch, args[1].u_obj, &pyb_timer_channel_cb_methods, true);
// reload the timer
uint32_t period_c;
uint32_t match;
compute_prescaler_period_and_match_value(ch, &period_c, &match);
MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c);
// enable the callback before returning
pyb_timer_channel_callback_enable(ch);
} else if (!_callback) {
_callback = mpcallback_new (ch, mp_const_none, &pyb_timer_channel_cb_methods, false);
// validate the power mode
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
goto invalid_args;
}
return _callback;
// disable the callback first
pyb_timer_channel_irq_disable(ch);
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
switch (_config) {
case TIMER_CFG_A_ONE_SHOT:
case TIMER_CFG_A_PERIODIC:
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
break;
case TIMER_CFG_A_CAP_COUNT:
ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift;
break;
case TIMER_CFG_A_CAP_TIME:
ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift;
break;
case TIMER_CFG_A_PWM:
// special case for the PWM match interrupt
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
break;
default:
break;
}
// special case for a 32-bit timer
if (ch->channel == (TIMER_A | TIMER_B)) {
ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8);
}
void (*pfnHandler)(void);
uint32_t intregister;
switch (ch->timer->timer) {
case TIMERA0_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER0BIntHandler;
intregister = INT_TIMERA0B;
} else {
pfnHandler = &TIMER0AIntHandler;
intregister = INT_TIMERA0A;
}
break;
case TIMERA1_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER1BIntHandler;
intregister = INT_TIMERA1B;
} else {
pfnHandler = &TIMER1AIntHandler;
intregister = INT_TIMERA1A;
}
break;
case TIMERA2_BASE:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER2BIntHandler;
intregister = INT_TIMERA2B;
} else {
pfnHandler = &TIMER2AIntHandler;
intregister = INT_TIMERA2A;
}
break;
default:
if (ch->channel == TIMER_B) {
pfnHandler = &TIMER3BIntHandler;
intregister = INT_TIMERA3B;
} else {
pfnHandler = &TIMER3AIntHandler;
intregister = INT_TIMERA3A;
}
break;
}
// register the interrupt and configure the priority
MAP_IntPrioritySet(intregister, priority);
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
// create the callback
mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods);
// enable the callback before returning
pyb_timer_channel_irq_enable(ch);
return _irq;
invalid_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_channel_callback);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq);
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
// instance methods
@@ -849,7 +835,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
};
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);

View File

@@ -45,9 +45,9 @@
#include "prcm.h"
#include "uart.h"
#include "pybuart.h"
#include "mpirq.h"
#include "pybioctl.h"
#include "pybsleep.h"
#include "mpcallback.h"
#include "mpexception.h"
#include "py/mpstate.h"
#include "osi.h"
@@ -55,6 +55,7 @@
#include "pin.h"
#include "pybpin.h"
#include "pins.h"
#include "moduos.h"
/// \moduleref pyb
/// \class UART - duplex serial communication bus
@@ -64,18 +65,18 @@
*******-***********************************************************************/
#define PYBUART_FRAME_TIME_US(baud) ((11 * 1000000) / baud)
#define PYBUART_2_FRAMES_TIME_US(baud) (PYBUART_FRAME_TIME_US(baud) * 2)
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud))
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud) * 8) // we need at least characters in the FIFO
#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1)
#define PYBUART_TX_MAX_TIMEOUT_MS (5)
#define PYBUART_RX_BUFFER_LEN (128)
#define PYBUART_RX_BUFFER_LEN (256)
// interrupt triggers
#define E_UART_TRIGGER_RX_ANY (0x01)
#define E_UART_TRIGGER_RX_HALF (0x02)
#define E_UART_TRIGGER_RX_FULL (0x04)
#define E_UART_TRIGGER_TX_DONE (0x08)
#define UART_TRIGGER_RX_ANY (0x01)
#define UART_TRIGGER_RX_HALF (0x02)
#define UART_TRIGGER_RX_FULL (0x04)
#define UART_TRIGGER_TX_DONE (0x08)
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
@@ -83,12 +84,12 @@
STATIC void uart_init (pyb_uart_obj_t *self);
STATIC bool uart_rx_wait (pyb_uart_obj_t *self);
STATIC void uart_check_init(pyb_uart_obj_t *self);
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler);
STATIC void UARTGenericIntHandler(uint32_t uart_id);
STATIC void UART0IntHandler(void);
STATIC void UART1IntHandler(void);
STATIC void uart_callback_enable (mp_obj_t self_in);
STATIC void uart_callback_disable (mp_obj_t self_in);
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
STATIC void uart_irq_enable (mp_obj_t self_in);
STATIC void uart_irq_disable (mp_obj_t self_in);
/******************************************************************************
DEFINE PRIVATE TYPES
@@ -105,7 +106,8 @@ struct _pyb_uart_obj_t {
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
byte peripheral;
byte irq_trigger;
bool callback_enabled;
bool irq_enabled;
byte irq_flags;
};
/******************************************************************************
@@ -113,7 +115,7 @@ struct _pyb_uart_obj_t {
******************************************************************************/
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0},
{.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} };
STATIC const mp_cb_methods_t uart_cb_methods;
STATIC const mp_irq_methods_t uart_irq_methods;
STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} };
@@ -167,37 +169,6 @@ bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) {
return true;
}
void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) {
for (const char *top = str + len; str < top; str++) {
if (*str == '\n') {
uart_tx_char(self, '\r');
}
uart_tx_char(self, *str);
}
}
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger) {
// disable the uart interrupts before updating anything
uart_callback_disable (self);
if (self->uart_id == PYB_UART_0) {
MAP_IntPrioritySet(INT_UARTA0, priority);
MAP_UARTIntRegister(self->reg, UART0IntHandler);
} else {
MAP_IntPrioritySet(INT_UARTA1, priority);
MAP_UARTIntRegister(self->reg, UART1IntHandler);
}
// create the callback
mp_obj_t _callback = mpcallback_new ((mp_obj_t)self, handler, &uart_cb_methods, true);
// enable the interrupts now
self->irq_trigger = trigger;
uart_callback_enable (self);
return _callback;
}
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
@@ -248,24 +219,44 @@ STATIC bool uart_rx_wait (pyb_uart_obj_t *self) {
}
}
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) {
// disable the uart interrupts before updating anything
uart_irq_disable (self);
if (self->uart_id == PYB_UART_0) {
MAP_IntPrioritySet(INT_UARTA0, priority);
MAP_UARTIntRegister(self->reg, UART0IntHandler);
} else {
MAP_IntPrioritySet(INT_UARTA1, priority);
MAP_UARTIntRegister(self->reg, UART1IntHandler);
}
// create the callback
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods);
// enable the interrupts now
self->irq_trigger = trigger;
uart_irq_enable (self);
return _irq;
}
STATIC void UARTGenericIntHandler(uint32_t uart_id) {
pyb_uart_obj_t *self;
uint32_t status;
bool exec_callback = false;
self = &pyb_uart_obj[uart_id];
status = MAP_UARTIntStatus(self->reg, true);
// receive interrupt
if (status & (UART_INT_RX | UART_INT_RT)) {
// set the flags
self->irq_flags = UART_TRIGGER_RX_ANY;
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
while (UARTCharsAvail(self->reg)) {
int data = MAP_UARTCharGetNonBlocking(self->reg);
if (pyb_stdio_uart == self && data == user_interrupt_char) {
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == user_interrupt_char) {
// raise an exception when interrupts are finished
mpexception_keyboard_nlr_jump();
}
// there's always a read buffer available
else {
} else { // there's always a read buffer available
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
if (next_head != self->read_buf_tail) {
// only store data if room in buf
@@ -274,17 +265,16 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
}
}
}
if (self->irq_trigger & E_UART_TRIGGER_RX_ANY) {
exec_callback = true;
}
if (exec_callback && self->callback_enabled) {
// call the user defined handler
mp_obj_t _callback = mpcallback_find(self);
mpcallback_handler(_callback);
}
}
// check the flags to see if the user handler should be called
if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) {
// call the user defined handler
mp_irq_handler(mp_irq_find(self));
}
// clear the flags
self->irq_flags = 0;
}
STATIC void uart_check_init(pyb_uart_obj_t *self) {
@@ -302,19 +292,24 @@ STATIC void UART1IntHandler(void) {
UARTGenericIntHandler(1);
}
STATIC void uart_callback_enable (mp_obj_t self_in) {
STATIC void uart_irq_enable (mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
// check for any of the rx interrupt types
if (self->irq_trigger & (E_UART_TRIGGER_RX_ANY | E_UART_TRIGGER_RX_HALF | E_UART_TRIGGER_RX_FULL)) {
if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) {
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
}
self->callback_enabled = true;
self->irq_enabled = true;
}
STATIC void uart_callback_disable (mp_obj_t self_in) {
STATIC void uart_irq_disable (mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
self->callback_enabled = false;
self->irq_enabled = false;
}
STATIC int uart_irq_flags (mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
return self->irq_flags;
}
/******************************************************************************/
@@ -428,9 +423,11 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a
// initialize and enable the uart
uart_init (self);
// register it with the sleep module
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
// enable the callback
uart_callback_new (self, mp_const_none, INT_PRIORITY_LVL_3, E_UART_TRIGGER_RX_ANY);
uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none);
// disable the irq (from the user point of view)
uart_irq_disable(self);
return mp_const_none;
@@ -439,7 +436,7 @@ error:
}
STATIC const mp_arg_t pyb_uart_init_args[] = {
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} },
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
@@ -455,7 +452,7 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
// work out the uart id
uint uart_id;
if (args[0].u_obj == mp_const_none) {
if (args[0].u_obj == MP_OBJ_NULL) {
if (args[5].u_obj != MP_OBJ_NULL) {
mp_obj_t *pins;
mp_uint_t n_pins = 2;
@@ -501,7 +498,7 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
pyb_uart_obj_t *self = self_in;
// unregister it with the sleep module
pybsleep_remove (self);
pyb_sleep_remove (self);
// invalidate the baudrate
self->baudrate = 0;
// free the read buffer
@@ -531,33 +528,37 @@ STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
STATIC mp_obj_t pyb_uart_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
/// \method irq(trigger, priority, handler, wake)
STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
// check if any parameters were passed
pyb_uart_obj_t *self = pos_args[0];
uart_check_init(self);
mp_obj_t _callback = mpcallback_find((mp_obj_t)self);
if (kw_args->used > 0) {
// convert the priority to the correct value
uint priority = mpcallback_translate_priority (args[2].u_int);
// convert the priority to the correct value
uint priority = mp_irq_translate_priority (args[1].u_int);
// check the power mode
if (PYB_PWR_MODE_ACTIVE != args[4].u_int) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
// register a new callback
// FIXME triggers!!
return uart_callback_new (self, args[1].u_obj, mp_obj_get_int(args[3].u_obj), priority);
} else if (!_callback) {
_callback = mpcallback_new (self, mp_const_none, &uart_cb_methods, false);
// check the power mode
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
if (PYB_PWR_MODE_ACTIVE != pwrmode) {
goto invalid_args;
}
return _callback;
// check the trigger
uint trigger = mp_obj_get_int(args[0].u_obj);
if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) {
goto invalid_args;
}
// register a new callback
return uart_irq_new (self, trigger, priority, args[2].u_obj);
invalid_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_callback);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
// instance methods
@@ -565,7 +566,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_uart_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_irq_obj },
/// \method read([nbytes])
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
@@ -581,7 +582,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(E_UART_TRIGGER_RX_ANY) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
@@ -598,9 +599,9 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
// wait for first char to become available
if (!uart_rx_wait(self)) {
// we can either return 0 to indicate EOF (then read() method returns b'')
// or return EAGAIN error to indicate non-blocking (then read() method returns None)
return 0;
// return EAGAIN error to indicate non-blocking (then read() method returns None)
*errcode = EAGAIN;
return MP_STREAM_ERROR;
}
// read the data
@@ -654,10 +655,11 @@ STATIC const mp_stream_p_t uart_stream_p = {
.is_text = false,
};
STATIC const mp_cb_methods_t uart_cb_methods = {
.init = pyb_uart_callback,
.enable = uart_callback_enable,
.disable = uart_callback_disable,
STATIC const mp_irq_methods_t uart_irq_methods = {
.init = pyb_uart_irq,
.enable = uart_irq_enable,
.disable = uart_irq_disable,
.flags = uart_irq_flags
};
const mp_obj_type_t pyb_uart_type = {

View File

@@ -42,7 +42,5 @@ uint32_t uart_rx_any(pyb_uart_obj_t *uart_obj);
int uart_rx_char(pyb_uart_obj_t *uart_obj);
bool uart_tx_char(pyb_uart_obj_t *self, int c);
bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger);
#endif // PYBUART_H_

View File

@@ -43,6 +43,7 @@
#define MICROPY_HELPER_REPL (1)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
@@ -67,6 +68,7 @@
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#ifndef DEBUG
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
@@ -96,7 +98,7 @@
#define MICROPY_PY_UZLIB (0)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URE (1)
#define MICROPY_PY_UHEAPQ (1)
#define MICROPY_PY_UHEAPQ (0)
#define MICROPY_PY_UHASHLIB (0)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
@@ -112,27 +114,26 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, \
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t pyb_module;
extern const struct _mp_obj_module_t machine_module;
extern const struct _mp_obj_module_t wipy_module;
extern const struct _mp_obj_module_t mp_module_ure;
extern const struct _mp_obj_module_t mp_module_ujson;
extern const struct _mp_obj_module_t mp_module_uheapq;
extern const struct _mp_obj_module_t mp_module_uos;
extern const struct _mp_obj_module_t mp_module_utime;
extern const struct _mp_obj_module_t mp_module_uselect;
extern const struct _mp_obj_module_t mp_module_usocket;
extern const struct _mp_obj_module_t mp_module_network;
extern const struct _mp_obj_module_t mp_module_uhashlib;
extern const struct _mp_obj_module_t mp_module_ubinascii;
extern const struct _mp_obj_module_t mp_module_ussl;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_wipy), (mp_obj_t)&wipy_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_uos }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&mp_module_utime }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uselect), (mp_obj_t)&mp_module_uselect }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii), (mp_obj_t)&mp_module_ubinascii }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_ussl), (mp_obj_t)&mp_module_ussl }, \
@@ -140,30 +141,29 @@ extern const struct _mp_obj_module_t mp_module_ussl;
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&mp_module_uos }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_utime }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
// extra constants
#define MICROPY_PORT_CONSTANTS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
// vm state and root pointers for the gc
#define MP_STATE_PORT MP_STATE_VM
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8]; \
mp_obj_t mp_const_user_interrupt; \
mp_obj_t pyb_config_main; \
mp_obj_list_t pybsleep_obj_list; \
mp_obj_list_t mpcallback_obj_list; \
mp_obj_t machine_config_main; \
mp_obj_list_t pyb_sleep_obj_list; \
mp_obj_list_t mp_irq_obj_list; \
mp_obj_list_t pyb_timer_channel_obj_list; \
mp_obj_list_t mount_obj_list; \
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
struct _os_term_dup_obj_t *os_term_dup_obj; \
// type definitions for the specific machine
@@ -207,7 +207,6 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
#define MICROPY_HAL_H "cc3200_hal.h"
#define MICROPY_PORT_HAS_TELNET (1)
#define MICROPY_PORT_HAS_FTP (1)
#define MICROPY_PORT_WLAN_URN (0)
#define MICROPY_PY_SYS_PLATFORM "WiPy"
#define MICROPY_PORT_WLAN_AP_SSID "wipy-wlan"

View File

@@ -64,10 +64,11 @@
#include "pins.h"
#include "pybsleep.h"
#include "pybtimer.h"
#include "mpcallback.h"
#include "cryptohash.h"
#include "mpirq.h"
#include "updater.h"
#include "moduos.h"
#include "antenna.h"
/******************************************************************************
DECLARE PRIVATE CONSTANTS
@@ -126,8 +127,8 @@ soft_reset:
// execute all basic initializations
mpexception_init0();
mpcallback_init0();
pybsleep_init0();
mp_irq_init0();
pyb_sleep_init0();
pin_init0();
mperror_init0();
uart_init0();
@@ -137,18 +138,7 @@ soft_reset:
moduos_init0();
rng_init0();
#ifdef LAUNCHXL
// instantiate the stdio uart on the default pins
mp_obj_t args[2] = {
mp_obj_new_int(MICROPY_STDIO_UART),
mp_obj_new_int(MICROPY_STDIO_UART_BAUD),
};
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
#else
pyb_stdio_uart = MP_OBJ_NULL;
#endif
pybsleep_reset_cause_t rstcause = pybsleep_get_reset_cause();
pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause();
if (rstcause < PYB_SLP_SOFT_RESET) {
if (rstcause == PYB_SLP_HIB_RESET) {
// when waking up from hibernate we just want
@@ -172,7 +162,7 @@ soft_reset:
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib));
// reset config variables; they should be set by boot.py
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL;
if (!safeboot) {
// run boot.py
@@ -196,10 +186,10 @@ soft_reset:
// run the main script from the current directory.
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
const char *main_py;
if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) {
main_py = "main.py";
} else {
main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main));
}
int ret = pyexec_file(main_py);
if (ret & PYEXEC_FORCED_EXIT) {
@@ -229,12 +219,15 @@ soft_reset:
soft_reset_exit:
// soft reset
pybsleep_signal_soft_reset();
pyb_sleep_signal_soft_reset();
mp_printf(&mp_plat_print, "PYB: soft reboot\n");
// disable all callbacks to avoid undefined behaviour
// when coming out of a soft reset
mpcallback_disable_all();
mp_irq_disable_all();
// cancel the RTC alarm which might be running independent of the irq state
pyb_rtc_disable_alarm();
// flush the serial flash buffer
sflash_disk_flush();
@@ -263,7 +256,7 @@ STATIC void mptask_pre_init (void) {
ASSERT ((sflash_fatfs = mem_Malloc(sizeof(FATFS))) != NULL);
// this one allocates memory for the nvic vault
pybsleep_pre_init();
pyb_sleep_pre_init();
// this one allocates memory for the WLAN semaphore
wlan_pre_init();
@@ -274,7 +267,7 @@ STATIC void mptask_pre_init (void) {
// this one allocates memory for the socket semaphore
modusocket_pre_init();
CRYPTOHASH_Init();
//CRYPTOHASH_Init();
#ifdef DEBUG
ASSERT (OSI_OK == osi_TaskCreate(TASK_Servers,
@@ -357,11 +350,11 @@ STATIC void mptask_init_sflash_filesystem (void) {
STATIC void mptask_enter_ap_mode (void) {
// append the mac only if it's not the first boot
bool append_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
bool add_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
// enable simplelink in ap mode (use the MAC address to make the ssid unique)
wlan_sl_enable (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID), MICROPY_PORT_WLAN_AP_SECURITY,
MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY), MICROPY_PORT_WLAN_AP_CHANNEL, append_mac);
wlan_sl_init (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID),
MICROPY_PORT_WLAN_AP_SECURITY, MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY),
MICROPY_PORT_WLAN_AP_CHANNEL, ANTENNA_TYPE_INTERNAL, add_mac);
}
STATIC void mptask_create_main_py (void) {
@@ -373,10 +366,3 @@ STATIC void mptask_create_main_py (void) {
f_close(&fp);
}
STATIC mp_obj_t pyb_main(mp_obj_t main) {
if (MP_OBJ_IS_STR(main)) {
MP_STATE_PORT(pyb_config_main) = main;
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);

View File

@@ -25,36 +25,54 @@
* THE SOFTWARE.
*/
// qstrs specific to this port
Q(__name__)
Q(help)
Q(pyb)
// for machine module
Q(machine)
#ifdef DEBUG
Q(info)
#endif
Q(reset)
Q(main)
Q(sync)
Q(gc)
Q(rng)
Q(toggle)
Q(write)
Q(input)
Q(freq)
Q(unique_id)
Q(disable_irq)
Q(enable_irq)
Q(flush)
Q(repl_uart)
Q(idle)
Q(sleep)
Q(deepsleep)
Q(reset_cause)
Q(wake_reason)
Q(IDLE)
Q(SLEEP)
Q(DEEPSLEEP)
Q(POWER_ON)
Q(HARD_RESET)
Q(WDT_RESET)
Q(DEEPSLEEP_RESET)
Q(SOFT_RESET)
Q(WLAN_WAKE)
Q(PIN_WAKE)
Q(RTC_WAKE)
// for wipy module
Q(wipy)
Q(heartbeat)
// entries for sys.path
Q(/flash)
Q(/flash/lib)
// interactive help
Q(help)
// for module weak links
Q(struct)
Q(binascii)
Q(re)
Q(json)
Q(heapq)
Q(hashlib)
//Q(hashlib)
// for os module
Q(os)
@@ -81,6 +99,7 @@ Q(urandom)
Q(mkfs)
Q(mount)
Q(unmount)
Q(dupterm)
Q(readonly)
Q(readblocks)
Q(writeblocks)
@@ -90,6 +109,8 @@ Q(count)
// for file class
Q(seek)
Q(tell)
Q(input)
Q(flush)
// for Pin class
Q(Pin)
@@ -176,13 +197,16 @@ Q(pins)
// for RTC class
Q(RTC)
Q(id)
Q(init)
Q(alarm)
Q(alarm_left)
Q(alarm_cancel)
Q(now)
Q(deinit)
Q(datetime)
Q(repeat)
Q(ALARM0)
// for time class
Q(time)
@@ -228,14 +252,11 @@ Q(protocol)
Q(error)
Q(timeout)
Q(AF_INET)
Q(AF_INET6)
Q(SOCK_STREAM)
Q(SOCK_DGRAM)
Q(SOCK_RAW)
Q(IPPROTO_SEC)
Q(IPPROTO_TCP)
Q(IPPROTO_UDP)
Q(IPPROTO_RAW)
// for ssl class
Q(ssl)
@@ -254,84 +275,59 @@ Q(CERT_REQUIRED)
// for network class
Q(network)
Q(server_running)
Q(server_login)
Q(server_timeout)
Q(server)
Q(init)
Q(deinit)
Q(login)
Q(timeout)
Q(isrunning)
// for WLAN class
Q(WLAN)
Q(iwconfig)
Q(key)
Q(security)
Q(id)
Q(init)
Q(mode)
Q(auth)
Q(ssid)
Q(bssid)
Q(mac)
Q(antenna)
Q(scan)
Q(connect)
Q(isconnected)
Q(disconnect)
Q(sec)
Q(channel)
Q(rssi)
Q(ifconfig)
Q(info)
Q(connections)
#if MICROPY_PORT_WLAN_URN
Q(urn)
#endif
Q(mode)
Q(ip)
Q(subnet)
Q(gateway)
Q(dns)
Q(mac)
Q(antenna)
Q(config)
//Q(connections)
//Q(urn)
Q(STA)
Q(AP)
Q(OPEN)
Q(WEP)
Q(WPA)
Q(WPA2)
Q(INTERNAL)
Q(EXTERNAL)
Q(INT_ANT)
Q(EXT_ANT)
Q(ANY_EVENT)
// for WDT class
Q(WDT)
Q(feed)
Q(timeout)
// for HeartBeat class
Q(HeartBeat)
Q(enable)
Q(disable)
// for callback class
// for irq class
Q(irq)
Q(init)
Q(enable)
Q(disable)
Q(callback)
Q(flags)
Q(trigger)
Q(handler)
Q(mode)
Q(value)
Q(priority)
Q(wake_from)
// for Sleep class
Q(Sleep)
Q(idle)
Q(suspend)
Q(hibernate)
Q(reset_cause)
Q(wake_reason)
Q(ACTIVE)
Q(SUSPENDED)
Q(HIBERNATING)
Q(POWER_ON)
Q(HARD_RESET)
Q(WDT_RESET)
Q(HIB_RESET)
Q(SOFT_RESET)
Q(WLAN_WAKE)
Q(PIN_WAKE)
Q(RTC_WAKE)
Q(wake)
// for SPI class
Q(SPI)
@@ -349,7 +345,6 @@ Q(read)
Q(readinto)
Q(write_readinto)
Q(nbytes)
Q(write)
Q(buf)
Q(MASTER)
Q(MSB)
@@ -380,12 +375,12 @@ Q(POSITIVE)
Q(NEGATIVE)
// for uhashlib module
Q(uhashlib)
Q(update)
Q(digest)
//Q(uhashlib)
//Q(update)
//Q(digest)
//Q(md5)
Q(sha1)
Q(sha256)
//Q(sha1)
//Q(sha256)
// for ubinascii module
Q(ubinascii)

View File

@@ -30,6 +30,7 @@
#include "py/mpconfig.h"
#include MICROPY_HAL_H
#include "py/misc.h"
#include "py/nlr.h"
#include "serverstask.h"
#include "simplelink.h"
#include "debug.h"
@@ -37,17 +38,9 @@
#include "ftp.h"
#include "pybwdt.h"
#include "modusocket.h"
#include "mpexception.h"
/******************************************************************************
DECLARE PRIVATE DEFINITIONS
******************************************************************************/
#define SERVERS_DEF_USER "micro"
#define SERVERS_DEF_PASS "python"
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
/******************************************************************************
DEFINE PRIVATE TYPES
******************************************************************************/
@@ -144,7 +137,7 @@ void TASK_Servers (void *pvParameters) {
void servers_start (void) {
servers_data.do_enable = true;
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
HAL_Delay (SERVERS_CYCLE_TIME_MS * 3);
}
void servers_stop (void) {
@@ -152,7 +145,7 @@ void servers_stop (void) {
do {
HAL_Delay (SERVERS_CYCLE_TIME_MS);
} while (servers_are_enabled());
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
HAL_Delay (SERVERS_CYCLE_TIME_MS * 3);
}
void servers_reset (void) {
@@ -177,16 +170,19 @@ void servers_close_socket (int16_t *sd) {
}
void servers_set_login (char *user, char *pass) {
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX);
memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX);
}
bool servers_set_timeout (uint32_t timeout) {
void servers_set_timeout (uint32_t timeout) {
if (timeout < SERVERS_MIN_TIMEOUT_MS) {
return false;
// timeout is too low
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
servers_data.timeout = timeout;
return true;
}
uint32_t servers_get_timeout (void) {

View File

@@ -36,10 +36,15 @@
#define SERVERS_SSID_LEN_MAX 16
#define SERVERS_KEY_LEN_MAX 16
#define SERVERS_USER_PASS_LEN_MAX 16
#define SERVERS_USER_PASS_LEN_MAX 32
#define SERVERS_CYCLE_TIME_MS 2
#define SERVERS_DEF_USER "micro"
#define SERVERS_DEF_PASS "python"
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
/******************************************************************************
DEFINE TYPES
******************************************************************************/
@@ -61,7 +66,7 @@ extern bool servers_are_enabled (void);
extern void servers_close_socket (int16_t *sd);
extern void servers_set_login (char *user, char *pass);
extern void server_sleep_sockets (void);
extern bool servers_set_timeout (uint32_t timeout);
extern void servers_set_timeout (uint32_t timeout);
extern uint32_t servers_get_timeout (void);
#endif /* SERVERSTASK_H_ */

View File

@@ -457,7 +457,7 @@ OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned portBASE_TYPE uxPriority)
ASSERT (xSimpleLinkSpawnQueue != NULL);
ASSERT (pdPASS == xTaskCreate( vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN",\
736 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
896 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
return OSI_OK;
}

View File

@@ -108,7 +108,7 @@ typedef struct {
DECLARE PRIVATE DATA
******************************************************************************/
static telnet_data_t telnet_data;
static const char* telnet_welcome_msg = "Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
static const char* telnet_request_user = "Login as: ";
static const char* telnet_request_password = "Password: ";
static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n";
@@ -244,34 +244,14 @@ void telnet_run (void) {
}
void telnet_tx_strn (const char *str, int len) {
if (len > 0 && telnet_data.n_sd > 0) {
if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
telnet_send_with_retries(telnet_data.n_sd, str, len);
}
}
void telnet_tx_strn_cooked (const char *str, uint len) {
int32_t nslen = 0;
const char *_str = str;
for (int i = 0; i < len; i++) {
if (str[i] == '\n') {
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
telnet_send_with_retries(telnet_data.n_sd, "\r\n", 2);
_str += nslen + 1;
nslen = 0;
}
else {
nslen++;
}
}
if (_str < str + len) {
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
}
}
bool telnet_rx_any (void) {
return (telnet_data.n_sd > 0) ? ((telnet_data.rxRindex != telnet_data.rxWindex) &&
(telnet_data.state == E_TELNET_STE_LOGGED_IN)) : false;
return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
}
int telnet_rx_char (void) {
@@ -300,14 +280,6 @@ void telnet_reset (void) {
telnet_data.state = E_TELNET_STE_START;
}
bool telnet_is_enabled (void) {
return telnet_data.enabled;
}
bool telnet_is_active (void) {
return (telnet_data.state == E_TELNET_STE_LOGGED_IN);
}
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/

View File

@@ -33,13 +33,10 @@
extern void telnet_init (void);
extern void telnet_run (void);
extern void telnet_tx_strn (const char *str, int len);
extern void telnet_tx_strn_cooked (const char *str, uint len);
extern bool telnet_rx_any (void);
extern int telnet_rx_char (void);
extern void telnet_enable (void);
extern void telnet_disable (void);
extern void telnet_reset (void);
extern bool telnet_is_enabled (void);
extern bool telnet_is_active (void);
#endif /* TELNET_H_ */

View File

@@ -1,4 +1,6 @@
import pyb
from machine import Pin
from machine import RTC
import time
import os
"""
@@ -13,31 +15,31 @@ test_bytes = os.urandom(1024)
def test_pin_read (pull):
# enable the pull resistor on all pins, then read the value
for p in pin_map:
pin = pyb.Pin('GP' + str(p), mode=pyb.Pin.IN, pull=pull)
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull)
# read the pin value
print(pin())
def test_pin_shorts (pull):
if pull == pyb.Pin.PULL_UP:
pull_inverted = pyb.Pin.PULL_DOWN
if pull == Pin.PULL_UP:
pull_inverted = Pin.PULL_DOWN
else:
pull_inverted = pyb.Pin.PULL_UP
pull_inverted = Pin.PULL_UP
# enable all pulls of the specified type
for p in pin_map:
pin = pyb.Pin('GP' + str(p), mode=pyb.Pin.IN, pull=pull_inverted)
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull_inverted)
# then change the pull one pin at a time and read its value
i = 0
while i < len(pin_map):
pin = pyb.Pin('GP' + str(pin_map[i]), mode=pyb.Pin.IN, pull=pull)
pyb.Pin('GP' + str(pin_map[i - 1]), mode=pyb.Pin.IN, pull=pull_inverted)
pin = Pin('GP' + str(pin_map[i]), mode=Pin.IN, pull=pull)
Pin('GP' + str(pin_map[i - 1]), mode=Pin.IN, pull=pull_inverted)
i += 1
# read the pin value
print(pin())
test_pin_read(pyb.Pin.PULL_UP)
test_pin_read(pyb.Pin.PULL_DOWN)
test_pin_shorts(pyb.Pin.PULL_UP)
test_pin_shorts(pyb.Pin.PULL_DOWN)
test_pin_read(Pin.PULL_UP)
test_pin_read(Pin.PULL_DOWN)
test_pin_shorts(Pin.PULL_UP)
test_pin_shorts(Pin.PULL_DOWN)
# create a test directory
os.mkdir('/flash/test')
@@ -62,12 +64,12 @@ print('test' not in ls)
print(ls)
# test the real time clock
rtc = pyb.RTC()
rtc = RTC()
while rtc.now()[6] > 800:
pass
time1 = rtc.now()
pyb.delay(1000)
time.sleep_ms(1000)
time2 = rtc.now()
print(time2[5] - time1[5] == 1)
print(time2[6] - time1[6] < 5000) # microseconds

View File

@@ -17,6 +17,7 @@ Or:
import sys
import argparse
import time
import socket
from ftplib import FTP
from telnetlib import Telnet
@@ -89,9 +90,9 @@ def reset_board(args):
time.sleep(1)
tn.write(b'\r\x02') # ctrl-B: enter friendly REPL
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
tn.write(b"import pyb\r\n")
tn.write(b"pyb.reset()\r\n")
time.sleep(1)
tn.write(b"import machine\r\n")
tn.write(b"machine.reset()\r\n")
time.sleep(2)
print("Reset performed")
success = True
else:
@@ -121,12 +122,23 @@ def verify_update(args):
print("Error: verification failed, the git tag doesn't match")
return False
try:
# Specify a longer time out value here because the board has just been
# reset and the wireless connection might not be fully established yet
tn = Telnet(args.ip, timeout=15)
print("Connected via telnet again, lets check the git tag")
retries = 0
while True:
try:
# Specify a longer time out value here because the board has just been
# reset and the wireless connection might not be fully established yet
tn = Telnet(args.ip, timeout=10)
print("Connected via telnet again, lets check the git tag")
break
except socket.timeout:
if retries < 5:
print("Timeout while connecting via telnet, retrying...")
retries += 1
else:
print('Error: Telnet connection timed out!')
return False
try:
firmware_tag = tn.read_until (b'with CC3200')
tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h'
@@ -170,10 +182,9 @@ def main():
if reset_board(args):
if args.verify:
print ('Waiting for the WiFi connection to come up again...')
# this time is to allow the system's wireless network card to connect to the
# WiPy again. Sometimes it might only take a couple of seconds, but let's
# leave 15s to be on the safe side
time.sleep(15)
# this time is to allow the system's wireless network card to
# connect to the WiPy again.
time.sleep(5)
if verify_update(args):
result = 0
else:

View File

@@ -32,14 +32,13 @@
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "rom_map.h"
#include "prcm.h"
#include "pybrtc.h"
#include "simplelink.h"
#include "modnetwork.h"
#include "modwlan.h"
#include "random.h"
#include "debug.h"
/******************************************************************************
* LOCAL TYPES
******************************************************************************/
@@ -57,20 +56,23 @@ static uint32_t s_seed;
/******************************************************************************
* LOCAL FUNCTION DECLARATIONS
******************************************************************************/
static uint32_t lfsr (uint32_t input);
STATIC uint32_t lfsr (uint32_t input);
/******************************************************************************
* PRIVATE FUNCTIONS
******************************************************************************/
static uint32_t lfsr (uint32_t input) {
STATIC uint32_t lfsr (uint32_t input) {
assert( input != 0 );
return (input >> 1) ^ (-(input & 0x01) & 0x00E10000);
}
STATIC mp_obj_t pyb_rng_get(void) {
/******************************************************************************/
// Micro Python bindings;
STATIC mp_obj_t machine_rng_get(void) {
return mp_obj_new_int(rng_get());
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
MP_DEFINE_CONST_FUN_OBJ_0(machine_rng_get_obj, machine_rng_get);
/******************************************************************************
* PUBLIC FUNCTIONS
@@ -81,7 +83,7 @@ void rng_init0 (void) {
uint16_t mseconds;
// get the seconds and the milliseconds from the RTC
MAP_PRCMRTCGet(&seconds, &mseconds);
pyb_rtc_get_time(&seconds, &mseconds);
wlan_get_mac (juggler.id8);

View File

@@ -30,6 +30,6 @@
void rng_init0 (void);
uint32_t rng_get (void);
MP_DECLARE_CONST_FUN_OBJ(pyb_rng_get_obj);
MP_DECLARE_CONST_FUN_OBJ(machine_rng_get_obj);
#endif // __RANDOM_H

View File

@@ -7,7 +7,7 @@
@ global variable with the backup registers
.extern vault_arm_registers
@ global function that performs the wake up actions
.extern pybsleep_suspend_exit
.extern pyb_sleep_suspend_exit
@ uint sleep_store(void)
.global sleep_store
@@ -58,4 +58,4 @@ sleep_restore:
msr basepri, r0
dsb
isb
bl pybsleep_suspend_exit
bl pyb_sleep_suspend_exit

View File

@@ -27,6 +27,6 @@
#ifndef VERSION_H_
#define VERSION_H_
#define WIPY_SW_VERSION_NUMBER "0.9.1"
#define WIPY_SW_VERSION_NUMBER "1.1.0"
#endif /* VERSION_H_ */

View File

@@ -58,9 +58,9 @@ copyright = '2014, Damien P. George'
# built documents.
#
# The short X.Y version.
version = '1.4'
version = '1.5'
# The full version, including alpha/beta/rc tags.
release = '1.4.6'
release = '1.5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -300,6 +300,11 @@ html_context = {
# Append the other ports' specific folders/files to the exclude pattern
exclude_patterns.extend([port + '*' for port in ports if port != micropy_port])
# Exclude pyb module if the port is the WiPy
if micropy_port == 'wipy':
exclude_patterns.append('library/pyb*')
else: # exclude machine
exclude_patterns.append('library/machine*')
# Specify a custom master document based on the port name
master_doc = micropy_port + '_' + 'index'

View File

@@ -10,18 +10,12 @@ The ``esp`` module contains specific functions related to the ESP8266 module.
Functions
---------
.. function:: status()
.. function:: mac([address])
Return the current status of the wireless connection.
Get or set the network interface's MAC address.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection susccessful.
If the ``address`` parameter is provided, sets the address to its value. If
the function is called wihout parameters, returns the current address.
.. function:: getaddrinfo((hostname, port, lambda))
@@ -31,6 +25,61 @@ Functions
called with two arguments, first being the hostname being resolved,
second a tuple with information about that hostname.
.. function:: wifi_mode([mode])
Get or set the wireless network operating mode.
If the ``mode`` parameter is provided, sets the mode to its value. If
the function is called wihout parameters, returns the current mode.
The possible modes are defined as constants:
* ``STA_MODE`` -- station mode,
* ``AP_MODE`` -- software access point mode,
* ``STA_AP_MODE`` -- mixed station and software access point mode.
.. function:: phy_mode([mode])
Get or set the network interface mode.
If the ``mode`` parameter is provided, sets the mode to its value. If
the function is called wihout parameters, returns the current mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
.. function:: sleep_type([sleep_type])
Get or set the sleep type.
If the ``sleep_type`` parameter is provided, sets the sleep type to its
value. If the function is called wihout parameters, returns the current
sleep type.
The possible sleep types are defined as constants:
* ``SLEEP_NONE`` -- all functions enabled,
* ``SLEEP_MODEM`` -- modem sleep, shuts down the WiFi Modem circuit.
* ``SLEEP_LIGHT`` -- light sleep, shuts down the WiFi Modem circuit
and suspends the processor periodically.
The system enters the set sleep mode automatically when possible.
.. function:: deepsleep(time=0)
Enter deep sleep.
The whole module powers down, except for the RTC clock circuit, which can
be used to restart the module after the specified time if the pin 16 is
connected to the reset pin. Otherwise the module will sleep until manually
reset.
.. function:: flash_id()
Read the device ID of the flash memory.
Classes
-------

View File

@@ -74,12 +74,12 @@ it will fallback to loading the built-in ``ujson`` module.
Libraries specific to the pyboard
---------------------------------
The following libraries are specific to the pyboard.
.. toctree::
:maxdepth: 2
pyb.rst
network.rst
@@ -87,13 +87,12 @@ it will fallback to loading the built-in ``ujson`` module.
.. toctree::
:maxdepth: 1
ubinascii.rst
uhashlib.rst
uheapq.rst
ujson.rst
ure.rst
usocket.rst
ussl.rst
.. only:: port_wipy
@@ -105,8 +104,9 @@ it will fallback to loading the built-in ``ujson`` module.
.. toctree::
:maxdepth: 2
pyb.rst
machine.rst
network.rst
wipy.rst
.. only:: port_esp8266

View File

@@ -0,0 +1,73 @@
.. _machine.ADC:
class ADC -- analog to digital conversion
=========================================
Usage::
import machine
adc = machine.ADC() # create an ADC object
apin = adc.channel(pin='GP3') # create an analog pin on GP3
val = apin() # read an analog value
Constructors
------------
.. class:: machine.ADC(id=0, \*, bits=12)
Create an ADC object associated with the given pin.
This allows you to then read analog values on that pin.
For more info check the `pinout and alternate functions
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
.. warning::
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
then the maximum allowed input is 3.6V.
Methods
-------
.. method:: adc.channel(id, \*, pin)
Create an analog pin. If only channel ID is given, the correct pin will
be selected. Alternatively, only the pin can be passed and the correct
channel will be selected. Examples::
# all of these are equivalent and enable ADC channel 1 on GP3
apin = adc.channel(1)
apin = adc.channel(pin='GP3')
apin = adc.channel(id=1, pin='GP3')
.. method:: adc.init()
Enable the ADC block.
.. method:: adc.deinit()
Disable the ADC block.
class ADCChannel --- read analog values from internal or external sources
=========================================================================
ADC channels can be connected to internal points of the MCU or to GPIO pins.
ADC channels are created using the ADC.channel method.
.. method:: adcchannel()
Fast method to read the channel value.
.. method:: adcchannel.value()
Read the channel value.
.. method:: adcchannel.init()
Re-init (and effectively enable) the ADC channel.
.. method:: adcchannel.deinit()
Disable the ADC channel.

View File

@@ -0,0 +1,117 @@
.. _machine.I2C:
class I2C -- a two-wire serial protocol
=======================================
I2C is a two-wire protocol for communicating between devices. At the physical
level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
I2C objects are created attached to a specific bus. They can be initialised
when created, or initialised later on.
.. only:: port_wipy
Example::
from machine import I2C
i2c = I2C(0) # create on bus 0
i2c = I2C(0, I2C.MASTER) # create and init as a master
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
i2c.deinit() # turn off the peripheral
Printing the i2c object gives you information about its configuration.
.. only:: port_wipy
A master must specify the recipient's address::
i2c.init(I2C.MASTER)
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
i2c.writeto(addr=0x42, b'456') # keyword for address
Master also has other methods::
i2c.scan() # scan for slaves on the bus, returning
# a list of valid addresses
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
# starting at address 2 in the slave
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
# starting at address 2 in the slave, timeout after 1 second
Constructors
------------
.. only:: port_wipy
.. class:: machine.I2C(bus, ...)
Construct an I2C object on the given bus. `bus` can only be 0.
If the bus is not given, the default one will be selected (0).
Methods
-------
.. method:: i2c.deinit()
Turn off the I2C bus.
.. only:: port_wipy
.. method:: i2c.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
Initialise the I2C bus with the given parameters:
- ``mode`` must be ``I2C.MASTER``
- ``baudrate`` is the SCL clock rate
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
.. method:: i2c.readfrom(addr, nbytes)
Read ``nbytes`` from the slave specified by ``addr``.
Returns a ``bytes`` object with the data read.
.. method:: i2c.readfrom_into(addr, buf)
Read into ``buf`` from the slave specified by ``addr``.
Returns the number of bytes read.
.. method:: i2c.writeto(addr, buf, \*, stop=True)
Write ``buf`` to the slave specified by ``addr``. Set ``stop`` to ``False``
if the transfer should be continued.
Returns the number of bytes written.
.. method:: i2c.readfrom_mem(addr, memaddr, nbytes, \*, addrsize=8)
Read ``nbytes`` from the slave specified by ``addr`` starting from the memory
address specified by ``memaddr``.
Param ``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)
Read into ``buf`` from the slave specified by ``addr`` starting from the memory
address specified by ``memaddr``.
Param ``addrsize`` specifies the address size in bits.
Returns the number of bytes read.
.. method:: i2c.writeto_mem(addr, memaddr, buf, \*, addrsize=8)
Write ``buf`` to the slave specified by ``addr`` starting from the
memory address specified by ``memaddr``. Param ``addrsize`` specifies the
address size in bits.
Set ``stop`` to ``False`` if the transfer should be continued.
Returns the number of bytes written.
.. method:: i2c.scan()
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
Only valid when in master mode.
Constants
---------
.. data:: I2C.MASTER
for initialising the bus to master mode

View File

@@ -0,0 +1,209 @@
.. _machine.Pin:
class Pin -- control I/O pins
=============================
A pin is the basic object to control I/O pins. It has methods to set
the mode of the pin (input, output, etc) and methods to get and set the
digital logic level. For analog control of a pin, see the ADC class.
Usage Model:
.. only:: port_wipy
Board pins are identified by their string id::
from machine import Pin
g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1)
You can also configure the Pin to generate interrupts. For instance::
from machine import Pin
def pincb(pin):
print(pin.id())
pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN)
pin_int.irq(mode=Pin.IRQ_RISING, handler=pincb)
# the callback can be triggered manually
pin_int.irq()()
# to disable the callback
pin_int.irq().disable()
Now every time a falling edge is seen on the gpio pin, the callback will be
executed. Caution: mechanical push buttons have "bounce" and pushing or
releasing a switch will often generate multiple edges.
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
explanation, along with various techniques for debouncing.
All pin objects go through the pin mapper to come up with one of the
gpio pins.
Constructors
------------
.. class:: machine.Pin(id, ...)
Create a new Pin object associated with the id. If additional arguments are given,
they are used to initialise the pin. See :meth:`pin.init`.
Methods
-------
.. only:: port_wipy
.. method:: pin.init(mode, pull, \*, drive, alt)
Initialise the pin:
- ``mode`` can be one of:
- ``Pin.IN`` - input pin.
- ``Pin.OUT`` - output pin in push-pull mode.
- ``Pin.OPEN_DRAIN`` - output pin in open-drain mode.
- ``Pin.ALT`` - pin mapped to an alternate function.
- ``Pin.ALT_OPEN_DRAIN`` - pin mapped to an alternate function in open-drain mode.
- ``pull`` can be one of:
- ``None`` - no pull up or down resistor.
- ``Pin.PULL_UP`` - pull up resistor enabled.
- ``Pin.PULL_DOWN`` - pull down resitor enabled.
- ``drive`` can be one of:
- ``Pin.LOW_POWER`` - 2mA drive capability.
- ``Pin.MED_POWER`` - 4mA drive capability.
- ``Pin.HIGH_POWER`` - 6mA drive capability.
- ``alt`` is the number of the alternate function. Please refer to the
`pinout and alternate functions table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
for the specific alternate functions that each pin supports.
Returns: ``None``.
.. method:: pin.id()
Get the pin id.
.. method:: pin.value([value])
Get or set the digital logic level of the pin:
- With no argument, return 0 or 1 depending on the logic level of the pin.
- With ``value`` given, set the logic level of the pin. ``value`` can be
anything that converts to a boolean. If it converts to ``True``, the pin
is set high, otherwise it is set low.
.. method:: pin.alt_list()
Returns a list of the alternate functions supported by the pin. List items are
a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)``
.. only:: port_wipy
.. method:: pin([value])
Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin.
See **pin.value** for more details.
.. method:: pin.toggle()
Toggle the value of the pin.
.. method:: pin.mode([mode])
Get or set the pin mode.
.. method:: pin.pull([pull])
Get or set the pin pull.
.. method:: pin.drive([drive])
Get or set the pin drive strength.
.. method:: pin.irq(\*, trigger, priority=1, handler=None, wake=None)
Create a callback to be triggered when the input level at the pin changes.
- ``trigger`` configures the pin level which can generate an interrupt. Possible values are:
- ``Pin.IRQ_FALLING`` interrupt on falling edge.
- ``Pin.IRQ_RISING`` interrupt on rising edge.
- ``Pin.IRQ_LOW_LEVEL`` interrupt on low level.
- ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level.
The values can be *ORed* together, for instance mode=Pin.IRQ_FALLING | Pin.IRQ_RISING
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` is an optional function to be called when new characters arrive.
- ``wakes`` selects the power mode in which this interrupt can wake up the
board. Please note:
- If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board.
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1
of this pins can be enabled as a wake source at the same time, so, only
the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect.
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the
6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time.
- Values can be ORed to make a pin generate interrupts in more than one power
mode.
Returns a callback object.
Attributes
----------
.. class:: Pin.board
Contains all ``Pin`` objects supported by the board. Examples::
Pin.board.GP25
led = Pin(Pin.board.GP25, mode=Pin.OUT)
Pin.board.GP2.alt_list()
Constants
---------
.. only:: port_wipy
.. data:: Pin.IN
.. data:: Pin.OUT
.. data:: Pin.OPEN_DRAIN
.. data:: Pin.ALT
.. data:: Pin.ALT_OPEN_DRAIN
Selects the pin mode.
.. data:: Pin.PULL_UP
.. data:: Pin.PULL_DOWN
Selectes the wether there's pull up/down resistor.
.. data:: Pin.LOW_POWER
.. data:: Pin.MED_POWER
.. data:: Pin.HIGH_POWER
Selects the drive strength.
.. data:: Pin.IRQ_FALLING
.. data:: Pin.IRQ_RISING
.. data:: Pin.IRQ_LOW_LEVEL
.. data:: Pin.IRQ_HIGH_LEVEL
Selects the IRQ trigger type.

View File

@@ -0,0 +1,68 @@
.. _machine.RTC:
class RTC -- real time clock
============================
The RTC is and independent clock that keeps track of the date
and time.
Example usage::
rtc = machine.RTC()
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
print(rtc.datetime())
Constructors
------------
.. class:: machine.RTC(id=0, ...)
Create an RTC object. See init for parameters of initialization.
Methods
-------
.. method:: rtc.init(id, datetime)
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
.. method:: rtc.now()
Get get the current datetime tuple.
.. method:: rtc.deinit()
Resets the RTC to the time of January 1, 2015 and starts running it again.
.. method:: rtc.alarm(id, time, /*, repeat=False)
Set the RTC alarm. Time might be either a milllisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
.. method:: rtc.alarm_left(alarm_id=0)
Get the number of milliseconds left before the alarm expires.
.. method:: rtc.cancel(alarm_id=0)
Cancel a running alarm.
.. method:: rtc.irq(\*, trigger, handler=None, wake=machine.IDLE)
Create an irq object triggered by a real time clock alarm.
- ``trigger`` must be ``RTC.ALARM0``
- ``handler`` is the function to be called when the callback is triggered.
- ``wake`` specifies the sleep mode from where this interrupt can wake
up the system.
Constants
---------
.. data:: RTC.ALARM0
irq trigger source

View File

@@ -1,4 +1,4 @@
.. _pyb.SD:
.. _machine.SD:
class SD -- secure digital memory card
======================================
@@ -13,36 +13,29 @@ more info regarding the pins which can be remapped to be used with a SD card.
Example usage::
# data, clk and cmd pins must be passed along with
from machine import SD
import os
# clk cmd and dat0 pins must be passed along with
# their respective alternate functions
sd = pyb.SD(('GP15', 8, 'GP10', 6, 'GP11', 6))
sd.mount()
sd = machine.SD(pins=('GP10', 'GP11', 'GP15'))
os.mount(sd, '/sd')
# do normal file operations
Constructors
------------
.. class:: pyb.SD([pins_tuple])
.. class:: machine.SD(id,... )
Create a SD card object. In order to initalize the card, give it a 6-tuple
``(dat_pin, dat_af, clk_pin, clk_af, cmd_pin, cmd_af)`` with the data, clock
and cmd pins together their respective alternate functions.
Create a SD card object. See ``init()`` for parameters if initialization.
Methods
-------
.. method:: sd.init([pins_tuple])
.. method:: sd.init(id=0, pins=('GP10', 'GP11', 'GP15'))
Enable the SD card.
Enable the SD card. In order to initalize the card, give it a 3-tuple:
``(clk_pin, cmd_pin, dat0_pin)``.
.. method:: sd.deinit()
Disable the SD card (also unmounts it to avoid file system crashes).
.. method:: sd.mount()
Mount the SD card on the file system. Accesible as ``/sd``.
.. method:: sd.unmount()
Unmount the SD card from the file system.
Disable the SD card.

View File

@@ -0,0 +1,85 @@
.. _machine.SPI:
class SPI -- a master-driven serial protocol
============================================
SPI is a serial protocol that is driven by a master. At the physical level
there are 3 lines: SCK, MOSI, MISO.
.. only:: port_wipy
See usage model of I2C; SPI is very similar. Main difference is
parameters to init the SPI bus::
from machine import SPI
spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
Only required parameter is mode, must be SPI.MASTER. Polarity can be 0 or
1, and is the level the idle clock line sits at. Phase can be 0 or 1 to
sample data on the first or second clock edge respectively.
Constructors
------------
.. only:: port_wipy
.. class:: machine.SPI(id, ...)
Construct an SPI object on the given bus. ``id`` can be only 0.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
Methods
-------
.. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO))
Initialise the SPI bus with the given parameters:
- ``mode`` must be ``SPI.MASTER``.
- ``baudrate`` is the SCK clock rate.
- ``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`` is the width of each transfer, accepted values are 8, 16 and 32.
- ``firstbit`` can be ``SPI.MSB`` only.
- ``pins`` is an optional tupple with the pins to assign to the SPI bus.
.. method:: spi.deinit()
Turn off the SPI bus.
.. method:: spi.write(buf)
Write the data contained in ``buf``.
Returns the number of bytes written.
.. method:: spi.read(nbytes, *, write=0x00)
Read the ``nbytes`` while writing the data specified by ``write``.
Return the number of bytes read.
.. method:: spi.readinto(buf, *, write=0x00)
Read into the buffer specified by ``buf`` while writing the data specified by
``write``.
Return the number of bytes read.
.. method:: spi.write_readinto(write_buf, read_buf)
Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the
same length.
Returns the number of bytes written
Constants
---------
.. data:: SPI.MASTER
for initialising the SPI bus to master
.. data:: SPI.MSB
set the first bit to be the most significant bit

View File

@@ -0,0 +1,196 @@
.. _machine.Timer:
class Timer -- control internal timers
======================================
.. only:: port_wipy
.. note::
Contrary with the rest of the API, timer IDs start at 1, not a t zero. This is because
the ``Timer`` API is still provisional. A new MicroPython wide API will come soon.
Timers can be used for a great variety of tasks, calling a function periodically,
counting events, and generating a PWM signal are among the most common use cases.
Each timer consists of 2 16-bit channels and this channels can be tied together to
form 1 32-bit timer. The operating mode needs to be configured per timer, but then
the period (or the frequency) can be independently configured on each channel.
By using the callback method, the timer event can call a Python function.
Example usage to toggle an LED at a fixed frequency::
from machine import Timer
tim = Timer(4) # create a timer object using timer 4
tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
Example using named function for the callback::
from machine import Timer
tim = Timer(1, mode=Timer.PERIODIC)
tim_a = tim.channel(Timer.A, freq=1000)
led = Pin('GPIO2', mode=Pin.OUT)
def tick(timer): # we will receive the timer object when being called
print(timer.time()) # show current timer's time value (is microseconds)
led.toggle() # toggle the LED
tim_a.callback(handler=tick)
Further examples::
from machine import Timer
tim1 = Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
tim2 = Timer(1, mode=Timer.PWM) # initialize it in PWM mode
tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
tim_ch.time() # get the current time in usec (can also be set)
tim_ch.freq(20) # set the frequency (can also get)
tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
tim_ch.event_count() # get the number of captured events
tim_ch.event_time() # get the the time of the last captured event
tim_ch.period(2000000) # change the period to 2 seconds
.. note::
Memory can't be allocated inside irq handlers (an interrupt) and so
exceptions raised within a handler don't give much information. See
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
limitation.
Constructors
------------
.. class:: machine.Timer(id, ...)
.. only:: port_wipy
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 4.
Methods
-------
.. only:: port_wipy
.. method:: timer.init(mode, \*, width=16)
Initialise the timer. Example::
tim.init(Timer.PERIODIC) # periodic 16-bit timer
tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.ONE_SHOT`` - The timer runs once until the configured
period of the channel expires.
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
frequency of the channel.
- ``Timer.EDGE_TIME`` - Meaure the time pin level changes.
- ``Timer.EDGE_COUNT`` - Count the number of pin level changes.
- ``width`` must be either 16 or 32 (bits). For really low frequencies <= ~1Hz
(or large periods), 32-bit timers should be used. 32-bit mode is only available
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
.. method:: timer.deinit()
Deinitialises the timer. Disables all channels and associated IRQs.
Stops the timer, and disables the timer peripheral.
.. only:: port_wipy
.. method:: timer.channel(channel, \**, freq, period, polarity=Timer.POSITIVE, duty_cycle=0)
If only a channel identifier passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Othwerwise, a TimerChannel object is initialized and returned.
The operating mode is is the one configured to the Timer object that was used to
create the channel.
- ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.
Keyword only arguments:
- ``freq`` sets the frequency in Hz.
- ``period`` sets the period in microseconds.
.. note::
Either ``freq`` or ``period`` must be given, never both.
- ``polarity`` this is applicable for:
- ``PWM``, defines the polarity of the duty cycle
- ``EDGE_TIME`` and ``EDGE_COUNT``, defines the polarity of the pin level change to detect.
To detect both rising and falling edges, make ``polarity=Timer.POSITIVE | Timer.NEGATIVE``.
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0-100)
class TimerChannel --- setup a channel for a timer
==================================================
Timer channels are used to generate/capture a signal using a timer.
TimerChannel objects are created using the Timer.channel() method.
Methods
-------
.. only:: port_wipy
.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None)
The behavior of this callback is heaviliy dependent on the operating
mode of the timer channel:
- If mode is ``Timer.PERIODIC`` the callback is executed periodically
with the configured frequency or period.
- If mode is ``Timer.ONE_SHOT`` the callback is executed once when
the configured timer expires.
- If mode is ``Timer.PWM`` the callback is executed when reaching the duty
cycle value.
The accepted params are:
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` is an optional function to be called when the interrupt is triggered.
Returns a callback object.
.. only:: port_wipy
.. method:: timerchannel.freq([value])
Get or set the timer channel frequency (in Hz).
.. method:: timerchannel.period([value])
Get or set the timer channel period (in microseconds).
.. method:: timerchannel.time([value])
Get or set the timer channel current **time** value (in microseconds).
.. method:: timerchannel.event_count()
Get the number of edge events counted.
.. method:: timerchannel.event_time()
Get the time of ocurrance of the last event.
.. method:: timerchannel.duty_cycle([value])
Get or set the duty cycle of the PWM signal (in the range of 0-100).

View File

@@ -0,0 +1,170 @@
.. _machine.UART:
class UART -- duplex serial communication bus
=============================================
UART implements the standard UART/USART duplex serial communications protocol. At
the physical level it consists of 2 lines: RX and TX. The unit of communication
is a character (not to be confused with a string character) which can be 8 or 9
bits wide.
UART objects can be created and initialised using::
from machine import UART
uart = UART(1, 9600) # init with given baudrate
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
.. only:: port_machineoard
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
only 7 and 8 bits are supported.
.. only:: port_wipy
Bits can be 5, 6, 7, 8. Parity can be ``None``, ``UART.EVEN`` or ``UART.ODD``. Stop can be 1 or 2.
A UART object acts like a stream object and reading and writing is done
using the standard stream methods::
uart.read(10) # read 10 characters, returns a bytes object
uart.readall() # read all available characters
uart.readline() # read a line
uart.readinto(buf) # read and store into the given buffer
uart.write('abc') # write the 3 characters
.. only:: port_machineoard
Individual characters can be read/written using::
uart.readchar() # read 1 character and returns it as an integer
uart.writechar(42) # write 1 character
To check if there is anything to be read, use::
uart.any() # returns True if any characters waiting
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
Earlier versions use ``uart.send`` and ``uart.recv``.
.. only:: port_wipy
To check if there is anything to be read, use::
uart.any() # returns the number of characters available for reading
Constructors
------------
.. only:: port_wipy
.. class:: machine.UART(bus, ...)
Construct a UART object on the given bus. ``bus`` can be 0 or 1.
If the bus is not given, the default one will be selected (0) or the selection
will be made based on the given pins.
Methods
-------
.. only:: port_wipy
.. method:: uart.init(baudrate=9600, bits=8, parity=None, stop=1, \*, pins=(TX, RX, RTS, CTS))
Initialise the UART bus with the given parameters:
- ``baudrate`` is the clock rate.
- ``bits`` is the number of bits per character, 7, 8 or 9.
- ``parity`` is the parity, ``None``, ``UART.EVEN`` or ``UART.ODD``.
- ``stop`` is the number of stop bits, 1 or 2.
- ``pins`` is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If pins=None, no pin assignment will be made.
.. method:: uart.deinit()
Turn off the UART bus.
.. method:: uart.any()
Return the number of characters available for reading.
.. method:: uart.read([nbytes])
Read characters. If ``nbytes`` is specified then read at most that many bytes.
Return value: a bytes object containing the bytes read in. Returns ``b''``
on timeout.
.. method:: uart.readall()
Read as much data as possible.
Return value: a bytes object.
.. method:: uart.readinto(buf[, nbytes])
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
Return value: number of bytes read and stored into ``buf``.
.. method:: uart.readline()
Read a line, ending in a newline character.
Return value: the line read.
.. method:: uart.write(buf)
Write the buffer of bytes to the bus.
Return value: number of bytes written.
.. method:: uart.sendbreak()
Send a break condition on the bus. This drives the bus low for a duration
of 13 bits.
Return value: ``None``.
.. only:: port_wipy
.. method:: uart.irq(trigger, priority=1, handler=None, wake=machine.IDLE)
Create a callback to be triggered when data is received on the UART.
- ``trigger`` can only be ``UART.RX_ANY``
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` an optional function to be called when new characters arrive.
- ``wake`` can only be ``machine.IDLE``.
.. note::
The handler will be called whenever any of the following two conditions are met:
- 8 new characters have been received.
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
silent for the duration of 1 complete frame.
This means that when the handler function is called there will be between 1 to 8
characters waiting.
Returns an irq object.
Constants
---------
.. data:: UART.EVEN
.. data:: UART.ODD
parity types (anlong with ``None``)
.. data:: UART.RX_ANY
IRQ trigger sources

View File

@@ -1,22 +1,23 @@
.. _pyb.WDT:
.. _machine.WDT:
class WDT -- watchdog timer
===========================
The WDT is used to restart the system when the application crashes and ends
up into a non recoverable state. Once started it cannot be stopped or
reconfigured in any way. After enabling, the application must "kick" the
reconfigured in any way. After enabling, the application must "feed" the
watchdog periodically to prevent it from expiring and resetting the system.
Example usage::
wdt = pyb.WDT(timeout=2000) # enable with a timeout of 2s
from machine import WDT
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
wdt.feed()
Constructors
------------
.. class:: pyb.WDT(id=0, timeout=5000)
.. class:: machine.WDT(id=0, timeout=5000)
Create a WDT object and start it. The timeout must be given in seconds and
the minimum value that is accepted is 1 second. Once it is running the timeout

131
docs/library/machine.rst Normal file
View File

@@ -0,0 +1,131 @@
:mod:`machine` --- functions related to the board
=================================================
.. module:: machine
:synopsis: functions related to the board
The ``machine`` module contains specific functions related to the board.
Reset related functions
-----------------------
.. function:: reset()
Resets the WiPy in a manner similar to pushing the external RESET
button.
.. function:: reset_cause()
Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values.
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.
.. function:: enable_irq(state=True)
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.
Power related functions
-----------------------
.. function:: freq()
Returns a tuple of clock frequencies: ``(sysclk,)``
These correspond to:
- sysclk: frequency of the CPU
.. function:: idle()
Gates the clock to the CPU, useful to reduce power consumption at any time during
short or long periods. Peripherals continue working and execution resumes as soon
as any interrupt is triggered (including the systick which has a period of 1ms).
Current consumption is reduced to ~12mA (in WLAN STA mode)
.. function:: sleep()
Stops the CPU and disables all peripherals except for WLAN. Execution is resumed from
the point where the sleep was requested. Wake sources are ``Pin``, ``RTC`` and ``WLAN``.
Current consumption is reduced to 950uA (in WLAN STA mode).
.. function:: deepsleep()
Stops the CPU and all peripherals including WLAN. Execution is resumed from main, just
as with a reset. The reset cause can be checked to know that we are coming from
from ``machine.DEEPSLEEP``. Wake sources are ``Pin`` and ``RTC``. Current consumption
is reduced to ~5uA.
.. function:: wake_reason()
Get the wake reason. See :ref:`constants <machine_constants>` for the possible return values.
Miscellaneous functions
-----------------------
.. function:: main(filename)
Set the filename of the main script to run after boot.py is finished. If
this function is not called then the default file main.py will be executed.
It only makes sense to call this function from within boot.py.
.. function:: rng()
Return a 24-bit software generated random number.
.. function:: unique_id()
Returns a string of 6 bytes (48 bits), which is the unique ID of the MCU.
This also corresponds to the ``MAC address`` of the WiPy.
.. _machine_constants:
Constants
---------
.. data:: machine.IDLE
.. data:: machine.SLEEP
.. data:: machine.DEEPSLEEP
irq wake values
.. data:: machine.POWER_ON
.. data:: machine.HARD_RESET
.. data:: machine.WDT_RESET
.. data:: machine.DEEPSLEEP_RESET
.. data:: machine.SOFT_RESET
reset causes
.. data:: machine.WLAN_WAKE
.. data:: machine.PIN_WAKE
.. data:: machine.RTC_WAKE
wake reasons
Classes
-------
.. toctree::
:maxdepth: 1
machine.ADC.rst
machine.I2C.rst
machine.Pin.rst
machine.RTC.rst
machine.SD.rst
machine.SPI.rst
machine.Timer.rst
machine.UART.rst
machine.WDT.rst

View File

@@ -27,6 +27,44 @@ For example::
data = s.recv(1000)
s.close()
.. only:: port_wipy
.. _network.server:
class server
============
The server class controls the behaviour and the configuration of the FTP and telnet
services running on the WiPy. Any changes performed using this class' methods will
affect both.
Constructors
------------
.. class:: network.server(id, ...)
Create a server instance, see ``init`` for parameters of initialization.
Methods
-------
.. method:: server.init(\*, login=('micro', 'python'), timeout=300)
Init (and effectively start the server). Optionally a new ``user``, ``password``
and ``timeout`` (in seconds) can be passed.
.. method:: server.deinit()
Stop the server
.. method:: server.timeout([timeout_in_seconds])
Get or set the server timeout.
.. method:: server.isrunning()
Returns ``True`` is the server is running, ``False`` otherwise.
.. only:: port_pyboard
class CC3K
@@ -178,13 +216,13 @@ For example::
Dump the WIZnet5x00 registers. Useful for debugging.
class WLAN
==========
.. _network.WLAN:
.. only:: port_esp8266
class WLAN
==========
This class provides a driver for WiFi network processor in the ESP8266. Example usage::
import network
@@ -236,17 +274,41 @@ class WLAN
* 0 -- visible
* 1 -- hidden
.. method:: status()
Return the current status of the wireless connection.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection susccessful.
.. method:: wlan.isconnected()
In case of STA mode, returns ``True`` if connected to a wifi access
point and has a valid IP address. In AP mode returns ``True`` when a
station is connected. Returns ``False`` otherwise.
.. only:: port_wipy
class WLAN
==========
This class provides a driver for WiFi network processor in the WiPy. Example usage::
import network
import time
# setup as a station
nic = network.WLAN(mode=WLAN.STA)
nic.connect('your-ssid', security=WLAN.WPA2, key='your-key')
while not nic.isconnected():
pyb.delay(50)
print(nic.ifconfig())
wlan = network.WLAN(mode=WLAN.STA)
wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key'))
while not wlan.isconnected():
time.sleep_ms(50)
print(wlan.ifconfig())
# now use socket as usual
...
@@ -254,14 +316,22 @@ class WLAN
Constructors
------------
.. class:: WLAN(..)
.. class:: WLAN(id=0, ...)
Create a WLAN object, and optionally configure it. See ``iwconfig`` for params of configuration.
Create a WLAN object, and optionally configure it. See ``init`` for params of configuration.
.. note::
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
it will return the already exisiting ``WLAN`` instance without re-configuring it. This is
because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not
initialized it will do the same as the other constructors an will initialize it with default
values.
Methods
-------
.. method:: iwconfig(\*, mode, ssid, security, key, channel, antenna)
.. method:: wlan.init(mode, \*, ssid, auth, channel, antenna)
Set or get the WiFi network processor configuration.
@@ -269,101 +339,111 @@ class WLAN
- ``mode`` can be either ``WLAN.STA`` or ``WLAN.AP``.
- ``ssid`` is a string with the ssid name. Only needed when mode is ``WLAN.AP``.
- ``security`` can be ``WLAN.OPEN``, ``WLAN.WEP``, ``WLAN.WPA`` or ``WLAN.WPA2``.
Only needed when mode is ``WLAN.AP``.
- ``key`` is a string with the network password. Not needed when mode is ``WLAN.STA``
or security is ``WLAN.OPEN``. If ``security`` is ``WLAN.WEP`` the key must be a
string representing hexadecimal values (e.g. 'ABC1DE45BF').
- ``auth`` is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``.
- ``channel`` a number in the range 1-11. Only needed when mode is ``WLAN.AP``.
- ``antenna`` selects between the internal and the external antenna. Can be either
``WLAN.INTERNAL`` or ``WLAN.EXTERNAL``.
``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``.
For example, you can do::
# create and configure as an access point
nic.iwconfig(mode=WLAN.AP, ssid='wipy-wlan', security=WLAN.WPA2, key='www.wipy.io', channel=7, antenna=WLAN.INTERNAL)
wlan.init(mode=WLAN.AP, ssid='wipy-wlan', auth=(WLAN.WPA2,'www.wipy.io'), channel=7, antenna=WLAN.INT_ANT)
or::
# configure as an station
nic.iwconfig(mode=WLAN.STA)
wlan.init(mode=WLAN.STA)
With no arguments given, the current configuration is returned as a namedtuple that looks like this:
``(mode=2, ssid='wipy-wlan', security=2, key='www.wipy.io', channel=5, antenna=0)``
.. method:: wlan.connect(ssid, \*, auth=None, bssid=None, timeout=5000)
.. method:: wlan.connect(ssid, \*, security=WLAN.OPEN, key=None, bssid=None, timeout=5000)
Connect to a wifi access point using the given SSID, and other security
parameters.
- ``key`` is always a string, but if ``security`` is ``WLAN.WEP`` the key must be a string
representing hexadecimal values (e.g. 'ABC1DE45BF').
- ``bssid`` is the MAC address of the AP to connect to. Useful when there are several APs
with the same ssid.
- ``auth`` is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``
- ``bssid`` is the MAC address of the AP to connect to. Useful when there are several
APs with the same ssid.
- ``timeout`` is the maximum time in milliseconds to wait for the connection to succeed.
.. method:: wlan.scan()
Performs a network scan and returns a list of named tuples with (ssid, bssid, security, channel, rssi).
Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi).
Note that channel is always ``None`` since this info is not provided by the WiPy.
.. method:: wlan.disconnect()
Disconnect from the wifi access point.
.. method:: wlan.isconnected()
In case of STA mode, returns ``True`` if connected to a wifi access point and has a valid IP address.
In AP mode returns ``True`` when a station is connected. Returns ``False`` otherwise.
.. method:: wlan.ifconfig(['dhcp' or configtuple])
With no parameters given eturns a 4-tuple of ``(ip, subnet mask, gateway, DNS server)``.
In AP mode returns ``True`` when a station is connected, ``False`` otherwise.
.. method:: wlan.ifconfig(if_id=0, config=['dhcp' or configtuple])
With no parameters given eturns a 4-tuple of ``(ip, subnet_mask, gateway, DNS_server)``.
if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params
are negotiated with the AP.
if the 4-tuple config is given then a static IP is configured. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
.. method:: wlan.mac()
Returns a 6-byte long bytes object with the MAC address.
.. method:: wlan.connections()
Returns a list of the devices currently connected. Each item in the list is a
tuple of ``(ssid, mac)``.
If the 4-tuple config is given then a static IP is configured. For instance::
.. method:: wlan.callback(wake_from)
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
Create a callback to be triggered when a WLAN event occurs during ``pyb.Sleep.SUSPENDED``
.. method:: wlan.mode([mode])
Get or set the WLAN mode.
.. method:: wlan.ssid([ssid])
Get or set the SSID when in AP mode.
.. method:: wlan.auth([auth])
Get or set the authentication type when in AP mode.
.. method:: wlan.channel([channel])
Get or set the channel (only applicable in AP mode).
.. method:: wlan.antenna([antenna])
Get or set the antenna type (external or internal).
.. method:: wlan.mac([mac_addr])
Get or set a 6-byte long bytes object with the MAC address.
.. method:: wlan.irq(\*, handler, wake)
Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP``
mode. Events are triggered by socket activity or by WLAN connection/disconnection.
- ``wake_from`` must be ``pyb.Sleep.SUSPENDED``.
- ``handler`` is the function that gets called when the irq is triggered.
- ``wake`` must be ``machine.SLEEP``.
Returns a callback object.
Returns an irq object.
Constants
---------
.. data:: WLAN.STA
WiFi station mode
.. data:: WLAN.AP
WiFi access point mode
selects the WLAN mode
.. data:: WLAN.OPEN
.. data:: WLAN.WEP
.. data:: WLAN.WPA
.. data:: WLAN.WPA2
selects the network security
.. data:: WLAN.INTERNAL
.. data:: WLAN.EXTERNAL
.. data:: WLAN.INT_ANT
.. data:: WLAN.EXT_ANT
selects the antenna type

View File

@@ -71,9 +71,27 @@ Functions
.. only:: port_wipy
.. function:: mkfs(drive)
Formats the specified drive, must be either ``/flash`` or ``/sd``.
.. function:: mount(block_device, mount_point, \*, readonly=False)
Mounts a block device (like an ``SD`` object) in the specified mount
point. Example::
os.mount(sd, '/sd')
.. function:: unmount(path)
Unmounts a prevoulsy mounted block device from the given path.
.. function:: mkfs(block_device or path)
Formats the specified path, must be either ``/flash`` or ``/sd``.
A block device can also be passed like an ``SD`` object before
being mounted.
.. function:: dupterm(stream_object)
Duplicate the terminal (the REPL) on the passed stream-like object.
The given object must at least implement the ``.read()`` and ``.write()`` methods.
Constants
---------

View File

@@ -18,16 +18,6 @@ class ADC -- analog to digital conversion
val = adc.read_core_vbat() # read MCU VBAT
val = adc.read_core_vref() # read MCU VREF
.. only:: port_wipy
Usage::
import pyb
adc = pyb.ADC() # create an ADC object
apin = adc.channel(pin='GP3') # create an analog pin on GP3
val = apin() # read an analog value
Constructors
------------
@@ -39,22 +29,6 @@ Constructors
Create an ADC object associated with the given pin.
This allows you to then read analog values on that pin.
.. only:: port_wipy
.. class:: pyb.ADC(id=0, \*, bits=12)
Create an ADC object associated with the given pin.
This allows you to then read analog values on that pin.
For more info check the `pinout and alternate functions
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
.. warning::
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
then the maximum allowed input is 3.6V.
Methods
-------
@@ -100,48 +74,3 @@ Methods
This function does not allocate any memory.
.. only:: port_wipy
.. method:: adc.channel(id, *, pin)
Create an analog pin. If only channel ID is given, the correct pin will be selected. Alternatively,
only the pin can be passed and the correct channel will be selected. Examples::
# all of these are equivalent and enable ADC channel 1 on GP3
apin = adc.channel(1)
apin = adc.channel(pin='GP3')
apin = adc.channel(id=1, pin='GP3')
.. method:: adc.init()
Enable the ADC block.
.. method:: adc.deinit()
Disable the ADC block.
.. only:: port_wipy
class ADCChannel --- read analog values from internal or external sources
=========================================================================
.. only:: port_wipy
ADC channels can be connected to internal points of the MCU or to GPIO pins.
ADC channels are created using the ADC.channel method.
.. method:: adcchannel()
Fast method to read the channel value.
.. method:: adcchannel.value()
Read the channel value.
.. method:: adcchannel.init()
Re-init (and effectively enable) the ADC channel.
.. method:: adcchannel.deinit()
Disable the ADC channel.

View File

@@ -15,6 +15,9 @@ Example usage::
dac = DAC(1) # create DAC 1 on pin X5
dac.write(128) # write a value to the DAC (makes X5 1.65V)
dac = DAC(1, bits=12) # use 12 bit resolution
dac.write(4095) # output maximum value, 3.3V
To output a continuous sine-wave::
import math
@@ -23,27 +26,46 @@ To output a continuous sine-wave::
# create a buffer containing a sine-wave
buf = bytearray(100)
for i in range(len(buf)):
buf[i] = 128 + int(127 \* math.sin(2 \* math.pi \* i / len(buf)))
buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))
# output the sine-wave at 400Hz
dac = DAC(1)
dac.write_timed(buf, 400 \* len(buf), mode=DAC.CIRCULAR)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
To output a continuous sine-wave at 12-bit resolution::
import math
from array import array
from pyb import DAC
# create a buffer containing a sine-wave, using half-word samples
buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128))
# output the sine-wave at 400Hz
dac = DAC(1, bits=12)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
Constructors
------------
.. class:: pyb.DAC(port)
.. class:: pyb.DAC(port, bits=8)
Construct a new DAC object.
``port`` can be a pin object, or an integer (1 or 2).
DAC(1) is on pin X5 and DAC(2) is on pin X6.
``bits`` is an integer specifying the resolution, and can be 8 or 12.
The maximum value for the write and write_timed methods will be
2\*\*``bits``-1.
Methods
-------
.. method:: dac.init(bits=8)
Reinitialise the DAC. ``bits`` can be 8 or 12.
.. method:: dac.noise(freq)
Generate a pseudo-random noise signal. A new random sample is written
@@ -57,13 +79,16 @@ Methods
.. method:: dac.write(value)
Direct access to the DAC output (8 bit only at the moment).
Direct access to the DAC output. The minimum value is 0. The maximum
value is 2\*\*``bits``-1, where ``bits`` is set when creating the DAC
object or by using the ``init`` method.
.. method:: dac.write_timed(data, freq, \*, mode=DAC.NORMAL)
Initiates a burst of RAM to DAC using a DMA transfer.
The input data is treated as an array of bytes (8 bit data).
The input data is treated as an array of bytes in 8-bit mode, and
an array of unsigned half-words (array typecode 'H') in 12-bit mode.
``freq`` can be an integer specifying the frequency to write the DAC
samples at, using Timer(6). Or it can be an already-initialised
Timer object which is used to trigger the DAC sample. Valid timers

View File

@@ -1,46 +0,0 @@
.. _pyb.HeartBeat:
class HeartBeat -- heart beat LED
=================================
The HeartBeat class controls the heart beat led which by default
flashes once every 5s. The user can disable the HeartBeat and then
is free to control this LED manually through GP25 using the Pin
class. The GP25 can also be remapped as a PWM output, an this
can be used to control the light intesity of the heart beat LED.
Example usage::
hb = pyb.HeartBeat()
hb.disable() # disable the heart beat
hb.enable() # enable the heart beat
Constructors
------------
.. class:: pyb.HeartBeat()
Create a HeartBeat object.
Methods
-------
.. method:: heartbeat.enable()
Enable the heart beat. The LED will flash once every 5 seconds.
.. method:: heartbeat.disable()
Disable the heart beat. The LED can then be controlled manually.
Example::
import pyb
# disable the heart beat
pyb.HeartBeat().disable()
# get the GP25 pin object
hbl = pyb.Pin('GP25')
# toggle the led
hbl.toggle()
...

View File

@@ -21,17 +21,6 @@ when created, or initialised later on.
i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
i2c.deinit() # turn off the peripheral
.. only:: port_wipy
Example::
from pyb import I2C
i2c = I2C(0) # create on bus 0
i2c = I2C(0, I2C.MASTER) # create and init as a master
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
i2c.deinit() # turn off the peripheral
Printing the i2c object gives you information about its configuration.
.. only:: port_pyboard
@@ -67,23 +56,6 @@ Printing the i2c object gives you information about its configuration.
i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of slave 0x42
# starting at address 2 in the slave, timeout after 1 second
.. only:: port_wipy
A master must specify the recipient's address::
i2c.init(I2C.MASTER)
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
i2c.writeto(addr=0x42, b'456') # keyword for address
Master also has other methods::
i2c.scan() # scan for slaves on the bus, returning
# a list of valid addresses
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
# starting at address 2 in the slave
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
# starting at address 2 in the slave, timeout after 1 second
Constructors
------------
@@ -102,13 +74,6 @@ Constructors
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
.. only:: port_wipy
.. class:: pyb.I2C(bus, ...)
Construct an I2C object on the given bus. `bus` can only be 0.
If the bus is not given, the default one will be selected (0).
Methods
-------
@@ -179,54 +144,6 @@ Methods
Return value: ``None``.
.. only:: port_wipy
.. method:: i2c.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
Initialise the I2C bus with the given parameters:
- ``mode`` must be ``I2C.MASTER``
- ``baudrate`` is the SCL clock rate
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
.. method:: i2c.readfrom(addr, nbytes)
Read ``nbytes`` from the slave specified by ``addr``.
Returns a ``bytes`` object with the data read.
.. method:: i2c.readfrom_into(addr, buf)
Read into ``buf`` from the slave specified by ``addr``.
Returns the number of bytes read.
.. method:: i2c.writeto(addr, buf, \*, stop=True)
Write ``buf`` to the slave specified by ``addr``. Set ``stop`` to ``False``
if the transfer should be continued.
Returns the number of bytes written.
.. method:: i2c.readfrom_mem(addr, memaddr, nbytes, \*, addrsize=8)
Read ``nbytes`` from the slave specified by ``addr`` starting from the memory
address specified by ``memaddr``.
Param ``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)
Read into ``buf`` from the slave specified by ``addr`` starting from the memory
address specified by ``memaddr``.
Param ``addrsize`` specifies the address size in bits.
Returns the number of bytes read.
.. method:: i2c.writeto_mem(addr, memaddr, buf, \*, addrsize=8)
Write ``buf`` to the slave specified by ``addr`` starting from the
memory address specified by ``memaddr``. Param ``addrsize`` specifies the
address size in bits.
Set ``stop`` to ``False`` if the transfer should be continued.
Returns the number of bytes written.
.. method:: i2c.scan()
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.

View File

@@ -63,24 +63,6 @@ Usage Model:
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
respectively (except pin Y5 which has 11k Ohm resistors).
.. only:: port_wipy
Board pins are identified by their string id::
g = pyb.Pin('GP9', mode=pyb.Pin.OUT, pull=None, drive=pyb.Pin.MED_POWER, alt=-1)
You can also configure the Pin to generate interrupts. For instance::
def pincb(pin):
print(pin.id())
pin_int = pyb.Pin('GP10', mode=Pin.IN, pull=pyb.Pin.PULL_DOWN)
pin_int.irq(mode=pyb.Pin.IRQ_RISING, handler=pincb)
# the callback can be triggered manually
pin_int.irq()()
# to disable the callback
pin_int.irq().disable()
Now every time a falling edge is seen on the gpio pin, the callback will be
executed. Caution: mechanical push buttons have "bounce" and pushing or
releasing a switch will often generate multiple edges.
@@ -149,42 +131,6 @@ Methods
Returns: ``None``.
.. only:: port_wipy
.. method:: pin.init(mode, pull, \*, drive, alt)
Initialise the pin:
- ``mode`` can be one of:
- ``Pin.IN`` - input pin.
- ``Pin.OUT`` - output pin in push-pull mode.
- ``Pin.OPEN_DRAIN`` - output pin in open-drain mode.
- ``Pin.ALT`` - pin mapped to an alternate function.
- ``Pin.ALT_OPEN_DRAIN`` - pin mapped to an alternate function in open-drain mode.
- ``pull`` can be one of:
- ``None`` - no pull up or down resistor.
- ``Pin.PULL_UP`` - pull up resistor enabled.
- ``Pin.PULL_DOWN`` - pull down resitor enabled.
- ``drive`` can be one of:
- ``Pin.LOW_POWER`` - 2mA drive capability.
- ``Pin.MED_POWER`` - 4mA drive capability.
- ``Pin.HIGH_POWER`` - 6mA drive capability.
- ``alt`` is the number of the alternate function. Please refer to the
`pinout and alternate functions table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
for the specific alternate functions that each pin supports.
Returns: ``None``.
.. method:: pin.id()
Get the pin id.
.. method:: pin.value([value])
Get or set the digital logic level of the pin:
@@ -238,62 +184,6 @@ Methods
will match one of the allowed constants for the pull argument to the init
function.
.. only:: port_wipy
.. method:: pin([value])
Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin.
See **pin.value** for more details.
.. method:: pin.toggle()
Toggle the value of the pin.
.. method:: pin.mode([mode])
Get or set the pin mode.
.. method:: pin.pull([pull])
Get or set the pin pull.
.. method:: pin.drive([drive])
Get or set the pin drive strength.
.. method:: pin.irq(\*, trigger, priority=1, handler=None, wake=None)
Create a callback to be triggered when the input level at the pin changes.
- ``trigger`` configures the pin level which can generate an interrupt. Possible values are:
- ``Pin.IRQ_FALLING`` interrupt on falling edge.
- ``Pin.IRQ_RISING`` interrupt on rising edge.
- ``Pin.IRQ_LOW_LEVEL`` interrupt on low level.
- ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level.
The values can be *ORed* together, for instance mode=Pin.IRQ_FALLING | Pin.IRQ_RISING
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` is an optional function to be called when new characters arrive.
- ``wakes`` selects the power mode in which this interrupt can wake up the
board. Please note:
- If ``wake_from=pyb.Sleep.ACTIVE`` any pin can wake the board.
- If ``wake_from=pyb.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1
of this pins can be enabled as a wake source at the same time, so, only
the last enabled pin as a ``pyb.Sleep.SUSPENDED`` wake source will have effect.
- If ``wake_from=pyb.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the
6 pins can be enabled as a ``pyb.Sleep.HIBERNATE`` wake source at the same time.
- Values can be ORed to make a pin generate interrupts in more than one power
mode.
Returns a callback object.
Constants
---------
@@ -335,44 +225,6 @@ Constants
enable the pull-up resistor on the pin
.. only:: port_wipy
.. data:: Pin.IN
.. data:: Pin.OUT
.. data:: Pin.OPEN_DRAIN
.. data:: Pin.ALT
.. data:: Pin.ALT_OPEN_DRAIN
Selects the pin mode.
.. data:: Pin.PULL_UP
.. data:: Pin.PULL_DOWN
Selectes the wether there's pull up/down resistor.
.. data:: Pin.LOW_POWER
.. data:: Pin.MED_POWER
.. data:: Pin.HIGH_POWER
Selects the drive strength.
.. data:: Pin.IRQ_FALLING
.. data:: Pin.IRQ_RISING
.. data:: Pin.IRQ_LOW_LEVEL
.. data:: Pin.IRQ_HIGH_LEVEL
Selects the IRQ trigger type.
.. only:: port_pyboard
class PinAF -- Pin Alternate Functions

View File

@@ -41,14 +41,6 @@ Methods
``weekday`` is 1-7 for Monday through Sunday.
``subseconds`` counts down from 255 to 0
.. only:: port_wipy
The 8-tuple has the following format:
``(year, month, day, weekday, hours, minutes, seconds, milliseconds)``
``weekday`` is 0-6 for Monday through Sunday.
.. only:: port_pyboard
@@ -88,14 +80,3 @@ Methods
usable calibration range is:
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
.. only:: port_wipy
.. method:: rtc.callback(\*, value, handler=None, wake_from=pyb.Sleep.ACTIVE)
Create a callback object triggered by a real time clock alarm.
- ``value`` is the alarm timeout in milliseconds. This parameter is required.
- ``handler`` is the function to be called when the callback is triggered.
- ``wake_from`` specifies the power mode from where this interrupt can wake
up the system.

View File

@@ -26,18 +26,6 @@ there are 3 lines: SCK, MOSI, MISO.
spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
.. only:: port_wipy
See usage model of I2C; SPI is very similar. Main difference is
parameters to init the SPI bus::
from pyb import SPI
spi = SPI(1, SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
Only required parameter is mode, must be SPI.MASTER. Polarity can be 0 or
1, and is the level the idle clock line sits at. Phase can be 0 or 1 to
sample data on the first or second clock edge respectively.
Constructors
------------
@@ -59,16 +47,6 @@ Constructors
At the moment, the NSS pin is not used by the SPI driver and is free
for other use.
.. only:: port_wipy
.. class:: pyb.SPI(bus, ...)
Construct an SPI object on the given bus. ``bus`` can be only 1.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
Methods
-------
@@ -102,43 +80,6 @@ Methods
Printing the SPI object will show you the computed baudrate and the chosen
prescaler.
.. only:: port_wipy
.. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO))
Initialise the SPI bus with the given parameters:
- ``mode`` must be ``SPI.MASTER``.
- ``baudrate`` is the SCK clock rate.
- ``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`` is the width of each transfer, accepted values are 8, 16 and 32.
- ``firstbit`` can be ``SPI.MSB`` only.
- ``pins`` is an optional tupple with the pins to assign to the SPI bus.
.. method:: spi.write(buf)
Write the data contained in ``buf``.
Returns the number of bytes written.
.. method:: spi.read(nbytes, *, write=0x00)
Read the ``nbytes`` while writing the data specified by ``write``.
Return the number of bytes read.
.. method:: spi.readinto(buf, *, write=0x00)
Read into the buffer specified by ``buf`` while writing the data specified by
``write``.
Return the number of bytes read.
.. method:: spi.write_readinto(write_buf, read_buf)
Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the
same length.
Returns the number of bytes written
.. only:: port_pyboard
.. method:: spi.recv(recv, \*, timeout=5000)
@@ -187,13 +128,3 @@ Constants
.. data:: SPI.MSB
set the first bit to be the least or most significant bit
.. only:: port_wipy
.. data:: SPI.MASTER
for initialising the SPI bus to master
.. data:: SPI.MSB
set the first bit to be the most significant bit

View File

@@ -41,50 +41,6 @@ class Timer -- control internal timers
the servo driver, and Timer 6 is used for timed ADC/DAC reading/writing.
It is recommended to use the other timers in your programs.
.. only:: port_wipy
Timers can be used for a great variety of tasks, calling a function periodically,
counting events, and generating a PWM signal are among the most common use cases.
Each timer consists of 2 16-bit channels and this channels can be tied together to
form 1 32-bit timer. The operating mode needs to be configured per timer, but then
the period (or the frequency) can be independently configured on each channel.
By using the callback method, the timer event can call a Python function.
Example usage to toggle an LED at a fixed frequency::
tim = pyb.Timer(4) # create a timer object using timer 4
tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
Example using named function for the callback::
tim = Timer(1, mode=Timer.PERIODIC)
tim_a = tim.channel(Timer.A, freq=1000)
led = Pin('GPIO2', af=0, mode=Pin.OUT)
def tick(timer): # we will receive the timer object when being called
print(timer.time()) # show current timer's time value (is microseconds)
led.toggle() # toggle the LED
tim_a.callback(handler=tick)
Further examples::
tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
tim2 = pyb.Timer(1, mode=Timer.PWM) # initialize it in PWM mode
tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
tim_ch.time() # get the current time in usec (can also be set)
tim_ch.freq(20) # set the frequency (can also get)
tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
tim_ch.event_count() # get the number of captured events
tim_ch.event_time() # get the the time of the last captured event
tim_ch.period(2000000) # change the period to 2 seconds
*Note:* Memory can't be allocated during a callback (an interrupt) and so
exceptions raised within a callback don't give much information. See
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
@@ -102,13 +58,6 @@ Constructors
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 14, excluding 3.
.. only:: port_wipy
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 4.
Methods
-------
@@ -161,30 +110,6 @@ Methods
You must either specify freq or both of period and prescaler.
.. only:: port_wipy
.. method:: timer.init(mode, \*, width=16)
Initialise the timer. Example::
tim.init(Timer.PERIODIC) # periodic 16-bit timer
tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.ONE_SHOT`` - The timer runs once until the configured
period of the channel expires.
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
frequency of the channel.
- ``Timer.EDGE_TIME`` - Meaure the time pin level changes.
- ``Timer.EDGE_COUNT`` - Count the number of pin level changes.
- ``width`` must be either 16 or 32 (bits). For really low frequencies <= ~1Hz
(or large periods), 32-bit timers should be used. 32-bit mode is only available
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
.. method:: timer.deinit()
Deinitialises the timer.
@@ -280,37 +205,6 @@ Methods
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
.. only:: port_wipy
.. method:: timer.channel(channel, \**, freq, period, polarity=Timer.POSITIVE, duty_cycle=0)
If only a channel identifier passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Othwerwise, a TimerChannel object is initialized and returned.
The operating mode is is the one configured to the Timer object that was used to
create the channel.
- ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.
Keyword only arguments:
- ``freq`` sets the frequency in Hz.
- ``period`` sets the period in microseconds.
.. note::
Either ``freq`` or ``period`` must be given, never both.
- ``polarity`` this is applicable for:
- ``PWM``, defines the polarity of the duty cycle
- ``EDGE_TIME`` and ``EDGE_COUNT``, defines the polarity of the pin level change to detect.
To detect both rising and falling edges, make ``polarity=Timer.POSITIVE | Timer.NEGATIVE``.
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0-100)
.. only:: port_pyboard
.. method:: timer.counter([value])
@@ -355,32 +249,6 @@ Methods
``fun`` is passed 1 argument, the timer object.
If ``fun`` is ``None`` then the callback will be disabled.
.. only:: port_wipy
.. method:: timerchannel.callback(\**, value, priority=1, handler=None)
The behavior of this callback is heaviliy dependent on the operating
mode of the timer channel:
- If mode is ``Timer.PERIODIC`` the callback is executed periodically
with the configured frequency or period.
- If mode is ``Timer.ONE_SHOT`` the callback is executed once when
the configured timer expires.
- If mode is ``Timer.EDGE_COUNT`` the callback is executed when reaching
the configured number of events (see ``value`` param below).
- If mode is ``Timer.PWM`` the callback is executed when reaching the duty
cycle value.
The accepted params are:
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` is an optional function to be called when the interrupt is triggered.
- ``value`` is **only valid** when in ``Timer.EDGE_COUNT`` mode and is used to set
the number of edge events that will trigger the interrupt.
Returns a callback object.
.. only:: port_pyboard
.. method:: timerchannel.capture([value])
@@ -411,29 +279,3 @@ Methods
for which the pulse is active. The value can be an integer or
floating-point number for more accuracy. For example, a value of 25 gives
a duty cycle of 25%.
.. only:: port_wipy
.. method:: timerchannel.freq([value])
Get or set the timer channel frequency (in Hz).
.. method:: timerchannel.period([value])
Get or set the timer channel period (in microseconds).
.. method:: timerchannel.time([value])
Get or set the timer channel current **time** value (in microseconds).
.. method:: timerchannel.event_count()
Get the number of edge events counted.
.. method:: timerchannel.event_time()
Get the time of ocurrance of the last event.
.. method:: timerchannel.duty_cycle([value])
Get or set the duty cycle of the PWM signal (in the range of 0-100).

View File

@@ -22,11 +22,6 @@ UART objects can be created and initialised using::
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
only 7 and 8 bits are supported.
.. only:: port_wipy
Bits can be 5, 6, 7, 8. Parity can be ``None``, ``UART.EVEN`` or ``UART.ODD``. Stop can be 1 or 2.
A UART object acts like a stream object and reading and writing is done
using the standard stream methods::
@@ -50,12 +45,6 @@ using the standard stream methods::
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
Earlier versions use ``uart.send`` and ``uart.recv``.
.. only:: port_wipy
To check if there is anything to be read, use::
uart.any() # returns the number of characters available for reading
Constructors
------------
@@ -77,14 +66,6 @@ Constructors
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
.. only:: port_wipy
.. class:: pyb.UART(bus, ...)
Construct a UART object on the given bus. ``bus`` can be 0 or 1.
If the bus is not given, the default one will be selected (0) or the selection
will be made based on the given pins.
Methods
-------
@@ -114,22 +95,6 @@ Methods
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
only 7 and 8 bits are supported.
.. only:: port_wipy
.. method:: uart.init(baudrate=9600, bits=8, parity=None, stop=1, \*, pins=(TX, RX, RTS, CTS))
Initialise the UART bus with the given parameters:
- ``baudrate`` is the clock rate.
- ``bits`` is the number of bits per character, 7, 8 or 9.
- ``parity`` is the parity, ``None``, ``UART.EVEN`` or ``UART.ODD``.
- ``stop`` is the number of stop bits, 1 or 2.
- ``pins`` is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If pins=None, no pin assignment will be made.
.. method:: uart.deinit()
Turn off the UART bus.
@@ -145,12 +110,6 @@ Methods
Write a single character on the bus. ``char`` is an integer to write.
Return value: ``None``.
.. only:: port_wipy
.. method:: uart.any()
Return the number of characters available for reading.
.. method:: uart.read([nbytes])
Read characters. If ``nbytes`` is specified then read at most that many bytes.
@@ -163,11 +122,6 @@ Methods
Return value: a bytes object containing the bytes read in. Returns ``b''``
on timeout.
.. only:: port_wipy
Return value: a bytes object containing the bytes read in. Returns ``b''``
on timeout.
.. method:: uart.readall()
Read as much data as possible.
@@ -204,43 +158,12 @@ Methods
Return value: number of bytes written.
.. only:: port_wipy
Write the buffer of bytes to the bus.
Return value: number of bytes written.
.. method:: uart.sendbreak()
Send a break condition on the bus. This drives the bus low for a duration
of 13 bits.
Return value: ``None``.
.. only:: port_wipy
.. method:: uart.callback(value, priority=1, handler=None)
Create a callback to be triggered when data is received on the UART.
- ``value`` sets the size in bytes of the Rx buffer. Every character
received is put into this buffer as long as there's space free.
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` an optional function to be called when new characters arrive.
.. note::
The handler will be called whenever any of the following two conditions are met:
- 4 new characters have been received.
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
silent for the duration of 1 complete frame.
This means that when the handler function is called there might be 1, 2, 3 or 4
characters waiting.
Return a callback object.
Constants
---------
@@ -250,9 +173,3 @@ Constants
.. data:: UART.CTS
to select the flow control type
.. only:: port_wipy
.. data:: UART.RX_ANY
IRQ trigger sources

View File

@@ -63,25 +63,14 @@ Time related functions
Reset related functions
-----------------------
.. only:: port_pyboard
.. function:: hard_reset()
.. function:: hard_reset()
Resets the pyboard in a manner similar to pushing the external RESET
button.
Resets the pyboard in a manner similar to pushing the external RESET
button.
.. only:: port_wipy
.. function:: bootloader()
.. function:: reset()
Resets the WiPy in a manner similar to pushing the external RESET
button.
.. only:: port_pyboard
.. function:: bootloader()
Activate the bootloader without BOOT\* pins.
Activate the bootloader without BOOT\* pins.
Interrupt related functions
---------------------------
@@ -169,20 +158,12 @@ Power related functions
Put the pyboard into a "deep sleep" state.
This reduces power consumption to less than 50 uA. To wake from this
sleep state requires an external interrupt or a real-time-clock event.
sleep state requires a real-time-clock event, or an external interrupt
on X1 (PA0=WKUP) or X18 (PC13=TAMP1).
Upon waking the system undergoes a hard reset.
See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event.
.. only:: port_wipy
.. function:: freq([sysclk])
Returns a tuple of clock frequencies: ``(sysclk)``
These correspond to:
- sysclk: frequency of the CPU
Miscellaneous functions
-----------------------
@@ -255,12 +236,6 @@ Miscellaneous functions
Return a 30-bit hardware generated random number.
.. only:: port_wipy
.. function:: rng()
Return a 24-bit software generated random number.
.. function:: sync()
Sync all file systems.
@@ -271,13 +246,6 @@ Miscellaneous functions
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
.. only:: port_wipy
.. function:: unique_id()
Returns a string of 6 bytes (48 bits), which is the unique ID of the MCU.
This also corresponds to the ``MAC address`` of the WiPy.
Classes
-------
@@ -302,19 +270,3 @@ Classes
pyb.Timer.rst
pyb.UART.rst
pyb.USB_VCP.rst
.. only:: port_wipy
.. toctree::
:maxdepth: 1
pyb.ADC.rst
pyb.HeartBeat.rst
pyb.I2C.rst
pyb.Pin.rst
pyb.RTC.rst
pyb.SD.rst
pyb.SPI.rst
pyb.Timer.rst
pyb.UART.rst
pyb.WDT.rst

View File

@@ -44,6 +44,46 @@ Functions
Sleep for the given number of seconds.
.. only:: port_wipy
.. function:: sleep_ms(ms)
Delay for given number of milliseconds, should be positive or 0.
.. function:: sleep_us(us)
Delay for given number of microseconds, should be positive or 0
.. function:: ticks_ms()
Returns an increasing millisecond counter with arbitrary reference point,
that wraps after some (unspecified) value. The value should be treated as
opaque, suitable for use only with ticks_diff().
.. function:: ticks_us()
Just like ``ticks_ms`` above, but in microseconds.
.. function:: ticks_cpu()
Similar to ``ticks_ms`` and ``ticks_us``, but with higher resolution (usually CPU clocks).
.. function:: ticks_diff(old, new)
Measure period between consecutive calls to ticks_ms(), ticks_us(), or ticks_cpu().
The value returned by these functions may wrap around at any time, so directly
subtracting them is not supported. ticks_diff() should be used instead. "old" value should
actually precede "new" value in time, or result is undefined. This function should not be
used to measure arbitrarily long periods of time (because ticks_*() functions wrap around
and usually would have short period). The expected usage pattern is implementing event
polling with timeout::
# Wait for GPIO pin to be asserted, but at most 500us
start = time.ticks_us()
while pin.value() == 0:
if time.ticks_diff(start, time.ticks_us()) > 500:
raise TimeoutError
.. function:: time()
Returns the number of seconds, as an integer, since 1/1/2000.

View File

@@ -1,17 +1,193 @@
*******************************
:mod:`usocket` -- socket module
===============================
*******************************
.. module:: usocket
:synopsis: socket module
Socket functionality.
This module provides access to the BSD socket interface.
Functions
---------
.. function:: getaddrinfo(host, port)
.. function:: socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
Create a new socket using the given address family, socket type and protocol number.
.. function:: socket(family=AF_INET, type=SOCK_STREAM, fileno=-1)
.. only:: port_wipy
Create a socket.
.. note::
SSL sockets need to be created the following way before wrapping them with
``ssl.wrap_socket``::
import socket
import ssl
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
ss = ssl.wrap_socket(s)
.. function:: socket.getaddrinfo(host, port)
Translate the host/port argument into a sequence of 5-tuples that contain all the
necessary arguments for creating a socket connected to that service. The list of
5-tuples has following structure::
(family, type, proto, canonname, sockaddr)
The following example shows how to connect to a given url::
s = socket.socket()
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][4])
Exceptions
----------
.. data:: socket.error
.. data:: socket.timeout
Constants
---------
.. data:: socket.AF_INET
family types
.. data:: socket.SOCK_STREAM
.. data:: socket.SOCK_DGRAM
socket types
.. data:: socket.IPPROTO_UDP
.. data:: socket.IPPROTO_TCP
.. data:: socket.IPPROTO_SEC
protocol numbers
class socket
============
Methods
-------
.. method:: socket.close
Mark the socket closed. Once that happens, all future operations on the socket
object will fail. The remote end will receive no more data (after queued data is flushed).
Sockets are automatically closed when they are garbage-collected, but it is recommended
to close() them explicitly, or to use a with statement around them.
.. method:: socket.bind(address)
Bind the socket to address. The socket must not already be bound. The format of ``address``
is: ``(ipv4 address, port)``
.. method:: socket.listen([backlog])
Enable a server to accept connections. If backlog is specified, it must be at least 0
(if it's lower, it will be set to 0); and specifies the number of unaccepted connections
tha the system will allow before refusing new connections. If not specified, a default
reasonable value is chosen.
.. method:: socket.accept()
Accept a connection. The socket must be bound to an address and listening for connections.
The return value is a pair (conn, address) where conn is a new socket object usable to send
and receive data on the connection, and address is the address bound to the socket on the
other end of the connection.
.. method:: socket.connect(address)
Connect to a remote socket at address. The format of address is: ``(ipv4 address, port)``
.. method:: socket.send(bytes)
Send data to the socket. The socket must be connected to a remote socket.
.. method:: socket.sendall(bytes)
Send data to the socket. The socket must be connected to a remote socket.
.. method:: socket.recv(bufsize)
Receive data from the socket. The return value is a bytes object representing the data
received. The maximum amount of data to be received at once is specified by bufsize.
.. method:: socket.sendto(bytes, address)
Send data to the socket. The socket should not be connected to a remote socket, since the
destination socket is specified by address. The ``address`` has the same format as the
rest of the methods, see above.
.. method:: socket.recvfrom(bufsize)
Receive data from the socket. The return value is a pair (bytes, address) where bytes is a
bytes object representing the data received and address is the address of the socket sending
the data.
.. method:: socket.setsockopt(level, optname, value)
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). The value can be an integer or a bytes-like object representing
a buffer.
.. method:: socket.settimeout(value)
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
will raise a timeout exception if the timeout period value has elapsed before the operation has
completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket
is put in blocking mode.
.. method:: socket.setblocking(flag)
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking,
else to blocking mode.
This method is a shorthand for certain ``settimeout()`` calls::
sock.setblocking(True) is equivalent to sock.settimeout(None)
sock.setblocking(False) is equivalent to sock.settimeout(0.0)
.. method:: socket.makefile(mode='rb')
Return a file object associated with the socket. The exact returned type depends on the arguments
given to makefile(). The support is limited to binary modes only ('rb' and 'wb').
CPython's arguments: ``encoding``, ``errors`` and ``newline`` are not supported.
The socket must be in blocking mode; it can have a timeout, but the file objects internal buffer
may end up in a inconsistent state if a timeout occurs.
.. note::
**CPython difference:** closing the file object returned by makefile() WILL close the
original socket as well.
.. method:: socket.read(size)
Read up to size bytes from the socket. Return a bytes object. If ``size`` is not given, it
behaves just like ``socket.readall()``, see below.
.. method:: socket.readall()
Read all data available from the socket until ``EOF``. This function will not return until
the socket is closed.
.. method:: socket.readinto(buf[, nbytes])
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
Return value: number of bytes read and stored into ``buf``.
.. method:: socket.readline()
Read a line, ending in a newline character.
Return value: the line read.
.. method:: socket.write(buf)
Write the buffer of bytes to the socket.
Return value: number of bytes written.

61
docs/library/ussl.rst Normal file
View File

@@ -0,0 +1,61 @@
:mod:`ussl` -- ssl module
===============================
.. module:: ussl
:synopsis: TLS/SSL wrapper for socket objects
This module provides access to Transport Layer Security (often known as
“Secure Sockets Layer”) encryption and peer authentication facilities for
network sockets, both client-side and server-side.
Functions
---------
.. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None)
Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of
``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM``
socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example::
import socket
import ssl
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
ss = ssl.wrap_socket(s)
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][4])
Certificates must be used in order to validate the other side of the connection, and also to
authenticate ourselves with the other end. Such certificates must be stored as files using the
FTP server, and they must be placed in specific paths with specific names.
- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'**
- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'**
- The key for our own certificate goes in: **'/flash/cert/private.key'**
.. note::
When these files are stored, they are placed inside the internal **hidden** file system
(just like firmware updates), and therefore they are never visible.
For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located
in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_
and put it in '/flash/cert/'. Then do::
import socket
import ssl
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][4])
Exceptions
----------
.. data:: ssl.SSLError
Constants
---------
.. data:: ssl.CERT_NONE
.. data:: ssl.CERT_OPTIONAL
.. data:: ssl.CERT_REQUIRED
supported values in ``cert_reqs``

17
docs/library/wipy.rst Normal file
View File

@@ -0,0 +1,17 @@
*************************************
:mod:`wipy` -- WiPy specific features
*************************************
.. module:: wipy
:synopsis: WiPy specific features
The ``wipy`` module contains functions to control specific features of the
WiPy, such as the heartbeat LED.
Functions
---------
.. function:: heartbeat([enable])
Get or set the state (enabled or disabled) of the heartbeat LED. Accepts and
returns boolean values (``True`` or ``False``).

View File

@@ -34,8 +34,6 @@
<a class="biglink" href="{{ pathto(port + "/general") }}">General information about {{ port_name }}</a><br/>
<span class="linkdescr">read this first for a quick overview</span>
</p>
{% endif %}
{% if port == "pyboard" %}
<p class="biglink">
<a class="biglink" href="{{ pathto(port + "/tutorial/index") }}">Tutorials and code examples</a><br/>
<span class="linkdescr">start here</span>
@@ -43,7 +41,11 @@
{% endif %}
<p class="biglink">
<a class="biglink" href="{{ pathto("library/index") }}">Library Reference</a><br/>
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
{% if port == "wipy" %}
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/machine") }}">machine module</a></span>
{% else %}
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
{% endif %}
</p>
</td>
<td width="40%" style="padding-left:2em;">

View File

@@ -1,6 +1,26 @@
General information about the WiPy
==================================
No floating point support
-------------------------
Due to space reasons, there's no floating point support, and no math module. This
means that floating point numbers cannot be used anywhere in the code, and that
all divisions must be performed using '//' instead of '/'. Example::
>>> r = 4 // 2 # this will work
>>> r = 4 / 2 # this WON'T
Before applying power
---------------------
.. warning::
The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higer
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
----------------------
@@ -11,22 +31,46 @@ to gain access to the interactive prompt, open a telnet session to that IP addre
the default port (23). You will be asked for credentials:
``login: micro`` and ``password: python``
Local file system and SD card
-----------------------------
.. _wipy_telnet:
Telnet REPL
-----------
Linux stock telnet works like a charm (also on OSX), but other tools like putty
work quite too. The default credentials are: **user:** ``micro``, **password:** ``python``.
See :ref:`network.server <network.server>` for info on how to change the defaults.
For instance, on a linux shell (when connected to the WiPy in AP mode)::
$ telnet 192.168.1.1
Local file system and FTP access
--------------------------------
There is a small internal file system (a drive) on the WiPy, called ``/flash``,
which is stored within the external serial flash memory. If a micro SD card
is hooked-up and enabled, it is available as ``/sd``.
is hooked-up and mounted, it will be available as well.
When the WiPy boots up, it always boots from the ``boot.py`` located in the
``/flash`` file system. If during the boot process the SD card is enabled and
it's selected as the current drive then the WiPy will try to execute ``main.py``
that should be located in the SD card.
When the WiPy starts up, it always boots from the ``boot.py`` located in the
``/flash`` file system.
The file system is accessible via the native FTP server running in the WiPy.
The file system is accessible via the native FTP server running in the WiPy.
Open your FTP client of choice and connect to:
``ftp://192.168.1.1``, ``user: micro``, ``password: python``
**url:** ``ftp://192.168.1.1``, **user:** ``micro``, **password:** ``python``
See :ref:`network.server <network.server>` for info on how to change the defaults.
The recommended clients are: Linux stock FTP (also in OSX), Filezilla and FireFTP.
For example, on a linux shell::
$ ftp 192.168.1.1
The FTP server on the WiPy doesn't support active mode, only passive, therefore,
if using the native unix ftp client, just after logging in do::
ftp> passive
Besides that, the FTP server only supports one data connection at a time. Check out
the Filezilla settings section below for more info.
FileZilla settings
------------------
@@ -37,20 +81,37 @@ to one, otherwise FileZilla will try to open a second command connection when re
and saving files, and for simplicity and to reduce code size, only one command and one
data connections are possible. Other FTP clients might behave in a similar way.
.. _wipy_firmware_upgrade:
Upgrading the firmware Over The Air
-----------------------------------
OTA software updates can be performed through the FTP server. Upload the ``mcuimg.bin`` file
to: ``/flash/sys/mcuimg.bin`` it will take around 6s. You won't see the file being stored
inside ``/flash/sys/`` because it's actually saved bypassing the user file system, but rest
assured that it was successfully transferred, and it has been signed with a MD5 checksum to
verify its integrity. Now, reset the MCU by pressing the switch on the board, or by typing::
inside ``/flash/sys/`` because it's actually saved bypassing the user file system, so it
ends up inside the internal **hidden** file system, but rest assured that it was successfully
transferred, and it has been signed with a MD5 checksum to verify its integrity. Now, reset
the WiPy by pressing the switch on the board, or by typing::
import pyb
pyb.reset()
>>> import machine
>>> machine.reset()
Boot modes
----------
Software updates can be found in: https://github.com/wipy/wipy/releases
It's always recommended to update to the latest software, but make sure to
read the **release notes** before.
In order to check your software version, do::
>>> import os
>>> os.uname().release
If the version number is lower than the latest release found in
`the releases <https://github.com/wipy/wipy/releases>`_, go ahead and update your WiPy!
.. _wipy_boot_modes:
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
@@ -61,7 +122,7 @@ it to the 3v3 output pin) during reset. This procedure also allows going
back in time to old firmware versions. The WiPy can hold up to 3 different
firmware versions, which are: the factory firmware plus 2 user updates.
After reset, if ``GP28`` is held high, the heart beat LED will start flashing
After reset, if ``GP28`` is held high, the heartbeat LED will start flashing
slowly, if after 3 seconds the pin is still being held high, the LED will start
blinking a bit faster and the WiPy will select the previous user update to boot.
If the previous user update is the desired firmware image, ``GP28`` must be
@@ -85,18 +146,19 @@ useful to recover from crash situations caused by the user scripts. The selectio
made during safe boot is not persistent, meaning that after the next normal reset,
the latest firmware will run again.
The heart beat LED
The heartbeat LED
------------------
By default the heart beat LED flashes once every 4s to signal that the system is
alive. This can be overridden through the HeartBeat class:
By default the heartbeat LED flashes once every 4s to signal that the system is
alive. This can be overridden through the :mod:`wipy` module::
``pyb.HeartBeat().disable()``
>>> import wipy
>>> wipy.heartbeat(False)
There are currently 2 kinds of errors that you might see:
1. If the heart beat LED flashes quickly, then a Python script(eg ``main.py``)
1. If the heartbeat LED flashes quickly, then a Python script(eg ``main.py``)
has an error. Use the REPL to debug it.
2. If the heart beat LED stays on, then there was a hard fault, you cannot
2. If the heartbeat LED stays on, then there was a hard fault, you cannot
recover from this, the only way out is to press the reset switch.

View File

@@ -7,27 +7,30 @@ Quick reference for the WiPy
:alt: WiPy pinout and alternate functions table
:width: 800px
General board control
---------------------
General board control (including sleep modes)
---------------------------------------------
See :mod:`pyb`. ::
See the :mod:`machine` module::
import pyb
import machine
help(pyb) # display all members from the pyb module
pyb.delay(50) # wait 50 milliseconds
pyb.millis() # number of milliseconds since boot-up
pyb.freq() # get the CPU frequency
pyb.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address)
help(machine) # display all members from the machine module
machine.freq() # get the CPU frequency
machine.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address)
machine.idle() # average curernt decreases to (~12mA), any interrupts wakes it up
machine.sleep() # everything except for WLAN is powered down (~950uA avg. current)
# wakes from Pin, RTC or WLAN
machine.deepsleep() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC.
Pins and GPIO
-------------
See :ref:`pyb.Pin <pyb.Pin>`. ::
See :ref:`machine.Pin <machine.Pin>`. ::
from pyb import Pin
from machine import Pin
# initialize GP2 in gpio mode (af=0) and make it an output
# initialize GP2 in gpio mode (alt=0) and make it an output
p_out = Pin('GP2', mode=Pin.OUT)
p_out.value(1)
p_out.value(0)
@@ -35,35 +38,35 @@ See :ref:`pyb.Pin <pyb.Pin>`. ::
p_out(True)
# make GP1 an input with the pull-up enabled
p_in = Pin('GP1', mode=Pin.IN, pull = Pin.PULL_UP)
p_in = Pin('GP1', mode=Pin.IN, pull=Pin.PULL_UP)
p_in() # get value, 0 or 1
Timers
------
See :ref:`pyb.Timer <pyb.Timer>` and :ref:`pyb.Pin <pyb.Pin>`. ::
See :ref:`machine.Timer <machine.Timer>` and :ref:`machine.Pin <machine.Pin>`. ::
from pyb import Timer
from pyb import Pin
from machine import Timer
from machine import Pin
tim = Timer(1, mode=Timer.PERIODIC)
tim_a = tim.channel(Timer.A, freq=1000)
tim_a.time() # get the value in microseconds
tim_a.freq(1) # 1 Hz
p_out = Pin('GP2', af=0, mode=Pin.OUT)
tim_a.callback(handler=lambda t: p_out.toggle())
p_out = Pin('GP2', mode=Pin.OUT)
tim_a.irq(handler=lambda t: p_out.toggle())
PWM (pulse width modulation)
----------------------------
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::
See :ref:`machine.Pin <machine.Pin>` and :ref:`machine.Timer <machine.Timer>`. ::
from pyb import Timer
from pyb import Pin
from machine import Timer
from machine import Pin
# assign GP25 to alternate function 5 (PWM)
p_out = Pin('GP25', af=9, type=Pin.STD)
# assign GP25 to alternate function 9 (PWM)
p_out = Pin('GP25', mode=Pin.AF, alt=9)
# timer 2 in PWM mode and width must be 16 buts
tim = Timer(2, mode=Timer.PWM, width=16)
@@ -74,9 +77,9 @@ See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::
ADC (analog to digital conversion)
----------------------------------
See :ref:`pyb.ADC <pyb.ADC>`. ::
See :ref:`machine.ADC <machine.ADC>`. ::
from pyb import ADC
from machine import ADC
adc = ADC()
apin = adc.channel(pin='GP3')
@@ -85,19 +88,19 @@ See :ref:`pyb.ADC <pyb.ADC>`. ::
UART (serial bus)
-----------------
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.UART <pyb.UART>`. ::
See :ref:`machine.UART <machine.UART>`. ::
from pyb import Pin, UART
uart = UART(0, 9600)
from machine import UART
uart = UART(0, baudrate=9600)
uart.write('hello')
uart.read(5) # read up to 5 bytes
SPI bus
-------
See :ref:`pyb.SPI <pyb.SPI>`. ::
See :ref:`machine.SPI <machine.SPI>`. ::
from pyb SPI
from machine import SPI
# configure the SPI master @ 2MHz
spi = SPI(0, SPI.MASTER, baudrate=200000, polarity=0, phase=0)
@@ -109,9 +112,9 @@ See :ref:`pyb.SPI <pyb.SPI>`. ::
I2C bus
-------
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.I2C <pyb.I2C>`. ::
See :ref:`machine.I2C <machine.I2C>`. ::
from pyb import Pin, I2C
from machine import I2C
# configure the I2C bus
i2c = I2C(0, I2C.MASTER, baudrate=100000)
i2c.scan() # returns list of slave addresses
@@ -123,9 +126,9 @@ See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.I2C <pyb.I2C>`. ::
Watchdog timer (WDT)
--------------------
See :ref:`pyb.WDT <pyb.WDT>`. ::
See :ref:`machine.WDT <machine.WDT>`. ::
from pyb import WDT
from machine import WDT
# enable the WDT with a timeout of 5s (1s is the minimum)
wdt = WDT(timeout=5000)
@@ -134,81 +137,87 @@ See :ref:`pyb.WDT <pyb.WDT>`. ::
Real time clock (RTC)
---------------------
See :ref:`pyb.RTC <pyb.RTC>` and ``pyb.Sleep``. ::
See :ref:`machine.RTC <machine.RTC>` ::
from pyb import RTC, Sleep
import machine
from machine import RTC
rtc = pyb.RTC()
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
print(rtc.datetime())
rtc = machine.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())
def some_handler (rtc_obj):
# trigger the callback again in 30s
rtc_obj.callback(value=30000, handler=some_handler)
def alarm_handler (rtc_o):
pass
# do some non blocking operations
# warning printing on an irq via telnet is not
# possible, only via UART
# create a RTC alarm that expires in 30s
rtc.callback(value=30000, handler=some_handler, wake_from=Sleep.SUSPENDED)
# create a RTC alarm that expires after 5 seconds
rtc.alarm(time=5000, repeat=False)
# enable RTC interrupts
rtc_i = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP)
# go into suspended mode waiting for the RTC alarm to expire and wake us up
Sleep.suspend()
machine.sleep()
SD card
-------
See :ref:`pyb.SD <pyb.SD>`. ::
See :ref:`machine.SD <machine.SD>`. ::
from pyb import SD
from machine import SD
import os
# SD card pins need special configuration so we pass them to the constructor
# clock pin, cmd pin, data0 pin
sd = SD(pins=('GP10', 'GP11', 'GP15'))
# or use default ones for the expansion board
sd = SD()
os.mount(sd, '/sd')
WLAN (WiFi)
-----------
See :ref:`network.WLAN <network.WLAN>` and ``pyb.Sleep``. ::
See :ref:`network.WLAN <network.WLAN>` and :mod:`machine`. ::
import machine
from network import WLAN
from pyb import Sleep
# configure the WLAN subsystem in station mode (the default is AP)
wifi = WLAN(WLAN.STA)
wifi = WLAN(mode=WLAN.STA)
# go for fixed IP settings
wifi.ifconfig(('192.168.0.107', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
wifi.ifconfig(config=('192.168.0.107', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
wifi.scan() # scan for available netrworks
wifi.connect(ssid='mynetwork', security=2, key='mynetworkkey')
wifi.connect(ssid='mynetwork', auth=(WLAN.WPA2, 'mynetworkkey'))
while not wifi.isconnected():
pass
print(wifi.ifconfig())
# enable wake on WLAN
wifi.callback(wake_from=Sleep.SUSPENDED)
wifi.irq(wake=machine.SLEEP)
# go to sleep
Sleep.suspend()
machine.sleep()
# now, connect to the FTP or the Telnet server and the WiPy will wake-up
Sleep and power modes control
-----------------------------
Telnet and FTP server
---------------------
See ``pyb.Sleep``. ::
See :ref:`network.server <network.server>` ::
from pyb import Sleep
from network import server
Sleep.idle() # lowest sleep mode (~12mA), any interrupts wakes it up
Sleep.suspend() # everything except for WLAN is powered down (~950uA)
# wakes from Pin, RTC or WLAN
Sleep.hibernate() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC.
# init with new user, pass word and seconds timeout
server = server.init(login=('user', 'password'), timeout=60)
server.timeout(300) # change the timeout
server.timeout() # get the timeout
server.isrunning() # check wether the server is running or not
Heart beat LED
--------------
See :ref:`pyb.HeartBeat <pyb.HeartBeat>`. ::
See :mod:`wipy`. ::
from pyb import HeartBeat
import wipy
# disable the heart beat indication (you are free to use this LED connected to GP25)
HeartBeat().disable()
# enable the heart beat again
HeartBeat().enable()
wipy.heartbeat(False) # disable the heartbeat LED
wipy.heartbeat(True) # enable the heartbeat LED
wipy.heartbeat() # get the heartbeat state

View File

@@ -0,0 +1,19 @@
Getting started with Blynk and the WiPy
---------------------------------------
Blynk is a platform with iOS and Android apps to control
Arduino, Raspberry Pi and the likes over the Internet.
You can easily build graphic interfaces for all your
projects by simply dragging and dropping widgets.
There are several examples available that work out-of-the-box with
the WiPy. Before anything else, make sure that your WiPy is running
the latest software, check :ref:`OTA How-To <wipy_firmware_upgrade>` for instructions.
1. Get the `Blynk library <https://github.com/wipy/wipy/blob/master/lib/blynk/BlynkLib.py>`_ and put it in ``/flash/lib/`` via FTP.
2. Get the `Blynk examples <https://github.com/wipy/wipy/tree/master/examples/blynk>`_ edit the network settings, and afterwards
upload them to ``/flash/lib/`` via FTP as well.
3. Follow the instructions on each example to setup the Blynk dashboard on your smartphone or tablet.
4. Give it a try, for instance::
>>> execfile('01_simple.py')

View File

@@ -0,0 +1,17 @@
.. _wipy_tutorial_index:
WiPy tutorials and examples
===========================
Before starting, make sure that you are running the latest firmware,
for instrucctions see :ref:`OTA How-To <wipy_firmware_upgrade>`.
.. toctree::
:maxdepth: 1
:numbered:
intro.rst
repl.rst
blynk.rst
wlan.rst
reset.rst

View File

@@ -0,0 +1,64 @@
Introduction to the WiPy
========================
To get the most out of your WiPy, there are a few basic things to
understand about how it works.
Caring for your WiPy and expansion board
----------------------------------------
Because the WiPy/expansion board does not have a housing it needs a bit of care:
- Be gentle when plugging/unplugging the USB cable. Whilst the USB connector
is well soldered and is relatively strong, if it breaks off it can be very
difficult to fix.
- Static electricity can shock the components on the WiPy and destroy them.
If you experience a lot of static electricity in your area (eg dry and cold
climates), take extra care not to shock the WiPy. If your WiPy came
in a ESD bag, then this bag is the best way to store and carry the
pyboard as it will protect it agains static discharges.
As long as you take care of the hardware, you should be okay. It's almost
impossible to break the software on the WiPy, so feel free to play around
with writing code as much as you like. If the filesystem gets corrupt, see
below on how to reset it. In the worst case you might need to do a safe boot,
which is explained in detail :ref:`here <wipy_boot_modes>`.
Plugging into the expansion board and powering on
-------------------------------------------------
The expansion board can power the WiPy via USB. The WiPy comes with a sticker
on top of the RF shield tha labels all pins, and this should match the label
numbers on the expansion board headers. When pluggin it in, the WiPy antenna
will end up on top of the SD card connector of the expansion board. A video
showing how to do this can be found `here <https://www.youtube.com/watch?v=47D9MZ9zFQw>`_.
Expansion board hardware guide
------------------------------
The document explaining the hardware details of the expansion board can be found
`here <https://github.com/wipy/wipy/blob/master/docs/User_manual_exp_board.pdf>`_.
Powering by an external power source
------------------------------------
The WiPy can be powered by a battery or other external power source.
**Be sure to connect the positive lead of the power supply to VIN, and
ground to GND. There is no polarity protection on the pyboard so you
must be careful when connecting anything to VIN.**
- When powering via ``VIN``:
**The input voltage must be between 3.6V and 5.5V.**
- When powering via ``3V3``:
**The input volatge must be exactly 3V3, ripple free and from a supply capable
of sourcing at least 300mA of current**
Performing firmware upgrades
----------------------------
For detalied instructions see :ref:`OTA How-To <wipy_firmware_upgrade>`.

137
docs/wipy/tutorial/repl.rst Normal file
View File

@@ -0,0 +1,137 @@
Getting a MicroPython REPL prompt
=================================
REPL stands for Read Evaluate Print Loop, and is the name given to the
interactive MicroPython prompt that you can access on the WiPy. Using
the REPL is by far the easiest way to test out your code and run commands.
You can use the REPL in addition to writing scripts in ``main.py``.
To use the REPL, you must connect to the WiPy either via :ref:`telnet <wipy_telnet>`,
or with a USB to serial converter wired to the one the two UARTs on the
WiPy. To enable REPL duplication on UART0 (the one accesible via the expansion board)
do::
>>> from machine import UART
>>> import os
>>> uart = UART(0, 115200)
>>> o.dupterm(uart)
Place this piece of code inside your `boot.py` so that it's done automatically after
reset.
Windows
-------
You need to install the pyboard driver to use the serial USB device.
The driver is on the pyboard's USB flash drive, and is called ``pybcdc.inf``.
To install this driver you need to go to Device Manager
for your computer, find the pyboard in the list of devices (it should have
a warning sign next to it because it's not working yet), right click on
the pyboard device, select Properties, then Install Driver. You need to
then select the option to find the driver manually (don't use Windows auto update),
navigate to the pyboard's USB drive, and select that. It should then install.
After installing, go back to the Device Manager to find the installed pyboard,
and see which COM port it is (eg COM4).
More comprehensive instructions can be found in the
`Guide for pyboard on Windows (PDF) <http://micropython.org/resources/Micro-Python-Windows-setup.pdf>`_.
Please consult this guide if you are having problems installing the driver.
The best option is to download the free program PuTTY:
`putty.exe <http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html>`_.
**In order to get to the telnet REPL:**
Using putty, select ``Telnet`` as connection type, leave the default port (23)
and enter the IP address of your WiPy (192.168.1.1 when in ``WLAN.AP`` mode),
then click open.
**In order to get to the REPL UART:**
Using your serial program you must connect to the COM port that you found in the
previous step. With PuTTY, click on "Session" in the left-hand panel, then click
the "Serial" radio button on the right, then enter you COM port (eg COM4) in the
"Serial Line" box. Finally, click the "Open" button.
Mac OS X
--------
Open a terminal and run::
$ telnet 192.168.1.1
or::
$ screen /dev/tty.usbmodem* 115200
When you are finished and want to exit screen, type CTRL-A CTRL-\\.
Linux
-----
Open a terminal and run::
$ telnet 192.168.1.1
or::
$ screen /dev/ttyUSB0 115200
You can also try ``picocom`` or ``minicom`` instead of screen. You may have to
use ``/dev/ttyUSB01`` or a higher number for ``ttyUSB``. And, you may need to give
yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``,
or use sudo).
Using the REPL prompt
---------------------
Now let's try running some MicroPython code directly on the WiPy.
With your serial program open (PuTTY, screen, picocom, etc) you may see a blank
screen with a flashing cursor. Press Enter and you should be presented with a
MicroPython prompt, i.e. ``>>>``. Let's make sure it is working with the obligatory test::
>>> print("hello WiPy!")
hello WiPy!
In the above, you should not type in the ``>>>`` characters. They are there to
indicate that you should type the text after it at the prompt. In the end, once
you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output
on your screen should look like it does above.
If you already know some python you can now try some basic commands here.
If any of this is not working you can try either a hard reset or a soft reset;
see below.
Go ahead and try typing in some other commands. For example::
>>> from machine import Pin
>>> import wipy
>>> wipy.heartbeat(False) # disable the heartbeat
>>> led = Pin('GP25', mode=Pin.OUT)
>>> led(1)
>>> led(0)
>>> led.toggle()
>>> 1 + 2
3
>>> 4 // 2
2
>>> 20 * 'py'
'pypypypypypypypypypypypypypypypypypypypy'
Resetting the board
-------------------
If something goes wrong, you can reset the board in two ways. The first is to press CTRL-D
at the MicroPython prompt, which performs a soft reset. You will see a message something like::
>>>
PYB: soft reboot
MicroPython v1.4.6-146-g1d8b5e5 on 2015-10-21; WiPy with CC3200
Type "help()" for more information.
>>>
If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the
RST switch (the small black button next to the heartbeat LED). During telnet, this will end
your session, disconnecting whatever program that you used to connect to the WiPy.

View File

@@ -0,0 +1,54 @@
Reset and boot modes
====================
There are soft resets and hard resets.
- A soft reset simply clears the state of the MicroPython virtual machine,
but leaves hardware peripherals unaffected. To do a soft reset, simply press
**Ctrl+D** on the REPL, or within a script do::
import sys
sys.exit()
- A hard reset is the same as performing a power cycle to the board. In order to
hard reset the WiPy, press the switch on the board or::
import machine
machine.reset()
Safe boot
---------
If something goes wrong with your WiPy, don't panic! It is almost
impossible for you to break the WiPy by programming the wrong thing.
The first thing to try is to boot in safe mode: this temporarily skips
execution of ``boot.py`` and ``main.py`` and gives default WLAN settings.
If you have problems with the filesystem you can :ref:`format the internal flash
drive <wipy_factory_reset>`.
To boot in safe mode, follow the detailed instructions described :ref:`here <wipy_boot_modes>`.
In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
the WiPy boots up with default settings. This means you now have access
to the filesystem, and you can edit ``boot.py`` and ``main.py`` to fix any problems.
Entering safe mode is temporary, and does not make any changes to the
files on the WiPy.
.. _wipy_factory_reset:
Factory reset the filesystem
----------------------------
If you WiPy's filesystem gets corrupted (very unlikely, but possible), you
can format it very easily byt doing::
>>> import os
>>> os.mkfs('/flash')
Resetting the filesystem deletes all files on the internal WiPy storage
(not the SD card), and restores the files ``boot.py`` and ``main.py`` back
to their original state after the next reset.

View File

@@ -0,0 +1,61 @@
WLAN step by step
=================
The WLAN is a system feature of the WiPy, therefore it is always enabled
(even while in ``machine.SLEEP``), except when deepsleep mode is entered.
In order to retrieve the current WLAN instance, do::
>>> from network import WLAN
>>> wlan = WLAN() # we call the constructor without params
You can check the current mode (which is always ``WLAN.AP`` after power up)::
>>> wlan.mode()
Connecting to your home router
------------------------------
The WLAN network card always boots in ``WLAN.AP`` mode, so we must first configure
it as a station::
from network import WLAN
wlan = WLAN(mode=WLAN.STA)
Now you can proceed to scan for networks::
nets = wlan.scan()
for net in nets:
if net.ssid == 'mywifi':
print('Network found!')
wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000)
while not wlan.isconnected():
machine.idle() # save power while waiting
print('WLAN connection succeeded!)
break
Assigning a static IP address when booting
------------------------------------------
If you want your WiPy to connect to your home router while after boot-up, and with a fixed
IP address so that you can access it via telnet or FTP, use the following script::
import machine
from network import WLAN
wlan = WLAN() # get current object, without changing the mode
if machine.reset_cause() != machine.SOFT_RESET:
wlan.init(WLAN.STA)
# configuration below MUST match your home router settings!!
wlan.ifconfig(config=('192.168.178.107', '255.255.255.0', '192.168.178.1', '8.8.8.8'))
if not wlan.isconnected():
wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000)
while not wlan.isconnected():
machine.idle() # save power while waiting
break
.. note::
Notice how we check for the reset cause and the connection status, this is crucial in order
to be able to soft reset the WiPy during a telnet session without breaking the connection.

View File

@@ -5,6 +5,7 @@ MicroPython documentation contents
wipy/quickref.rst
wipy/general.rst
wipy/tutorial/index.rst
library/index.rst
reference/index.rst
license.rst

View File

@@ -5,6 +5,7 @@ MicroPython documentation and references
wipy/quickref.rst
wipy/general.rst
wipy/tutorial/index.rst
library/index.rst
license.rst
wipy_contents.rst

View File

@@ -51,10 +51,12 @@ class SDCard:
for i in range(16):
self.spi.send(0xff)
# CMD0: init card; should return R1_IDLE_STATE (allow 2 attempts)
if self.cmd(0, 0, 0x95) != R1_IDLE_STATE:
if self.cmd(0, 0, 0x95) != R1_IDLE_STATE:
raise OSError("no SD card")
# CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts)
for _ in range(5):
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)

Some files were not shown because too many files have changed in this diff Show More