diff options
author | Damien George <damien.p.george@gmail.com> | 2017-08-14 12:15:54 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-08-14 12:15:54 +1000 |
commit | 5e76ea4affd0bd46e67b456496818803010a2d24 (patch) | |
tree | 2be81a889e765b8e24614bcd8bc80c0a4063e2f3 | |
parent | b4078cbbf3354229fc81ecfd26295237d808caa9 (diff) | |
parent | 1459a8d5c9b29c78da2cf5c7cf3c37ab03b34b8e (diff) | |
download | micropython-5e76ea4affd0bd46e67b456496818803010a2d24.tar.gz micropython-5e76ea4affd0bd46e67b456496818803010a2d24.zip |
Merge tag 'v1.8.2' into parse-bytecode
Thread support, ESP8266 memory improvements, btree module, improved docs
This release brings multi-threading support in the form of the _thread
module, which closely matches the semantics of the corresponding CPython
module. There is support for GIL and non-GIL builds; without the GIL
enabled one must protect concurrent access to mutable Python state at the
Python level using Lock objects. Threading with the GIL is enabled in
the cc3200 port on the WiPy. Threading without the GIL is enabled on the
unix port. The ESP8266 port has support for frozen bytecode (for scripts
in the modules/ subdirectory), as well as optimisations for reduced
memory usage and decreased memory fragmentation. The ESP8266 RTC also
resumes correctly after a deepsleep. An initial "btree" module has been
implemented for database support (unix port only), and the documentation
has been further improved, with pre-built PDF versions of the docs now
available.
py core:
- parse: treat constants that start with underscore as private
- objdict: implemented OrderedDict equality check
- support to build berkeley db 1.85 and "btree" module
- mpconfig.h: MP_NOINLINE is universally useful, move from unix port
- makeqstrdefs.py: remove restriction that source path can't be absolute
- mkrules.mk: define "lib" outside conditional block
- rename __QSTR_EXTRACT flag to NO_QSTR
- objtype: instance: inherit protocol vtable from a base class
- mphal.h: if virtpin API is used, automagically include its header
- objtype: inherit protocol vtable from base class only if it exists
- add MP_STATE_THREAD to hold state specific to a given thread
- add basic _thread module, with ability to start a new thread
- modthread: properly cast concrete exception pointer to an object
- modthread: add stack_size() function
- modthread: add exit() function
- modthread: implement lock object, for creating a mutex
- modthread: add with-context capabilities to lock object
- gc: make memory manager and garbage collector thread safe
- modthread: satisfy unused-args warning
- gc: fix 2 cases of concurrent access to ATB and FTB
- modthread: be more careful with root pointers when creating a thread
- modthread: call mp_thread_start/mp_thread_finish around threads
- gc: fix GC+thread bug where ptr gets lost because it's not computed
- make interning of qstrs thread safe
- implement a simple global interpreter lock (GIL)
- don't use gc or qstr mutex when the GIL is enabled, there is no need
- modthread: make Lock objects work when GIL is enabled
- mpthread.h: move GIL macros outside MICROPY_PY_THREAD block
- modthread: allow to properly set the stack limit of a thread
- nlrthumb: convert NLR thumb funcs from asm to C with inline-asm
- nlrsetjmp: update to take into account new location of nlr_top
- mpthread: include mpstate.h when defining GIL macros
- gc: be sure to count last allocated block at heap end in stats
- gc: calculate (and report) maximum contiguous free block size
- builtinimport: disable "imported as namespace package" warning
- mpconfig.h: mention MICROPY_PY_BTREE config option
- objarray: split out header to allow direct access to object
- rename mp_obj_type_t::stream_p to "protocol"
extmod:
- modbtree: initial implementation of "btree" module based on BerkeleyDB
- modbtree: handle default value and error check
- modbtree: implement .items() iterator
- modbtree: actually implement end key support for .items()
- modbtree: items(): Implement "end key inclusive" flag
- modbtree: items(): Implement DESC flag
- modbtree: __getitem__() should raise KeyError for non-existing key
- modbtree: open(): Support "in-memory" database with filename=None
- machine_pinbase: implementation of PinBase class
- machine_pinbase: fix nanbox build
- modlwip: store a chain of incoming pbufs, instead of only one
- modbtree: implement keys(), values(), items() iterators
- modbtree: cleverly implement "for key in btree:" syntax
- modwebsocket: add readinto() method
- modwebrepl: add readinto() method
- modbtree: fix unused argument warning
- modbtree: fixes for nanbox build
- moduos_dupterm: reserve buffer bytearray object for dupterm
- moduos_dupterm: reuse dupterm_arr_obj for write operations
lib:
- berkeley-db-1.xx: add Berkeley DB 1.85 as a submodule
- berkeley-db-1.xx: update to upstream which builds for uPy
- fatfs/option/ccsbcs: follow uPy optional features model
- libm: format code to pass gcc v6.1.1 warning
- libm: remove unused definition of "one"
drivers:
- display/ssd1306: add width arg and support 64px wide displays
tests:
- recursive_iternext: clang/Linux is even more stack-frugal than MacOS
- bench: add testcase to compare bytes(N) vs b"\0" * N
- add testcase for OrderedDict equality
- add a testcase for machine.PinBase class
- extmod: add "btree" module test
- btree1: add testcase for iterating btree object directly
- add tests for _thread module
- add 3 more tests for _thread module
- thread: remove need to sleep to wait for completion in some tests
- thread: add tests for running GC within a thread, and heap stress
- thread: rename thread_stress_XXX.py to stress_XXX.py
- thread: add tests that mutate shared objects
- thread: add test for concurrent interning of strings
- thread: add test for concurrent mutating of user instance
- thread: make stack-size test run correctly and reliable on uPy
- thread: make sure that thread tests don't rely on floating point
- thread: allow thread_sleep1 to run without floating point
- thread: allow some tests to run on ports with not much heap
- meminfo: update for addition of "max free sz" output
- run-tests: If running thread tests on unix, don't run mutate ones
unix port:
- unbreak "minimal" target by disabling FatFs
- mpconfigport_minimal.h: clearly mark where user-define config ends
- deprecate support for GNU Readline (MICROPY_USE_READLINE=2)
- time to build with --gc-sections
- move "utime" module config to C level instead of make level
- Makefile: libffi: Build with -Os
- alloc: add option to use uPy's alloc-exec implementation even for libffi
- alloc: make coverage build and its overzealous warnings happy
- disable FatFs VFS for normal build, keep enabled for coverage
- modmachine: include PinBase class
- modmachine: enable time_pulse_us() function
- fix Makefile to handle gc-sections linker flags on Mac OS
- add basic thread support using pthreads
- file: if write syscall returns because of EINTR then try again
- implement garbage collection with threading
- mpthreadport: use SA_SIGINFO for GC signal handler
- gccollect: provide declaration of exported function
- mpthreadport: suppress compiler warning about unused arguments
- modtime: release the GIL when sleeping
- enable btree module
- Makefile: make "minimal" build be minimal again
- mpconfigport_minimal.h: allow to print a string within 1KB of heap
- main: error out on unknown value of suffix in -X heapsize= option
- main: improve help for -X options a bit
- main: when preparing sys.path, allocate exact strings on uPy heap
- disable the GIL to improve performance of non-thread code
windows port:
- follow unix port changes regarding "utime" module
- msvc: include machine_pinbase.c in build and enable umachine module
stmhal port:
- add board definition files for Olimex STM32-E407
- port of f4 hal commit 1d7fb82 to l4 hal (SD card modifications)
- correct DMA to allow SD card on L4 MCUs
- enable SD card on L4 MCUs
cc3200 port:
- update FreeRTOS to v9.0.0
- define our own FreeRTOS heap so it can go in a special segment
- add basic threading capabilities
- fix call to new exception to be _msg instead of _arg1
- use xTaskCreateStatic instead of osi_TaskCreate
- mpthreadport: make mutex statically allocated
- mpthreadport: properly initialise the main thread's data
- gccollect: use MP_STATE_THREAD(stack_top) to get top of stack
- mpthreadport: scan more root pointers from thread data
- mpthreadport: move mem alloc outside the thread_mutex lock
- enable the GIL
- in FreeRTOSConfig.h, comment on configSUPPORT_STATIC_ALLOCATION
- remove .boot section attribute from osi_TaskCreate function
- start the simplelink spawn task using the static task creator
- shrink the FreeRTOS heap and place TCB+stack in freed location
- allow to compile bootloader with threading enabled
- remove obsolete singleton heart-beat object
teensy port:
- update the README with OSX specific information and tips
esp8266 port:
- modnetwork: use struct bss_info::ssid_len for ESSID length
- let RTC work correctly after deepsleep
- switch floating-point arith routines to BootROM
- Makefile: enable --verify option for esptool.py write_flash
- use RTC to set date & time stamps for files
- main.c: clear the command line history when (re)booting
- enable frozen bytecode, with scripts in modules/ subdir
- README: describe how to build mpy-cross
- websocket_helper.py: avoid extra string allocations
- websocket_helper.py: fix typo in debug output
- modpybuart: allow setting baudrate and other params
- explicitly collect garbage in bootstrap scripts
- switch webrepl_setup to use frozen bytecode
- switch webrepl to use frozen bytecode
- README: promote from "highly experimental" to "experimental"
- main: init recently added dupterm_arr_obj port state var
- esp_mphal: call_dupterm_read: Use readinto() method
- esp_mphal: properly handle dupterm EOF after switching to readinto()
qemu-arm port:
- disable gcc LTO option for nlrthumb.c
docs:
- esp8266/tutorial/network_basics: minor typo fix, ap becomes ap_if
- add link to PDF version of docs in sidebar
- library/network: wipy: fix literal block indentation
- esp.socket: remove unused file
- ure: typo fix
- usocket: there must be empty line after .only::
- library/machine.Pin: mention GPIO and cross-link .value() function
- machine.*: add "currentmodule:: machine" directive
- pyb.*: add "currentmodule:: pyb" directive
- machine.Pin: remove explicit target
- machine.UART: cleanup pyboard section
- machine.*: use proper class case in method headers
- machine.Pin: add class designator to all constants
- pyb.CAN: mark CAN.initfilterbanks() as classmethod explicitly
- pyb.Pin: af_list() is a normal method, not a class method
- pyb.ExtInt,pyb.Pin: mark up class methods as such
- pyb.*: use proper class case in method headers
- pyb.Pin: sort .af() and .af_list() methods together
- builtins: enumerate all builtin functions implemented
- library/index: add builtins.rst
- machine.Pin: disambiguate object call method
- machine*: remove explicit targets and "machine." prefixes on classes
- uctypes: improve documentation
- sys: detailed description of print_exception() diff from traceback module
- add sphinx_selective_exclude extension suite
- conf.py: active sphinx_selective_exclude extensions
- rebuild docs from scratch, as required for proper only:: handling
- select: add an article
- sys: print_exception: Fixes/clarifications
- conf.py: exclude cmath from modindex for wipy
- library: fix typo in docs for usocket.listen()
examples:
- unix/ffi_example.py: update for current "ffi" module API
- unix/ffi_example.py: remove TODO, make output more clear
237 files changed, 11693 insertions, 3526 deletions
diff --git a/.gitmodules b/.gitmodules index 254dabf02c..7735bc2d03 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "lib/lwip"] path = lib/lwip url = http://git.savannah.gnu.org/r/lwip.git +[submodule "lib/berkeley-db-1.xx"] + path = lib/berkeley-db-1.xx + url = https://github.com/pfalcon/berkeley-db-1.xx diff --git a/.travis.yml b/.travis.yml index 7ae9f4952d..f9ee2ab0fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,7 @@ script: # run tests with coverage info - make -C unix coverage - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests) + - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests -d thread) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --emit native) after_success: diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index 2e9a514381..2f25bbd7e8 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -84,7 +84,13 @@ #define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 ) -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( \ + 16384 /* 16kbytes for FreeRTOS data structures and heap */ \ + - sizeof(StaticTask_t) - configMINIMAL_STACK_SIZE * sizeof(StackType_t) /* TCB+stack for idle task */ \ + - sizeof(StaticTask_t) - 1024 /* TCB+stack for servers task */ \ + - sizeof(StaticTask_t) - 6656 /* TCB+stack for main MicroPython task */ \ + - sizeof(StaticTask_t) - 896 /* TCB+stack for simplelink spawn task */ \ + ) ) #define configMAX_TASK_NAME_LEN ( 8 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 @@ -151,4 +157,17 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ version. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +/* We provide a definition of ucHeap so it can go in a special segment. */ +#define configAPPLICATION_ALLOCATED_HEAP 1 + +/* We use static versions of functions (like xTaskCreateStatic) */ +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* For threading */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#undef configUSE_MUTEXES +#define configUSE_MUTEXES 1 +#undef INCLUDE_vTaskDelete +#define INCLUDE_vTaskDelete 1 + #endif /* FREERTOS_CONFIG_H */ diff --git a/cc3200/FreeRTOS/License/license.txt b/cc3200/FreeRTOS/License/license.txt index be959bb331..5d243b8966 100644 --- a/cc3200/FreeRTOS/License/license.txt +++ b/cc3200/FreeRTOS/License/license.txt @@ -1,54 +1,59 @@ -The FreeRTOS source code is licensed by a *modified* GNU General Public -License (GPL). The modification is provided in the form of an exception. +The FreeRTOS open source license covers the FreeRTOS source files, +which are located in the /FreeRTOS/Source directory of the official FreeRTOS +download. It also covers most of the source files in the demo application +projects, which are located in the /FreeRTOS/Demo directory of the official +FreeRTOS download. The demo projects may also include third party software that +is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of +third party software includes header files provided by chip or tools vendors, +linker scripts, peripheral drivers, etc. All the software in subdirectories of +the /FreeRTOS directory is either open source or distributed with permission, +and is free for use. For the avoidance of doubt, refer to the comments at the +top of each source file. + +---------------------------------------------------------------------------- NOTE: The modification to the GPL is included to allow you to distribute a combined work that includes FreeRTOS without being obliged to provide the source -code for proprietary components outside of the FreeRTOS kernel. - - +code for proprietary components. ---------------------------------------------------------------------------- -The FreeRTOS GPL Exception Text: +Applying to FreeRTOS V8.2.3 up to the latest version, the FreeRTOS GPL Exception +Text follows: -Any FreeRTOS source code, whether modified or in it's original release form, +Any FreeRTOS *source code*, whether modified or in it's original release form, or whether in whole or in part, can only be distributed by you under the terms -of the GNU General Public License plus this exception. An independent module is +of the GNU General Public License plus this exception. An independent module is a module which is not derived from or based on FreeRTOS. Clause 1: -Linking FreeRTOS statically or dynamically with other modules is making a -combined work based on FreeRTOS. Thus, the terms and conditions of the GNU -General Public License cover the whole combination. +Linking FreeRTOS with other modules is making a combined work based on FreeRTOS. +Thus, the terms and conditions of the GNU General Public License V2 cover the +whole combination. -As a special exception, the copyright holder of FreeRTOS gives you permission -to link FreeRTOS with independent modules that communicate with FreeRTOS -solely through the FreeRTOS API interface, regardless of the license terms of -these independent modules, and to copy and distribute the resulting combined -work under terms of your choice, provided that +As a special exception, the copyright holders of FreeRTOS give you permission to +link FreeRTOS with independent modules to produce a statically linked +executable, regardless of the license terms of these independent modules, and to +copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms and +conditions of the license of that module. An independent module is a module +which is not derived from or based on FreeRTOS. - + Every copy of the combined work is accompanied by a written statement that - details to the recipient the version of FreeRTOS used and an offer by yourself - to provide the FreeRTOS source code (including any modifications you may have - made) should the recipient request it. +Clause 2: - + The combined work is not itself an RTOS, scheduler, kernel or related product. +FreeRTOS may not be used for any competitive or comparative purpose, including +the publication of any form of run time or compile time metric, without the +express permission of Real Time Engineers Ltd. (this is the norm within the +industry and is intended to ensure information accuracy). - + The independent modules add significant and primary functionality to FreeRTOS - and do not merely extend the existing functionality already present in FreeRTOS. -Clause 2: -FreeRTOS may not be used for any competitive or comparative purpose, including the -publication of any form of run time or compile time metric, without the express -permission of Real Time Engineers Ltd. (this is the norm within the industry and -is intended to ensure information accuracy). +-------------------------------------------------------------------- --------------------------------------------------------------------- -The standard GPL exception text: +The standard GPL V2 text: GNU GENERAL PUBLIC LICENSE diff --git a/cc3200/FreeRTOS/Source/croutine.c b/cc3200/FreeRTOS/Source/croutine.c index 3c5bd6f6ec..993e09b29e 100644 --- a/cc3200/FreeRTOS/Source/croutine.c +++ b/cc3200/FreeRTOS/Source/croutine.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -67,6 +71,9 @@ #include "task.h" #include "croutine.h" +/* Remove the whole file is co-routines are not being used. */ +#if( configUSE_CO_ROUTINES != 0 ) + /* * Some kernel aware debuggers require data to be viewed to be global, rather * than file scope. @@ -384,3 +391,5 @@ BaseType_t xReturn; return xReturn; } +#endif /* configUSE_CO_ROUTINES == 0 */ + diff --git a/cc3200/FreeRTOS/Source/event_groups.c b/cc3200/FreeRTOS/Source/event_groups.c index caecbbb586..b8df5fd956 100644 --- a/cc3200/FreeRTOS/Source/event_groups.c +++ b/cc3200/FreeRTOS/Source/event_groups.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -83,14 +87,6 @@ header files above, but not in this file, in order to generate the correct privileged Vs unprivileged linkage and placement. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ -#if ( INCLUDE_xEventGroupSetBitFromISR == 1 ) && ( configUSE_TIMERS == 0 ) - #error configUSE_TIMERS must be set to 1 to make the xEventGroupSetBitFromISR() function available. -#endif - -#if ( INCLUDE_xEventGroupSetBitFromISR == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 0 ) - #error INCLUDE_xTimerPendFunctionCall must also be set to one to make the xEventGroupSetBitFromISR() function available. -#endif - /* The following bit fields convey control information in a task's event list item value. It is important they don't clash with the taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */ @@ -115,6 +111,9 @@ typedef struct xEventGroupDefinition UBaseType_t uxEventGroupNumber; #endif + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ + #endif } EventGroup_t; /*-----------------------------------------------------------*/ @@ -127,28 +126,83 @@ typedef struct xEventGroupDefinition * wait condition is met if any of the bits set in uxBitsToWait for are also set * in uxCurrentEventBits. */ -static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ); +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ -EventGroupHandle_t xEventGroupCreate( void ) -{ -EventGroup_t *pxEventBits; +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) - pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) ); - if( pxEventBits != NULL ) + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) { - pxEventBits->uxEventBits = 0; - vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); - traceEVENT_GROUP_CREATE( pxEventBits ); + EventGroup_t *pxEventBits; + + /* A StaticEventGroup_t object must be provided. */ + configASSERT( pxEventGroupBuffer ); + + /* The user has provided a statically allocated event group - use it. */ + pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note that + this event group was created statically in case the event group + is later deleted. */ + pxEventBits->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; } - else + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + EventGroupHandle_t xEventGroupCreate( void ) { - traceEVENT_GROUP_CREATE_FAILED(); + EventGroup_t *pxEventBits; + + /* Allocate the event group. */ + pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note this + event group was allocated statically in case the event group is + later deleted. */ + pxEventBits->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; } - return ( EventGroupHandle_t ) pxEventBits; -} +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) @@ -276,6 +330,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; /* Check the user is not attempting to wait on the bits used by the kernel itself, and that at least one bit is being requested. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( uxBitsToWaitFor != 0 ); #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) @@ -421,6 +476,7 @@ EventBits_t uxReturn; /* Check the user is not attempting to clear the bits used by the kernel itself. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); taskENTER_CRITICAL(); @@ -482,6 +538,7 @@ BaseType_t xMatchFound = pdFALSE; /* Check the user is not attempting to set the bits used by the kernel itself. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); pxList = &( pxEventBits->xTasksWaitingForBits ); @@ -581,7 +638,26 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } - vPortFree( pxEventBits ); + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The event group can only have been allocated dynamically - free + it again. */ + vPortFree( pxEventBits ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The event group could have been allocated statically or + dynamically, so check before attempting to free the memory. */ + if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxEventBits ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ } ( void ) xTaskResumeAll(); } diff --git a/cc3200/FreeRTOS/Source/include/FreeRTOS.h b/cc3200/FreeRTOS/Source/include/FreeRTOS.h index 08d2f14b48..f81172dbe4 100644 --- a/cc3200/FreeRTOS/Source/include/FreeRTOS.h +++ b/cc3200/FreeRTOS/Source/include/FreeRTOS.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -99,6 +103,15 @@ extern "C" { /* Definitions specific to the port being used. */ #include "portable.h" +/* Must be defaulted before configUSE_NEWLIB_REENTRANT is used below. */ +#ifndef configUSE_NEWLIB_REENTRANT + #define configUSE_NEWLIB_REENTRANT 0 +#endif + +/* Required if struct _reent is used. */ +#if ( configUSE_NEWLIB_REENTRANT == 1 ) + #include <reent.h> +#endif /* * Check all the required application specific macros have been defined. * These macros are application specific and (as downloaded) are defined @@ -125,54 +138,48 @@ extern "C" { #error Missing definition: configUSE_TICK_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif +#ifndef configUSE_16_BIT_TICKS + #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configMAX_PRIORITIES + #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + #ifndef configUSE_CO_ROUTINES - #error Missing definition: configUSE_CO_ROUTINES must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define configUSE_CO_ROUTINES 0 #endif #ifndef INCLUDE_vTaskPrioritySet - #error Missing definition: INCLUDE_vTaskPrioritySet must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define INCLUDE_vTaskPrioritySet 0 #endif #ifndef INCLUDE_uxTaskPriorityGet - #error Missing definition: INCLUDE_uxTaskPriorityGet must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define INCLUDE_uxTaskPriorityGet 0 #endif #ifndef INCLUDE_vTaskDelete - #error Missing definition: INCLUDE_vTaskDelete must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define INCLUDE_vTaskDelete 0 #endif #ifndef INCLUDE_vTaskSuspend - #error Missing definition: INCLUDE_vTaskSuspend must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define INCLUDE_vTaskSuspend 0 #endif #ifndef INCLUDE_vTaskDelayUntil - #error Missing definition: INCLUDE_vTaskDelayUntil must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #define INCLUDE_vTaskDelayUntil 0 #endif #ifndef INCLUDE_vTaskDelay - #error Missing definition: INCLUDE_vTaskDelay must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. -#endif - -#ifndef configUSE_16_BIT_TICKS - #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. -#endif - -#if configUSE_CO_ROUTINES != 0 - #ifndef configMAX_CO_ROUTINE_PRIORITIES - #error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. - #endif -#endif - -#ifndef configMAX_PRIORITIES - #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. + #define INCLUDE_vTaskDelay 0 #endif #ifndef INCLUDE_xTaskGetIdleTaskHandle #define INCLUDE_xTaskGetIdleTaskHandle 0 #endif -#ifndef INCLUDE_xTimerGetTimerDaemonTaskHandle - #define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#ifndef INCLUDE_xTaskAbortDelay + #define INCLUDE_xTaskAbortDelay 0 #endif #ifndef INCLUDE_xQueueGetMutexHolder @@ -183,12 +190,8 @@ extern "C" { #define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder #endif -#ifndef INCLUDE_pcTaskGetTaskName - #define INCLUDE_pcTaskGetTaskName 0 -#endif - -#ifndef configUSE_APPLICATION_TASK_TAG - #define configUSE_APPLICATION_TASK_TAG 0 +#ifndef INCLUDE_xTaskGetHandle + #define INCLUDE_xTaskGetHandle 0 #endif #ifndef INCLUDE_uxTaskGetStackHighWaterMark @@ -199,6 +202,40 @@ extern "C" { #define INCLUDE_eTaskGetState 0 #endif +#ifndef INCLUDE_xTaskResumeFromISR + #define INCLUDE_xTaskResumeFromISR 1 +#endif + +#ifndef INCLUDE_xTimerPendFunctionCall + #define INCLUDE_xTimerPendFunctionCall 0 +#endif + +#ifndef INCLUDE_xTaskGetSchedulerState + #define INCLUDE_xTaskGetSchedulerState 0 +#endif + +#ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 +#endif + +#if configUSE_CO_ROUTINES != 0 + #ifndef configMAX_CO_ROUTINE_PRIORITIES + #error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. + #endif +#endif + +#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK + #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#endif + +#ifndef configUSE_APPLICATION_TASK_TAG + #define configUSE_APPLICATION_TASK_TAG 0 +#endif + +#ifndef configNUM_THREAD_LOCAL_STORAGE_POINTERS + #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#endif + #ifndef configUSE_RECURSIVE_MUTEXES #define configUSE_RECURSIVE_MUTEXES 0 #endif @@ -235,18 +272,6 @@ extern "C" { #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h #endif -#ifndef INCLUDE_xTaskResumeFromISR - #define INCLUDE_xTaskResumeFromISR 1 -#endif - -#ifndef INCLUDE_xEventGroupSetBitFromISR - #define INCLUDE_xEventGroupSetBitFromISR 0 -#endif - -#ifndef INCLUDE_xTimerPendFunctionCall - #define INCLUDE_xTimerPendFunctionCall 0 -#endif - #ifndef configASSERT #define configASSERT( x ) #define configASSERT_DEFINED 0 @@ -271,15 +296,6 @@ extern "C" { #endif /* configUSE_TIMERS */ -#ifndef INCLUDE_xTaskGetSchedulerState - #define INCLUDE_xTaskGetSchedulerState 0 -#endif - -#ifndef INCLUDE_xTaskGetCurrentTaskHandle - #define INCLUDE_xTaskGetCurrentTaskHandle 0 -#endif - - #ifndef portSET_INTERRUPT_MASK_FROM_ISR #define portSET_INTERRUPT_MASK_FROM_ISR() 0 #endif @@ -307,6 +323,7 @@ extern "C" { #if ( configQUEUE_REGISTRY_SIZE < 1 ) #define vQueueAddToRegistry( xQueue, pcName ) #define vQueueUnregisterQueue( xQueue ) + #define pcQueueGetName( xQueue ) #endif #ifndef portPOINTER_SIZE_TYPE @@ -397,6 +414,10 @@ extern "C" { #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) #endif +#ifndef tracePOST_MOVED_TASK_TO_READY_STATE + #define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + #ifndef traceQUEUE_CREATE #define traceQUEUE_CREATE( pxNewQueue ) #endif @@ -498,7 +519,7 @@ extern "C" { #endif #ifndef traceTASK_DELAY_UNTIL - #define traceTASK_DELAY_UNTIL() + #define traceTASK_DELAY_UNTIL( x ) #endif #ifndef traceTASK_DELAY @@ -609,6 +630,34 @@ extern "C" { #define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName) #endif +#ifndef traceTASK_NOTIFY_TAKE_BLOCK + #define traceTASK_NOTIFY_TAKE_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_TAKE + #define traceTASK_NOTIFY_TAKE() +#endif + +#ifndef traceTASK_NOTIFY_WAIT_BLOCK + #define traceTASK_NOTIFY_WAIT_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_WAIT + #define traceTASK_NOTIFY_WAIT() +#endif + +#ifndef traceTASK_NOTIFY + #define traceTASK_NOTIFY() +#endif + +#ifndef traceTASK_NOTIFY_FROM_ISR + #define traceTASK_NOTIFY_FROM_ISR() +#endif + +#ifndef traceTASK_NOTIFY_GIVE_FROM_ISR + #define traceTASK_NOTIFY_GIVE_FROM_ISR() +#endif + #ifndef configGENERATE_RUN_TIME_STATS #define configGENERATE_RUN_TIME_STATS 0 #endif @@ -643,14 +692,6 @@ extern "C" { #define portYIELD_WITHIN_API portYIELD #endif -#ifndef pvPortMallocAligned - #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) ) -#endif - -#ifndef vPortFreeAligned - #define vPortFreeAligned( pvBlockToFree ) vPortFree( pvBlockToFree ) -#endif - #ifndef portSUPPRESS_TICKS_AND_SLEEP #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) #endif @@ -691,10 +732,6 @@ extern "C" { #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 #endif -#ifndef configUSE_NEWLIB_REENTRANT - #define configUSE_NEWLIB_REENTRANT 0 -#endif - #ifndef configUSE_STATS_FORMATTING_FUNCTIONS #define configUSE_STATS_FORMATTING_FUNCTIONS 0 #endif @@ -711,6 +748,10 @@ extern "C" { #define mtCOVERAGE_TEST_MARKER() #endif +#ifndef mtCOVERAGE_TEST_DELAY + #define mtCOVERAGE_TEST_DELAY() +#endif + #ifndef portASSERT_IF_IN_ISR #define portASSERT_IF_IN_ISR() #endif @@ -719,6 +760,60 @@ extern "C" { #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #endif +#ifndef configAPPLICATION_ALLOCATED_HEAP + #define configAPPLICATION_ALLOCATED_HEAP 0 +#endif + +#ifndef configUSE_TASK_NOTIFICATIONS + #define configUSE_TASK_NOTIFICATIONS 1 +#endif + +#ifndef portTICK_TYPE_IS_ATOMIC + #define portTICK_TYPE_IS_ATOMIC 0 +#endif + +#ifndef configSUPPORT_STATIC_ALLOCATION + /* Defaults to 0 for backward compatibility. */ + #define configSUPPORT_STATIC_ALLOCATION 0 +#endif + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION + /* Defaults to 1 for backward compatibility. */ + #define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +/* Sanity check the configuration. */ +#if( configUSE_TICKLESS_IDLE != 0 ) + #if( INCLUDE_vTaskSuspend != 1 ) + #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 + #endif /* INCLUDE_vTaskSuspend */ +#endif /* configUSE_TICKLESS_IDLE */ + +#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) + #error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. +#endif + +#if( ( configUSE_RECURSIVE_MUTEXES == 1 ) && ( configUSE_MUTEXES != 1 ) ) + #error configUSE_MUTEXES must be set to 1 to use recursive mutexes +#endif + +#if( portTICK_TYPE_IS_ATOMIC == 0 ) + /* Either variables of tick type cannot be read atomically, or + portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when + the tick count is returned to the standard critical section macros. */ + #define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) ) +#else + /* The tick type can be read atomically, so critical sections used when the + tick count is returned can be defined away. */ + #define portTICK_TYPE_ENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0 + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) ( void ) x +#endif + /* Definitions to allow backward compatibility with FreeRTOS versions prior to V8 if desired. */ #ifndef configENABLE_BACKWARD_COMPATIBILITY @@ -741,6 +836,10 @@ V8 if desired. */ #define xCoRoutineHandle CoRoutineHandle_t #define pdTASK_HOOK_CODE TaskHookFunction_t #define portTICK_RATE_MS portTICK_PERIOD_MS + #define pcTaskGetTaskName pcTaskGetName + #define pcTimerGetTimerName pcTimerGetName + #define pcQueueGetQueueName pcQueueGetName + #define vTaskGetTaskInfo vTaskGetInfo /* Backward compatibility within the scheduler code only - these definitions are not really required but are included for completeness. */ @@ -750,6 +849,212 @@ V8 if desired. */ #define xList List_t #endif /* configENABLE_BACKWARD_COMPATIBILITY */ +#if( configUSE_ALTERNATIVE_API != 0 ) + #error The alternative API was deprecated some time ago, and was removed in FreeRTOS V9.0 0 +#endif + +/* Set configUSE_TASK_FPU_SUPPORT to 0 to omit floating point support even +if floating point hardware is otherwise supported by the FreeRTOS port in use. +This constant is not supported by all FreeRTOS ports that include floating +point support. */ +#ifndef configUSE_TASK_FPU_SUPPORT + #define configUSE_TASK_FPU_SUPPORT 1 +#endif + +/* + * In line with software engineering best practice, FreeRTOS implements a strict + * data hiding policy, so the real structures used by FreeRTOS to maintain the + * state of tasks, queues, semaphores, etc. are not accessible to the application + * code. However, if the application writer wants to statically allocate such + * an object then the size of the object needs to be know. Dummy structures + * that are guaranteed to have the same size and alignment requirements of the + * real objects are used for this purpose. The dummy list and list item + * structures below are used for inclusion in such a dummy structure. + */ +struct xSTATIC_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 4 ]; +}; +typedef struct xSTATIC_LIST_ITEM StaticListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +struct xSTATIC_MINI_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 2 ]; +}; +typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +typedef struct xSTATIC_LIST +{ + UBaseType_t uxDummy1; + void *pvDummy2; + StaticMiniListItem_t xDummy3; +} StaticList_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. + */ +typedef struct xSTATIC_TCB +{ + void *pxDummy1; + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; + #endif + StaticListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + #if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; + #endif + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; + #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; + #endif + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; + #endif + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; + #endif + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; + #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + uint8_t ucDummy19; + #endif + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t uxDummy20; + #endif + +} StaticTask_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. + */ +typedef struct xSTATIC_QUEUE +{ + void *pvDummy1[ 3 ]; + + union + { + void *pvDummy2; + UBaseType_t uxDummy2; + } u; + + StaticList_t xDummy3[ 2 ]; + UBaseType_t uxDummy4[ 3 ]; + uint8_t ucDummy5[ 2 ]; + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy6; + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + void *pvDummy7; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy8; + uint8_t ucDummy9; + #endif + +} StaticQueue_t; +typedef StaticQueue_t StaticSemaphore_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the event group structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create an event group then the size of the event group object needs to be + * know. The StaticEventGroup_t structure below is provided for this purpose. + * Its sizes and alignment requirements are guaranteed to match those of the + * genuine structure, no matter which architecture is being used, and no matter + * how the values in FreeRTOSConfig.h are set. Its contents are somewhat + * obfuscated in the hope users will recognise that it would be unwise to make + * direct use of the structure members. + */ +typedef struct xSTATIC_EVENT_GROUP +{ + TickType_t xDummy1; + StaticList_t xDummy2; + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy3; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy4; + #endif + +} StaticEventGroup_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the software timer structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create a software timer then the size of the queue object needs to be know. + * The StaticTimer_t structure below is provided for this purpose. Its sizes + * and alignment requirements are guaranteed to match those of the genuine + * structure, no matter which architecture is being used, and no matter how the + * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in + * the hope users will recognise that it would be unwise to make direct use of + * the structure members. + */ +typedef struct xSTATIC_TIMER +{ + void *pvDummy1; + StaticListItem_t xDummy2; + TickType_t xDummy3; + UBaseType_t uxDummy4; + void *pvDummy5[ 2 ]; + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy6; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy7; + #endif + +} StaticTimer_t; + #ifdef __cplusplus } #endif diff --git a/cc3200/FreeRTOS/Source/include/StackMacros.h b/cc3200/FreeRTOS/Source/include/StackMacros.h index c7cfb2869d..13c6b829be 100644 --- a/cc3200/FreeRTOS/Source/include/StackMacros.h +++ b/cc3200/FreeRTOS/Source/include/StackMacros.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -82,28 +86,10 @@ /*-----------------------------------------------------------*/ -#if( configCHECK_FOR_STACK_OVERFLOW == 0 ) - - /* FreeRTOSConfig.h is not set to check for stack overflows. */ - #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() - -#endif /* configCHECK_FOR_STACK_OVERFLOW == 0 */ -/*-----------------------------------------------------------*/ - -#if( configCHECK_FOR_STACK_OVERFLOW == 1 ) - - /* FreeRTOSConfig.h is only set to use the first method of - overflow checking. */ - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() - -#endif -/*-----------------------------------------------------------*/ - -#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH < 0 ) ) +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) /* Only the current stack state is to be checked. */ - #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ + #define taskCHECK_FOR_STACK_OVERFLOW() \ { \ /* Is the currently saved stack pointer within the stack limit? */ \ if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ @@ -112,13 +98,13 @@ } \ } -#endif /* configCHECK_FOR_STACK_OVERFLOW > 0 */ +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ /*-----------------------------------------------------------*/ -#if( ( configCHECK_FOR_STACK_OVERFLOW > 0 ) && ( portSTACK_GROWTH > 0 ) ) +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) /* Only the current stack state is to be checked. */ - #define taskFIRST_CHECK_FOR_STACK_OVERFLOW() \ + #define taskCHECK_FOR_STACK_OVERFLOW() \ { \ \ /* Is the currently saved stack pointer within the stack limit? */ \ @@ -133,20 +119,18 @@ #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ - { \ - static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ - tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ - \ - \ - /* Has the extremity of the task stack ever been written over? */ \ - if( memcmp( ( void * ) pxCurrentTCB->pxStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ - { \ - vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ + const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ + \ + if( ( pulStack[ 0 ] != ulCheckValue ) || \ + ( pulStack[ 1 ] != ulCheckValue ) || \ + ( pulStack[ 2 ] != ulCheckValue ) || \ + ( pulStack[ 3 ] != ulCheckValue ) ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ } #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ @@ -154,7 +138,7 @@ #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) - #define taskSECOND_CHECK_FOR_STACK_OVERFLOW() \ + #define taskCHECK_FOR_STACK_OVERFLOW() \ { \ int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ @@ -176,5 +160,12 @@ #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ /*-----------------------------------------------------------*/ +/* Remove stack overflow macro if not being used. */ +#ifndef taskCHECK_FOR_STACK_OVERFLOW + #define taskCHECK_FOR_STACK_OVERFLOW() +#endif + + + #endif /* STACK_MACROS_H */ diff --git a/cc3200/FreeRTOS/Source/include/croutine.h b/cc3200/FreeRTOS/Source/include/croutine.h index e9a86d0006..4f003a0bae 100644 --- a/cc3200/FreeRTOS/Source/include/croutine.h +++ b/cc3200/FreeRTOS/Source/include/croutine.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and diff --git a/cc3200/FreeRTOS/Source/include/deprecated_definitions.h b/cc3200/FreeRTOS/Source/include/deprecated_definitions.h new file mode 100644 index 0000000000..4ea816ccfd --- /dev/null +++ b/cc3200/FreeRTOS/Source/include/deprecated_definitions.h @@ -0,0 +1,321 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEPRECATED_DEFINITIONS_H +#define DEPRECATED_DEFINITIONS_H + + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. The +definitions below remain in the code for backward compatibility only. New +projects should not use them. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT + #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT + #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef GCC_MEGA_AVR + #include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR + #include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT + #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT + #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" +#endif + +#ifdef _FEDPICC + #include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL + #include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 + #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE + #include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx + #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 + #include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 + #include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 + #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS + #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC + #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR + #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR + #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR + #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR + #include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR + #include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC + #include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR + #include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S + #include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 + #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 + #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR + #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC + #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE + #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 + #include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 + #include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC + #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR + #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 + #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 + #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE + #include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef __GNUC__ + #ifdef __AVR32_AVR32A__ + #include "portmacro.h" + #endif +#endif + +#ifdef __ICCAVR32__ + #ifdef __CORE__ + #if __CORE__ == __AVR32A__ + #include "portmacro.h" + #endif + #endif +#endif + +#ifdef __91467D + #include "portmacro.h" +#endif + +#ifdef __96340 + #include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#endif /* DEPRECATED_DEFINITIONS_H */ + diff --git a/cc3200/FreeRTOS/Source/include/event_groups.h b/cc3200/FreeRTOS/Source/include/event_groups.h index 51e7ea2773..7331c91c25 100644 --- a/cc3200/FreeRTOS/Source/include/event_groups.h +++ b/cc3200/FreeRTOS/Source/include/event_groups.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -70,6 +74,7 @@ #error "include FreeRTOS.h" must appear in source files before "include event_groups.h" #endif +/* FreeRTOS includes. */ #include "timers.h" #ifdef __cplusplus @@ -117,10 +122,10 @@ extern "C" { */ typedef void * EventGroupHandle_t; -/* +/* * The type that holds event bits always matches TickType_t - therefore the * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, - * 32 bits if set to 0. + * 32 bits if set to 0. * * \defgroup EventBits_t EventBits_t * \ingroup EventGroup @@ -133,7 +138,17 @@ typedef TickType_t EventBits_t; EventGroupHandle_t xEventGroupCreate( void ); </pre> * - * Create a new event group. This function cannot be called from an interrupt. + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. * * Although event groups are not related to ticks, for internal implementation * reasons the number of bits available for use in an event group is dependent @@ -169,7 +184,62 @@ typedef TickType_t EventBits_t; * \defgroup xEventGroupCreate xEventGroupCreate * \ingroup EventGroup */ -EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; +#endif + +/** + * event_groups.h + *<pre> + EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer ); + </pre> + * + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store + * event bits within an event group. + * + * @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type + * StaticEventGroup_t, which will be then be used to hold the event group's data + * structures, removing the need for the memory to be allocated dynamically. + * + * @return If the event group was created then a handle to the event group is + * returned. If pxEventGroupBuffer was NULL then NULL is returned. + * + * Example usage: + <pre> + // StaticEventGroup_t is a publicly accessible structure that has the same + // size and alignment requirements as the real event group structure. It is + // provided as a mechanism for applications to know the size of the event + // group (which is dependent on the architecture and configuration file + // settings) without breaking the strict data hiding policy by exposing the + // real event group internals. This StaticEventGroup_t variable is passed + // into the xSemaphoreCreateEventGroupStatic() function and is used to store + // the event group's data structures + StaticEventGroup_t xEventGroupBuffer; + + // Create the event group without dynamically allocating any memory. + xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer ); + </pre> + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION; +#endif /** * event_groups.h @@ -336,8 +406,8 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit * while interrupts are disabled, so protects event groups that are accessed * from tasks by suspending the scheduler rather than disabling interrupts. As * a result event groups cannot be accessed directly from an interrupt service - * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the - * timer task to have the clear operation performed in the context of the timer + * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the + * timer task to have the clear operation performed in the context of the timer * task. * * @param xEventGroup The event group in which the bits are to be cleared. @@ -346,8 +416,8 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit * For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3 * and bit 0 set uxBitsToClear to 0x09. * - * @return If the request to execute the function was posted successfully then - * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned * if the timer service queue was full. * * Example usage: @@ -372,11 +442,11 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit } } </pre> - * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR + * \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR * \ingroup EventGroup */ #if( configUSE_TRACE_FACILITY == 1 ) - BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; #else #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ) #endif @@ -466,7 +536,7 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ * Setting bits in an event group is not a deterministic operation because there * are an unknown number of tasks that may be waiting for the bit or bits being * set. FreeRTOS does not allow nondeterministic operations to be performed in - * interrupts or from critical sections. Therefore xEventGroupSetBitFromISR() + * interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR() * sends a message to the timer task to have the set operation performed in the * context of the timer task - where a scheduler lock is used in place of a * critical section. @@ -487,8 +557,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the * example code below. * - * @return If the request to execute the function was posted successfully then - * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned * if the timer service queue was full. * * Example usage: @@ -517,8 +587,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ if( xResult == pdPASS ) { // If xHigherPriorityTaskWoken is now set to pdTRUE then a context - // switch should be requested. The macro used is port specific and - // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - + // switch should be requested. The macro used is port specific and + // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - // refer to the documentation page for the port being used. portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } @@ -528,7 +598,7 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ * \ingroup EventGroup */ #if( configUSE_TRACE_FACILITY == 1 ) - BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ); + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; #else #define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ) #endif @@ -693,7 +763,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t u * \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR * \ingroup EventGroup */ -EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ); +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; /** * event_groups.h @@ -707,14 +777,15 @@ EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ); * * @param xEventGroup The event group being deleted. */ -void vEventGroupDelete( EventGroupHandle_t xEventGroup ); +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; /* For internal use only. */ -void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ); -void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ); +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION; +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; + #if (configUSE_TRACE_FACILITY == 1) - UBaseType_t uxEventGroupGetNumber( void* xEventGroup ); + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION; #endif #ifdef __cplusplus diff --git a/cc3200/FreeRTOS/Source/include/list.h b/cc3200/FreeRTOS/Source/include/list.h index c08b11d6cc..a080d27def 100644 --- a/cc3200/FreeRTOS/Source/include/list.h +++ b/cc3200/FreeRTOS/Source/include/list.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -91,6 +95,9 @@ * \ingroup FreeRTOSIntro */ +#ifndef INC_FREERTOS_H + #error FreeRTOS.h must be included before list.h +#endif #ifndef LIST_H #define LIST_H @@ -130,21 +137,62 @@ #ifdef __cplusplus extern "C" { #endif + +/* Macros that can be used to place known values within the list structures, +then check that the known values do not get corrupted during the execution of +the application. These may catch the list data structures being overwritten in +memory. They will not catch data errors caused by incorrect configuration or +use of FreeRTOS.*/ +#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) + /* Define the macros to do nothing. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) + #define listTEST_LIST_INTEGRITY( pxList ) +#else + /* Define macros that add new members into the list structures. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1; + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2; + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1; + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2; + + /* Define macros that set the new structure members to known values. */ + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + + /* Define macros that will assert if one of the structure members does not + contain its expected value. */ + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) + #define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) +#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */ + + /* * Definition of the only type of object that a list can contain. */ struct xLIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ }; typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ struct xMINI_LIST_ITEM { + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; struct xLIST_ITEM * configLIST_VOLATILE pxNext; struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; @@ -156,9 +204,11 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t; */ typedef struct xLIST { + listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE UBaseType_t uxNumberOfItems; - ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ - MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ + MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ } List_t; /* @@ -333,7 +383,7 @@ List_t * const pxConstList = ( pxList ); \ * \page vListInitialise vListInitialise * \ingroup LinkedList */ -void vListInitialise( List_t * const pxList ); +void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION; /* * Must be called before a list item is used. This sets the list container to @@ -344,7 +394,7 @@ void vListInitialise( List_t * const pxList ); * \page vListInitialiseItem vListInitialiseItem * \ingroup LinkedList */ -void vListInitialiseItem( ListItem_t * const pxItem ); +void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION; /* * Insert a list item into a list. The item will be inserted into the list in @@ -357,19 +407,19 @@ void vListInitialiseItem( ListItem_t * const pxItem ); * \page vListInsert vListInsert * \ingroup LinkedList */ -void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ); +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; /* * Insert a list item into a list. The item will be inserted in a position * such that it will be the last item within the list returned by multiple * calls to listGET_OWNER_OF_NEXT_ENTRY. * - * The list member pvIndex is used to walk through a list. Calling - * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list. + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list. * Placing an item in a list using vListInsertEnd effectively places the item - * in the list position pointed to by pvIndex. This means that every other + * in the list position pointed to by pxIndex. This means that every other * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before - * the pvIndex parameter again points to the item being inserted. + * the pxIndex parameter again points to the item being inserted. * * @param pxList The list into which the item is to be inserted. * @@ -378,7 +428,7 @@ void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ); * \page vListInsertEnd vListInsertEnd * \ingroup LinkedList */ -void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ); +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; /* * Remove an item from a list. The list item has a pointer to the list that @@ -393,7 +443,7 @@ void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ); * \page uxListRemove uxListRemove * \ingroup LinkedList */ -UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ); +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/cc3200/FreeRTOS/Source/include/mpu_prototypes.h b/cc3200/FreeRTOS/Source/include/mpu_prototypes.h new file mode 100644 index 0000000000..8f7500b022 --- /dev/null +++ b/cc3200/FreeRTOS/Source/include/mpu_prototypes.h @@ -0,0 +1,177 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * When the MPU is used the standard (non MPU) API functions are mapped to + * equivalents that start "MPU_", the prototypes for which are defined in this + * header files. This will cause the application code to call the MPU_ version + * which wraps the non-MPU version with privilege promoting then demoting code, + * so the kernel code always runs will full privileges. + */ + + +#ifndef MPU_PROTOTYPES_H +#define MPU_PROTOTYPES_H + +/* MPU versions of tasks.h API function. */ +BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); +TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); +BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); +void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); +void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); +void MPU_vTaskDelay( const TickType_t xTicksToDelay ); +void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ); +BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ); +UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t xTask ); +eTaskState MPU_eTaskGetState( TaskHandle_t xTask ); +void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); +void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); +void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ); +void MPU_vTaskResume( TaskHandle_t xTaskToResume ); +void MPU_vTaskStartScheduler( void ); +void MPU_vTaskSuspendAll( void ); +BaseType_t MPU_xTaskResumeAll( void ); +TickType_t MPU_xTaskGetTickCount( void ); +UBaseType_t MPU_uxTaskGetNumberOfTasks( void ); +char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ); +TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ); +UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); +void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ); +TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ); +void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ); +void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ); +BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); +TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ); +UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); +void MPU_vTaskList( char * pcWriteBuffer ); +void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ); +BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ); +BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); +uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); +BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ); +BaseType_t MPU_xTaskIncrementTick( void ); +TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ); +void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ); +BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ); +void MPU_vTaskMissedYield( void ); +BaseType_t MPU_xTaskGetSchedulerState( void ); + +/* MPU versions of queue.h API function. */ +BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); +BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); +UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); +UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); +void MPU_vQueueDelete( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ); +QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ); +QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ); +void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); +BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ); +void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ); +void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ); +const char * MPU_pcQueueGetName( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ); +QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ); +BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ); +void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ); +UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ); +uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ); + +/* MPU versions of timers.h API function. */ +TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ); +TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ); +void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ); +void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); +BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ); +TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ); +BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); +const char * MPU_pcTimerGetName( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ); +BaseType_t MPU_xTimerCreateTimerTask( void ); +BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ); + +/* MPU versions of event_group.h API function. */ +EventGroupHandle_t MPU_xEventGroupCreate( void ); +EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ); +EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); +EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ); +EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); +EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ); +void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ); +UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ); + +#endif /* MPU_PROTOTYPES_H */ + diff --git a/cc3200/FreeRTOS/Source/include/mpu_wrappers.h b/cc3200/FreeRTOS/Source/include/mpu_wrappers.h index 6777be5d19..78f5a9aea1 100644 --- a/cc3200/FreeRTOS/Source/include/mpu_wrappers.h +++ b/cc3200/FreeRTOS/Source/include/mpu_wrappers.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -75,60 +79,104 @@ only for ports that are using the MPU. */ those files. */ #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE - #define xTaskGenericCreate MPU_xTaskGenericCreate - #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions - #define vTaskDelete MPU_vTaskDelete - #define vTaskDelayUntil MPU_vTaskDelayUntil - #define vTaskDelay MPU_vTaskDelay - #define uxTaskPriorityGet MPU_uxTaskPriorityGet - #define vTaskPrioritySet MPU_vTaskPrioritySet - #define eTaskGetState MPU_eTaskGetState - #define vTaskSuspend MPU_vTaskSuspend - #define vTaskResume MPU_vTaskResume - #define vTaskSuspendAll MPU_vTaskSuspendAll - #define xTaskResumeAll MPU_xTaskResumeAll - #define xTaskGetTickCount MPU_xTaskGetTickCount - #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks - #define vTaskList MPU_vTaskList - #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats - #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag - #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag - #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook - #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark - #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle - #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState - #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle - #define uxTaskGetSystemState MPU_uxTaskGetSystemState - - #define xQueueGenericCreate MPU_xQueueGenericCreate - #define xQueueCreateMutex MPU_xQueueCreateMutex - #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive - #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive - #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore - #define xQueueGenericSend MPU_xQueueGenericSend - #define xQueueAltGenericSend MPU_xQueueAltGenericSend - #define xQueueAltGenericReceive MPU_xQueueAltGenericReceive - #define xQueueGenericReceive MPU_xQueueGenericReceive - #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting - #define vQueueDelete MPU_vQueueDelete - #define xQueueGenericReset MPU_xQueueGenericReset - #define xQueueCreateSet MPU_xQueueCreateSet - #define xQueueSelectFromSet MPU_xQueueSelectFromSet - #define xQueueAddToSet MPU_xQueueAddToSet - #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet - #define xQueuePeekFromISR MPU_xQueuePeekFromISR - #define xQueueGetMutexHolder MPU_xQueueGetMutexHolder - - #define pvPortMalloc MPU_pvPortMalloc - #define vPortFree MPU_vPortFree - #define xPortGetFreeHeapSize MPU_xPortGetFreeHeapSize - #define vPortInitialiseBlocks MPU_vPortInitialiseBlocks - - #if configQUEUE_REGISTRY_SIZE > 0 - #define vQueueAddToRegistry MPU_vQueueAddToRegistry - #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue + /* + * Map standard (non MPU) API functions to equivalents that start + * "MPU_". This will cause the application code to call the MPU_ + * version, which wraps the non-MPU version with privilege promoting + * then demoting code, so the kernel code always runs will full + * privileges. + */ + + /* Map standard tasks.h API functions to the MPU equivalents. */ + #define xTaskCreate MPU_xTaskCreate + #define xTaskCreateStatic MPU_xTaskCreateStatic + #define xTaskCreateRestricted MPU_xTaskCreateRestricted + #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions + #define vTaskDelete MPU_vTaskDelete + #define vTaskDelay MPU_vTaskDelay + #define vTaskDelayUntil MPU_vTaskDelayUntil + #define xTaskAbortDelay MPU_xTaskAbortDelay + #define uxTaskPriorityGet MPU_uxTaskPriorityGet + #define eTaskGetState MPU_eTaskGetState + #define vTaskGetInfo MPU_vTaskGetInfo + #define vTaskPrioritySet MPU_vTaskPrioritySet + #define vTaskSuspend MPU_vTaskSuspend + #define vTaskResume MPU_vTaskResume + #define vTaskSuspendAll MPU_vTaskSuspendAll + #define xTaskResumeAll MPU_xTaskResumeAll + #define xTaskGetTickCount MPU_xTaskGetTickCount + #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks + #define pcTaskGetName MPU_pcTaskGetName + #define xTaskGetHandle MPU_xTaskGetHandle + #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark + #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag + #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag + #define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer + #define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer + #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook + #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle + #define uxTaskGetSystemState MPU_uxTaskGetSystemState + #define vTaskList MPU_vTaskList + #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats + #define xTaskGenericNotify MPU_xTaskGenericNotify + #define xTaskNotifyWait MPU_xTaskNotifyWait + #define ulTaskNotifyTake MPU_ulTaskNotifyTake + #define xTaskNotifyStateClear MPU_xTaskNotifyStateClear + + #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle + #define vTaskSetTimeOutState MPU_vTaskSetTimeOutState + #define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut + #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + + /* Map standard queue.h API functions to the MPU equivalents. */ + #define xQueueGenericSend MPU_xQueueGenericSend + #define xQueueGenericReceive MPU_xQueueGenericReceive + #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting + #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable + #define vQueueDelete MPU_vQueueDelete + #define xQueueCreateMutex MPU_xQueueCreateMutex + #define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic + #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore + #define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic + #define xQueueGetMutexHolder MPU_xQueueGetMutexHolder + #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive + #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive + #define xQueueGenericCreate MPU_xQueueGenericCreate + #define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic + #define xQueueCreateSet MPU_xQueueCreateSet + #define xQueueAddToSet MPU_xQueueAddToSet + #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet + #define xQueueSelectFromSet MPU_xQueueSelectFromSet + #define xQueueGenericReset MPU_xQueueGenericReset + + #if( configQUEUE_REGISTRY_SIZE > 0 ) + #define vQueueAddToRegistry MPU_vQueueAddToRegistry + #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue + #define pcQueueGetName MPU_pcQueueGetName #endif + /* Map standard timer.h API functions to the MPU equivalents. */ + #define xTimerCreate MPU_xTimerCreate + #define xTimerCreateStatic MPU_xTimerCreateStatic + #define pvTimerGetTimerID MPU_pvTimerGetTimerID + #define vTimerSetTimerID MPU_vTimerSetTimerID + #define xTimerIsTimerActive MPU_xTimerIsTimerActive + #define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle + #define xTimerPendFunctionCall MPU_xTimerPendFunctionCall + #define pcTimerGetName MPU_pcTimerGetName + #define xTimerGetPeriod MPU_xTimerGetPeriod + #define xTimerGetExpiryTime MPU_xTimerGetExpiryTime + #define xTimerGenericCommand MPU_xTimerGenericCommand + + /* Map standard event_group.h API functions to the MPU equivalents. */ + #define xEventGroupCreate MPU_xEventGroupCreate + #define xEventGroupCreateStatic MPU_xEventGroupCreateStatic + #define xEventGroupWaitBits MPU_xEventGroupWaitBits + #define xEventGroupClearBits MPU_xEventGroupClearBits + #define xEventGroupSetBits MPU_xEventGroupSetBits + #define xEventGroupSync MPU_xEventGroupSync + #define vEventGroupDelete MPU_vEventGroupDelete + /* Remove the privileged function macro. */ #define PRIVILEGED_FUNCTION diff --git a/cc3200/FreeRTOS/Source/include/portable.h b/cc3200/FreeRTOS/Source/include/portable.h index f63e99f23e..b9f8be39dd 100644 --- a/cc3200/FreeRTOS/Source/include/portable.h +++ b/cc3200/FreeRTOS/Source/include/portable.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -70,259 +74,36 @@ #ifndef PORTABLE_H #define PORTABLE_H -/* Include the macro file relevant to the port being used. -NOTE: The following definitions are *DEPRECATED* as it is preferred to instead -just add the path to the correct portmacro.h header file to the compiler's -include path. */ -#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT - #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT - #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef GCC_MEGA_AVR - #include "../portable/GCC/ATMega323/portmacro.h" -#endif - -#ifdef IAR_MEGA_AVR - #include "../portable/IAR/ATMega323/portmacro.h" -#endif - -#ifdef MPLAB_PIC24_PORT - #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" -#endif - -#ifdef MPLAB_DSPIC_PORT - #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" -#endif - -#ifdef MPLAB_PIC18F_PORT - #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" -#endif - -#ifdef MPLAB_PIC32MX_PORT - #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" -#endif - -#ifdef _FEDPICC - #include "libFreeRTOS/Include/portmacro.h" -#endif - -#ifdef SDCC_CYGNAL - #include "../../Source/portable/SDCC/Cygnal/portmacro.h" -#endif - -#ifdef GCC_ARM7 - #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" -#endif - -#ifdef GCC_ARM7_ECLIPSE - #include "portmacro.h" -#endif - -#ifdef ROWLEY_LPC23xx - #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" -#endif - -#ifdef IAR_MSP430 - #include "..\..\Source\portable\IAR\MSP430\portmacro.h" -#endif - -#ifdef GCC_MSP430 - #include "../../Source/portable/GCC/MSP430F449/portmacro.h" -#endif - -#ifdef ROWLEY_MSP430 - #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" -#endif - -#ifdef ARM7_LPC21xx_KEIL_RVDS - #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" -#endif - -#ifdef SAM7_GCC - #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" -#endif - -#ifdef SAM7_IAR - #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" -#endif - -#ifdef SAM9XE_IAR - #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" -#endif - -#ifdef LPC2000_IAR - #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" -#endif - -#ifdef STR71X_IAR - #include "..\..\Source\portable\IAR\STR71x\portmacro.h" -#endif - -#ifdef STR75X_IAR - #include "..\..\Source\portable\IAR\STR75x\portmacro.h" -#endif - -#ifdef STR75X_GCC - #include "..\..\Source\portable\GCC\STR75x\portmacro.h" -#endif - -#ifdef STR91X_IAR - #include "..\..\Source\portable\IAR\STR91x\portmacro.h" -#endif - -#ifdef GCC_H8S - #include "../../Source/portable/GCC/H8S2329/portmacro.h" -#endif - -#ifdef GCC_AT91FR40008 - #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" -#endif - -#ifdef RVDS_ARMCM3_LM3S102 - #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" -#endif - -#ifdef GCC_ARMCM3_LM3S102 - #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" -#endif - -#ifdef GCC_ARMCM3 - #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" -#endif - -#ifdef IAR_ARM_CM3 - #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" -#endif - -#ifdef IAR_ARMCM3_LM - #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" -#endif - -#ifdef HCS12_CODE_WARRIOR - #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" -#endif - -#ifdef MICROBLAZE_GCC - #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" -#endif - -#ifdef TERN_EE - #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" -#endif - -#ifdef GCC_HCS12 - #include "../../Source/portable/GCC/HCS12/portmacro.h" -#endif - -#ifdef GCC_MCF5235 - #include "../../Source/portable/GCC/MCF5235/portmacro.h" -#endif - -#ifdef COLDFIRE_V2_GCC - #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" -#endif - -#ifdef COLDFIRE_V2_CODEWARRIOR - #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" -#endif - -#ifdef GCC_PPC405 - #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" -#endif - -#ifdef GCC_PPC440 - #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" -#endif - -#ifdef _16FX_SOFTUNE - #include "..\..\Source\portable\Softune\MB96340\portmacro.h" -#endif - -#ifdef BCC_INDUSTRIAL_PC_PORT - /* A short file name has to be used in place of the normal - FreeRTOSConfig.h when using the Borland compiler. */ - #include "frconfig.h" - #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef BCC_FLASH_LITE_186_PORT - /* A short file name has to be used in place of the normal - FreeRTOSConfig.h when using the Borland compiler. */ - #include "frconfig.h" - #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef __GNUC__ - #ifdef __AVR32_AVR32A__ - #include "portmacro.h" - #endif -#endif - -#ifdef __ICCAVR32__ - #ifdef __CORE__ - #if __CORE__ == __AVR32A__ - #include "portmacro.h" - #endif - #endif -#endif - -#ifdef __91467D - #include "portmacro.h" -#endif - -#ifdef __96340 +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. +Purely for reasons of backward compatibility the old method is still valid, but +to make it clear that new projects should not use it, support for the port +specific constants has been moved into the deprecated_definitions.h header +file. */ +#include "deprecated_definitions.h" + +/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h +did not result in a portmacro.h header file being included - and it should be +included here. In this case the path to the correct portmacro.h header file +must be set in the compiler's include path. */ +#ifndef portENTER_CRITICAL #include "portmacro.h" #endif - -#ifdef __IAR_V850ES_Fx3__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx3__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx3_L__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx2__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Hx2__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_78K0R_Kx3__ - #include "../../Source/portable/IAR/78K0R/portmacro.h" -#endif - -#ifdef __IAR_78K0R_Kx3L__ - #include "../../Source/portable/IAR/78K0R/portmacro.h" +#if portBYTE_ALIGNMENT == 32 + #define portBYTE_ALIGNMENT_MASK ( 0x001f ) #endif -/* Catch all to ensure portmacro.h is included in the build. Newer demos -have the path as part of the project options, rather than as relative from -the project location. If portENTER_CRITICAL() has not been defined then -portmacro.h has not yet been included - as every portmacro.h provides a -portENTER_CRITICAL() definition. Check the demo application for your demo -to find the path to the correct portmacro.h file. */ -#ifndef portENTER_CRITICAL - #include "portmacro.h" +#if portBYTE_ALIGNMENT == 16 + #define portBYTE_ALIGNMENT_MASK ( 0x000f ) #endif #if portBYTE_ALIGNMENT == 8 - #define portBYTE_ALIGNMENT_MASK ( 0x0007U ) + #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) #endif #if portBYTE_ALIGNMENT == 4 @@ -370,18 +151,18 @@ typedef struct HeapRegion size_t xSizeInBytes; } HeapRegion_t; -/* +/* * Used to define multiple heap regions for use by heap_5.c. This function * must be called before any calls to pvPortMalloc() - not creating a task, * queue, semaphore, mutex, software timer, event group, etc. will result in * pvPortMalloc being called. * * pxHeapRegions passes in an array of HeapRegion_t structures - each of which - * defines a region of memory that can be used as the heap. The array is - * terminated by a HeapRegions_t structure that has a size of 0. The region + * defines a region of memory that can be used as the heap. The array is + * terminated by a HeapRegions_t structure that has a size of 0. The region * with the lowest start address must appear first in the array. */ -void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ); +void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION; /* @@ -415,7 +196,7 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; */ #if( portUSING_MPU_WRAPPERS == 1 ) struct xMEMORY_REGION; - void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint16_t usStackDepth ) PRIVILEGED_FUNCTION; + void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION; #endif #ifdef __cplusplus diff --git a/cc3200/FreeRTOS/Source/include/projdefs.h b/cc3200/FreeRTOS/Source/include/projdefs.h index 9eccedff47..0b63fd8a9f 100644 --- a/cc3200/FreeRTOS/Source/include/projdefs.h +++ b/cc3200/FreeRTOS/Source/include/projdefs.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -72,8 +76,12 @@ */ typedef void (*TaskFunction_t)( void * ); -/* Converts a time in milliseconds to a time in ticks. */ -#define pdMS_TO_TICKS( xTimeInMs ) ( ( ( TickType_t ) ( xTimeInMs ) * configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) +/* Converts a time in milliseconds to a time in ticks. This macro can be +overridden by a macro of the same name defined in FreeRTOSConfig.h in case the +definition here is not suitable for your application. */ +#ifndef pdMS_TO_TICKS + #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +#endif #define pdFALSE ( ( BaseType_t ) 0 ) #define pdTRUE ( ( BaseType_t ) 1 ) @@ -83,11 +91,70 @@ typedef void (*TaskFunction_t)( void * ); #define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) #define errQUEUE_FULL ( ( BaseType_t ) 0 ) -/* Error definitions. */ +/* FreeRTOS error definitions. */ #define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) #define errQUEUE_BLOCKED ( -4 ) #define errQUEUE_YIELD ( -5 ) +/* Macros used for basic data corruption checks. */ +#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES + #define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0 +#endif + +#if( configUSE_16_BIT_TICKS == 1 ) + #define pdINTEGRITY_CHECK_VALUE 0x5a5a +#else + #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL +#endif + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_ERRNO_NONE 0 /* No errors */ +#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ +#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ +#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ +#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ +#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ +#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ +#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ +#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ +#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ +#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ +#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ +#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ +#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ +#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ +#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ +#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ +#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ +#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ +#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ +#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ +#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ +#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ +#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ +#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ +#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ +#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ +#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ +#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ +#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ +#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ +#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ +#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ +#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ +#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ +#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ +#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ +#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ +#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + +/* The following endian values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_LITTLE_ENDIAN 0 +#define pdFREERTOS_BIG_ENDIAN 1 + #endif /* PROJDEFS_H */ diff --git a/cc3200/FreeRTOS/Source/include/queue.h b/cc3200/FreeRTOS/Source/include/queue.h index a728a7c51c..30be360136 100644 --- a/cc3200/FreeRTOS/Source/include/queue.h +++ b/cc3200/FreeRTOS/Source/include/queue.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -119,8 +123,20 @@ typedef void * QueueSetMemberHandle_t; ); * </pre> * - * Creates a new queue instance. This allocates the storage required by the - * new queue and returns a handle for the queue. + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html * * @param uxQueueLength The maximum number of items that the queue can contain. * @@ -166,7 +182,95 @@ typedef void * QueueSetMemberHandle_t; * \defgroup xQueueCreate xQueueCreate * \ingroup QueueManagement */ -#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) +#endif + +/** + * queue. h + * <pre> + QueueHandle_t xQueueCreateStatic( + UBaseType_t uxQueueLength, + UBaseType_t uxItemSize, + uint8_t *pucQueueStorageBuffer, + StaticQueue_t *pxQueueBuffer + ); + * </pre> + * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @param pucQueueStorageBuffer If uxItemSize is not zero then + * pucQueueStorageBuffer must point to a uint8_t array that is at least large + * enough to hold the maximum number of items that can be in the queue at any + * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * zero then pucQueueStorageBuffer can be NULL. + * + * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which + * will be used to hold the queue's data structure. + * + * @return If the queue is created then a handle to the created queue is + * returned. If pxQueueBuffer is NULL then NULL is returned. + * + * Example usage: + <pre> + struct AMessage + { + char ucMessageID; + char ucData[ 20 ]; + }; + + #define QUEUE_LENGTH 10 + #define ITEM_SIZE sizeof( uint32_t ) + + // xQueueBuffer will hold the queue structure. + StaticQueue_t xQueueBuffer; + + // ucQueueStorage will hold the items posted to the queue. Must be at least + // [(queue length) * ( queue item size)] bytes long. + uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ]; + + void vATask( void *pvParameters ) + { + QueueHandle_t xQueue1; + + // Create a queue capable of containing 10 uint32_t values. + xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold. + ITEM_SIZE // The size of each item in the queue + &( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue. + &xQueueBuffer ); // The buffer that will hold the queue structure. + + // The queue is guaranteed to be created successfully as no dynamic memory + // allocation is used. Therefore xQueue1 is now a handle to a valid queue. + + // ... Rest of task code. + } + </pre> + * \defgroup xQueueCreateStatic xQueueCreateStatic + * \ingroup QueueManagement + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * queue. h @@ -1269,7 +1373,8 @@ uint32_t ulVarToSend, ulValReceived; * * It is preferred that the macros xQueueSendFromISR(), * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place - * of calling this function directly. + * of calling this function directly. xQueueGiveFromISR() is an + * equivalent for use by semaphores that don't actually copy any data. * * Post an item on a queue. It is safe to use this function from within an * interrupt service routine. @@ -1333,6 +1438,7 @@ uint32_t ulVarToSend, ulValReceived; * \ingroup QueueManagement */ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1431,28 +1537,6 @@ BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FU BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; - -/* - * xQueueAltGenericSend() is an alternative version of xQueueGenericSend(). - * Likewise xQueueAltGenericReceive() is an alternative version of - * xQueueGenericReceive(). - * - * The source code that implements the alternative (Alt) API is much - * simpler because it executes everything from within a critical section. - * This is the approach taken by many other RTOSes, but FreeRTOS.org has the - * preferred fully featured API too. The fully featured API has more - * complex code that takes longer to execute, but makes much less use of - * critical sections. Therefore the alternative API sacrifices interrupt - * responsiveness to gain execution speed, whereas the fully featured API - * sacrifices execution speed to ensure better interrupt responsiveness. - */ -BaseType_t xQueueAltGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ); -BaseType_t xQueueAltGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ); -#define xQueueAltSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) -#define xQueueAltSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueAltGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) -#define xQueueAltReceive( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) -#define xQueueAltPeek( xQueue, pvBuffer, xTicksToWait ) xQueueAltGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) - /* * The functions defined above are for passing data to and from tasks. The * functions below are the equivalents for passing data to and from @@ -1473,7 +1557,9 @@ BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTi * these functions directly. */ QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; /* @@ -1484,10 +1570,8 @@ BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWa BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION; /* - * Reset a queue back to its original empty state. pdPASS is returned if the - * queue is successfully reset. pdFAIL is returned if the queue could not be - * reset because there are tasks blocked on the queue waiting to either - * receive from the queue or send to the queue. + * Reset a queue back to its original empty state. The return value is now + * obsolete and is always set to pdPASS. */ #define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) @@ -1513,7 +1597,7 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION * stores a pointer to the string - so the string must be persistent (global or * preferably in ROM/Flash), not on the stack. */ -#if configQUEUE_REGISTRY_SIZE > 0 +#if( configQUEUE_REGISTRY_SIZE > 0 ) void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #endif @@ -1527,15 +1611,42 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION * * @param xQueue The handle of the queue being removed from the registry. */ -#if configQUEUE_REGISTRY_SIZE > 0 +#if( configQUEUE_REGISTRY_SIZE > 0 ) void vQueueUnregisterQueue( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; #endif /* - * Generic version of the queue creation function, which is in turn called by - * any queue, semaphore or mutex creation function or macro. + * The queue registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call pcQueueGetName() to look + * up and return the name of a queue in the queue registry from the queue's + * handle. + * + * @param xQueue The handle of the queue the name of which will be returned. + * @return If the queue is in the registry then a pointer to the name of the + * queue is returned. If the queue is not in the registry then NULL is + * returned. */ -QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#if( configQUEUE_REGISTRY_SIZE > 0 ) + const char *pcQueueGetName( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif /* * Queue sets provide a mechanism to allow a task to block (pend) on a read @@ -1672,7 +1783,7 @@ QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const Ti QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; /* Not public API functions. */ -void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION; void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION; UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; diff --git a/cc3200/FreeRTOS/Source/include/semphr.h b/cc3200/FreeRTOS/Source/include/semphr.h index 5275895438..a674b02a41 100644 --- a/cc3200/FreeRTOS/Source/include/semphr.h +++ b/cc3200/FreeRTOS/Source/include/semphr.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -83,6 +87,10 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h * <pre>vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )</pre> * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the * xSemaphoreCreateBinary() function. Note that binary semaphores created using * the vSemaphoreCreateBinary() macro are created in a state such that the @@ -124,19 +132,37 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \ingroup Semaphores */ -#define vSemaphoreCreateBinary( xSemaphore ) \ - { \ - ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ - if( ( xSemaphore ) != NULL ) \ - { \ - ( void ) xSemaphoreGive( ( xSemaphore ) ); \ - } \ - } +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } +#endif /** * semphr. h * <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre> * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this * xSemaphoreCreateBinary() function. Note that binary semaphores created using * the vSemaphoreCreateBinary() macro are created in a state such that the @@ -144,11 +170,6 @@ typedef QueueHandle_t SemaphoreHandle_t; * created using xSemaphoreCreateBinary() are created in a state such that the * the semaphore must first be 'given' before it can be 'taken'. * - * Function that creates a semaphore by using the existing queue mechanism. - * The queue length is 1 as this is a binary semaphore. The data size is 0 - * as nothing is actually stored - all that is important is whether the queue is - * empty or full (the binary semaphore is available or not). - * * This type of semaphore can be used for pure synchronisation between tasks or * between an interrupt and a task. The semaphore need not be given back once * obtained, so one task/interrupt can continuously 'give' the semaphore while @@ -156,7 +177,8 @@ typedef QueueHandle_t SemaphoreHandle_t; * semaphore does not use a priority inheritance mechanism. For an alternative * that does use priority inheritance see xSemaphoreCreateMutex(). * - * @return Handle to the created semaphore. + * @return Handle to the created semaphore, or NULL if the memory required to + * hold the semaphore's data structures could not be allocated. * * Example usage: <pre> @@ -164,7 +186,7 @@ typedef QueueHandle_t SemaphoreHandle_t; void vATask( void * pvParameters ) { - // Semaphore cannot be used before a call to vSemaphoreCreateBinary (). + // Semaphore cannot be used before a call to xSemaphoreCreateBinary(). // This is a macro so pass the variable in directly. xSemaphore = xSemaphoreCreateBinary(); @@ -175,10 +197,71 @@ typedef QueueHandle_t SemaphoreHandle_t; } } </pre> - * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary * \ingroup Semaphores */ -#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif + +/** + * semphr. h + * <pre>SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )</pre> + * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * NOTE: In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the semaphore is created then a handle to the created semaphore is + * returned. If pxSemaphoreBuffer is NULL then NULL is returned. + * + * Example usage: + <pre> + SemaphoreHandle_t xSemaphore = NULL; + StaticSemaphore_t xSemaphoreBuffer; + + void vATask( void * pvParameters ) + { + // Semaphore cannot be used before a call to xSemaphoreCreateBinary(). + // The semaphore's data structures will be placed in the xSemaphoreBuffer + // variable, the address of which is passed into the function. The + // function's parameter is not NULL, so the function will not attempt any + // dynamic memory allocation, and therefore the function will not return + // return NULL. + xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer ); + + // Rest of task code goes here. + } + </pre> + * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h @@ -188,7 +271,7 @@ typedef QueueHandle_t SemaphoreHandle_t; * )</pre> * * <i>Macro</i> to obtain a semaphore. The semaphore must have previously been - * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or * xSemaphoreCreateCounting(). * * @param xSemaphore A handle to the semaphore being taken - obtained when @@ -211,7 +294,7 @@ typedef QueueHandle_t SemaphoreHandle_t; void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + xSemaphore = xSemaphoreCreateBinary(); } // A task that uses the semaphore. @@ -338,29 +421,16 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive * \ingroup Semaphores */ -#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) - - -/* - * xSemaphoreAltTake() is an alternative version of xSemaphoreTake(). - * - * The source code that implements the alternative (Alt) API is much - * simpler because it executes everything from within a critical section. - * This is the approach taken by many other RTOSes, but FreeRTOS.org has the - * preferred fully featured API too. The fully featured API has more - * complex code that takes longer to execute, but makes much less use of - * critical sections. Therefore the alternative API sacrifices interrupt - * responsiveness to gain execution speed, whereas the fully featured API - * sacrifices execution speed to ensure better interrupt responsiveness. - */ -#define xSemaphoreAltTake( xSemaphore, xBlockTime ) xQueueAltGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) +#endif /** * semphr. h * <pre>xSemaphoreGive( SemaphoreHandle_t xSemaphore )</pre> * * <i>Macro</i> to release a semaphore. The semaphore must have previously been - * created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). * * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for @@ -384,7 +454,7 @@ typedef QueueHandle_t SemaphoreHandle_t; void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + xSemaphore = vSemaphoreCreateBinary(); if( xSemaphore != NULL ) { @@ -500,21 +570,9 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive * \ingroup Semaphores */ -#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) - -/* - * xSemaphoreAltGive() is an alternative version of xSemaphoreGive(). - * - * The source code that implements the alternative (Alt) API is much - * simpler because it executes everything from within a critical section. - * This is the approach taken by many other RTOSes, but FreeRTOS.org has the - * preferred fully featured API too. The fully featured API has more - * complex code that takes longer to execute, but makes much less use of - * critical sections. Therefore the alternative API sacrifices interrupt - * responsiveness to gain execution speed, whereas the fully featured API - * sacrifices execution speed to ensure better interrupt responsiveness. - */ -#define xSemaphoreAltGive( xSemaphore ) xQueueAltGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) +#endif /** * semphr. h @@ -525,7 +583,7 @@ typedef QueueHandle_t SemaphoreHandle_t; )</pre> * * <i>Macro</i> to release a semaphore. The semaphore must have previously been - * created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting(). + * created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting(). * * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) * must not be used with this macro. @@ -605,7 +663,7 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR * \ingroup Semaphores */ -#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) /** * semphr. h @@ -616,7 +674,7 @@ typedef QueueHandle_t SemaphoreHandle_t; )</pre> * * <i>Macro</i> to take a semaphore from an ISR. The semaphore must have - * previously been created with a call to vSemaphoreCreateBinary() or + * previously been created with a call to xSemaphoreCreateBinary() or * xSemaphoreCreateCounting(). * * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) @@ -645,12 +703,21 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h * <pre>SemaphoreHandle_t xSemaphoreCreateMutex( void )</pre> * - * <i>Macro</i> that implements a mutex semaphore by using the existing queue - * mechanism. + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. * - * Mutexes created using this macro can be accessed using the xSemaphoreTake() + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and - * xSemaphoreGiveRecursive() macros should not be used. + * xSemaphoreGiveRecursive() macros must not be used. * * This type of semaphore uses a priority inheritance mechanism so a task * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the @@ -658,13 +725,14 @@ typedef QueueHandle_t SemaphoreHandle_t; * * Mutex type semaphores cannot be used from within interrupt service routines. * - * See vSemaphoreCreateBinary() for an alternative implementation that can be + * See xSemaphoreCreateBinary() for an alternative implementation that can be * used for pure synchronisation (where one task or interrupt always 'gives' the * semaphore and another always 'takes' the semaphore) and from within interrupt * service routines. * - * @return xSemaphore Handle to the created mutex semaphore. Should be of type - * SemaphoreHandle_t. + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. * * Example usage: <pre> @@ -683,22 +751,96 @@ typedef QueueHandle_t SemaphoreHandle_t; } } </pre> - * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex * \ingroup Semaphores */ -#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) +#endif + +/** + * semphr. h + * <pre>SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre> + * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will be used to hold the mutex's data structure, removing the need for + * the memory to be allocated dynamically. + * + * @return If the mutex was successfully created then a handle to the created + * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. + * + * Example usage: + <pre> + SemaphoreHandle_t xSemaphore; + StaticSemaphore_t xMutexBuffer; + + void vATask( void * pvParameters ) + { + // A mutex cannot be used before it has been created. xMutexBuffer is + // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is + // attempted. + xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer ); + + // As no dynamic memory allocation was performed, xSemaphore cannot be NULL, + // so there is no need to check it. + } + </pre> + * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h * <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</pre> * - * <i>Macro</i> that implements a recursive mutex by using the existing queue - * mechanism. + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. * * Mutexes created using this macro can be accessed using the * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The - * xSemaphoreTake() and xSemaphoreGive() macros should not be used. + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. * * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex * doesn't become available again until the owner has called @@ -713,13 +855,13 @@ typedef QueueHandle_t SemaphoreHandle_t; * * Mutex type semaphores cannot be used from within interrupt service routines. * - * See vSemaphoreCreateBinary() for an alternative implementation that can be + * See xSemaphoreCreateBinary() for an alternative implementation that can be * used for pure synchronisation (where one task or interrupt always 'gives' the * semaphore and another always 'takes' the semaphore) and from within interrupt * service routines. * * @return xSemaphore Handle to the created mutex semaphore. Should be of type - * SemaphoreHandle_t. + * SemaphoreHandle_t. * * Example usage: <pre> @@ -738,17 +880,107 @@ typedef QueueHandle_t SemaphoreHandle_t; } } </pre> - * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex * \ingroup Semaphores */ -#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#endif + +/** + * semphr. h + * <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre> + * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the recursive mutex's data structure, + * removing the need for the memory to be allocated dynamically. + * + * @return If the recursive mutex was successfully created then a handle to the + * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is + * returned. + * + * Example usage: + <pre> + SemaphoreHandle_t xSemaphore; + StaticSemaphore_t xMutexBuffer; + + void vATask( void * pvParameters ) + { + // A recursive semaphore cannot be used before it is created. Here a + // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic(). + // The address of xMutexBuffer is passed into the function, and will hold + // the mutexes data structures - so no dynamic memory allocation will be + // attempted. + xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer ); + + // As no dynamic memory allocation was performed, xSemaphore cannot be NULL, + // so there is no need to check it. + } + </pre> + * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h * <pre>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )</pre> * - * <i>Macro</i> that creates a counting semaphore by using the existing - * queue mechanism. + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer can + * instead optionally provide the memory that will get used by the counting + * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting + * semaphore to be created without using any dynamic memory allocation. * * Counting semaphores are typically used for two things: * @@ -804,7 +1036,94 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting * \ingroup Semaphores */ -#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#endif + +/** + * semphr. h + * <pre>SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )</pre> + * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer must + * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a + * counting semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the counting semaphore was successfully created then a handle to + * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL + * then NULL is returned. + * + * Example usage: + <pre> + SemaphoreHandle_t xSemaphore; + StaticSemaphore_t xSemaphoreBuffer; + + void vATask( void * pvParameters ) + { + SemaphoreHandle_t xSemaphore = NULL; + + // Counting semaphore cannot be used before they have been created. Create + // a counting semaphore using xSemaphoreCreateCountingStatic(). The max + // value to which the semaphore can count is 10, and the initial value + // assigned to the count will be 0. The address of xSemaphoreBuffer is + // passed in and will be used to hold the semaphore structure, so no dynamic + // memory allocation will be used. + xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer ); + + // No memory allocation was attempted so xSemaphore cannot be NULL, so there + // is no need to check its value. + } + </pre> + * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h @@ -835,6 +1154,18 @@ typedef QueueHandle_t SemaphoreHandle_t; */ #define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) +/** + * semphr.h + * <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre> + * + * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns + * its current count value. If the semaphore is a binary semaphore then + * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the + * semaphore is not available. + * + */ +#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) + #endif /* SEMAPHORE_H */ diff --git a/cc3200/FreeRTOS/Source/include/task.h b/cc3200/FreeRTOS/Source/include/task.h index 8ed65bc28f..d0643c09e8 100644 --- a/cc3200/FreeRTOS/Source/include/task.h +++ b/cc3200/FreeRTOS/Source/include/task.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -81,10 +85,10 @@ extern "C" { * MACROS AND DEFINITIONS *----------------------------------------------------------*/ -#define tskKERNEL_VERSION_NUMBER "V8.1.2" -#define tskKERNEL_VERSION_MAJOR 8 -#define tskKERNEL_VERSION_MINOR 1 -#define tskKERNEL_VERSION_BUILD 2 +#define tskKERNEL_VERSION_NUMBER "V9.0.0" +#define tskKERNEL_VERSION_MAJOR 9 +#define tskKERNEL_VERSION_MINOR 0 +#define tskKERNEL_VERSION_BUILD 0 /** * task. h @@ -111,16 +115,27 @@ typedef enum eReady, /* The task being queried is in a read or pending ready list. */ eBlocked, /* The task being queried is in the Blocked state. */ eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ - eDeleted /* The task being queried has been deleted, but its TCB has not yet been freed. */ + eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */ + eInvalid /* Used as an 'invalid state' value. */ } eTaskState; +/* Actions that can be performed when vTaskNotify() is called. */ +typedef enum +{ + eNoAction = 0, /* Notify the task without updating its notify value. */ + eSetBits, /* Set bits in the task's notification value. */ + eIncrement, /* Increment the task's notification value. */ + eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ + eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ +} eNotifyAction; + /* * Used internally only. */ typedef struct xTIME_OUT { BaseType_t xOverflowCount; - TickType_t xTimeOnEntering; + TickType_t xTimeOnEntering; } TimeOut_t; /* @@ -158,6 +173,7 @@ typedef struct xTASK_STATUS UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ } TaskStatus_t; @@ -169,7 +185,6 @@ typedef enum eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ } eSleepModeStatus; - /** * Defines the priority used by the idle task. This must not be modified. * @@ -200,6 +215,7 @@ typedef enum * \ingroup SchedulerControl */ #define taskENTER_CRITICAL() portENTER_CRITICAL() +#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() /** * task. h @@ -214,7 +230,7 @@ typedef enum * \ingroup SchedulerControl */ #define taskEXIT_CRITICAL() portEXIT_CRITICAL() - +#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) /** * task. h * @@ -261,6 +277,19 @@ is used in assert() statements. */ * * Create a new task and add it to the list of tasks that are ready to run. * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * See xTaskCreateStatic() for a version that does not use any dynamic memory + * allocation. + * * xTaskCreate() can only be used to create a task that has unrestricted * access to the entire microcontroller memory map. Systems that include MPU * support can alternatively create an MPU constrained task using @@ -327,7 +356,131 @@ is used in assert() statements. */ * \defgroup xTaskCreate xTaskCreate * \ingroup Tasks */ -#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) ) +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * task. h + *<pre> + TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode, + const char * const pcName, + uint32_t ulStackDepth, + void *pvParameters, + UBaseType_t uxPriority, + StackType_t *pxStackBuffer, + StaticTask_t *pxTaskBuffer );</pre> + * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param ulStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pxStackBuffer Must point to a StackType_t array that has at least + * ulStackDepth indexes - the array will then be used as the task's stack, + * removing the need for the stack to be allocated dynamically. + * + * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will + * then be used to hold the task's data structures, removing the need for the + * memory to be allocated dynamically. + * + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will + * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer + * are NULL then the task will not be created and + * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * + * Example usage: + <pre> + + // Dimensions the buffer that the task being created will use as its stack. + // NOTE: This is the number of words the stack will hold, not the number of + // bytes. For example, if each stack item is 32-bits, and this is set to 100, + // then 400 bytes (100 * 32-bits) will be allocated. + #define STACK_SIZE 200 + + // Structure that will hold the TCB of the task being created. + StaticTask_t xTaskBuffer; + + // Buffer that the task being created will use as its stack. Note this is + // an array of StackType_t variables. The size of StackType_t is dependent on + // the RTOS port. + StackType_t xStack[ STACK_SIZE ]; + + // Function that implements the task being created. + void vTaskCode( void * pvParameters ) + { + // The parameter value is expected to be 1 as 1 is passed in the + // pvParameters value in the call to xTaskCreateStatic(). + configASSERT( ( uint32_t ) pvParameters == 1UL ); + + for( ;; ) + { + // Task code goes here. + } + } + + // Function that creates a task. + void vOtherFunction( void ) + { + TaskHandle_t xHandle = NULL; + + // Create the task without using any dynamic memory allocation. + xHandle = xTaskCreateStatic( + vTaskCode, // Function that implements the task. + "NAME", // Text name for the task. + STACK_SIZE, // Stack size in words, not bytes. + ( void * ) 1, // Parameter passed into the task. + tskIDLE_PRIORITY,// Priority at which the task is created. + xStack, // Array to use as the task's stack. + &xTaskBuffer ); // Variable to hold the task's data structure. + + // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have + // been created, and xHandle will be the task's handle. Use the handle + // to suspend the task. + vTaskSuspend( xHandle ); + } + </pre> + * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * task. h @@ -396,7 +549,9 @@ TaskHandle_t xHandle; * \defgroup xTaskCreateRestricted xTaskCreateRestricted * \ingroup Tasks */ -#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) ) +#if( portUSING_MPU_WRAPPERS == 1 ) + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /** * task. h @@ -600,6 +755,31 @@ void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xT /** * task. h + * <pre>BaseType_t xTaskAbortDelay( TaskHandle_t xTask );</pre> + * + * INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this + * function to be available. + * + * A task will enter the Blocked state when it is waiting for an event. The + * event it is waiting for can be a temporal event (waiting for a time), such + * as when vTaskDelay() is called, or an event on an object, such as when + * xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task + * that is in the Blocked state is used in a call to xTaskAbortDelay() then the + * task will leave the Blocked state, and return from whichever function call + * placed the task into the Blocked state. + * + * @param xTask The handle of the task to remove from the Blocked state. + * + * @return If the task referenced by xTask was not in the Blocked state then + * pdFAIL is returned. Otherwise pdPASS is returned. + * + * \defgroup xTaskAbortDelay xTaskAbortDelay + * \ingroup TaskCtrl + */ +BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h * <pre>UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );</pre> * * INCLUDE_uxTaskPriorityGet must be defined as 1 for this function to be available. @@ -647,6 +827,14 @@ UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h + * <pre>UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask );</pre> + * + * A version of uxTaskPriorityGet() that can be used from an ISR. + */ +UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h * <pre>eTaskState eTaskGetState( TaskHandle_t xTask );</pre> * * INCLUDE_eTaskGetState must be defined as 1 for this function to be available. @@ -665,6 +853,62 @@ eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; /** * task. h + * <pre>void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );</pre> + * + * configUSE_TRACE_FACILITY must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * Populates a TaskStatus_t structure with information about a task. + * + * @param xTask Handle of the task being queried. If xTask is NULL then + * information will be returned about the calling task. + * + * @param pxTaskStatus A pointer to the TaskStatus_t structure that will be + * filled with information about the task referenced by the handle passed using + * the xTask parameter. + * + * @xGetFreeStackSpace The TaskStatus_t structure contains a member to report + * the stack high water mark of the task being queried. Calculating the stack + * high water mark takes a relatively long time, and can make the system + * temporarily unresponsive - so the xGetFreeStackSpace parameter is provided to + * allow the high water mark checking to be skipped. The high watermark value + * will only be written to the TaskStatus_t structure if xGetFreeStackSpace is + * not set to pdFALSE; + * + * @param eState The TaskStatus_t structure contains a member to report the + * state of the task being queried. Obtaining the task state is not as fast as + * a simple assignment - so the eState parameter is provided to allow the state + * information to be omitted from the TaskStatus_t structure. To obtain state + * information then set eState to eInvalid - otherwise the value passed in + * eState will be reported as the task state in the TaskStatus_t structure. + * + * Example usage: + <pre> + void vAFunction( void ) + { + TaskHandle_t xHandle; + TaskStatus_t xTaskDetails; + + // Obtain the handle of a task from its name. + xHandle = xTaskGetHandle( "Task_Name" ); + + // Check the handle is not NULL. + configASSERT( xHandle ); + + // Use the handle to obtain further information about the task. + vTaskGetInfo( xHandle, + &xTaskDetails, + pdTRUE, // Include the high water mark in xTaskDetails. + eInvalid ); // Include the task state in xTaskDetails. + } + </pre> + * \defgroup vTaskGetInfo vTaskGetInfo + * \ingroup TaskCtrl + */ +void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) PRIVILEGED_FUNCTION; + +/** + * task. h * <pre>void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );</pre> * * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. @@ -1075,17 +1319,32 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; /** * task. h - * <PRE>char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery );</PRE> + * <PRE>char *pcTaskGetName( TaskHandle_t xTaskToQuery );</PRE> * * @return The text (human readable) name of the task referenced by the handle * xTaskToQuery. A task can query its own name by either passing in its own - * handle, or by setting xTaskToQuery to NULL. INCLUDE_pcTaskGetTaskName must be - * set to 1 in FreeRTOSConfig.h for pcTaskGetTaskName() to be available. + * handle, or by setting xTaskToQuery to NULL. * - * \defgroup pcTaskGetTaskName pcTaskGetTaskName + * \defgroup pcTaskGetName pcTaskGetName * \ingroup TaskUtils */ -char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + * <PRE>TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );</PRE> + * + * NOTE: This function takes a relatively long time to complete and should be + * used sparingly. + * + * @return The handle of the task that has the human readable name pcNameToQuery. + * NULL is returned if no matching name is found. INCLUDE_xTaskGetHandle + * must be set to 1 in FreeRTOSConfig.h for pcTaskGetHandle() to be available. + * + * \defgroup pcTaskGetHandle pcTaskGetHandle + * \ingroup TaskUtils + */ +TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /** * task.h @@ -1136,6 +1395,18 @@ constant. */ #endif /* configUSE_APPLICATION_TASK_TAG ==1 */ #endif /* ifdef configUSE_APPLICATION_TASK_TAG */ +#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + + /* Each task contains an array of pointers that is dimensioned by the + configNUM_THREAD_LOCAL_STORAGE_POINTERS setting in FreeRTOSConfig.h. The + kernel does not use the pointers itself, so the application writer can use + the pointers for any purpose they wish. The following two functions are + used to set and query a pointer respectively. */ + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) PRIVILEGED_FUNCTION; + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; + +#endif + /** * task.h * <pre>BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );</pre> @@ -1156,7 +1427,7 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) * Simply returns the handle of the idle task. It is not valid to call * xTaskGetIdleTaskHandle() before the scheduler has been started. */ -TaskHandle_t xTaskGetIdleTaskHandle( void ); +TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; /** * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for @@ -1255,7 +1526,7 @@ TaskHandle_t xTaskGetIdleTaskHandle( void ); } </pre> */ -UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); +UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) PRIVILEGED_FUNCTION; /** * task. h @@ -1358,6 +1629,441 @@ void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unquali */ void vTaskGetRunTimeStats( char *pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/** + * task. h + * <PRE>BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );</PRE> + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * pulPreviousNotificationValue - + * Can be used to pass out the subject task's notification value before any + * bits are modified by the notify function. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION; +#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL ) +#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) + +/** + * task. h + * <PRE>BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );</PRE> + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotify() that can be used from an interrupt service routine + * (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * xTaskNotifyFromISR() sets this value to pdTRUE then a context switch should + * be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; +#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) +#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) ) + +/** + * task. h + * <PRE>BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );</pre> + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param ulBitsToClearOnEntry Bits that are set in ulBitsToClearOnEntry value + * will be cleared in the calling task's notification value before the task + * checks to see if any notifications are pending, and optionally blocks if no + * notifications are pending. Setting ulBitsToClearOnEntry to ULONG_MAX (if + * limits.h is included) or 0xffffffffUL (if limits.h is not included) will have + * the effect of resetting the task's notification value to 0. Setting + * ulBitsToClearOnEntry to 0 will leave the task's notification value unchanged. + * + * @param ulBitsToClearOnExit If a notification is pending or received before + * the calling task exits the xTaskNotifyWait() function then the task's + * notification value (see the xTaskNotify() API function) is passed out using + * the pulNotificationValue parameter. Then any bits that are set in + * ulBitsToClearOnExit will be cleared in the task's notification value (note + * *pulNotificationValue is set before any bits are cleared). Setting + * ulBitsToClearOnExit to ULONG_MAX (if limits.h is included) or 0xffffffffUL + * (if limits.h is not included) will have the effect of resetting the task's + * notification value to 0 before the function exits. Setting + * ulBitsToClearOnExit to 0 will leave the task's notification value unchanged + * when the function exits (in which case the value passed out in + * pulNotificationValue will match the task's notification value). + * + * @param pulNotificationValue Used to pass the task's notification value out + * of the function. Note the value passed out will not be effected by the + * clearing of any bits caused by ulBitsToClearOnExit being non-zero. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for a notification to be received, should a notification + * not already be pending when xTaskNotifyWait() was called. The task + * will not consume any processing time while it is in the Blocked state. This + * is specified in kernel ticks, the macro pdMS_TO_TICSK( value_in_ms ) can be + * used to convert a time specified in milliseconds to a time specified in + * ticks. + * + * @return If a notification was received (including notifications that were + * already pending when xTaskNotifyWait was called) then pdPASS is + * returned. Otherwise pdFAIL is returned. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + * <PRE>BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );</PRE> + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro + * to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * xTaskNotifyGive() is a helper macro intended for use when task notifications + * are used as light weight and faster binary or counting semaphore equivalents. + * Actual FreeRTOS semaphores are given using the xSemaphoreGive() API function, + * the equivalent action that instead uses a task notification is + * xTaskNotifyGive(). + * + * When task notifications are being used as a binary or counting semaphore + * equivalent then the task being notified should wait for the notification + * using the ulTaskNotificationTake() API function rather than the + * xTaskNotifyWait() API function. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @return xTaskNotifyGive() is a macro that calls xTaskNotify() with the + * eAction parameter set to eIncrement - so pdPASS is always returned. + * + * \defgroup xTaskNotifyGive xTaskNotifyGive + * \ingroup TaskNotifications + */ +#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL ) + +/** + * task. h + * <PRE>void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken ); + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro + * to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotifyGive() that can be called from an interrupt service + * routine (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * vTaskNotifyGiveFromISR() is intended for use when task notifications are + * used as light weight and faster binary or counting semaphore equivalents. + * Actual FreeRTOS semaphores are given from an ISR using the + * xSemaphoreGiveFromISR() API function, the equivalent action that instead uses + * a task notification is vTaskNotifyGiveFromISR(). + * + * When task notifications are being used as a binary or counting semaphore + * equivalent then the task being notified should wait for the notification + * using the ulTaskNotificationTake() API function rather than the + * xTaskNotifyWait() API function. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param pxHigherPriorityTaskWoken vTaskNotifyGiveFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * vTaskNotifyGiveFromISR() sets this value to pdTRUE then a context switch + * should be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * task. h + * <PRE>uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );</pre> + * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * ulTaskNotifyTake() is intended for use when a task notification is used as a + * faster and lighter weight binary or counting semaphore alternative. Actual + * FreeRTOS semaphores are taken using the xSemaphoreTake() API function, the + * equivalent action that instead uses a task notification is + * ulTaskNotifyTake(). + * + * When a task is using its notification value as a binary or counting semaphore + * other tasks should send notifications to it using the xTaskNotifyGive() + * macro, or xTaskNotify() function with the eAction parameter set to + * eIncrement. + * + * ulTaskNotifyTake() can either clear the task's notification value to + * zero on exit, in which case the notification value acts like a binary + * semaphore, or decrement the task's notification value on exit, in which case + * the notification value acts like a counting semaphore. + * + * A task can use ulTaskNotifyTake() to [optionally] block to wait for a + * the task's notification value to be non-zero. The task does not consume any + * CPU time while it is in the Blocked state. + * + * Where as xTaskNotifyWait() will return when a notification is pending, + * ulTaskNotifyTake() will return when the task's notification value is + * not zero. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xClearCountOnExit if xClearCountOnExit is pdFALSE then the task's + * notification value is decremented when the function exits. In this way the + * notification value acts like a counting semaphore. If xClearCountOnExit is + * not pdFALSE then the task's notification value is cleared to zero when the + * function exits. In this way the notification value acts like a binary + * semaphore. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for the task's notification value to be greater than zero, + * should the count not already be greater than zero when + * ulTaskNotifyTake() was called. The task will not consume any processing + * time while it is in the Blocked state. This is specified in kernel ticks, + * the macro pdMS_TO_TICSK( value_in_ms ) can be used to convert a time + * specified in milliseconds to a time specified in ticks. + * + * @return The task's notification count before it is either cleared to zero or + * decremented (see the xClearCountOnExit parameter). + * + * \defgroup ulTaskNotifyTake ulTaskNotifyTake + * \ingroup TaskNotifications + */ +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + * <PRE>BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask );</pre> + * + * If the notification state of the task referenced by the handle xTask is + * eNotified, then set the task's notification state to eNotWaitingNotification. + * The task's notification value is not altered. Set xTask to NULL to clear the + * notification state of the calling task. + * + * @return pdTRUE if the task's notification state was set to + * eNotWaitingNotification, otherwise pdFALSE. + * \defgroup xTaskNotifyStateClear xTaskNotifyStateClear + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); + /*----------------------------------------------------------- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES *----------------------------------------------------------*/ @@ -1424,7 +2130,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xIte * indefinitely, whereas vTaskPlaceOnEventList() does. * */ -void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -1510,12 +2216,6 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; /* - * Generic version of the task creation function which is in turn called by the - * xTaskCreate() and xTaskCreateRestricted() macros. - */ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - -/* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. */ UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; @@ -1556,7 +2256,7 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; * For internal use only. Increment the mutex held count when a mutex is * taken and return the handle of the task that has taken the mutex. */ -void *pvTaskIncrementMutexHeldCount( void ); +void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/cc3200/FreeRTOS/Source/include/timers.h b/cc3200/FreeRTOS/Source/include/timers.h index 3949135db7..798c955bb3 100644 --- a/cc3200/FreeRTOS/Source/include/timers.h +++ b/cc3200/FreeRTOS/Source/include/timers.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -74,7 +78,7 @@ /*lint -e537 This headers are only multiply included if the application code happens to also be including task.h. */ #include "task.h" -/*lint +e956 */ +/*lint +e537 */ #ifdef __cplusplus extern "C" { @@ -131,9 +135,17 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * void * pvTimerID, * TimerCallbackFunction_t pxCallbackFunction ); * - * Creates a new software timer instance. This allocates the storage required - * by the new timer, initialises the new timers internal state, and returns a - * handle by which the new timer can be referenced. + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. * * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and @@ -246,14 +258,151 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * * // Starting the scheduler will start the timers running as they have already * // been set into the active state. - * xTaskStartScheduler(); + * vTaskStartScheduler(); * * // Should not reach here. * for( ;; ); * } * @endverbatim */ -TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * TimerHandle_t xTimerCreateStatic(const char * const pcTimerName, + * TickType_t xTimerPeriodInTicks, + * UBaseType_t uxAutoReload, + * void * pvTimerID, + * TimerCallbackFunction_t pxCallbackFunction, + * StaticTimer_t *pxTimerBuffer ); + * + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a + * timer into the active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer + * by its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick + * periods so the constant portTICK_PERIOD_MS can be used to convert a time that + * has been specified in milliseconds. For example, if the timer must expire + * after 100 ticks, then xTimerPeriodInTicks should be set to 100. + * Alternatively, if the timer must expire after 500ms, then xPeriod can be set + * to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or + * equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. + * If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by TimerCallbackFunction_t, + * which is "void vCallbackFunction( TimerHandle_t xTimer );". + * + * @param pxTimerBuffer Must point to a variable of type StaticTimer_t, which + * will be then be used to hold the software timer's data structures, removing + * the need for the memory to be allocated dynamically. + * + * @return If the timer is created then a handle to the created timer is + * returned. If pxTimerBuffer was NULL then NULL is returned. + * + * Example usage: + * @verbatim + * + * // The buffer used to hold the software timer's data structure. + * static StaticTimer_t xTimerBuffer; + * + * // A variable that will be incremented by the software timer's callback + * // function. + * UBaseType_t uxVariableToIncrement = 0; + * + * // A software timer callback function that increments a variable passed to + * // it when the software timer was created. After the 5th increment the + * // callback function stops the software timer. + * static void prvTimerCallback( TimerHandle_t xExpiredTimer ) + * { + * UBaseType_t *puxVariableToIncrement; + * BaseType_t xReturned; + * + * // Obtain the address of the variable to increment from the timer ID. + * puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); + * + * // Increment the variable to show the timer callback has executed. + * ( *puxVariableToIncrement )++; + * + * // If this callback has executed the required number of times, stop the + * // timer. + * if( *puxVariableToIncrement == 5 ) + * { + * // This is called from a timer callback so must not block. + * xTimerStop( xExpiredTimer, staticDONT_BLOCK ); + * } + * } + * + * + * void main( void ) + * { + * // Create the software time. xTimerCreateStatic() has an extra parameter + * // than the normal xTimerCreate() API function. The parameter is a pointer + * // to the StaticTimer_t structure that will hold the software timer + * // structure. If the parameter is passed as NULL then the structure will be + * // allocated dynamically, just as if xTimerCreate() had been called. + * xTimer = xTimerCreateStatic( "T1", // Text name for the task. Helps debugging only. Not used by FreeRTOS. + * xTimerPeriod, // The period of the timer in ticks. + * pdTRUE, // This is an auto-reload timer. + * ( void * ) &uxVariableToIncrement, // A variable incremented by the software timer's callback function + * prvTimerCallback, // The function to execute when the timer expires. + * &xTimerBuffer ); // The buffer that will hold the software timer structure. + * + * // The scheduler has not started yet so a block time is not used. + * xReturned = xTimerStart( xTimer, 0 ); + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * void *pvTimerGetTimerID( TimerHandle_t xTimer ); @@ -261,11 +410,11 @@ TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTi * Returns the ID assigned to the timer. * * IDs are assigned to timers using the pvTimerID parameter of the call to - * xTimerCreated() that was used to create the timer. + * xTimerCreated() that was used to create the timer, and by calling the + * vTimerSetTimerID() API function. * * If the same callback function is assigned to multiple timers then the timer - * ID can be used within the callback function to identify which timer actually - * expired. + * ID can be used as time specific (timer local) storage. * * @param xTimer The timer being queried. * @@ -275,7 +424,28 @@ TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTi * * See the xTimerCreate() API function example usage scenario. */ -void *pvTimerGetTimerID( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** + * void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); + * + * Sets the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used as time specific (timer local) storage. + * + * @param xTimer The timer being updated. + * + * @param pvNewID The ID to assign to the timer. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); @@ -317,13 +487,10 @@ BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /** * TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); * - * xTimerGetTimerDaemonTaskHandle() is only available if - * INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h. - * * Simply returns the handle of the timer service/daemon task. It it not valid * to call xTimerGetTimerDaemonTaskHandle() before the scheduler has been started. */ -TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ); @@ -652,7 +819,7 @@ TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); * * // Starting the scheduler will start the timer running as it has already * // been set into the active state. - * xTaskStartScheduler(); + * vTaskStartScheduler(); * * // Should not reach here. * for( ;; ); @@ -1058,7 +1225,7 @@ TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); * } * @endverbatim */ -BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ); +BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; /** * BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, @@ -1092,10 +1259,10 @@ BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void * timer daemon task, otherwise pdFALSE is returned. * */ -BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); +BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** - * const char * const pcTimerGetTimerName( TimerHandle_t xTimer ); + * const char * const pcTimerGetName( TimerHandle_t xTimer ); * * Returns the name that was assigned to a timer when the timer was created. * @@ -1103,7 +1270,33 @@ BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvPar * * @return The name assigned to the timer specified by the xTimer parameter. */ -const char * pcTimerGetTimerName( TimerHandle_t xTimer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); + * + * Returns the period of a timer. + * + * @param xTimer The handle of the timer being queried. + * + * @return The period of the timer in ticks. + */ +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** +* TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ); +* +* Returns the time in ticks at which the timer will expire. If this is less +* than the current tick count then the expiry time has overflowed from the +* current time. +* +* @param xTimer The handle of the timer being queried. +* +* @return If the timer is running then the time in ticks at which the timer +* will next expire is returned. If the timer is not running then the return +* value is undefined. +*/ +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /* * Functions beyond this part are not part of the public API and are intended diff --git a/cc3200/FreeRTOS/Source/list.c b/cc3200/FreeRTOS/Source/list.c index 701472a482..5e207c1608 100644 --- a/cc3200/FreeRTOS/Source/list.c +++ b/cc3200/FreeRTOS/Source/list.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -89,6 +93,11 @@ void vListInitialise( List_t * const pxList ) pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->uxNumberOfItems = ( UBaseType_t ) 0U; + + /* Write known values into the list if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); + listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); } /*-----------------------------------------------------------*/ @@ -96,6 +105,11 @@ void vListInitialiseItem( ListItem_t * const pxItem ) { /* Make sure the list item is not recorded as being on a list. */ pxItem->pvContainer = NULL; + + /* Write known values into the list item if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); + listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); } /*-----------------------------------------------------------*/ @@ -103,11 +117,21 @@ void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) { ListItem_t * const pxIndex = pxList->pxIndex; + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + /* Insert a new list item into pxList, but rather than sort the list, makes the new list item the last item to be removed by a call to listGET_OWNER_OF_NEXT_ENTRY(). */ pxNewListItem->pxNext = pxIndex; pxNewListItem->pxPrevious = pxIndex->pxPrevious; + + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + pxIndex->pxPrevious->pxNext = pxNewListItem; pxIndex->pxPrevious = pxNewListItem; @@ -123,15 +147,20 @@ void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) ListItem_t *pxIterator; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + /* Insert the new list item into the list, sorted in xItemValue order. - If the list already contains a list item with the same item value then - the new list item should be placed after it. This ensures that TCB's which - are stored in ready lists (all of which have the same xItemValue value) - get an equal share of the CPU. However, if the xItemValue is the same as - the back marker the iteration loop below will not end. This means we need - to guard against this by checking the value first and modifying the - algorithm slightly if necessary. */ + If the list already contains a list item with the same item value then the + new list item should be placed after it. This ensures that TCB's which are + stored in ready lists (all of which have the same xItemValue value) get a + share of the CPU. However, if the xItemValue is the same as the back marker + the iteration loop below will not end. Therefore the value is checked + first, and the algorithm slightly modified if necessary. */ if( xValueOfInsertion == portMAX_DELAY ) { pxIterator = pxList->xListEnd.pxPrevious; @@ -139,27 +168,31 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; else { /* *** NOTE *********************************************************** - If you find your application is crashing here then likely causes are: + If you find your application is crashing here then likely causes are + listed below. In addition see http://www.freertos.org/FAQHelp.html for + more tips, and ensure configASSERT() is defined! + http://www.freertos.org/a00110.html#configASSERT + 1) Stack overflow - see http://www.freertos.org/Stacks-and-stack-overflow-checking.html - 2) Incorrect interrupt priority assignment, especially on Cortex-M3 + 2) Incorrect interrupt priority assignment, especially on Cortex-M parts where numerically high priority values denote low actual interrupt priorities, which can seem counter intuitive. See - configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html + http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition + of configMAX_SYSCALL_INTERRUPT_PRIORITY on + http://www.freertos.org/a00110.html 3) Calling an API function from within a critical section or when the scheduler is suspended, or calling an API function that does not end in "FromISR" from an interrupt. 4) Using a queue or semaphore before it has been initialised or before the scheduler has been started (are interrupts firing before vTaskStartScheduler() has been called?). - See http://www.freertos.org/FAQHelp.html for more tips, and ensure - configASSERT() is defined! http://www.freertos.org/a00110.html#configASSERT **********************************************************************/ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ { - /* There is nothing to do here, we are just iterating to the - wanted insertion position. */ + /* There is nothing to do here, just iterating to the wanted + insertion position. */ } } @@ -185,6 +218,9 @@ List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + /* Make sure the index is left pointing to a valid item. */ if( pxList->pxIndex == pxItemToRemove ) { diff --git a/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c index 8c94d7d795..f6fe755fbd 100644 --- a/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -113,6 +117,9 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ #define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) #define portPRIGROUP_SHIFT ( 8UL ) +/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ +#define portVECTACTIVE_MASK ( 0xFFUL ) + /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000UL ) @@ -124,8 +131,12 @@ occurred while the SysTick counter is stopped during tickless idle calculations. */ #define portMISSED_COUNTS_FACTOR ( 45UL ) +/* For strict compliance with the Cortex-M spec the task start address should +have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ +#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) + /* Let the user override the pre-loading of the initial LR with the address of -prvTaskExitError() in case is messes up unwinding of the stack in the +prvTaskExitError() in case it messes up unwinding of the stack in the debugger. */ #ifdef configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS @@ -202,7 +213,6 @@ static void prvTaskExitError( void ); /* * See header file for description. */ -__attribute__ ((section (".boot"))) StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) { /* Simulate the stack frame as it would be created by a context switch @@ -210,7 +220,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC */ + *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ @@ -221,7 +231,6 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px } /*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) static void prvTaskExitError( void ) { /* A function that implements a task must not exit or attempt to return to @@ -250,13 +259,12 @@ void vPortSVCHandler( void ) " orr r14, #0xd \n" " bx r14 \n" " \n" - " .align 2 \n" + " .align 4 \n" "pxCurrentTCBConst2: .word pxCurrentTCB \n" ); } /*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) static void prvPortStartFirstTask( void ) { __asm volatile( @@ -277,7 +285,6 @@ static void prvPortStartFirstTask( void ) /* * See header file for description. */ -__attribute__ ((section (".boot"))) BaseType_t xPortStartScheduler( void ) { /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. @@ -361,27 +368,13 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ -void vPortYield( void ) -{ - /* Set a PendSV to request a context switch. */ - portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; - - /* Barriers are normally not required but do ensure the code is completely - within the specified behaviour for the architecture. */ - __asm volatile( "dsb" ); - __asm volatile( "isb" ); -} -/*-----------------------------------------------------------*/ - void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; - __asm volatile( "dsb" ); - __asm volatile( "isb" ); - + /* This is not the interrupt safe version of the enter critical function so - assert() if it is being called from an interrupt context. Only API + assert() if it is being called from an interrupt context. Only API functions that end in "FromISR" can be used in an interrupt. Only assert if the critical nesting count is 1 to protect against recursive calls if the assert function also uses a critical section. */ @@ -403,37 +396,6 @@ void vPortExitCritical( void ) } /*-----------------------------------------------------------*/ -__attribute__(( naked )) uint32_t ulPortSetInterruptMask( void ) -{ - __asm volatile \ - ( \ - " mrs r0, basepri \n" \ - " mov r1, %0 \n" \ - " msr basepri, r1 \n" \ - " bx lr \n" \ - :: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r0", "r1" \ - ); - - /* This return will not be reached but is necessary to prevent compiler - warnings. */ - return 0; -} -/*-----------------------------------------------------------*/ - -__attribute__(( naked )) void vPortClearInterruptMask( uint32_t ulNewMaskValue ) -{ - __asm volatile \ - ( \ - " msr basepri, r0 \n" \ - " bx lr \n" \ - :::"r0" \ - ); - - /* Just to avoid compiler warnings. */ - ( void ) ulNewMaskValue; -} -/*-----------------------------------------------------------*/ - void xPortPendSVHandler( void ) { /* This is a naked function. */ @@ -464,7 +426,7 @@ void xPortPendSVHandler( void ) " isb \n" " bx r14 \n" " \n" - " .align 2 \n" + " .align 4 \n" "pxCurrentTCBConst: .word pxCurrentTCB \n" ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY) ); @@ -477,7 +439,7 @@ void xPortSysTickHandler( void ) executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known. */ - ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); + portDISABLE_INTERRUPTS(); { /* Increment the RTOS tick. */ if( xTaskIncrementTick() != pdFALSE ) @@ -487,7 +449,7 @@ void xPortSysTickHandler( void ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); + portENABLE_INTERRUPTS(); } /*-----------------------------------------------------------*/ @@ -522,6 +484,8 @@ void xPortSysTickHandler( void ) /* Enter a critical section but don't use the taskENTER_CRITICAL() method as that will mask interrupts that should exit sleep mode. */ __asm volatile( "cpsid i" ); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); /* If a context switch is pending or a task is waiting for the scheduler to be unsuspended then abandon the low power entry. */ @@ -621,7 +585,7 @@ void xPortSysTickHandler( void ) /* The reload value is set to whatever fraction of a single tick period remains. */ - portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; } /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG @@ -647,7 +611,6 @@ void xPortSysTickHandler( void ) * Setup the systick timer to generate the tick interrupts at the required * frequency. */ -__attribute__ ((section (".boot"))) __attribute__(( weak )) void vPortSetupTimerInterrupt( void ) { /* Calculate the constants required to configure the tick interrupt. */ diff --git a/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h b/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h index f497393e60..d44fc92228 100644 --- a/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h +++ b/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -100,6 +104,10 @@ typedef unsigned long UBaseType_t; #else typedef uint32_t TickType_t; #define portMAX_DELAY ( TickType_t ) 0xffffffffUL + + /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do + not need to be guarded with a critical section. */ + #define portTICK_TYPE_IS_ATOMIC 1 #endif /*-----------------------------------------------------------*/ @@ -109,29 +117,34 @@ typedef unsigned long UBaseType_t; #define portBYTE_ALIGNMENT 8 /*-----------------------------------------------------------*/ - /* Scheduler utilities. */ -extern void vPortYield( void ); +#define portYIELD() \ +{ \ + /* Set a PendSV to request a context switch. */ \ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ + \ + /* Barriers are normally not required but do ensure the code is completely \ + within the specified behaviour for the architecture. */ \ + __asm volatile( "dsb" ); \ + __asm volatile( "isb" ); \ +} + #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) -/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) -#define portYIELD() vPortYield() -#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ /* Critical section management. */ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -extern uint32_t ulPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( uint32_t ulNewMaskValue ); -#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) -#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask(0) +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) +#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() + /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. These are @@ -175,7 +188,7 @@ not necessary for to use this port. They are defined so the common demo files /*-----------------------------------------------------------*/ - #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ @@ -189,6 +202,80 @@ not necessary for to use this port. They are defined so the common demo files /* portNOP() is not required by this port. */ #define portNOP() +#define portINLINE __inline + +#ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__(( always_inline)) +#endif + +portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) +{ +uint32_t ulCurrentInterrupt; +BaseType_t xReturn; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + if( ulCurrentInterrupt == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortRaiseBASEPRI( void ) +{ +uint32_t ulNewBASEPRI; + + __asm volatile + ( + " mov %0, %1 \n" \ + " msr basepri, %0 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulOriginalBASEPRI, ulNewBASEPRI; + + __asm volatile + ( + " mrs %0, basepri \n" \ + " mov %1, %2 \n" \ + " msr basepri, %1 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return ulOriginalBASEPRI; +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) +{ + __asm volatile + ( + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + ); +} +/*-----------------------------------------------------------*/ + + #ifdef __cplusplus } #endif diff --git a/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c b/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c index 94551c25c3..e7c7ade682 100644 --- a/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c +++ b/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -83,15 +87,24 @@ task.h is included from an application file. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE +#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) + #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 +#endif + /* Block sizes must not get too small. */ -#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize * 2 ) ) +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) ) /* Assumes 8bit bytes! */ #define heapBITS_PER_BYTE ( ( size_t ) 8 ) /* Allocate the memory for the heap. */ -static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".rtos_heap"))) -__attribute__((aligned (8))); +#if( configAPPLICATION_ALLOCATED_HEAP == 1 ) + /* The application writer has already defined the array used for the RTOS + heap - probably so it can be placed in a special segment or address. */ + extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#else + static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#endif /* configAPPLICATION_ALLOCATED_HEAP */ /* Define the linked list structure. This is used to link free blocks in order of their memory address. */ @@ -121,7 +134,7 @@ static void prvHeapInit( void ); /* The size of the structure placed at the beginning of each allocated memory block must by correctly byte aligned. */ -static const size_t xHeapStructSize = ( ( sizeof( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); +static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, *pxEnd = NULL; @@ -220,7 +233,7 @@ void *pvReturn = NULL; cast is used to prevent byte alignment warnings from the compiler. */ pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); - configASSERT( ( ( ( uint32_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 ); + configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 ); /* Calculate the sizes of two blocks split from the single block. */ @@ -228,7 +241,7 @@ void *pvReturn = NULL; pxBlock->xBlockSize = xWantedSize; /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + prvInsertBlockIntoFreeList( pxNewBlockLink ); } else { @@ -284,7 +297,7 @@ void *pvReturn = NULL; } #endif - configASSERT( ( ( ( uint32_t ) pvReturn ) & portBYTE_ALIGNMENT_MASK ) == 0 ); + configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 ); return pvReturn; } /*-----------------------------------------------------------*/ @@ -359,20 +372,20 @@ static void prvHeapInit( void ) { BlockLink_t *pxFirstFreeBlock; uint8_t *pucAlignedHeap; -uint32_t ulAddress; +size_t uxAddress; size_t xTotalHeapSize = configTOTAL_HEAP_SIZE; /* Ensure the heap starts on a correctly aligned boundary. */ - ulAddress = ( uint32_t ) ucHeap; + uxAddress = ( size_t ) ucHeap; - if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) + if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) { - ulAddress += ( portBYTE_ALIGNMENT - 1 ); - ulAddress &= ~portBYTE_ALIGNMENT_MASK; - xTotalHeapSize -= ulAddress - ( uint32_t ) ucHeap; + uxAddress += ( portBYTE_ALIGNMENT - 1 ); + uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); + xTotalHeapSize -= uxAddress - ( size_t ) ucHeap; } - pucAlignedHeap = ( uint8_t * ) ulAddress; + pucAlignedHeap = ( uint8_t * ) uxAddress; /* xStart is used to hold a pointer to the first item in the list of free blocks. The void cast is used to prevent compiler warnings. */ @@ -381,17 +394,17 @@ size_t xTotalHeapSize = configTOTAL_HEAP_SIZE; /* pxEnd is used to mark the end of the list of free blocks and is inserted at the end of the heap space. */ - ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalHeapSize; - ulAddress -= xHeapStructSize; - ulAddress &= ~portBYTE_ALIGNMENT_MASK; - pxEnd = ( void * ) ulAddress; + uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize; + uxAddress -= xHeapStructSize; + uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); + pxEnd = ( void * ) uxAddress; pxEnd->xBlockSize = 0; pxEnd->pxNextFreeBlock = NULL; /* To start with there is a single free block that is sized to take up the entire heap space, minus the space taken by pxEnd. */ pxFirstFreeBlock = ( void * ) pucAlignedHeap; - pxFirstFreeBlock->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlock; + pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock; pxFirstFreeBlock->pxNextFreeBlock = pxEnd; /* Only one block exists - and it covers the entire usable heap space. */ diff --git a/cc3200/FreeRTOS/Source/queue.c b/cc3200/FreeRTOS/Source/queue.c index 5e5250d00a..ce623bec26 100644 --- a/cc3200/FreeRTOS/Source/queue.c +++ b/cc3200/FreeRTOS/Source/queue.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -86,9 +90,9 @@ privileged Vs unprivileged linkage and placement. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ -/* Constants used with the xRxLock and xTxLock structure members. */ -#define queueUNLOCKED ( ( BaseType_t ) -1 ) -#define queueLOCKED_UNMODIFIED ( ( BaseType_t ) 0 ) +/* Constants used with the cRxLock and cTxLock structure members. */ +#define queueUNLOCKED ( ( int8_t ) -1 ) +#define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) /* When the Queue_t structure is used to represent a base queue its pcHead and pcTail members are used as pointers into the queue storage area. When the @@ -120,7 +124,8 @@ zero. */ /* * Definition of the queue used by the scheduler. - * Items are queued by copy, not reference. + * Items are queued by copy, not reference. See the following link for the + * rationale: http://www.freertos.org/Embedded-RTOS-Queues.html */ typedef struct QueueDefinition { @@ -141,18 +146,22 @@ typedef struct QueueDefinition UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */ - volatile BaseType_t xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ - volatile BaseType_t xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ - #if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxQueueNumber; - uint8_t ucQueueType; + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ #endif #if ( configUSE_QUEUE_SETS == 1 ) struct QueueDefinition *pxQueueSetContainer; #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxQueueNumber; + uint8_t ucQueueType; + #endif + } xQUEUE; /* The old xQUEUE name is maintained above then typedefed to the new Queue_t @@ -184,7 +193,7 @@ typedef xQUEUE Queue_t; /* The queue registry is simply an array of QueueRegistryItem_t structures. The pcQueueName member of a structure being NULL is indicative of the array position being vacant. */ - QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; + PRIVILEGED_DATA QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; #endif /* configQUEUE_REGISTRY_SIZE */ @@ -231,6 +240,21 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; #endif +/* + * Called after a Queue_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; + +/* + * Mutexes are a special type of queue. When a mutex is created, first the + * queue is created, then prvInitialiseMutex() is called to configure the queue + * as a mutex. + */ +#if( configUSE_MUTEXES == 1 ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; +#endif + /*-----------------------------------------------------------*/ /* @@ -240,13 +264,13 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer #define prvLockQueue( pxQueue ) \ taskENTER_CRITICAL(); \ { \ - if( ( pxQueue )->xRxLock == queueUNLOCKED ) \ + if( ( pxQueue )->cRxLock == queueUNLOCKED ) \ { \ - ( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED; \ + ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \ } \ - if( ( pxQueue )->xTxLock == queueUNLOCKED ) \ + if( ( pxQueue )->cTxLock == queueUNLOCKED ) \ { \ - ( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED; \ + ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \ } \ } \ taskEXIT_CRITICAL() @@ -264,8 +288,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; pxQueue->pcWriteTo = pxQueue->pcHead; pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize ); - pxQueue->xRxLock = queueUNLOCKED; - pxQueue->xTxLock = queueUNLOCKED; + pxQueue->cRxLock = queueUNLOCKED; + pxQueue->cTxLock = queueUNLOCKED; if( xNewQueue == pdFALSE ) { @@ -276,7 +300,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; it will be possible to write to it. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } @@ -305,119 +329,163 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } /*-----------------------------------------------------------*/ -QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) -{ -Queue_t *pxNewQueue; -size_t xQueueSizeInBytes; -QueueHandle_t xReturn = NULL; - - /* Remove compiler warnings about unused parameters should - configUSE_TRACE_FACILITY not be set to 1. */ - ( void ) ucQueueType; +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) - /* Allocate the new queue structure. */ - if( uxQueueLength > ( UBaseType_t ) 0 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) { - pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) ); - if( pxNewQueue != NULL ) - { - /* Create the list of pointers to queue items. The queue is one byte - longer than asked for to make wrap checking easier/faster. */ - xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + Queue_t *pxNewQueue; - pxNewQueue->pcHead = ( int8_t * ) pvPortMalloc( xQueueSizeInBytes ); - if( pxNewQueue->pcHead != NULL ) - { - /* Initialise the queue members as described above where the - queue type is defined. */ - pxNewQueue->uxLength = uxQueueLength; - pxNewQueue->uxItemSize = uxItemSize; - ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); - #if ( configUSE_TRACE_FACILITY == 1 ) - { - pxNewQueue->ucQueueType = ucQueueType; - } - #endif /* configUSE_TRACE_FACILITY */ + /* The StaticQueue_t structure and the queue storage area must be + supplied. */ + configASSERT( pxStaticQueue != NULL ); - #if( configUSE_QUEUE_SETS == 1 ) - { - pxNewQueue->pxQueueSetContainer = NULL; - } - #endif /* configUSE_QUEUE_SETS */ + /* A queue storage area should be provided if the item size is not 0, and + should not be provided if the item size is 0. */ + configASSERT( !( ( pucQueueStorage != NULL ) && ( uxItemSize == 0 ) ) ); + configASSERT( !( ( pucQueueStorage == NULL ) && ( uxItemSize != 0 ) ) ); - traceQUEUE_CREATE( pxNewQueue ); - xReturn = pxNewQueue; - } - else + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticQueue_t or StaticSemaphore_t equals the size of + the real queue and semaphore structures. */ + volatile size_t xSize = sizeof( StaticQueue_t ); + configASSERT( xSize == sizeof( Queue_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* The address of a statically allocated queue was passed in, use it. + The address of a statically allocated storage area was also passed in + but is already set. */ + pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewQueue != NULL ) + { + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) { - traceQUEUE_CREATE_FAILED( ucQueueType ); - vPortFree( pxNewQueue ); + /* Queues can be allocated wither statically or dynamically, so + note this queue was allocated statically in case the queue is + later deleted. */ + pxNewQueue->ucStaticallyAllocated = pdTRUE; } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + size_t xQueueSizeInBytes; + uint8_t *pucQueueStorage; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* There is not going to be a queue storage area. */ + xQueueSizeInBytes = ( size_t ) 0; } else { - mtCOVERAGE_TEST_MARKER(); + /* Allocate enough space to hold the maximum number of items that + can be in the queue at any time. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + + if( pxNewQueue != NULL ) + { + /* Jump past the queue structure to find the location of the queue + storage area. */ + pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Queues can be created either statically or dynamically, so + note this task was created dynamically in case it is later + deleted. */ + pxNewQueue->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) +{ + /* Remove compiler warnings about unused parameters should + configUSE_TRACE_FACILITY not be set to 1. */ + ( void ) ucQueueType; + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* No RAM was allocated for the queue storage area, but PC head cannot + be set to NULL because NULL is used as a key to say the queue is used as + a mutex. Therefore just set pcHead to point to the queue as a benign + value that is known to be within the memory map. */ + pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; } else { - mtCOVERAGE_TEST_MARKER(); + /* Set the head to the start of the queue storage area. */ + pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage; } - configASSERT( xReturn ); + /* Initialise the queue members as described where the queue type is + defined. */ + pxNewQueue->uxLength = uxQueueLength; + pxNewQueue->uxItemSize = uxItemSize; + ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); - return xReturn; + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxNewQueue->ucQueueType = ucQueueType; + } + #endif /* configUSE_TRACE_FACILITY */ + + #if( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif /* configUSE_QUEUE_SETS */ + + traceQUEUE_CREATE( pxNewQueue ); } /*-----------------------------------------------------------*/ -#if ( configUSE_MUTEXES == 1 ) +#if( configUSE_MUTEXES == 1 ) - QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) { - Queue_t *pxNewQueue; - - /* Prevent compiler warnings about unused parameters if - configUSE_TRACE_FACILITY does not equal 1. */ - ( void ) ucQueueType; - - /* Allocate the new queue structure. */ - pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) ); if( pxNewQueue != NULL ) { - /* Information required for priority inheritance. */ + /* The queue create function will set all the queue structure members + correctly for a generic queue, but this function is creating a + mutex. Overwrite those members that need to be set differently - + in particular the information required for priority inheritance. */ pxNewQueue->pxMutexHolder = NULL; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; - /* Queues used as a mutex no data is actually copied into or out - of the queue. */ - pxNewQueue->pcWriteTo = NULL; - pxNewQueue->u.pcReadFrom = NULL; - - /* Each mutex has a length of 1 (like a binary semaphore) and - an item size of 0 as nothing is actually copied into or out - of the mutex. */ - pxNewQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; - pxNewQueue->uxLength = ( UBaseType_t ) 1U; - pxNewQueue->uxItemSize = ( UBaseType_t ) 0U; - pxNewQueue->xRxLock = queueUNLOCKED; - pxNewQueue->xTxLock = queueUNLOCKED; - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - pxNewQueue->ucQueueType = ucQueueType; - } - #endif - - #if ( configUSE_QUEUE_SETS == 1 ) - { - pxNewQueue->pxQueueSetContainer = NULL; - } - #endif - - /* Ensure the event queues start with the correct state. */ - vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); - vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); + /* In case this is a recursive mutex. */ + pxNewQueue->u.uxRecursiveCallCount = 0; traceCREATE_MUTEX( pxNewQueue ); @@ -428,8 +496,41 @@ QueueHandle_t xReturn = NULL; { traceCREATE_MUTEX_FAILED(); } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + /* Prevent compiler warnings about unused parameters if + configUSE_TRACE_FACILITY does not equal 1. */ + ( void ) ucQueueType; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); - configASSERT( pxNewQueue ); return pxNewQueue; } @@ -492,7 +593,7 @@ QueueHandle_t xReturn = NULL; uxRecursiveCallCount member. */ ( pxMutex->u.uxRecursiveCallCount )--; - /* Have we unwound the call count? */ + /* Has the recursive call count unwound to 0? */ if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) { /* Return the mutex. This will automatically unblock any other @@ -547,7 +648,7 @@ QueueHandle_t xReturn = NULL; /* pdPASS will only be returned if the mutex was successfully obtained. The calling task may have entered the Blocked state before reaching here. */ - if( xReturn == pdPASS ) + if( xReturn != pdFAIL ) { ( pxMutex->u.uxRecursiveCallCount )++; } @@ -563,7 +664,35 @@ QueueHandle_t xReturn = NULL; #endif /* configUSE_RECURSIVE_MUTEXES */ /*-----------------------------------------------------------*/ -#if ( configUSE_COUNTING_SEMAPHORES == 1 ) +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreateStatic( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) { @@ -585,11 +714,10 @@ QueueHandle_t xReturn = NULL; traceCREATE_COUNTING_SEMAPHORE_FAILED(); } - configASSERT( xHandle ); return xHandle; } -#endif /* configUSE_COUNTING_SEMAPHORES */ +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ /*-----------------------------------------------------------*/ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) @@ -615,10 +743,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { taskENTER_CRITICAL(); { - /* Is there room on the queue now? The running task must be - the highest priority task wanting to access the queue. If - the head item in the queue is to be overwritten then it does - not matter if the queue is full. */ + /* Is there room on the queue now? The running task must be the + highest priority task wanting to access the queue. If the head item + in the queue is to be overwritten then it does not matter if the + queue is full. */ if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) { traceQUEUE_SEND( pxQueue ); @@ -628,7 +756,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to @@ -646,7 +774,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The unblocked task has a priority higher than our own so yield immediately. Yes it is ok to @@ -679,7 +807,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The unblocked task has a priority higher than our own so yield immediately. Yes it is ok to do @@ -783,8 +911,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); - /* Return to the original privilege level before exiting the - function. */ traceQUEUE_SEND_FAILED( pxQueue ); return errQUEUE_FULL; } @@ -792,171 +918,95 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; } /*-----------------------------------------------------------*/ -#if ( configUSE_ALTERNATIVE_API == 1 ) +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; - BaseType_t xQueueAltGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ) - { - BaseType_t xEntryTimeSet = pdFALSE; - TimeOut_t xTimeOut; - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); - configASSERT( pxQueue ); - configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - for( ;; ) + /* Similar to xQueueGenericSend, except without blocking if there is no room + in the queue. Also don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) { - taskENTER_CRITICAL(); - { - /* Is there room on the queue now? To be running we must be - the highest priority task wanting to access the queue. */ - if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) - { - traceQUEUE_SEND( pxQueue ); - prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); - - /* If there was a task waiting for data to arrive on the - queue then unblock it now. */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) - { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) - { - /* The unblocked task has a priority higher than - our own so yield immediately. */ - portYIELD_WITHIN_API(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - taskEXIT_CRITICAL(); - return pdPASS; - } - else - { - if( xTicksToWait == ( TickType_t ) 0 ) - { - taskEXIT_CRITICAL(); - return errQUEUE_FULL; - } - else if( xEntryTimeSet == pdFALSE ) - { - vTaskSetTimeOutState( &xTimeOut ); - xEntryTimeSet = pdTRUE; - } - } - } - taskEXIT_CRITICAL(); - - taskENTER_CRITICAL(); - { - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) - { - if( prvIsQueueFull( pxQueue ) != pdFALSE ) - { - traceBLOCKING_ON_QUEUE_SEND( pxQueue ); - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); - portYIELD_WITHIN_API(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - taskEXIT_CRITICAL(); - traceQUEUE_SEND_FAILED( pxQueue ); - return errQUEUE_FULL; - } - } - taskEXIT_CRITICAL(); - } - } + const int8_t cTxLock = pxQueue->cTxLock; -#endif /* configUSE_ALTERNATIVE_API */ -/*-----------------------------------------------------------*/ - -#if ( configUSE_ALTERNATIVE_API == 1 ) - - BaseType_t xQueueAltGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ) - { - BaseType_t xEntryTimeSet = pdFALSE; - TimeOut_t xTimeOut; - int8_t *pcOriginalReadPosition; - Queue_t * const pxQueue = ( Queue_t * ) xQueue; + traceQUEUE_SEND_FROM_ISR( pxQueue ); - configASSERT( pxQueue ); - configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + /* Semaphores use xQueueGiveFromISR(), so pxQueue will not be a + semaphore or mutex. That means prvCopyDataToQueue() cannot result + in a task disinheriting a priority and prvCopyDataToQueue() can be + called here even though the disinherit function does not check if + the scheduler is suspended before accessing the ready lists. */ + ( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); - for( ;; ) - { - taskENTER_CRITICAL(); + /* The event list is not altered if the queue is locked. This will + be done when the queue is unlocked later. */ + if( cTxLock == queueUNLOCKED ) { - if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + #if ( configUSE_QUEUE_SETS == 1 ) { - /* Remember our read position in case we are just peeking. */ - pcOriginalReadPosition = pxQueue->u.pcReadFrom; - - prvCopyDataFromQueue( pxQueue, pvBuffer ); - - if( xJustPeeking == pdFALSE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - traceQUEUE_RECEIVE( pxQueue ); - - /* Data is actually being removed (not just peeked). */ - --( pxQueue->uxMessagesWaiting ); - - #if ( configUSE_MUTEXES == 1 ) + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) { - if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) { - /* Record the information required to implement - priority inheritance should it become necessary. */ - pxQueue->pxMutexHolder = ( int8_t * ) xTaskGetCurrentTaskHandle(); + *pxHigherPriorityTaskWoken = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } } - #endif - - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + else { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) - { - portYIELD_WITHIN_API(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + mtCOVERAGE_TEST_MARKER(); } } else { - traceQUEUE_PEEK( pxQueue ); - - /* We are not removing the data, so reset our read - pointer. */ - pxQueue->u.pcReadFrom = pcOriginalReadPosition; - - /* The data is being left in the queue, so see if there are - any other tasks waiting for the data. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* Tasks that are removed from the event list will get added to - the pending ready list as the scheduler is still suspended. */ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The task waiting has a higher priority than this task. */ - portYIELD_WITHIN_API(); + /* The task waiting has a higher priority so + record that a context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { @@ -968,84 +1018,79 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; mtCOVERAGE_TEST_MARKER(); } } - - taskEXIT_CRITICAL(); - return pdPASS; - } - else - { - if( xTicksToWait == ( TickType_t ) 0 ) - { - taskEXIT_CRITICAL(); - traceQUEUE_RECEIVE_FAILED( pxQueue ); - return errQUEUE_EMPTY; - } - else if( xEntryTimeSet == pdFALSE ) - { - vTaskSetTimeOutState( &xTimeOut ); - xEntryTimeSet = pdTRUE; - } } - } - taskEXIT_CRITICAL(); - - taskENTER_CRITICAL(); - { - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + #else /* configUSE_QUEUE_SETS */ { - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); - - #if ( configUSE_MUTEXES == 1 ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) { - taskENTER_CRITICAL(); - { - vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); - } - taskEXIT_CRITICAL(); + *pxHigherPriorityTaskWoken = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } } - #endif - - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); - portYIELD_WITHIN_API(); + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { mtCOVERAGE_TEST_MARKER(); } } - else - { - taskEXIT_CRITICAL(); - traceQUEUE_RECEIVE_FAILED( pxQueue ); - return errQUEUE_EMPTY; - } + #endif /* configUSE_QUEUE_SETS */ } - taskEXIT_CRITICAL(); + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; } } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); - -#endif /* configUSE_ALTERNATIVE_API */ + return xReturn; +} /*-----------------------------------------------------------*/ -BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; Queue_t * const pxQueue = ( Queue_t * ) xQueue; + /* Similar to xQueueGenericSendFromISR() but used with semaphores where the + item size is 0. Don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + configASSERT( pxQueue ); - configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); - configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + + /* xQueueGenericSendFromISR() should be used instead of xQueueGiveFromISR() + if the item size is not 0. */ + configASSERT( pxQueue->uxItemSize == 0 ); + + /* Normally a mutex would not be given from an interrupt, especially if + there is a mutex holder, as priority inheritance makes no sense for an + interrupts, only tasks. */ + configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) ); /* RTOS ports that support interrupt nesting have the concept of a maximum system call (or maximum API call) interrupt priority. Interrupts that are @@ -1063,45 +1108,40 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - /* Similar to xQueueGenericSend, except without blocking if there is no room - in the queue. Also don't directly wake a task that was blocked on a queue - read, instead return a flag to say whether a context switch is required or - not (i.e. has a task with a higher priority than us been woken by this - post). */ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { - if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* When the queue is used to implement a semaphore no data is ever + moved through the queue but it is still valid to see if the queue 'has + space'. */ + if( uxMessagesWaiting < pxQueue->uxLength ) { + const int8_t cTxLock = pxQueue->cTxLock; + traceQUEUE_SEND_FROM_ISR( pxQueue ); - if( prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ) != pdFALSE ) - { - /* This is a special case that can only be executed if a task - holds multiple mutexes and then gives the mutexes back in an - order that is different to that in which they were taken. */ - if( pxHigherPriorityTaskWoken != NULL ) - { - *pxHigherPriorityTaskWoken = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } + /* A task can only have an inherited priority if it is a mutex + holder - and if there is a mutex holder then the mutex cannot be + given from an ISR. As this is the ISR version of the function it + can be assumed there is no mutex holder and no need to determine if + priority disinheritance is needed. Simply increase the count of + messages (semaphores) available. */ + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; /* The event list is not altered if the queue is locked. This will be done when the queue is unlocked later. */ - if( pxQueue->xTxLock == queueUNLOCKED ) + if( cTxLock == queueUNLOCKED ) { #if ( configUSE_QUEUE_SETS == 1 ) { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) { - /* The queue is a member of a queue set, and posting - to the queue set caused a higher priority task to - unblock. A context switch is required. */ + /* The semaphore is a member of a queue set, and + posting to the queue set caused a higher priority + task to unblock. A context switch is required. */ if( pxHigherPriorityTaskWoken != NULL ) { *pxHigherPriorityTaskWoken = pdTRUE; @@ -1177,7 +1217,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { /* Increment the lock count so the task that unlocks the queue knows that data was posted while it was locked. */ - ++( pxQueue->xTxLock ); + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); } xReturn = pdPASS; @@ -1217,9 +1257,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { taskENTER_CRITICAL(); { - /* Is there data in the queue now? To be running we must be - the highest priority task wanting to access the queue. */ - if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) { /* Remember the read position in case the queue is only being peeked. */ @@ -1232,7 +1274,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; traceQUEUE_RECEIVE( pxQueue ); /* Actually removing data, not just peeking. */ - --( pxQueue->uxMessagesWaiting ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; #if ( configUSE_MUTEXES == 1 ) { @@ -1251,7 +1293,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } @@ -1277,8 +1319,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; any other tasks waiting for the data. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* Tasks that are removed from the event list will get added to - the pending ready list as the scheduler is still suspended. */ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The task waiting has a higher priority than this task. */ @@ -1376,8 +1416,16 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); - traceQUEUE_RECEIVE_FAILED( pxQueue ); - return errQUEUE_EMPTY; + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } } @@ -1410,19 +1458,23 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + /* Cannot block in an ISR, so check there is data available. */ - if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) { + const int8_t cRxLock = pxQueue->cRxLock; + traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); prvCopyDataFromQueue( pxQueue, pvBuffer ); - --( pxQueue->uxMessagesWaiting ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; /* If the queue is locked the event list will not be modified. Instead update the lock count so the task that unlocks the queue will know that an ISR has removed data while the queue was locked. */ - if( pxQueue->xRxLock == queueUNLOCKED ) + if( cRxLock == queueUNLOCKED ) { if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { @@ -1453,7 +1505,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { /* Increment the lock count so the task that unlocks the queue knows that data was removed while it was locked. */ - ++( pxQueue->xRxLock ); + pxQueue->cRxLock = ( int8_t ) ( cRxLock + 1 ); } xReturn = pdPASS; @@ -1479,6 +1531,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; configASSERT( pxQueue ); configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( pxQueue->uxItemSize != 0 ); /* Can't peek a semaphore. */ /* RTOS ports that support interrupt nesting have the concept of a maximum system call (or maximum API call) interrupt priority. Interrupts that are @@ -1574,18 +1627,40 @@ void vQueueDelete( QueueHandle_t xQueue ) Queue_t * const pxQueue = ( Queue_t * ) xQueue; configASSERT( pxQueue ); - traceQUEUE_DELETE( pxQueue ); + #if ( configQUEUE_REGISTRY_SIZE > 0 ) { vQueueUnregisterQueue( pxQueue ); } #endif - if( pxQueue->pcHead != NULL ) + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The queue can only have been allocated dynamically - free it + again. */ + vPortFree( pxQueue ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The queue could have been allocated statically or dynamically, so + check before attempting to free the memory. */ + if( pxQueue->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxQueue ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #else { - vPortFree( pxQueue->pcHead ); + /* The queue must have been statically allocated, so is not going to be + deleted. Avoid compiler warnings about the unused parameter. */ + ( void ) pxQueue; } - vPortFree( pxQueue ); + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ } /*-----------------------------------------------------------*/ @@ -1622,6 +1697,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) { BaseType_t xReturn = pdFALSE; +UBaseType_t uxMessagesWaiting; + + /* This function is called from a critical section. */ + + uxMessagesWaiting = pxQueue->uxMessagesWaiting; if( pxQueue->uxItemSize == ( UBaseType_t ) 0 ) { @@ -1668,13 +1748,13 @@ BaseType_t xReturn = pdFALSE; if( xPosition == queueOVERWRITE ) { - if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) { /* An item is not being added but overwritten, so subtract one from the recorded number of items in the queue so when one is added again below the number of recorded items remains correct. */ - --( pxQueue->uxMessagesWaiting ); + --uxMessagesWaiting; } else { @@ -1687,7 +1767,7 @@ BaseType_t xReturn = pdFALSE; } } - ++( pxQueue->uxMessagesWaiting ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; return xReturn; } @@ -1721,8 +1801,10 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) updated. */ taskENTER_CRITICAL(); { + int8_t cTxLock = pxQueue->cTxLock; + /* See if data was added to the queue while it was locked. */ - while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED ) + while( cTxLock > queueLOCKED_UNMODIFIED ) { /* Data was posted while the queue was locked. Are any tasks blocked waiting for data to become available? */ @@ -1730,7 +1812,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to unblock. @@ -1744,8 +1826,9 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) } else { - /* Tasks that are removed from the event list will get added to - the pending ready list as the scheduler is still suspended. */ + /* Tasks that are removed from the event list will get + added to the pending ready list as the scheduler is still + suspended. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) @@ -1773,8 +1856,8 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The task waiting has a higher priority so record that a - context switch is required. */ + /* The task waiting has a higher priority so record that + a context switch is required. */ vTaskMissedYield(); } else @@ -1789,17 +1872,19 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) } #endif /* configUSE_QUEUE_SETS */ - --( pxQueue->xTxLock ); + --cTxLock; } - pxQueue->xTxLock = queueUNLOCKED; + pxQueue->cTxLock = queueUNLOCKED; } taskEXIT_CRITICAL(); /* Do the same for the Rx lock. */ taskENTER_CRITICAL(); { - while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) + int8_t cRxLock = pxQueue->cRxLock; + + while( cRxLock > queueLOCKED_UNMODIFIED ) { if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { @@ -1812,7 +1897,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) mtCOVERAGE_TEST_MARKER(); } - --( pxQueue->xRxLock ); + --cRxLock; } else { @@ -1820,7 +1905,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) } } - pxQueue->xRxLock = queueUNLOCKED; + pxQueue->cRxLock = queueUNLOCKED; } taskEXIT_CRITICAL(); } @@ -2210,6 +2295,34 @@ BaseType_t xReturn; #if ( configQUEUE_REGISTRY_SIZE > 0 ) + const char *pcQueueGetName( QueueHandle_t xQueue ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t ux; + const char *pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + /* Note there is nothing here to protect against another task adding or + removing entries from the registry while it is being searched. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + pcReturn = xQueueRegistry[ ux ].pcQueueName; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return pcReturn; + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + void vQueueUnregisterQueue( QueueHandle_t xQueue ) { UBaseType_t ux; @@ -2222,6 +2335,11 @@ BaseType_t xReturn; { /* Set the name to NULL to show that this slot if free again. */ xQueueRegistry[ ux ].pcQueueName = NULL; + + /* Set the handle to NULL to ensure the same queue handle cannot + appear in the registry twice if it is added, removed, then + added again. */ + xQueueRegistry[ ux ].xHandle = ( QueueHandle_t ) 0; break; } else @@ -2237,7 +2355,7 @@ BaseType_t xReturn; #if ( configUSE_TIMERS == 1 ) - void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait ) + void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) { Queue_t * const pxQueue = ( Queue_t * ) xQueue; @@ -2259,7 +2377,7 @@ BaseType_t xReturn; if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U ) { /* There is nothing in the queue, block for the specified period. */ - vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely ); } else { @@ -2271,7 +2389,7 @@ BaseType_t xReturn; #endif /* configUSE_TIMERS */ /*-----------------------------------------------------------*/ -#if ( configUSE_QUEUE_SETS == 1 ) +#if( ( configUSE_QUEUE_SETS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) { @@ -2394,16 +2512,26 @@ BaseType_t xReturn; if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) { + const int8_t cTxLock = pxQueueSetContainer->cTxLock; + traceQUEUE_SEND( pxQueueSetContainer ); + /* The data copied is the handle of the queue that contains data. */ xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); - if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + if( cTxLock == queueUNLOCKED ) { - if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* The task waiting has a higher priority */ - xReturn = pdTRUE; + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { @@ -2412,7 +2540,7 @@ BaseType_t xReturn; } else { - mtCOVERAGE_TEST_MARKER(); + pxQueueSetContainer->cTxLock = ( int8_t ) ( cTxLock + 1 ); } } else diff --git a/cc3200/FreeRTOS/Source/tasks.c b/cc3200/FreeRTOS/Source/tasks.c index ea3ff3c571..6c261a6510 100644 --- a/cc3200/FreeRTOS/Source/tasks.c +++ b/cc3200/FreeRTOS/Source/tasks.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -84,6 +88,8 @@ header files above, but not in this file, in order to generate the correct privileged Vs unprivileged linkage and placement. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting +functions but without including stdio.h here. */ #if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) /* At the bottom of this file are two optional functions that can be used to generate human readable text from the raw data generated by the @@ -92,18 +98,6 @@ privileged Vs unprivileged linkage and placement. */ #include <stdio.h> #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ -/* Sanity check the configuration. */ -#if configUSE_TICKLESS_IDLE != 0 - #if INCLUDE_vTaskSuspend != 1 - #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 - #endif /* INCLUDE_vTaskSuspend */ -#endif /* configUSE_TICKLESS_IDLE */ - -/* - * Defines the size, in words, of the stack allocated to the idle task. - */ -#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE - #if( configUSE_PREEMPTION == 0 ) /* If the cooperative scheduler is being used then a yield should not be performed just because a higher priority task has been woken. */ @@ -112,139 +106,10 @@ privileged Vs unprivileged linkage and placement. */ #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() #endif -/* - * Task control block. A task control block (TCB) is allocated for each task, - * and stores task state information, including a pointer to the task's context - * (the task's run time environment, including register values) - */ -typedef struct tskTaskControlBlock -{ - volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ - - #if ( portUSING_MPU_WRAPPERS == 1 ) - xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ - #endif - - ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ - ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ - UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ - StackType_t *pxStack; /*< Points to the start of the stack. */ - char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - - #if ( portSTACK_GROWTH > 0 ) - StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ - #endif - - #if ( portCRITICAL_NESTING_IN_TCB == 1 ) - UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ - #endif - - #if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ - UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ - #endif - - #if ( configUSE_MUTEXES == 1 ) - UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ - UBaseType_t uxMutexesHeld; - #endif - - #if ( configUSE_APPLICATION_TASK_TAG == 1 ) - TaskHookFunction_t pxTaskTag; - #endif - - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ - #endif - - #if ( configUSE_NEWLIB_REENTRANT == 1 ) - /* Allocate a Newlib reent structure that is specific to this task. - Note Newlib support has been included by popular demand, but is not - used by the FreeRTOS maintainers themselves. FreeRTOS is not - responsible for resulting newlib operation. User must be familiar with - newlib and must provide system-wide implementations of the necessary - stubs. Be warned that (at the time of writing) the current newlib design - implements a system-wide malloc() that must be provided with locks. */ - struct _reent xNewLib_reent; - #endif - -} tskTCB; - -/* The old tskTCB name is maintained above then typedefed to the new TCB_t name -below to enable the use of older kernel aware debuggers. */ -typedef tskTCB TCB_t; - -/* - * Some kernel aware debuggers require the data the debugger needs access to to - * be global, rather than file scope. - */ -#ifdef portREMOVE_STATIC_QUALIFIER - #define static -#endif - -/*lint -e956 A manual analysis and inspection has been used to determine which -static variables must be declared volatile. */ - -PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; - -/* Lists for ready and blocked tasks. --------------------*/ -PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ -PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ - -#if ( INCLUDE_vTaskDelete == 1 ) - - PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ - PRIVILEGED_DATA static volatile UBaseType_t uxTasksDeleted = ( UBaseType_t ) 0U; - -#endif - -#if ( INCLUDE_vTaskSuspend == 1 ) - - PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */ - -#endif - -#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) - - PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ - -#endif - -/* Other file private variables. --------------------------------*/ -PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; -PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; -PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; -PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; -PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; -PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = portMAX_DELAY; - -/* Context switches are held pending while the scheduler is suspended. Also, -interrupts must not manipulate the xStateListItem of a TCB, or any of the -lists the xStateListItem can be referenced from, if the scheduler is suspended. -If an interrupt needs to unblock a task while the scheduler is suspended then it -moves the task's event list item into the xPendingReadyList, ready for the -kernel to move the task from the pending ready list into the real ready list -when the scheduler is unsuspended. The pending ready list itself can only be -accessed from a critical section. */ -PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; - -#if ( configGENERATE_RUN_TIME_STATS == 1 ) - - PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ - PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ - -#endif - -/*lint +e956 */ - -/* Debugging and trace facilities private variables and macros. ------------*/ +/* Values that can be assigned to the ucNotifyState member of the TCB. */ +#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) +#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) +#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) /* * The value used to fill the stack of a task when the task is created. This @@ -252,6 +117,26 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t */ #define tskSTACK_FILL_BYTE ( 0xa5U ) +/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using +dynamically allocated RAM, in which case when any task is deleted it is known +that both the task's stack and TCB need to be freed. Sometimes the +FreeRTOSConfig.h settings only allow a task to be created using statically +allocated RAM, in which case when any task is deleted it is known that neither +the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h +settings allow a task to be created using either statically or dynamically +allocated RAM, in which case a member of the TCB is used to record whether the +stack and/or TCB were allocated statically or dynamically, so when a task is +deleted the RAM that was allocated dynamically is freed again and no attempt is +made to free the RAM that was allocated statically. +tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a +task to be created using either statically or dynamically allocated RAM. Note +that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with +a statically allocated stack and a dynamically allocated TCB. */ +#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) +#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) +#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) +#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) + /* * Macros used by vListTask to indicate which state a task is in. */ @@ -260,7 +145,13 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t #define tskDELETED_CHAR ( 'D' ) #define tskSUSPENDED_CHAR ( 'S' ) -/*-----------------------------------------------------------*/ +/* + * Some kernel aware debuggers require the data the debugger needs access to be + * global, rather than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) @@ -282,16 +173,19 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t #define taskSELECT_HIGHEST_PRIORITY_TASK() \ { \ + UBaseType_t uxTopPriority = uxTopReadyPriority; \ + \ /* Find the highest priority queue that contains ready tasks. */ \ - while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \ { \ - configASSERT( uxTopReadyPriority ); \ - --uxTopReadyPriority; \ + configASSERT( uxTopPriority ); \ + --uxTopPriority; \ } \ \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ the same priority get an equal share of the processor time. */ \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + uxTopReadyPriority = uxTopPriority; \ } /* taskSELECT_HIGHEST_PRIORITY_TASK */ /*-----------------------------------------------------------*/ @@ -317,7 +211,7 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t { \ UBaseType_t uxTopPriority; \ \ - /* Find the highest priority queue that contains ready tasks. */ \ + /* Find the highest priority list that contains ready tasks. */ \ portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ @@ -363,9 +257,10 @@ count overflows. */ * the task. It is inserted at the end of the list. */ #define prvAddTaskToReadyList( pxTCB ) \ - traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + traceMOVED_TASK_TO_READY_STATE( pxTCB ); \ taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ - vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) + vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \ + tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) /*-----------------------------------------------------------*/ /* @@ -384,37 +279,175 @@ being used for another purpose. The following bit definition is used to inform the scheduler that the value should not be changed - in which case it is the responsibility of whichever module is using the value to ensure it gets set back to its original value when it is released. */ -#if configUSE_16_BIT_TICKS == 1 +#if( configUSE_16_BIT_TICKS == 1 ) #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U #else #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL #endif +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock +{ + volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ + UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + StackType_t *pxStack; /*< Points to the start of the stack. */ + char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + #if ( portSTACK_GROWTH > 0 ) + StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + TaskHookFunction_t pxTaskTag; + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + + #if( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. */ + struct _reent xNewLib_reent; + #endif + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; + #endif + + /* See the comments above the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; + #endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; + +/* Lists for ready and blocked tasks. --------------------*/ +PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ + +#if( INCLUDE_vTaskDelete == 1 ) + + PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ + PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; + +#endif + +#if ( INCLUDE_vTaskSuspend == 1 ) + + PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */ + +#endif + +/* Other file private variables. --------------------------------*/ +PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; +PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; +PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ + +/* Context switches are held pending while the scheduler is suspended. Also, +interrupts must not manipulate the xStateListItem of a TCB, or any of the +lists the xStateListItem can be referenced from, if the scheduler is suspended. +If an interrupt needs to unblock a task while the scheduler is suspended then it +moves the task's event list item into the xPendingReadyList, ready for the +kernel to move the task from the pending ready list into the real ready list +when the scheduler is unsuspended. The pending ready list itself can only be +accessed from a critical section. */ +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ + +#endif + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + /* Callback function prototypes. --------------------------*/ -#if configCHECK_FOR_STACK_OVERFLOW > 0 +#if( configCHECK_FOR_STACK_OVERFLOW > 0 ) extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); #endif -#if configUSE_TICK_HOOK > 0 +#if( configUSE_TICK_HOOK > 0 ) extern void vApplicationTickHook( void ); #endif -/* File private functions. --------------------------------*/ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); +#endif -/* - * Utility to ready a TCB for a given task. Mainly just copies the parameters - * into the TCB structure. - */ -static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/* File private functions. --------------------------------*/ -#if ( INCLUDE_vTaskSuspend == 1 ) /** * Utility task that simply returns pdTRUE if the task referenced by xTask is * currently in the Suspended state, or pdFALSE if the task referenced by xTask * is in any other state. */ -static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; -#endif +#if ( INCLUDE_vTaskSuspend == 1 ) + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +#endif /* INCLUDE_vTaskSuspend */ /* * Utility to ready all the lists used by the scheduler. This is called @@ -459,13 +492,7 @@ static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; * The currently executing task is entering the Blocked state. Add the task to * either the current or the overflow delayed task list. */ -static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION; - -/* - * Allocates memory from the heap for a TCB and associated stack. Checks the - * allocation was successful. - */ -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION; +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION; /* * Fills an TaskStatus_t structure with information on each task that is @@ -477,7 +504,17 @@ static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * */ #if ( configUSE_TRACE_FACILITY == 1 ) - static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Searches pxList for a task with name pcNameToQuery - returning a handle to + * the task if it is found, or NULL if the task is not found. + */ +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION; #endif @@ -513,184 +550,496 @@ static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * */ static void prvResetNextTaskUnblockTime( void ); -/*-----------------------------------------------------------*/ +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) -__attribute__ ((section (".boot"))) -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ -{ -BaseType_t xReturn; -TCB_t * pxNewTCB; + /* + * Helper function used to pad task names with spaces when printing out + * human readable tables of task information. + */ + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Called after a Task_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - configASSERT( pxTaskCode ); - configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) ); +/* + * Called after a new task has been created and initialised to place the task + * under the control of the scheduler. + */ +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ - /* Allocate the memory required by the TCB and stack for the new task, - checking that the allocation was successful. */ - pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) - if( pxNewTCB != NULL ) + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { - StackType_t *pxTopOfStack; + TCB_t *pxNewTCB; + TaskHandle_t xReturn; + + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); - #if( portUSING_MPU_WRAPPERS == 1 ) - /* Should the task be created in privileged mode? */ - BaseType_t xRunPrivileged; - if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) + if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) + { + /* The memory used for the task's TCB and stack are passed into this + function - use them. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; + + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) { - xRunPrivileged = pdTRUE; + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; } - else + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + } + else + { + xReturn = NULL; + } + + return xReturn; + } + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( portUSING_MPU_WRAPPERS == 1 ) + + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT( pxTaskDefinition->puxStackBuffer ); + + if( pxTaskDefinition->puxStackBuffer != NULL ) + { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) { - xRunPrivileged = pdFALSE; + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + + prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + ( uint32_t ) pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, pxNewTCB, + pxTaskDefinition->xRegions ); + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; } - uxPriority &= ~portPRIVILEGE_BIT; - #endif /* portUSING_MPU_WRAPPERS == 1 */ + } - /* Calculate the top of stack address. This depends on whether the - stack grows from high memory to low (as per the 80x86) or vice versa. - portSTACK_GROWTH is used to make the result positive or negative as - required by the port. */ - #if( portSTACK_GROWTH < 0 ) + return xReturn; + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + TCB_t *pxNewTCB; + BaseType_t xReturn; + + /* If the stack grows down then allocate the stack then the TCB so the stack + does not grow into the TCB. Likewise if the stack grows up then allocate + the TCB then the stack. */ + #if( portSTACK_GROWTH > 0 ) { - pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 ); - pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function and whether or not static + allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - /* Check the alignment of the calculated top of stack is correct. */ - configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree( pxNewTCB ); + pxNewTCB = NULL; + } + } } #else /* portSTACK_GROWTH */ { - pxTopOfStack = pxNewTCB->pxStack; + StackType_t *pxStack; + + /* Allocate space for the stack used by the task being created. */ + pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - /* Check the alignment of the stack buffer is correct. */ - configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + if( pxStack != NULL ) + { + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ - /* If we want to use stack checking on architectures that use - a positive stack growth direction then we also need to store the - other extreme of the stack space. */ - pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } + else + { + /* The stack cannot be used as the TCB was not created. Free + it again. */ + vPortFree( pxStack ); + } + } + else + { + pxNewTCB = NULL; + } } #endif /* portSTACK_GROWTH */ - /* Setup the newly allocated TCB with the initial state of the task. */ - prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); + if( pxNewTCB != NULL ) + { + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ - /* Initialize the TCB stack to look as if the task was already running, - but had been interrupted by the scheduler. The return address is set - to the start of the task function. Once the stack has been initialised - the top of stack variable is updated. */ - #if( portUSING_MPU_WRAPPERS == 1 ) + prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + else { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } - #else /* portUSING_MPU_WRAPPERS */ + + return xReturn; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +StackType_t *pxTopOfStack; +UBaseType_t x; + + #if( portUSING_MPU_WRAPPERS == 1 ) + /* Should the task be created in privileged mode? */ + BaseType_t xRunPrivileged; + if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) { - pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + xRunPrivileged = pdTRUE; } - #endif /* portUSING_MPU_WRAPPERS */ + else + { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; + #endif /* portUSING_MPU_WRAPPERS == 1 */ + + /* Avoid dependency on memset() if it is not required. */ + #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + { + /* Fill the stack with a known value to assist debugging. */ + ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); + } + #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + + /* Calculate the top of stack address. This depends on whether the stack + grows from high memory to low (as per the 80x86) or vice versa. + portSTACK_GROWTH is used to make the result positive or negative as required + by the port. */ + #if( portSTACK_GROWTH < 0 ) + { + pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + } + #else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + /* The other extreme of the stack space is required if stack checking is + performed. */ + pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + } + #endif /* portSTACK_GROWTH */ + + /* Store the task name in the TCB. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + pxNewTCB->pcTaskName[ x ] = pcName[ x ]; - if( ( void * ) pxCreatedTask != NULL ) + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == 0x00 ) { - /* Pass the TCB out - in an anonymous way. The calling function/ - task can use this as a handle to delete the task later if - required.*/ - *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + break; } else { mtCOVERAGE_TEST_MARKER(); } + } - /* Ensure interrupts don't access the task lists while they are being - updated. */ - taskENTER_CRITICAL(); + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxNewTCB->uxPriority = uxPriority; + #if ( configUSE_MUTEXES == 1 ) + { + pxNewTCB->uxBasePriority = uxPriority; + pxNewTCB->uxMutexesHeld = 0; + } + #endif /* configUSE_MUTEXES */ + + vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); + vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); + + /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get + back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB ); + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + { + pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U; + } + #endif /* portCRITICAL_NESTING_IN_TCB */ + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + { + pxNewTCB->pxTaskTag = NULL; + } + #endif /* configUSE_APPLICATION_TASK_TAG */ + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxNewTCB->ulRunTimeCounter = 0UL; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + { + vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth ); + } + #else + { + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) xRegions; + } + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + { + for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) { - uxCurrentNumberOfTasks++; - if( pxCurrentTCB == NULL ) - { - /* There are no other tasks, or all the other tasks are in - the suspended state - make this the current task. */ - pxCurrentTCB = pxNewTCB; + pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL; + } + } + #endif - if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) - { - /* This is the first task to be created so do the preliminary - initialisation required. We will not recover if this call - fails, but we will report the failure. */ - prvInitialiseTaskLists(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + pxNewTCB->ulNotifiedValue = 0; + pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Initialise this task's Newlib reent structure. */ + _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) ); + } + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + pxNewTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Initialize the TCB stack to look as if the task was already running, + but had been interrupted by the scheduler. The return address is set + to the start of the task function. Once the stack has been initialised + the top of stack variable is updated. */ + #if( portUSING_MPU_WRAPPERS == 1 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portUSING_MPU_WRAPPERS */ + + if( ( void * ) pxCreatedTask != NULL ) + { + /* Pass the handle out in an anonymous way. The handle can be used to + change the created task's priority, delete the created task, etc.*/ + *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) +{ + /* Ensure interrupts don't access the task lists while the lists are being + updated. */ + taskENTER_CRITICAL(); + { + uxCurrentNumberOfTasks++; + if( pxCurrentTCB == NULL ) + { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB = pxNewTCB; + + if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) + { + /* This is the first task to be created so do the preliminary + initialisation required. We will not recover if this call + fails, but we will report the failure. */ + prvInitialiseTaskLists(); } else { - /* If the scheduler is not already running, make this task the - current task if it is the highest priority task to be created - so far. */ - if( xSchedulerRunning == pdFALSE ) + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ + if( xSchedulerRunning == pdFALSE ) + { + if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ) { - if( pxCurrentTCB->uxPriority <= uxPriority ) - { - pxCurrentTCB = pxNewTCB; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + pxCurrentTCB = pxNewTCB; } else { mtCOVERAGE_TEST_MARKER(); } } - - uxTaskNumber++; - - #if ( configUSE_TRACE_FACILITY == 1 ) + else { - /* Add a counter into the TCB for tracing only. */ - pxNewTCB->uxTCBNumber = uxTaskNumber; + mtCOVERAGE_TEST_MARKER(); } - #endif /* configUSE_TRACE_FACILITY */ - traceTASK_CREATE( pxNewTCB ); + } - prvAddTaskToReadyList( pxNewTCB ); + uxTaskNumber++; - xReturn = pdPASS; - portSETUP_TCB( pxNewTCB ); + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; } - taskEXIT_CRITICAL(); - } - else - { - xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - traceTASK_CREATE_FAILED(); + #endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE( pxNewTCB ); + + prvAddTaskToReadyList( pxNewTCB ); + + portSETUP_TCB( pxNewTCB ); } + taskEXIT_CRITICAL(); - if( xReturn == pdPASS ) + if( xSchedulerRunning != pdFALSE ) { - if( xSchedulerRunning != pdFALSE ) + /* If the created task is of a higher priority than the current task + then it should run now. */ + if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ) { - /* If the created task is of a higher priority than the current task - then it should run now. */ - if( pxCurrentTCB->uxPriority < uxPriority ) - { - taskYIELD_IF_USING_PREEMPTION(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + taskYIELD_IF_USING_PREEMPTION(); } else { mtCOVERAGE_TEST_MARKER(); } } - - return xReturn; + else + { + mtCOVERAGE_TEST_MARKER(); + } } /*-----------------------------------------------------------*/ @@ -706,11 +1055,8 @@ TCB_t * pxNewTCB; being deleted. */ pxTCB = prvGetTCBFromHandle( xTaskToDelete ); - /* Remove task from the ready list and place in the termination list. - This will stop the task from be scheduled. The idle task will check - the termination list and free up any memory allocated by the - scheduler for the TCB and stack. */ - if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + /* Remove task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } @@ -729,16 +1075,42 @@ TCB_t * pxNewTCB; mtCOVERAGE_TEST_MARKER(); } - vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) ); + /* Increment the uxTaskNumber also so kernel aware debuggers can + detect that the task lists need re-generating. This is done before + portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will + not return. */ + uxTaskNumber++; - /* Increment the ucTasksDeleted variable so the idle task knows - there is a task that has been deleted and that it should therefore - check the xTasksWaitingTermination list. */ - ++uxTasksDeleted; + if( pxTCB == pxCurrentTCB ) + { + /* A task is deleting itself. This cannot complete within the + task itself, as a context switch to another task is required. + Place the task in the termination list. The idle task will + check the termination list and free up any memory allocated by + the scheduler for the TCB and stack of the deleted task. */ + vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); + + /* Increment the ucTasksDeleted variable so the idle task knows + there is a task that has been deleted and that it should therefore + check the xTasksWaitingTermination list. */ + ++uxDeletedTasksWaitingCleanUp; - /* Increment the uxTaskNumberVariable also so kernel aware debuggers - can detect that the task lists need re-generating. */ - uxTaskNumber++; + /* The pre-delete hook is primarily for the Windows simulator, + in which Windows specific clean up operations are performed, + after which it is not possible to yield away from this task - + hence xYieldPending is used to latch that a context switch is + required. */ + portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); + } + else + { + --uxCurrentNumberOfTasks; + prvDeleteTCB( pxTCB ); + + /* Reset the next expected unblock time in case it referred to + the task that has just been deleted. */ + prvResetNextTaskUnblockTime(); + } traceTASK_DELETE( pxTCB ); } @@ -751,24 +1123,11 @@ TCB_t * pxNewTCB; if( pxTCB == pxCurrentTCB ) { configASSERT( uxSchedulerSuspended == 0 ); - - /* The pre-delete hook is primarily for the Windows simulator, - in which Windows specific clean up operations are performed, - after which it is not possible to yield away from this task - - hence xYieldPending is used to latch that a context switch is - required. */ - portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); portYIELD_WITHIN_API(); } else { - /* Reset the next expected unblock time in case it referred to - the task that has just been deleted. */ - taskENTER_CRITICAL(); - { - prvResetNextTaskUnblockTime(); - } - taskEXIT_CRITICAL(); + mtCOVERAGE_TEST_MARKER(); } } } @@ -832,23 +1191,11 @@ TCB_t * pxNewTCB; if( xShouldDelay != pdFALSE ) { - traceTASK_DELAY_UNTIL(); - - /* Remove the task from the ready list before adding it to the - blocked list as the same list item is used for both lists. */ - if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) - { - /* The current task must be in a ready list, so there is - no need to check, and the port reset macro can be called - directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + traceTASK_DELAY_UNTIL( xTimeToWake ); - prvAddCurrentTaskToDelayedList( xTimeToWake ); + /* prvAddCurrentTaskToDelayedList() needs the block time, not + the time to wake, so subtract the current tick count. */ + prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE ); } else { @@ -876,10 +1223,8 @@ TCB_t * pxNewTCB; void vTaskDelay( const TickType_t xTicksToDelay ) { - TickType_t xTimeToWake; BaseType_t xAlreadyYielded = pdFALSE; - /* A delay time of zero just forces a reschedule. */ if( xTicksToDelay > ( TickType_t ) 0U ) { @@ -895,26 +1240,7 @@ TCB_t * pxNewTCB; This task cannot be in an event list as it is the currently executing task. */ - - /* Calculate the time to wake - this may overflow but this is - not a problem. */ - xTimeToWake = xTickCount + xTicksToDelay; - - /* We must remove ourselves from the ready list before adding - ourselves to the blocked list as the same list item is used for - both lists. */ - if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) - { - /* The current task must be in a ready list, so there is - no need to check, and the port reset macro can be called - directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - prvAddCurrentTaskToDelayedList( xTimeToWake ); + prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); } xAlreadyYielded = xTaskResumeAll(); } @@ -938,7 +1264,7 @@ TCB_t * pxNewTCB; #endif /* INCLUDE_vTaskDelay */ /*-----------------------------------------------------------*/ -#if ( INCLUDE_eTaskGetState == 1 ) +#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) ) eTaskState eTaskGetState( TaskHandle_t xTask ) { @@ -957,7 +1283,7 @@ TCB_t * pxNewTCB; { taskENTER_CRITICAL(); { - pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) ); + pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); } taskEXIT_CRITICAL(); @@ -986,15 +1312,16 @@ TCB_t * pxNewTCB; #endif #if ( INCLUDE_vTaskDelete == 1 ) - else if( pxStateList == &xTasksWaitingTermination ) + else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) { /* The task being queried is referenced from the deleted - tasks list. */ + tasks list, or it is not referenced from any lists at + all. */ eReturn = eDeleted; } #endif - else + else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ { /* If the task is not in any other state, it must be in the Ready (including pending ready) state. */ @@ -1017,8 +1344,8 @@ TCB_t * pxNewTCB; taskENTER_CRITICAL(); { - /* If null is passed in here then we are changing the - priority of the calling function. */ + /* If null is passed in here then it is the priority of the that + called uxTaskPriorityGet() that is being queried. */ pxTCB = prvGetTCBFromHandle( xTask ); uxReturn = pxTCB->uxPriority; } @@ -1030,6 +1357,46 @@ TCB_t * pxNewTCB; #endif /* INCLUDE_uxTaskPriorityGet */ /*-----------------------------------------------------------*/ +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn, uxSavedInterruptState; + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* If null is passed in here then it is the priority of the calling + task that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + #if ( INCLUDE_vTaskPrioritySet == 1 ) void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) @@ -1151,12 +1518,12 @@ TCB_t * pxNewTCB; nothing more than change it's priority variable. However, if the task is in a ready list it needs to be removed and placed in the list appropriate to its new priority. */ - if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { /* The task is currently in its ready list - remove before adding it to it's new ready list. As we are in a critical section we can do this even if the scheduler is suspended. */ - if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* It is known that the task is in its ready list so there is no need to check again and the port level @@ -1174,7 +1541,7 @@ TCB_t * pxNewTCB; mtCOVERAGE_TEST_MARKER(); } - if( xYieldRequired == pdTRUE ) + if( xYieldRequired != pdFALSE ) { taskYIELD_IF_USING_PREEMPTION(); } @@ -1210,7 +1577,7 @@ TCB_t * pxNewTCB; /* Remove task from the ready/delayed list and place in the suspended list. */ - if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } @@ -1229,10 +1596,25 @@ TCB_t * pxNewTCB; mtCOVERAGE_TEST_MARKER(); } - vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); + vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); } taskEXIT_CRITICAL(); + if( xSchedulerRunning != pdFALSE ) + { + /* Reset the next expected unblock time in case it referred to the + task that is now in the Suspended state. */ + taskENTER_CRITICAL(); + { + prvResetNextTaskUnblockTime(); + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + if( pxTCB == pxCurrentTCB ) { if( xSchedulerRunning != pdFALSE ) @@ -1262,21 +1644,7 @@ TCB_t * pxNewTCB; } else { - if( xSchedulerRunning != pdFALSE ) - { - /* A task other than the currently running task was suspended, - reset the next expected unblock time in case it referred to the - task that is now in the Suspended state. */ - taskENTER_CRITICAL(); - { - prvResetNextTaskUnblockTime(); - } - taskEXIT_CRITICAL(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + mtCOVERAGE_TEST_MARKER(); } } @@ -1297,7 +1665,7 @@ TCB_t * pxNewTCB; configASSERT( xTask ); /* Is the task being resumed actually in the suspended list? */ - if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) + if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE ) { /* Has the task already been resumed from within an ISR? */ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) @@ -1344,13 +1712,13 @@ TCB_t * pxNewTCB; { taskENTER_CRITICAL(); { - if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { traceTASK_RESUME( pxTCB ); /* As we are in a critical section we can access the ready lists even if the scheduler is suspended. */ - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); /* We may have just resumed a higher priority task. */ @@ -1413,7 +1781,7 @@ TCB_t * pxNewTCB; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { - if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { traceTASK_RESUME_FROM_ISR( pxTCB ); @@ -1431,7 +1799,7 @@ TCB_t * pxNewTCB; mtCOVERAGE_TEST_MARKER(); } - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); } else @@ -1455,24 +1823,47 @@ TCB_t * pxNewTCB; #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ /*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) void vTaskStartScheduler( void ) { BaseType_t xReturn; /* Add the idle task at the lowest priority. */ - #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { - /* Create the idle task, storing its handle in xIdleTaskHandle so it can - be returned by the xTaskGetIdleTaskHandle() function. */ - xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + StaticTask_t *pxIdleTaskTCBBuffer = NULL; + StackType_t *pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, + "IDLE", + ulIdleTaskStackSize, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + + if( xIdleTaskHandle != NULL ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } } #else { - /* Create the idle task without storing its handle. */ - xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreate( prvIdleTask, + "IDLE", configMINIMAL_STACK_SIZE, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } - #endif /* INCLUDE_xTaskGetIdleTaskHandle */ + #endif /* configSUPPORT_STATIC_ALLOCATION */ #if ( configUSE_TIMERS == 1 ) { @@ -1504,6 +1895,7 @@ BaseType_t xReturn; } #endif /* configUSE_NEWLIB_REENTRANT */ + xNextTaskUnblockTime = portMAX_DELAY; xSchedulerRunning = pdTRUE; xTickCount = ( TickType_t ) 0U; @@ -1529,8 +1921,12 @@ BaseType_t xReturn; /* This line will only be reached if the kernel could not be started, because there was not enough FreeRTOS heap to create the idle task or the timer task. */ - configASSERT( xReturn ); + configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); } + + /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, + meaning xIdleTaskHandle is not used anywhere else. */ + ( void ) xIdleTaskHandle; } /*-----------------------------------------------------------*/ @@ -1560,6 +1956,34 @@ void vTaskSuspendAll( void ) static TickType_t prvGetExpectedIdleTime( void ) { TickType_t xReturn; + UBaseType_t uxHigherPriorityReadyTasks = pdFALSE; + + /* uxHigherPriorityReadyTasks takes care of the case where + configUSE_PREEMPTION is 0, so there may be tasks above the idle priority + task that are in the Ready state, even though the idle task is + running. */ + #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + { + if( uxTopReadyPriority > tskIDLE_PRIORITY ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #else + { + const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01; + + /* When port optimised task selection is used the uxTopReadyPriority + variable is used as a bit map. If bits other than the least + significant bit are set then there are tasks that have a priority + above the idle priority that are in the Ready state. This takes + care of the case where the co-operative scheduler is in use. */ + if( uxTopReadyPriority > uxLeastSignificantBit ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #endif if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) { @@ -1572,6 +1996,13 @@ void vTaskSuspendAll( void ) processed. */ xReturn = 0; } + else if( uxHigherPriorityReadyTasks != pdFALSE ) + { + /* There are tasks in the Ready state that have a priority above the + idle priority. This path can only be reached if + configUSE_PREEMPTION is 0. */ + xReturn = 0; + } else { xReturn = xNextTaskUnblockTime - xTickCount; @@ -1585,7 +2016,7 @@ void vTaskSuspendAll( void ) BaseType_t xTaskResumeAll( void ) { -TCB_t *pxTCB; +TCB_t *pxTCB = NULL; BaseType_t xAlreadyYielded = pdFALSE; /* If uxSchedulerSuspended is zero then this function does not match a @@ -1611,11 +2042,11 @@ BaseType_t xAlreadyYielded = pdFALSE; { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); - /* If we have moved a task that has a priority higher than - the current task then we should yield. */ + /* If the moved task has a priority higher than the current + task then a yield must be performed. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldPending = pdTRUE; @@ -1626,31 +2057,48 @@ BaseType_t xAlreadyYielded = pdFALSE; } } + if( pxTCB != NULL ) + { + /* A task was unblocked while the scheduler was suspended, + which may have prevented the next unblock time from being + re-calculated, in which case re-calculate it now. Mainly + important for low power tickless implementations, where + this can prevent an unnecessary exit from low power + state. */ + prvResetNextTaskUnblockTime(); + } + /* If any ticks occurred while the scheduler was suspended then they should be processed now. This ensures the tick count does not slip, and that any delayed tasks are resumed at the correct time. */ - if( uxPendedTicks > ( UBaseType_t ) 0U ) { - while( uxPendedTicks > ( UBaseType_t ) 0U ) + UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */ + + if( uxPendedCounts > ( UBaseType_t ) 0U ) { - if( xTaskIncrementTick() != pdFALSE ) - { - xYieldPending = pdTRUE; - } - else + do { - mtCOVERAGE_TEST_MARKER(); - } - --uxPendedTicks; + if( xTaskIncrementTick() != pdFALSE ) + { + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --uxPendedCounts; + } while( uxPendedCounts > ( UBaseType_t ) 0U ); + + uxPendedTicks = 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); } - } - else - { - mtCOVERAGE_TEST_MARKER(); } - if( xYieldPending == pdTRUE ) + if( xYieldPending != pdFALSE ) { #if( configUSE_PREEMPTION != 0 ) { @@ -1681,11 +2129,11 @@ TickType_t xTaskGetTickCount( void ) TickType_t xTicks; /* Critical section required if running on a 16 bit processor. */ - taskENTER_CRITICAL(); + portTICK_TYPE_ENTER_CRITICAL(); { xTicks = xTickCount; } - taskEXIT_CRITICAL(); + portTICK_TYPE_EXIT_CRITICAL(); return xTicks; } @@ -1712,11 +2160,11 @@ UBaseType_t uxSavedInterruptStatus; link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); { xReturn = xTickCount; } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); return xReturn; } @@ -1730,19 +2178,142 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) } /*-----------------------------------------------------------*/ -#if ( INCLUDE_pcTaskGetTaskName == 1 ) +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +TCB_t *pxTCB; + + /* If null is passed in here then the name of the calling task is being + queried. */ + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + configASSERT( pxTCB ); + return &( pxTCB->pcTaskName[ 0 ] ); +} +/*-----------------------------------------------------------*/ - char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) { - TCB_t *pxTCB; + TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL; + UBaseType_t x; + char cNextChar; - /* If null is passed in here then the name of the calling task is being queried. */ - pxTCB = prvGetTCBFromHandle( xTaskToQuery ); - configASSERT( pxTCB ); - return &( pxTCB->pcTaskName[ 0 ] ); + /* This function is called with the scheduler suspended. */ + + if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + + /* Check each character in the name looking for a match or + mismatch. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + cNextChar = pxNextTCB->pcTaskName[ x ]; + + if( cNextChar != pcNameToQuery[ x ] ) + { + /* Characters didn't match. */ + break; + } + else if( cNextChar == 0x00 ) + { + /* Both strings terminated, a match must have been + found. */ + pxReturn = pxNextTCB; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( pxReturn != NULL ) + { + /* The handle has been found. */ + break; + } + + } while( pxNextTCB != pxFirstTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return pxReturn; + } + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetHandle == 1 ) + + TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t uxQueue = configMAX_PRIORITIES; + TCB_t* pxTCB; + + /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ + configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN ); + + vTaskSuspendAll(); + { + /* Search the ready lists. */ + do + { + uxQueue--; + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery ); + + if( pxTCB != NULL ) + { + /* Found the handle. */ + break; + } + + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Search the delayed lists. */ + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery ); + } + + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery ); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the suspended list. */ + pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery ); + } + } + #endif + + #if( INCLUDE_vTaskDelete == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the deleted list. */ + pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery ); + } + } + #endif + } + ( void ) xTaskResumeAll(); + + return ( TaskHandle_t ) pxTCB; } -#endif /* INCLUDE_pcTaskGetTaskName */ +#endif /* INCLUDE_xTaskGetHandle */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) @@ -1761,20 +2332,20 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) do { uxQueue--; - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ /* Fill in an TaskStatus_t structure with information on each task in the Blocked state. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); #if( INCLUDE_vTaskDelete == 1 ) { /* Fill in an TaskStatus_t structure with information on each task that has been deleted but not yet cleaned up. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); } #endif @@ -1782,7 +2353,7 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) { /* Fill in an TaskStatus_t structure with information on each task in the Suspended state. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); } #endif @@ -1851,6 +2422,80 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than #endif /* configUSE_TICKLESS_IDLE */ /*----------------------------------------------------------*/ +#if ( INCLUDE_xTaskAbortDelay == 1 ) + + BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) + { + TCB_t *pxTCB = ( TCB_t * ) xTask; + BaseType_t xReturn = pdFALSE; + + configASSERT( pxTCB ); + + vTaskSuspendAll(); + { + /* A task can only be prematurely removed from the Blocked state if + it is actually in the Blocked state. */ + if( eTaskGetState( xTask ) == eBlocked ) + { + /* Remove the reference to the task from the blocked list. An + interrupt won't touch the xStateListItem because the + scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + + /* Is the task waiting on an event also? If so remove it from + the event list too. Interrupts can touch the event list item, + even though the scheduler is suspended, so a critical section + is used. */ + taskENTER_CRITICAL(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + pxTCB->ucDelayAborted = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Place the unblocked task into the appropriate ready list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate context + switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should only be + performed if the unblocked task has a priority that is + equal to or higher than the currently executing task. */ + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Pend the yield to be performed when the scheduler + is unsuspended. */ + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xTaskResumeAll(); + + return xReturn; + } + +#endif /* INCLUDE_xTaskAbortDelay */ +/*----------------------------------------------------------*/ + BaseType_t xTaskIncrementTick( void ) { TCB_t * pxTCB; @@ -1863,103 +2508,101 @@ BaseType_t xSwitchRequired = pdFALSE; traceTASK_INCREMENT_TICK( xTickCount ); if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount + 1; + /* Increment the RTOS tick, switching the delayed and overflowed delayed lists if it wraps to 0. */ - ++xTickCount; + xTickCount = xConstTickCount; + if( xConstTickCount == ( TickType_t ) 0U ) { - /* Minor optimisation. The tick count cannot change in this - block. */ - const TickType_t xConstTickCount = xTickCount; - - if( xConstTickCount == ( TickType_t ) 0U ) - { - taskSWITCH_DELAYED_LISTS(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + taskSWITCH_DELAYED_LISTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* See if this tick has made a timeout expire. Tasks are stored in - the queue in the order of their wake time - meaning once one task - has been found whose block time has not expired there is no need to - look any further down the list. */ - if( xConstTickCount >= xNextTaskUnblockTime ) + /* See if this tick has made a timeout expire. Tasks are stored in + the queue in the order of their wake time - meaning once one task + has been found whose block time has not expired there is no need to + look any further down the list. */ + if( xConstTickCount >= xNextTaskUnblockTime ) + { + for( ;; ) { - for( ;; ) + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { - if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + /* The delayed list is empty. Set xNextTaskUnblockTime + to the maximum possible value so it is extremely + unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass + next time through. */ + xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + break; + } + else + { + /* The delayed list is not empty, get the value of the + item at the head of the delayed list. This is the time + at which the task at the head of the delayed list must + be removed from the Blocked state. */ + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); + + if( xConstTickCount < xItemValue ) { - /* The delayed list is empty. Set xNextTaskUnblockTime - to the maximum possible value so it is extremely - unlikely that the - if( xTickCount >= xNextTaskUnblockTime ) test will pass - next time through. */ - xNextTaskUnblockTime = portMAX_DELAY; + /* It is not time to unblock this item yet, but the + item value is the time at which the task at the head + of the blocked list must be removed from the Blocked + state - so record the item value in + xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; break; } else { - /* The delayed list is not empty, get the value of the - item at the head of the delayed list. This is the time - at which the task at the head of the delayed list must - be removed from the Blocked state. */ - pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); - xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); - - if( xConstTickCount < xItemValue ) - { - /* It is not time to unblock this item yet, but the - item value is the time at which the task at the head - of the blocked list must be removed from the Blocked - state - so record the item value in - xNextTaskUnblockTime. */ - xNextTaskUnblockTime = xItemValue; - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + mtCOVERAGE_TEST_MARKER(); + } - /* It is time to remove the item from the Blocked state. */ - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + /* It is time to remove the item from the Blocked state. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); - /* Is the task waiting on an event also? If so remove - it from the event list. */ - if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + /* Is the task waiting on an event also? If so remove + it from the event list. */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Place the unblocked task into the appropriate ready + list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate + context switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should + only be performed if the unblocked task has a + priority that is equal to or higher than the + currently executing task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { - ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + xSwitchRequired = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } - - /* Place the unblocked task into the appropriate ready - list. */ - prvAddTaskToReadyList( pxTCB ); - - /* A task being unblocked cannot cause an immediate - context switch if preemption is turned off. */ - #if ( configUSE_PREEMPTION == 1 ) - { - /* Preemption is on, but a context switch should - only be performed if the unblocked task has a - priority that is equal to or higher than the - currently executing task. */ - if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) - { - xSwitchRequired = pdTRUE; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif /* configUSE_PREEMPTION */ } + #endif /* configUSE_PREEMPTION */ } } } @@ -2137,9 +2780,9 @@ void vTaskSwitchContext( void ) #endif /* Add the amount of time the task has been running to the - accumulated time so far. The time the task started running was + accumulated time so far. The time the task started running was stored in ulTaskSwitchedInTime. Note that there is no overflow - protection here so count values are only valid until the timer + protection here so count values are only valid until the timer overflows. The guard against negative values is to protect against suspect run time stat counter implementations - which are provided by the application, not the kernel. */ @@ -2156,8 +2799,7 @@ void vTaskSwitchContext( void ) #endif /* configGENERATE_RUN_TIME_STATS */ /* Check for stack overflow, if configured. */ - taskFIRST_CHECK_FOR_STACK_OVERFLOW(); - taskSECOND_CHECK_FOR_STACK_OVERFLOW(); + taskCHECK_FOR_STACK_OVERFLOW(); /* Select a new task to run using either the generic C or port optimised asm code. */ @@ -2177,8 +2819,6 @@ void vTaskSwitchContext( void ) void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) { -TickType_t xTimeToWake; - configASSERT( pxEventList ); /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE @@ -2190,54 +2830,12 @@ TickType_t xTimeToWake; list is locked, preventing simultaneous access from interrupts. */ vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); - /* The task must be removed from from the ready list before it is added to - the blocked list as the same list item is used for both lists. Exclusive - access to the ready lists guaranteed because the scheduler is locked. */ - if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) - { - /* The current task must be in a ready list, so there is no need to - check, and the port reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - #if ( INCLUDE_vTaskSuspend == 1 ) - { - if( xTicksToWait == portMAX_DELAY ) - { - /* Add the task to the suspended task list instead of a delayed task - list to ensure the task is not woken by a timing event. It will - block indefinitely. */ - vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* Calculate the time at which the task should be woken if the event - does not occur. This may overflow but this doesn't matter, the - scheduler will handle it. */ - xTimeToWake = xTickCount + xTicksToWait; - prvAddCurrentTaskToDelayedList( xTimeToWake ); - } - } - #else /* INCLUDE_vTaskSuspend */ - { - /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter, the scheduler - will handle it. */ - xTimeToWake = xTickCount + xTicksToWait; - prvAddCurrentTaskToDelayedList( xTimeToWake ); - } - #endif /* INCLUDE_vTaskSuspend */ + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); } /*-----------------------------------------------------------*/ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) { -TickType_t xTimeToWake; - configASSERT( pxEventList ); /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by @@ -2256,62 +2854,20 @@ TickType_t xTimeToWake; the task level). */ vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); - /* The task must be removed from the ready list before it is added to the - blocked list. Exclusive access can be assured to the ready list as the - scheduler is locked. */ - if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) - { - /* The current task must be in a ready list, so there is no need to - check, and the port reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - #if ( INCLUDE_vTaskSuspend == 1 ) - { - if( xTicksToWait == portMAX_DELAY ) - { - /* Add the task to the suspended task list instead of a delayed task - list to ensure it is not woken by a timing event. It will block - indefinitely. */ - vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* Calculate the time at which the task should be woken if the event - does not occur. This may overflow but this doesn't matter, the - kernel will manage it correctly. */ - xTimeToWake = xTickCount + xTicksToWait; - prvAddCurrentTaskToDelayedList( xTimeToWake ); - } - } - #else /* INCLUDE_vTaskSuspend */ - { - /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter, the kernel - will manage it correctly. */ - xTimeToWake = xTickCount + xTicksToWait; - prvAddCurrentTaskToDelayedList( xTimeToWake ); - } - #endif /* INCLUDE_vTaskSuspend */ + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); } /*-----------------------------------------------------------*/ -#if configUSE_TIMERS == 1 +#if( configUSE_TIMERS == 1 ) - void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait ) + void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) { - TickType_t xTimeToWake; - configASSERT( pxEventList ); /* This function should not be called by application code hence the 'Restricted' in its name. It is not part of the public API. It is designed for use by kernel code, and has special calling requirements - - it should be called from a critical section. */ + it should be called with the scheduler suspended. */ /* Place the event list item of the TCB in the appropriate event list. @@ -2320,26 +2876,16 @@ TickType_t xTimeToWake; can be used in place of vListInsert. */ vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); - /* We must remove this task from the ready list before adding it to the - blocked list as the same list item is used for both lists. This - function is called form a critical section. */ - if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + /* If the task should block indefinitely then set the block time to a + value that will be recognised as an indefinite delay inside the + prvAddCurrentTaskToDelayedList() function. */ + if( xWaitIndefinitely != pdFALSE ) { - /* The current task must be in a ready list, so there is no need to - check, and the port reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + xTicksToWait = portMAX_DELAY; } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter. */ - xTimeToWake = xTickCount + xTicksToWait; - traceTASK_DELAY_UNTIL(); - prvAddCurrentTaskToDelayedList( xTimeToWake ); + traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) ); + prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); } #endif /* configUSE_TIMERS */ @@ -2369,7 +2915,7 @@ BaseType_t xReturn; if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { - ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); } else @@ -2395,6 +2941,20 @@ BaseType_t xReturn; xReturn = pdFALSE; } + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + return xReturn; } /*-----------------------------------------------------------*/ @@ -2420,7 +2980,7 @@ BaseType_t xReturn; /* Remove the task from the delayed list and add it to the ready list. The scheduler is suspended so interrupts will not be accessing the ready lists. */ - ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) @@ -2464,29 +3024,41 @@ BaseType_t xReturn; /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount; + #if( INCLUDE_xTaskAbortDelay == 1 ) + if( pxCurrentTCB->ucDelayAborted != pdFALSE ) + { + /* The delay was aborted, which is not the same as a time out, + but has the same result. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + xReturn = pdTRUE; + } + else + #endif + #if ( INCLUDE_vTaskSuspend == 1 ) - /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is - the maximum block time then the task should block indefinitely, and - therefore never time out. */ if( *pxTicksToWait == portMAX_DELAY ) { + /* If INCLUDE_vTaskSuspend is set to 1 and the block time + specified is the maximum block time then the task should block + indefinitely, and therefore never time out. */ xReturn = pdFALSE; } - else /* We are not blocking indefinitely, perform the checks below. */ + else #endif if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ { - /* The tick count is greater than the time at which vTaskSetTimeout() - was called, but has also overflowed since vTaskSetTimeOut() was called. - It must have wrapped all the way around and gone past us again. This - passed since vTaskSetTimeout() was called. */ + /* The tick count is greater than the time at which + vTaskSetTimeout() was called, but has also overflowed since + vTaskSetTimeOut() was called. It must have wrapped all the way + around and gone past again. This passed since vTaskSetTimeout() + was called. */ xReturn = pdTRUE; } - else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait ) + else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ { /* Not a genuine timeout. Adjust parameters for time remaining. */ - *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); + *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); vTaskSetTimeOutState( pxTimeOut ); xReturn = pdFALSE; } @@ -2561,9 +3133,13 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) /* Stop warnings. */ ( void ) pvParameters; + /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE + SCHEDULER IS STARTED. **/ + for( ;; ) { - /* See if any tasks have been deleted. */ + /* See if any tasks have deleted themselves - if so then the idle task + is responsible for freeing the deleted task's TCB and stack. */ prvCheckTasksWaitingTermination(); #if ( configUSE_PREEMPTION == 0 ) @@ -2659,10 +3235,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) } /*-----------------------------------------------------------*/ -#if configUSE_TICKLESS_IDLE != 0 +#if( configUSE_TICKLESS_IDLE != 0 ) eSleepModeStatus eTaskConfirmSleepModeStatus( void ) { + /* The idle task exists in addition to the application tasks. */ + const UBaseType_t uxNonApplicationTasks = 1; eSleepModeStatus eReturn = eStandardSleep; if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) @@ -2677,124 +3255,63 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) } else { - #if configUSE_TIMERS == 0 + /* If all the tasks are in the suspended list (which might mean they + have an infinite block time rather than actually being suspended) + then it is safe to turn all clocks off and just wait for external + interrupts. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) { - /* The idle task exists in addition to the application tasks. */ - const UBaseType_t uxNonApplicationTasks = 1; - - /* If timers are not being used and all the tasks are in the - suspended list (which might mean they have an infinite block - time rather than actually being suspended) then it is safe to - turn all clocks off and just wait for external interrupts. */ - if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) - { - eReturn = eNoTasksWaitingTimeout; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + eReturn = eNoTasksWaitingTimeout; + } + else + { + mtCOVERAGE_TEST_MARKER(); } - #endif /* configUSE_TIMERS */ } return eReturn; } + #endif /* configUSE_TICKLESS_IDLE */ /*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) -static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ -{ -UBaseType_t x; - /* Store the task name in the TCB. */ - for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) { - pxTCB->pcTaskName[ x ] = pcName[ x ]; + TCB_t *pxTCB; - /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than - configMAX_TASK_NAME_LEN characters just in case the memory after the - string is not accessible (extremely unlikely). */ - if( pcName[ x ] == 0x00 ) + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) { - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); + pxTCB = prvGetTCBFromHandle( xTaskToSet ); + pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; } } - /* Ensure the name string is terminated in the case that the string length - was greater or equal to configMAX_TASK_NAME_LEN. */ - pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; - - /* This is used as an array index so must ensure it's not too large. First - remove the privilege bit if one is present. */ - if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) - { - uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - pxTCB->uxPriority = uxPriority; - #if ( configUSE_MUTEXES == 1 ) - { - pxTCB->uxBasePriority = uxPriority; - pxTCB->uxMutexesHeld = 0; - } - #endif /* configUSE_MUTEXES */ - - vListInitialiseItem( &( pxTCB->xGenericListItem ) ); - vListInitialiseItem( &( pxTCB->xEventListItem ) ); - - /* Set the pxTCB as a link back from the ListItem_t. This is so we can get - back to the containing TCB from a generic item in a list. */ - listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); - - /* Event lists are always in priority order. */ - listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ - #if ( portCRITICAL_NESTING_IN_TCB == 1 ) - { - pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U; - } - #endif /* portCRITICAL_NESTING_IN_TCB */ +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) - #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) { - pxTCB->pxTaskTag = NULL; - } - #endif /* configUSE_APPLICATION_TASK_TAG */ + void *pvReturn = NULL; + TCB_t *pxTCB; - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - { - pxTCB->ulRunTimeCounter = 0UL; - } - #endif /* configGENERATE_RUN_TIME_STATS */ + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ]; + } + else + { + pvReturn = NULL; + } - #if ( portUSING_MPU_WRAPPERS == 1 ) - { - vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); - } - #else /* portUSING_MPU_WRAPPERS */ - { - ( void ) xRegions; - ( void ) usStackDepth; + return pvReturn; } - #endif /* portUSING_MPU_WRAPPERS */ - #if ( configUSE_NEWLIB_REENTRANT == 1 ) - { - /* Initialise this task's Newlib reent structure. */ - _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); - } - #endif /* configUSE_NEWLIB_REENTRANT */ -} +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ /*-----------------------------------------------------------*/ #if ( portUSING_MPU_WRAPPERS == 1 ) @@ -2803,15 +3320,16 @@ UBaseType_t x; { TCB_t *pxTCB; - /* If null is passed in here then we are deleting ourselves. */ + /* If null is passed in here then we are modifying the MPU settings of + the calling task. */ pxTCB = prvGetTCBFromHandle( xTaskToModify ); - vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); + vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); } #endif /* portUSING_MPU_WRAPPERS */ /*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) + static void prvInitialiseTaskLists( void ) { UBaseType_t uxPriority; @@ -2846,13 +3364,16 @@ UBaseType_t uxPriority; static void prvCheckTasksWaitingTermination( void ) { + + /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ + #if ( INCLUDE_vTaskDelete == 1 ) { BaseType_t xListIsEmpty; /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called too often in the idle task. */ - while( uxTasksDeleted > ( UBaseType_t ) 0U ) + while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ) { vTaskSuspendAll(); { @@ -2867,9 +3388,9 @@ static void prvCheckTasksWaitingTermination( void ) taskENTER_CRITICAL(); { pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); - ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); --uxCurrentNumberOfTasks; - --uxTasksDeleted; + --uxDeletedTasksWaitingCleanUp; } taskEXIT_CRITICAL(); @@ -2881,80 +3402,102 @@ static void prvCheckTasksWaitingTermination( void ) } } } - #endif /* vTaskDelete */ + #endif /* INCLUDE_vTaskDelete */ } /*-----------------------------------------------------------*/ -static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) -{ - /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); +#if( configUSE_TRACE_FACILITY == 1 ) - if( xTimeToWake < xTickCount ) + void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) { - /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so the current block list is used. */ - vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + TCB_t *pxTCB; + + /* xTask is NULL then get the state of the calling task. */ + pxTCB = prvGetTCBFromHandle( xTask ); - /* If the task entering the blocked state was placed at the head of the - list of blocked tasks then xNextTaskUnblockTime needs to be updated - too. */ - if( xTimeToWake < xNextTaskUnblockTime ) + pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB; + pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] ); + pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; + pxTaskStatus->pxStackBase = pxTCB->pxStack; + pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + + #if ( INCLUDE_vTaskSuspend == 1 ) { - xNextTaskUnblockTime = xTimeToWake; + /* If the task is in the suspended list then there is a chance it is + actually just blocked indefinitely - so really it should be reported as + being in the Blocked state. */ + if( pxTaskStatus->eCurrentState == eSuspended ) + { + vTaskSuspendAll(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatus->eCurrentState = eBlocked; + } + } + xTaskResumeAll(); + } } - else + #endif /* INCLUDE_vTaskSuspend */ + + #if ( configUSE_MUTEXES == 1 ) { - mtCOVERAGE_TEST_MARKER(); + pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; } - } -} -/*-----------------------------------------------------------*/ -__attribute__ ((section (".boot"))) -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) -{ -TCB_t *pxNewTCB; - - /* Allocate space for the TCB. Where the memory comes from depends on - the implementation of the port malloc function. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + #else + { + pxTaskStatus->uxBasePriority = 0; + } + #endif - if( pxNewTCB != NULL ) - { - /* Allocate space for the stack used by the task being created. - The base of the stack memory stored in the TCB so the task can - be deleted later if required. */ - pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; + } + #else + { + pxTaskStatus->ulRunTimeCounter = 0; + } + #endif - if( pxNewTCB->pxStack == NULL ) + /* Obtaining the task state is a little fiddly, so is only done if the value + of eState passed into this function is eInvalid - otherwise the state is + just set to whatever is passed in. */ + if( eState != eInvalid ) { - /* Could not allocate the stack. Delete the allocated TCB. */ - vPortFree( pxNewTCB ); - pxNewTCB = NULL; + pxTaskStatus->eCurrentState = eState; } else { - /* Avoid dependency on memset() if it is not required. */ - #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + pxTaskStatus->eCurrentState = eTaskGetState( xTask ); + } + + /* Obtaining the stack space takes some time, so the xGetFreeStackSpace + parameter is provided to allow it to be skipped. */ + if( xGetFreeStackSpace != pdFALSE ) + { + #if ( portSTACK_GROWTH > 0 ) + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack ); + } + #else { - /* Just to help debugging. */ - ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) ); + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ); } - #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + #endif + } + else + { + pxTaskStatus->usStackHighWaterMark = 0; } } - return pxNewTCB; -} +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) - static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) { volatile TCB_t *pxNextTCB, *pxFirstTCB; UBaseType_t uxTask = 0; @@ -2970,60 +3513,8 @@ TCB_t *pxNewTCB; do { listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); - - pxTaskStatusArray[ uxTask ].xHandle = ( TaskHandle_t ) pxNextTCB; - pxTaskStatusArray[ uxTask ].pcTaskName = ( const char * ) &( pxNextTCB->pcTaskName [ 0 ] ); - pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber; - pxTaskStatusArray[ uxTask ].eCurrentState = eState; - pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority; - - #if ( INCLUDE_vTaskSuspend == 1 ) - { - /* If the task is in the suspended list then there is a chance - it is actually just blocked indefinitely - so really it should - be reported as being in the Blocked state. */ - if( eState == eSuspended ) - { - if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL ) - { - pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked; - } - } - } - #endif /* INCLUDE_vTaskSuspend */ - - #if ( configUSE_MUTEXES == 1 ) - { - pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority; - } - #else - { - pxTaskStatusArray[ uxTask ].uxBasePriority = 0; - } - #endif - - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - { - pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter; - } - #else - { - pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0; - } - #endif - - #if ( portSTACK_GROWTH > 0 ) - { - pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxEndOfStack ); - } - #else - { - pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxStack ); - } - #endif - + vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); uxTask++; - } while( pxNextTCB != pxFirstTCB ); } else @@ -3101,8 +3592,41 @@ TCB_t *pxNewTCB; _reclaim_reent( &( pxTCB->xNewLib_reent ) ); } #endif /* configUSE_NEWLIB_REENTRANT */ - vPortFreeAligned( pxTCB->pxStack ); - vPortFree( pxTCB ); + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) ) + { + /* The task can only have been allocated dynamically - free both + the stack and TCB. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) + { + /* The task could have been allocated statically or dynamically, so + check what was statically allocated before trying to free the + memory. */ + if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ) + { + /* Both the stack and TCB were allocated dynamically, so both + must be freed. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ) + { + /* Only the stack was statically allocated, so the TCB is the + only memory that must be freed. */ + vPortFree( pxTCB ); + } + else + { + /* Neither the stack nor the TCB were allocated dynamically, so + nothing needs to be freed. */ + configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ } #endif /* INCLUDE_vTaskDelete */ @@ -3114,9 +3638,8 @@ TCB_t *pxTCB; if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { - /* The new current delayed list is empty. Set - xNextTaskUnblockTime to the maximum possible value so it is - extremely unlikely that the + /* The new current delayed list is empty. Set xNextTaskUnblockTime to + the maximum possible value so it is extremely unlikely that the if( xTickCount >= xNextTaskUnblockTime ) test will pass until there is an item in the delayed list. */ xNextTaskUnblockTime = portMAX_DELAY; @@ -3128,7 +3651,7 @@ TCB_t *pxTCB; which the task at the head of the delayed list should be removed from the Blocked state. */ ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); - xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xGenericListItem ) ); + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) ); } } /*-----------------------------------------------------------*/ @@ -3188,6 +3711,9 @@ TCB_t *pxTCB; locked then the mutex holder might now be NULL. */ if( pxMutexHolder != NULL ) { + /* If the holder of the mutex has a priority below the priority of + the task attempting to obtain the mutex then it will temporarily + inherit the priority of the task attempting to obtain the mutex. */ if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) { /* Adjust the mutex holder state to account for its new @@ -3202,11 +3728,11 @@ TCB_t *pxTCB; mtCOVERAGE_TEST_MARKER(); } - /* If the task being modified is in the ready state it will need to - be moved into a new list. */ - if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) + /* If the task being modified is in the ready state it will need + to be moved into a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) { - if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } @@ -3250,17 +3776,28 @@ TCB_t *pxTCB; if( pxMutexHolder != NULL ) { + /* A task can only have an inherited priority if it holds the mutex. + If the mutex is held by a task then it cannot be given from an + interrupt, and if a mutex is given by the holding task then it must + be the running state task. */ + configASSERT( pxTCB == pxCurrentTCB ); + configASSERT( pxTCB->uxMutexesHeld ); ( pxTCB->uxMutexesHeld )--; + /* Has the holder of the mutex inherited the priority of another + task? */ if( pxTCB->uxPriority != pxTCB->uxBasePriority ) { /* Only disinherit if no other mutexes are held. */ if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) { - /* The holding task must be the running task to be able to give - the mutex back. Remove the holding task from the ready list. */ - if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + /* A task can only have an inherited priority if it holds + the mutex. If the mutex is held by a task then it cannot be + given from an interrupt, and if a mutex is given by the + holding task then it must be the running state task. Remove + the holding task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { taskRESET_READY_PRIORITY( pxTCB->uxPriority ); } @@ -3269,8 +3806,8 @@ TCB_t *pxTCB; mtCOVERAGE_TEST_MARKER(); } - /* Disinherit the priority before adding the task into the new - ready list. */ + /* Disinherit the priority before adding the task into the + new ready list. */ traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); pxTCB->uxPriority = pxTCB->uxBasePriority; @@ -3283,7 +3820,11 @@ TCB_t *pxTCB; /* Return true to indicate that a context switch is required. This is only actually required in the corner case whereby multiple mutexes were held and the mutexes were given back - in an order different to that in which they were taken. */ + in an order different to that in which they were taken. + If a context switch did not occur when the first mutex was + returned, even if a task was waiting on it, then a context + switch should occur when the last mutex is returned whether + a task is waiting on it or not. */ xReturn = pdTRUE; } else @@ -3327,7 +3868,6 @@ TCB_t *pxTCB; { portASSERT_IF_IN_ISR(); } - } else { @@ -3371,7 +3911,33 @@ TCB_t *pxTCB; #endif /* portCRITICAL_NESTING_IN_TCB */ /*-----------------------------------------------------------*/ -#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) + { + size_t x; + + /* Start by copying the entire string. */ + strcpy( pcBuffer, pcTaskName ); + + /* Pad the end of the string with spaces to ensure columns line up when + printed out. */ + for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ ) + { + pcBuffer[ x ] = ' '; + } + + /* Terminate. */ + pcBuffer[ x ] = 0x00; + + /* Return the new end of string. */ + return &( pcBuffer[ x ] ); + } + +#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) void vTaskList( char * pcWriteBuffer ) { @@ -3411,7 +3977,9 @@ TCB_t *pxTCB; function is executing. */ uxArraySize = uxCurrentNumberOfTasks; - /* Allocate an array index for each task. */ + /* Allocate an array index for each task. NOTE! if + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) @@ -3424,29 +3992,35 @@ TCB_t *pxTCB; { switch( pxTaskStatusArray[ x ].eCurrentState ) { - case eReady: cStatus = tskREADY_CHAR; - break; + case eReady: cStatus = tskREADY_CHAR; + break; - case eBlocked: cStatus = tskBLOCKED_CHAR; - break; + case eBlocked: cStatus = tskBLOCKED_CHAR; + break; - case eSuspended: cStatus = tskSUSPENDED_CHAR; - break; + case eSuspended: cStatus = tskSUSPENDED_CHAR; + break; - case eDeleted: cStatus = tskDELETED_CHAR; - break; + case eDeleted: cStatus = tskDELETED_CHAR; + break; - default: /* Should not get here, but it is included - to prevent static checking errors. */ - cStatus = 0x00; - break; + default: /* Should not get here, but it is included + to prevent static checking errors. */ + cStatus = 0x00; + break; } - sprintf( pcWriteBuffer, "%s\t\t%c\t%u\t%u\t%u\r\n", pxTaskStatusArray[ x ].pcTaskName, cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + /* Write the task name to the string, padding with spaces so it + can be printed in tabular form more easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + /* Write the rest of the string. */ + sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); pcWriteBuffer += strlen( pcWriteBuffer ); } - /* Free the array again. */ + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ vPortFree( pxTaskStatusArray ); } else @@ -3455,10 +4029,10 @@ TCB_t *pxTCB; } } -#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) */ +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ /*----------------------------------------------------------*/ -#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) +#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) void vTaskGetRunTimeStats( char *pcWriteBuffer ) { @@ -3504,7 +4078,9 @@ TCB_t *pxTCB; function is executing. */ uxArraySize = uxCurrentNumberOfTasks; - /* Allocate an array index for each task. */ + /* Allocate an array index for each task. NOTE! If + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); if( pxTaskStatusArray != NULL ) @@ -3526,17 +4102,22 @@ TCB_t *pxTCB; ulTotalRunTimeDiv100 has already been divided by 100. */ ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; + /* Write the task name to the string, padding with + spaces so it can be printed in tabular form more + easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + if( ulStatsAsPercentage > 0UL ) { #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); } #else { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); } #endif } @@ -3546,13 +4127,13 @@ TCB_t *pxTCB; consumed less than 1% of the total run time. */ #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcWriteBuffer, "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter ); + sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); } #else { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); } #endif } @@ -3565,7 +4146,8 @@ TCB_t *pxTCB; mtCOVERAGE_TEST_MARKER(); } - /* Free the array again. */ + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ vPortFree( pxTaskStatusArray ); } else @@ -3574,7 +4156,7 @@ TCB_t *pxTCB; } } -#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) */ +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ /*-----------------------------------------------------------*/ TickType_t uxTaskResetEventItemValue( void ) @@ -3606,9 +4188,619 @@ TickType_t uxReturn; } #endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) + { + uint32_t ulReturn; + + taskENTER_CRITICAL(); + { + /* Only block if the notification count is not already non-zero. */ + if( pxCurrentTCB->ulNotifiedValue == 0UL ) + { + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_TAKE_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_TAKE(); + ulReturn = pxCurrentTCB->ulNotifiedValue; + + if( ulReturn != 0UL ) + { + if( xClearCountOnExit != pdFALSE ) + { + pxCurrentTCB->ulNotifiedValue = 0UL; + } + else + { + pxCurrentTCB->ulNotifiedValue = ulReturn - 1; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return ulReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + /* Only block if a notification is not already pending. */ + if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) + { + /* Clear bits in the task's notification value as bits may get + set by the notifying task or interrupt. This can be used to + clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; + + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_WAIT_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_WAIT(); + + if( pulNotificationValue != NULL ) + { + /* Output the current notification value, which may or may not + have changed. */ + *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; + } + + /* If ucNotifyValue is set then either the task never entered the + blocked state (because a notification was already pending) or the + task unblocked because of a notification. Otherwise the task + unblocked because of a timeout. */ + if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + { + /* A notification was not received. */ + xReturn = pdFALSE; + } + else + { + /* A notification was already pending or a notification was + received while the task was waiting. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; + xReturn = pdTRUE; + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) + { + TCB_t * pxTCB; + BaseType_t xReturn = pdPASS; + uint8_t ucOriginalNotifyState; + + configASSERT( xTaskToNotify ); + pxTCB = ( TCB_t * ) xTaskToNotify; + + taskENTER_CRITICAL(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction: + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked waiting for a notification then + xNextTaskUnblockTime might be set to the blocked task's time + out time. If the task is unblocked for a reason other than + a timeout xNextTaskUnblockTime is normally left unchanged, + because it will automatically get reset to a new value when + the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter + sleep mode at the earliest possible time - so reset + xNextTaskUnblockTime here to ensure it is updated at the + earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + BaseType_t xReturn = pdPASS; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction : + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + /* 'Giving' is equivalent to incrementing a count in a counting + semaphore. */ + ( pxTCB->ulNotifiedValue )++; + + traceTASK_NOTIFY_GIVE_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ /*-----------------------------------------------------------*/ +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + BaseType_t xReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + taskENTER_CRITICAL(); + { + if( pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED ) + { + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + + +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) +{ +TickType_t xTimeToWake; +const TickType_t xConstTickCount = xTickCount; + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + /* About to enter a delayed list, so ensure the ucDelayAborted flag is + reset to pdFALSE so it can be detected as having been set to pdTRUE + when the task leaves the Blocked state. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Remove the task from the ready list before adding it to the blocked list + as the same list item is used for both lists. */ + if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ) + { + /* Add the task to the suspended task list instead of a delayed task + list to ensure it is not woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the + kernel will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow + list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list + is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the + head of the list of blocked tasks then xNextTaskUnblockTime + needs to be updated too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the kernel + will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */ + ( void ) xCanBlockIndefinitely; + } + #endif /* INCLUDE_vTaskSuspend */ +} + + #ifdef FREERTOS_MODULE_TEST #include "tasks_test_access_functions.h" #endif diff --git a/cc3200/FreeRTOS/Source/timers.c b/cc3200/FreeRTOS/Source/timers.c index 32e89a1f07..d4a821a263 100644 --- a/cc3200/FreeRTOS/Source/timers.c +++ b/cc3200/FreeRTOS/Source/timers.c @@ -1,60 +1,64 @@ /* - FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following + FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html - 1 tab == 4 spaces! - *************************************************************************** * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * * * - * http://www.FreeRTOS.org/FAQHelp.html * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and @@ -108,6 +112,10 @@ typedef struct tmrTimerControl #if( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */ + #endif } xTIMER; /* The old xTIMER name is maintained above then typedefed to the new Timer_t @@ -163,16 +171,21 @@ PRIVILEGED_DATA static List_t *pxOverflowTimerList; /* A queue that is used to send commands to the timer service task. */ PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; +PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; -#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) +/*lint +e956 */ - PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; +/*-----------------------------------------------------------*/ -#endif +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) -/*lint +e956 */ + /* If static allocation is supported then the application must provide the + following callback function - which enables the application to optionally + provide the memory that will be used by the timer task as the task's stack + and TCB. */ + extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ); -/*-----------------------------------------------------------*/ +#endif /* * Initialise the infrastructure used by the timer service task if it has not @@ -191,7 +204,7 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; * Called by the timer service task to interpret and process a command it * received on the timer queue. */ -static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; /* * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, @@ -229,8 +242,18 @@ static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIV * If a timer has expired, process it. Otherwise, block the timer service task * until either a timer does expire or a command is received. */ -static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; +/* + * Called after a Timer_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /*-----------------------------------------------------------*/ BaseType_t xTimerCreateTimerTask( void ) @@ -245,18 +268,36 @@ BaseType_t xReturn = pdFAIL; if( xTimerQueue != NULL ) { - #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { - /* Create the timer task, storing its handle in xTimerTaskHandle so - it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */ - xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle ); + StaticTask_t *pxTimerTaskTCBBuffer = NULL; + StackType_t *pxTimerTaskStackBuffer = NULL; + uint32_t ulTimerTaskStackSize; + + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); + xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, + "Tmr Svc", + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer ); + + if( xTimerTaskHandle != NULL ) + { + xReturn = pdPASS; + } } #else { - /* Create the timer task without storing its handle. */ - xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL); + xReturn = xTaskCreate( prvTimerTask, + "Tmr Svc", + configTIMER_TASK_STACK_DEPTH, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + &xTimerTaskHandle ); } - #endif + #endif /* configSUPPORT_STATIC_ALLOCATION */ } else { @@ -268,44 +309,108 @@ BaseType_t xReturn = pdFAIL; } /*-----------------------------------------------------------*/ -TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ -{ -Timer_t *pxNewTimer; +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - /* Allocate the timer structure. */ - if( xTimerPeriodInTicks == ( TickType_t ) 0U ) - { - pxNewTimer = NULL; - } - else + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { + Timer_t *pxNewTimer; + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + if( pxNewTimer != NULL ) { - /* Ensure the infrastructure used by the timer service task has been - created/initialised. */ - prvCheckForValidListAndQueue(); - - /* Initialise the timer structure members using the function parameters. */ - pxNewTimer->pcTimerName = pcTimerName; - pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; - pxNewTimer->uxAutoReload = uxAutoReload; - pxNewTimer->pvTimerID = pvTimerID; - pxNewTimer->pxCallbackFunction = pxCallbackFunction; - vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); - - traceTIMER_CREATE( pxNewTimer ); + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically, so note this + timer was created dynamically in case the timer is later + deleted. */ + pxNewTimer->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } - else + + return pxNewTimer; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + Timer_t *pxNewTimer; + + #if( configASSERT_DEFINED == 1 ) { - traceTIMER_CREATE_FAILED(); + /* Sanity check that the size of the structure used to declare a + variable of type StaticTimer_t equals the size of the real timer + structures. */ + volatile size_t xSize = sizeof( StaticTimer_t ); + configASSERT( xSize == sizeof( Timer_t ) ); } + #endif /* configASSERT_DEFINED */ + + /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ + configASSERT( pxTimerBuffer ); + pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewTimer != NULL ) + { + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically so note this + timer was created statically in case it is later deleted. */ + pxNewTimer->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + + return pxNewTimer; } +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ /* 0 is not a valid value for xTimerPeriodInTicks. */ configASSERT( ( xTimerPeriodInTicks > 0 ) ); - return ( TimerHandle_t ) pxNewTimer; + if( pxNewTimer != NULL ) + { + /* Ensure the infrastructure used by the timer service task has been + created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function + parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->uxAutoReload = uxAutoReload; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + traceTIMER_CREATE( pxNewTimer ); + } } /*-----------------------------------------------------------*/ @@ -314,6 +419,8 @@ BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommand BaseType_t xReturn = pdFAIL; DaemonTaskMessage_t xMessage; + configASSERT( xTimer ); + /* Send a message to the timer service task to perform a particular action on a particular timer definition. */ if( xTimerQueue != NULL ) @@ -350,23 +457,40 @@ DaemonTaskMessage_t xMessage; } /*-----------------------------------------------------------*/ -#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) +{ + /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been + started, then xTimerTaskHandle will be NULL. */ + configASSERT( ( xTimerTaskHandle != NULL ) ); + return xTimerTaskHandle; +} +/*-----------------------------------------------------------*/ - TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) - { - /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been - started, then xTimerTaskHandle will be NULL. */ - configASSERT( ( xTimerTaskHandle != NULL ) ); - return xTimerTaskHandle; - } +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) +{ +Timer_t *pxTimer = ( Timer_t * ) xTimer; -#endif + configASSERT( xTimer ); + return pxTimer->xTimerPeriodInTicks; +} /*-----------------------------------------------------------*/ -const char * pcTimerGetTimerName( TimerHandle_t xTimer ) +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) +{ +Timer_t * pxTimer = ( Timer_t * ) xTimer; +TickType_t xReturn; + + configASSERT( xTimer ); + xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { Timer_t *pxTimer = ( Timer_t * ) xTimer; + configASSERT( xTimer ); return pxTimer->pcTimerName; } /*-----------------------------------------------------------*/ @@ -388,7 +512,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi /* The timer is inserted into a list using a time relative to anything other than the current time. It will therefore be inserted into the correct list relative to the time this task thinks it is now. */ - if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE ) + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) { /* The timer expired before it was added to the active timer list. Reload it now. */ @@ -419,6 +543,18 @@ BaseType_t xListWasEmpty; /* Just to avoid compiler warnings. */ ( void ) pvParameters; + #if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) + { + extern void vApplicationDaemonTaskStartupHook( void ); + + /* Allow the application writer to execute some code in the context of + this task at the point the task starts executing. This is useful if the + application includes initialisation code that would benefit from + executing after the scheduler has been started. */ + vApplicationDaemonTaskStartupHook(); + } + #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */ + for( ;; ) { /* Query the timers list to see if it contains any timers, and if so, @@ -435,7 +571,7 @@ BaseType_t xListWasEmpty; } /*-----------------------------------------------------------*/ -static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty ) +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) { TickType_t xTimeNow; BaseType_t xTimerListsWereSwitched; @@ -464,14 +600,21 @@ BaseType_t xTimerListsWereSwitched; received - whichever comes first. The following line cannot be reached unless xNextExpireTime > xTimeNow, except in the case when the current timer list is empty. */ - vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) ); + if( xListWasEmpty != pdFALSE ) + { + /* The current timer list is empty - is the overflow list + also empty? */ + xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList ); + } + + vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); if( xTaskResumeAll() == pdFALSE ) { - /* Yield to wait for either a command to arrive, or the block time - to expire. If a command arrived between the critical section being - exited and this yield then the yield will not cause the task - to block. */ + /* Yield to wait for either a command to arrive, or the + block time to expire. If a command arrived between the + critical section being exited and this yield then the yield + will not cause the task to block. */ portYIELD_WITHIN_API(); } else @@ -548,7 +691,7 @@ BaseType_t xProcessTimerNow = pdFALSE; { /* Has the expiry time elapsed between the command to start/reset a timer was issued, and the time the command was processed? */ - if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks ) + if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ { /* The time between a command being issued and the command being processed actually exceeds the timers period. */ @@ -645,7 +788,7 @@ TickType_t xTimeNow; case tmrCOMMAND_RESET_FROM_ISR : case tmrCOMMAND_START_DONT_TRACE : /* Start or restart a timer. */ - if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE ) + if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) { /* The timer expired before it was added to the active timer list. Process it now. */ @@ -680,19 +823,40 @@ TickType_t xTimeNow; pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); - /* The new period does not really have a reference, and can be - longer or shorter than the old one. The command time is - therefore set to the current time, and as the period cannot be - zero the next expiry time can only be in the future, meaning - (unlike for the xTimerStart() case above) there is no fail case - that needs to be handled here. */ + /* The new period does not really have a reference, and can + be longer or shorter than the old one. The command time is + therefore set to the current time, and as the period cannot + be zero the next expiry time can only be in the future, + meaning (unlike for the xTimerStart() case above) there is + no fail case that needs to be handled here. */ ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); break; case tmrCOMMAND_DELETE : /* The timer has already been removed from the active list, - just free up the memory. */ - vPortFree( pxTimer ); + just free up the memory if the memory was dynamically + allocated. */ + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The timer can only have been allocated dynamically - + free it again. */ + vPortFree( pxTimer ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The timer could have been allocated statically or + dynamically, so check before attempting to free the + memory. */ + if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxTimer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ break; default : @@ -776,8 +940,21 @@ static void prvCheckForValidListAndQueue( void ) vListInitialise( &xActiveTimerList2 ); pxCurrentTimerList = &xActiveTimerList1; pxOverflowTimerList = &xActiveTimerList2; - xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); - configASSERT( xTimerQueue ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* The timer queue is allocated statically in case + configSUPPORT_DYNAMIC_ALLOCATION is 0. */ + static StaticQueue_t xStaticTimerQueue; + static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; + + xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); + } + #else + { + xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); + } + #endif #if ( configQUEUE_REGISTRY_SIZE > 0 ) { @@ -806,6 +983,8 @@ BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) BaseType_t xTimerIsInActiveList; Timer_t *pxTimer = ( Timer_t * ) xTimer; + configASSERT( xTimer ); + /* Is the timer in the list of active timers? */ taskENTER_CRITICAL(); { @@ -823,8 +1002,31 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer; void *pvTimerGetTimerID( const TimerHandle_t xTimer ) { Timer_t * const pxTimer = ( Timer_t * ) xTimer; +void *pvReturn; + + configASSERT( xTimer ); + + taskENTER_CRITICAL(); + { + pvReturn = pxTimer->pvTimerID; + } + taskEXIT_CRITICAL(); + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) +{ +Timer_t * const pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); - return pxTimer->pvTimerID; + taskENTER_CRITICAL(); + { + pxTimer->pvTimerID = pvNewID; + } + taskEXIT_CRITICAL(); } /*-----------------------------------------------------------*/ @@ -843,7 +1045,7 @@ Timer_t * const pxTimer = ( Timer_t * ) xTimer; xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); - + tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); return xReturn; @@ -859,6 +1061,11 @@ Timer_t * const pxTimer = ( Timer_t * ) xTimer; DaemonTaskMessage_t xMessage; BaseType_t xReturn; + /* This function can only be called after a timer has been created or + after the scheduler has been started because, until then, the timer + queue does not exist. */ + configASSERT( xTimerQueue ); + /* Complete the message with the function parameters and post it to the daemon task. */ xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; @@ -869,7 +1076,7 @@ Timer_t * const pxTimer = ( Timer_t * ) xTimer; xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); - + return xReturn; } diff --git a/cc3200/application.mk b/cc3200/application.mk index b862212a54..dca6fcbc65 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -142,6 +142,7 @@ APP_UTIL_SRC_S = $(addprefix util/,\ APP_MAIN_SRC_C = \ main.c \ mptask.c \ + mpthreadport.c \ serverstask.c APP_LIB_SRC_C = $(addprefix lib/,\ diff --git a/cc3200/hal/cc3200_hal.c b/cc3200/hal/cc3200_hal.c index f0987ae9d2..f4d38d120e 100644 --- a/cc3200/hal/cc3200_hal.c +++ b/cc3200/hal/cc3200_hal.c @@ -111,6 +111,7 @@ mp_uint_t mp_hal_ticks_ms(void) { void mp_hal_delay_ms(mp_uint_t delay) { // only if we are not within interrupt context and interrupts are enabled if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + MP_THREAD_GIL_EXIT(); #ifdef USE_FREERTOS vTaskDelay (delay / portTICK_PERIOD_MS); #else @@ -121,6 +122,7 @@ void mp_hal_delay_ms(mp_uint_t delay) { __WFI(); } #endif + MP_THREAD_GIL_ENTER(); } else { for (int ms = 0; ms < delay; ms++) { UtilsDelay(UTILS_DELAY_US_TO_COUNT(1000)); diff --git a/cc3200/main.c b/cc3200/main.c index 78b4e3161c..06b3604b67 100644 --- a/cc3200/main.c +++ b/cc3200/main.c @@ -36,6 +36,7 @@ #include "debug.h" #include "antenna.h" #include "mperror.h" +#include "task.h" /****************************************************************************** DECLARE PRIVATE CONSTANTS @@ -49,6 +50,10 @@ DECLARE PRIVATE DATA ******************************************************************************/ +// This is the static memory (TCB and stack) for the idle task +static StaticTask_t xIdleTaskTCB __attribute__ ((section (".rtos_heap"))); +static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ @@ -56,6 +61,13 @@ OsiTaskHandle mpTaskHandle; #endif +// This is the FreeRTOS heap, defined here so we can put it in a special segment +uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +// This is the static memory (TCB and stack) for the main MicroPython task +StaticTask_t mpTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t mpTaskStack[MICROPY_TASK_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + /****************************************************************************** DEFINE PUBLIC FUNCTIONS ******************************************************************************/ @@ -74,15 +86,12 @@ int main (void) { // Init the watchdog pybwdt_init0(); -#ifdef DEBUG - ASSERT (OSI_OK == osi_TaskCreate(TASK_Micropython, - (const signed char *)"MicroPy", - MICROPY_TASK_STACK_SIZE, NULL, MICROPY_TASK_PRIORITY, &mpTaskHandle)); -#else - ASSERT (OSI_OK == osi_TaskCreate(TASK_Micropython, - (const signed char *)"MicroPy", - MICROPY_TASK_STACK_SIZE, NULL, MICROPY_TASK_PRIORITY, NULL)); +#ifndef DEBUG + OsiTaskHandle mpTaskHandle; #endif + mpTaskHandle = xTaskCreateStatic(TASK_Micropython, "MicroPy", + MICROPY_TASK_STACK_LEN, NULL, MICROPY_TASK_PRIORITY, mpTaskStack, &mpTaskTCB); + ASSERT(mpTaskHandle != NULL); osi_start(); @@ -95,3 +104,12 @@ void stoupper (char *str) { str++; } } + +// We need this when configSUPPORT_STATIC_ALLOCATION is enabled +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize ) { + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} diff --git a/cc3200/misc/mperror.c b/cc3200/misc/mperror.c index 5561b03056..81b853b482 100644 --- a/cc3200/misc/mperror.c +++ b/cc3200/misc/mperror.c @@ -63,10 +63,6 @@ /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ -#ifndef BOOTLOADER -STATIC const mp_obj_base_t pyb_heartbeat_obj = {&pyb_heartbeat_type}; -#endif - struct mperror_heart_beat { uint32_t off_time; uint32_t on_time; diff --git a/cc3200/misc/mperror.h b/cc3200/misc/mperror.h index 44c77909c3..e38d129db0 100644 --- a/cc3200/misc/mperror.h +++ b/cc3200/misc/mperror.h @@ -28,10 +28,6 @@ #ifndef MPERROR_H_ #define MPERROR_H_ -#ifndef BOOTLOADER -extern const mp_obj_type_t pyb_heartbeat_type; -#endif - extern void NORETURN __fatal_error(const char *msg); void mperror_init0 (void); diff --git a/cc3200/mods/modusocket.c b/cc3200/mods/modusocket.c index 43b7a840a8..360d034875 100644 --- a/cc3200/mods/modusocket.c +++ b/cc3200/mods/modusocket.c @@ -486,7 +486,7 @@ STATIC const mp_obj_type_t socket_type = { { &mp_type_type }, .name = MP_QSTR_socket, .make_new = socket_make_new, - .stream_p = &socket_stream_p, + .protocol = &socket_stream_p, .locals_dict = (mp_obj_t)&socket_locals_dict, }; diff --git a/cc3200/mods/modussl.c b/cc3200/mods/modussl.c index 410588dd25..8342306bf7 100644 --- a/cc3200/mods/modussl.c +++ b/cc3200/mods/modussl.c @@ -67,7 +67,7 @@ STATIC const mp_obj_type_t ssl_socket_type = { .name = MP_QSTR_ussl, .getiter = NULL, .iternext = NULL, - .stream_p = &socket_stream_p, + .protocol = &socket_stream_p, .locals_dict = (mp_obj_t)&socket_locals_dict, }; diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index 87d89f02fb..e7b5255bdf 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -669,6 +669,6 @@ const mp_obj_type_t pyb_uart_type = { .make_new = pyb_uart_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &uart_stream_p, + .protocol = &uart_stream_p, .locals_dict = (mp_obj_t)&pyb_uart_locals_dict, }; diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index d3aacc082f..fbf227b86e 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -102,6 +102,8 @@ #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (1) #define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (1) #define MICROPY_PY_UBINASCII (0) #define MICROPY_PY_UCTYPES (0) #define MICROPY_PY_UZLIB (0) diff --git a/cc3200/mptask.c b/cc3200/mptask.c index f8f33c2959..eb673b08cf 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -28,6 +28,7 @@ #include <stdint.h> #include "py/mpconfig.h" +#include "py/stackctrl.h" #include "py/obj.h" #include "py/runtime.h" #include "py/gc.h" @@ -69,6 +70,7 @@ #include "updater.h" #include "moduos.h" #include "antenna.h" +#include "task.h" /****************************************************************************** DECLARE PRIVATE CONSTANTS @@ -103,9 +105,8 @@ static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" ******************************************************************************/ void TASK_Micropython (void *pvParameters) { - // initialize the garbage collector with the top of our stack + // get the top of the stack to initialize the garbage collector uint32_t sp = gc_helper_get_sp(); - gc_collect_init (sp); bool safeboot = false; mptask_pre_init(); @@ -116,6 +117,14 @@ void TASK_Micropython (void *pvParameters) { soft_reset: + // Thread init + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif + + // initialise the stack pointer for the main thread (must be done after mp_thread_init) + mp_stack_set_top((void*)sp); + // GC init gc_init(&_boot, &_eheap); @@ -272,15 +281,12 @@ STATIC void mptask_pre_init (void) { //CRYPTOHASH_Init(); -#ifdef DEBUG - ASSERT (OSI_OK == osi_TaskCreate(TASK_Servers, - (const signed char *)"Servers", - SERVERS_STACK_SIZE, NULL, SERVERS_PRIORITY, &svTaskHandle)); -#else - ASSERT (OSI_OK == osi_TaskCreate(TASK_Servers, - (const signed char *)"Servers", - SERVERS_STACK_SIZE, NULL, SERVERS_PRIORITY, NULL)); +#ifndef DEBUG + OsiTaskHandle svTaskHandle; #endif + svTaskHandle = xTaskCreateStatic(TASK_Servers, "Servers", + SERVERS_STACK_LEN, NULL, SERVERS_PRIORITY, svTaskStack, &svTaskTCB); + ASSERT(svTaskHandle != NULL); } STATIC void mptask_init_sflash_filesystem (void) { diff --git a/cc3200/mptask.h b/cc3200/mptask.h index 6ac419b9d6..e0d2f0eec1 100644 --- a/cc3200/mptask.h +++ b/cc3200/mptask.h @@ -31,7 +31,13 @@ DEFINE CONSTANTS ******************************************************************************/ #define MICROPY_TASK_PRIORITY (2) -#define MICROPY_TASK_STACK_SIZE ((6 * 1024) + 512) +#define MICROPY_TASK_STACK_SIZE ((6 * 1024) + 512) // in bytes +#define MICROPY_TASK_STACK_LEN (MICROPY_TASK_STACK_SIZE / sizeof(StackType_t)) + +/****************************************************************************** + EXPORTED DATA + ******************************************************************************/ +extern StackType_t mpTaskStack[]; /****************************************************************************** DECLARE PUBLIC FUNCTIONS diff --git a/cc3200/mpthreadport.c b/cc3200/mpthreadport.c new file mode 100644 index 0000000000..064aa6ba10 --- /dev/null +++ b/cc3200/mpthreadport.c @@ -0,0 +1,178 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "mptask.h" +#include "task.h" + +#if MICROPY_PY_THREAD + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + size_t stack_len; // number of words in the stack + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled bp mp_thread_gc_others + +void mp_thread_init(void) { + mp_thread_mutex_init(&thread_mutex); + mp_thread_set_state(&mp_state_ctx.thread); + + // create first entry in linked list of all threads + thread = &thread_entry0; + thread->id = xTaskGetCurrentTaskHandle(); + thread->ready = 1; + thread->arg = NULL; + thread->stack = mpTaskStack; + thread->stack_len = MICROPY_TASK_STACK_LEN; + thread->next = NULL; +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); // probably not needed + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); // probably not needed + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 0); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 0, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;) { + } +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (*stack_size == 0) { + *stack_size = 4096; // default stack size + } else if (*stack_size < 2048) { + *stack_size = 2048; // minimum stack size + } + + // allocate TCB, stack and linked-list node (must be outside thread_mutex lock) + StaticTask_t *tcb = m_new(StaticTask_t, 1); + StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t)); + thread_t *th = m_new_obj(thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", *stack_size / sizeof(void*), arg, 2, stack, tcb); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + } + + // add thread to linked list of all threads + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->stack_len = *stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); + + // adjust stack_size to provide room to recover from hitting the limit + *stack_size -= 512; +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + // TODO unlink from list + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); + return ret == pdTRUE; +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + xSemaphoreGive(mutex->handle); + // TODO check return value +} + +#endif // MICROPY_PY_THREAD diff --git a/cc3200/mpthreadport.h b/cc3200/mpthreadport.h new file mode 100644 index 0000000000..2b49232ddf --- /dev/null +++ b/cc3200/mpthreadport.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __MICROPY_INCLUDED_CC3200_MPTHREADPORT_H__ +#define __MICROPY_INCLUDED_CC3200_MPTHREADPORT_H__ + +#ifndef BOOTLOADER +#include "FreeRTOS.h" +#endif + +typedef struct _mp_thread_mutex_t { + #ifndef BOOTLOADER + SemaphoreHandle_t handle; + StaticSemaphore_t buffer; + #endif +} mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); + +#endif // __MICROPY_INCLUDED_CC3200_MPTHREADPORT_H__ diff --git a/cc3200/serverstask.c b/cc3200/serverstask.c index 82c43bf8e0..1305afda0b 100644 --- a/cc3200/serverstask.c +++ b/cc3200/serverstask.c @@ -67,6 +67,11 @@ static volatile bool sleep_sockets = false; /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ + +// This is the static memory (TCB and stack) for the servers task +StaticTask_t svTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t svTaskStack[SERVERS_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + char servers_user[SERVERS_USER_PASS_LEN_MAX + 1]; char servers_pass[SERVERS_USER_PASS_LEN_MAX + 1]; diff --git a/cc3200/serverstask.h b/cc3200/serverstask.h index 7689cf461b..2786ff6976 100644 --- a/cc3200/serverstask.h +++ b/cc3200/serverstask.h @@ -31,7 +31,8 @@ DEFINE CONSTANTS ******************************************************************************/ #define SERVERS_PRIORITY 2 -#define SERVERS_STACK_SIZE 1024 +#define SERVERS_STACK_SIZE 1024 // in bytes +#define SERVERS_STACK_LEN (SERVERS_STACK_SIZE / sizeof(StackType_t)) #define SERVERS_SSID_LEN_MAX 16 #define SERVERS_KEY_LEN_MAX 16 @@ -52,6 +53,8 @@ /****************************************************************************** EXPORTED DATA ******************************************************************************/ +extern StaticTask_t svTaskTCB; +extern StackType_t svTaskStack[]; extern char servers_user[]; extern char servers_pass[]; diff --git a/cc3200/simplelink/oslib/osi_freertos.c b/cc3200/simplelink/oslib/osi_freertos.c index 80d92dc4dd..53822add73 100644 --- a/cc3200/simplelink/oslib/osi_freertos.c +++ b/cc3200/simplelink/oslib/osi_freertos.c @@ -61,6 +61,10 @@ TaskHandle_t xSimpleLinkSpawnTaskHndl = NULL; #define slQUEUE_SIZE ( 3 ) #define SL_SPAWN_MAX_WAIT_MS ( 200 ) +// This is the static memory (TCB and stack) for the SL spawn task +static StaticTask_t spawnTaskTCB __attribute__ ((section (".rtos_heap"))); +static portSTACK_TYPE spawnTaskStack[896 / sizeof(portSTACK_TYPE)] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + /*! \brief This function registers an interrupt in NVIC table @@ -273,7 +277,6 @@ OsiReturnVal_e osi_LockObjCreate(OsiLockObj_t* pLockObj) \note \warning */ -__attribute__ ((section (".boot"))) OsiReturnVal_e osi_TaskCreate(P_OSI_TASK_ENTRY pEntry,const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned long uxPriority,OsiTaskHandle* pTaskHandle) @@ -454,8 +457,19 @@ OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned portBASE_TYPE uxPriority) xSimpleLinkSpawnQueue = xQueueCreate( slQUEUE_SIZE, sizeof( tSimpleLinkSpawnMsg ) ); ASSERT (xSimpleLinkSpawnQueue != NULL); + /* + // This is the original code to create a task dynamically ASSERT (pdPASS == xTaskCreate( vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN",\ 896 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl )); + */ + + // This code creates the task using static memory for the TCB and stack + xSimpleLinkSpawnTaskHndl = xTaskCreateStatic( + vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN", + 896 / sizeof(portSTACK_TYPE), NULL, uxPriority, + spawnTaskStack, &spawnTaskTCB); + + ASSERT(xSimpleLinkSpawnTaskHndl != NULL); return OSI_OK; } diff --git a/cc3200/util/gccollect.c b/cc3200/util/gccollect.c index 094ca73bc6..8963852f7a 100644 --- a/cc3200/util/gccollect.c +++ b/cc3200/util/gccollect.c @@ -29,22 +29,15 @@ #include <stdint.h> #include "py/mpconfig.h" +#include "py/mpstate.h" #include "py/gc.h" +#include "py/mpthread.h" #include "gccollect.h" #include "gchelper.h" /****************************************************************************** -DECLARE PRIVATE DATA - ******************************************************************************/ -static uint32_t stackend; - - -/****************************************************************************** DECLARE PUBLIC FUNCTIONS ******************************************************************************/ -void gc_collect_init (uint32_t sp) { - stackend = sp; -} void gc_collect(void) { // start the GC @@ -55,7 +48,12 @@ void gc_collect(void) { mp_uint_t sp = gc_helper_get_regs_and_sp(regs); // trace the stack, including the registers (since they live on the stack in this function) - gc_collect_root((void**)sp, (stackend - sp) / sizeof(uint32_t)); + gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif // end the GC gc_collect_end(); diff --git a/cc3200/util/gccollect.h b/cc3200/util/gccollect.h index 24cd60288e..281e84aa83 100644 --- a/cc3200/util/gccollect.h +++ b/cc3200/util/gccollect.h @@ -38,5 +38,4 @@ extern uint32_t _eheap; extern uint32_t _stack; extern uint32_t _estack; -void gc_collect_init (uint32_t sp); void gc_collect(void); diff --git a/docs/Makefile b/docs/Makefile index 9756fab286..d81d11eeb2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -6,6 +6,9 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build/$(MICROPY_PORT) +# Run "make FORCE= ..." to avoid rebuilding from scratch (and risk +# producing incorrect docs). +FORCE = -E # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) @@ -50,7 +53,7 @@ clean: rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) $(FORCE) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." @@ -111,7 +114,7 @@ latex: "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + $(SPHINXBUILD) $(FORCE) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." diff --git a/docs/conf.py b/docs/conf.py index 6faeb60406..ba69cf7f7a 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,7 +19,7 @@ import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('.')) # Work out the port to generate the docs for from collections import OrderedDict @@ -48,6 +48,9 @@ html_context = { (ver, url_pattern % (ver, micropy_port)) for ver in micropy_all_versions ], + 'downloads':[ + ('PDF', url_pattern % (micropy_version, 'micropython-%s.pdf' % micropy_port)), + ], } @@ -68,6 +71,9 @@ extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', + 'sphinx_selective_exclude.modindex_exclude', + 'sphinx_selective_exclude.eager_only', + 'sphinx_selective_exclude.search_auto_exclude', ] # Add any paths that contain templates here, relative to this directory. @@ -93,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors' # The short X.Y version. version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.8.1' +release = '1.8.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -313,6 +319,21 @@ intersphinx_mapping = {'http://docs.python.org/': None} # 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*') + +modules_port_specific = { + 'pyboard': ['pyb'], + 'wipy': ['wipy'], + 'esp8266': ['esp'], +} + +modindex_exclude = [] + +for p, l in modules_port_specific.items(): + if p != micropy_port: + modindex_exclude += l + +# Exclude extra modules per port +modindex_exclude += { + 'esp8266': ['cmath', 'select'], + 'wipy': ['cmath'], +}.get(micropy_port, []) diff --git a/docs/esp8266/tutorial/network_basics.rst b/docs/esp8266/tutorial/network_basics.rst index 42aed56642..95d8cba4f9 100644 --- a/docs/esp8266/tutorial/network_basics.rst +++ b/docs/esp8266/tutorial/network_basics.rst @@ -19,7 +19,7 @@ You can check if the interfaces are active by:: You can also check the network settings of the interface by:: - >>> ap.ifconfig() + >>> ap_if.ifconfig() ('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8') The returned values are: IP address, netmask, gateway, DNS. diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst new file mode 100644 index 0000000000..d99eadce3e --- /dev/null +++ b/docs/library/builtins.rst @@ -0,0 +1,127 @@ +Builtin Functions +================= + +All builtin functions are described here. They are alse available via +``builtins`` module. + +.. function:: abs() + +.. function:: all() + +.. function:: any() + +.. function:: bin() + +.. class:: bool() + +.. class:: bytearray() + +.. class:: bytes() + +.. function:: callable() + +.. function:: chr() + +.. function:: classmethod() + +.. function:: compile() + +.. class:: complex() + +.. class:: dict() + +.. function:: dir() + +.. function:: divmod() + +.. function:: enumerate() + +.. function:: eval() + +.. function:: exec() + +.. function:: filter() + +.. class:: float() + +.. class:: frozenset() + +.. function:: getattr() + +.. function:: globals() + +.. function:: hasattr() + +.. function:: hash() + +.. function:: hex() + +.. function:: id() + +.. function:: input() + +.. class:: int() + +.. function:: isinstance() + +.. function:: issubclass() + +.. function:: iter() + +.. function:: len() + +.. class:: list() + +.. function:: locals() + +.. function:: map() + +.. function:: max() + +.. class:: memoryview() + +.. function:: min() + +.. function:: next() + +.. class:: object() + +.. function:: oct() + +.. function:: open() + +.. function:: ord() + +.. function:: pow() + +.. function:: print() + +.. function:: property() + +.. function:: range() + +.. function:: repr() + +.. function:: reversed() + +.. function:: round() + +.. class:: set() + +.. function:: setattr() + +.. function:: sorted() + +.. function:: staticmethod() + +.. class:: str() + +.. function:: sum() + +.. function:: super() + +.. class:: tuple() + +.. function:: type() + +.. function:: zip() diff --git a/docs/library/esp.socket.rst b/docs/library/esp.socket.rst deleted file mode 100644 index 4f5234a154..0000000000 --- a/docs/library/esp.socket.rst +++ /dev/null @@ -1,82 +0,0 @@ -class socket -- network socket -============================== - -``socket`` is an object that represents a network socket. Example usage:: - - socket = esp.socket() - socket.onrecv(print) - socket.connect(('207.58.139.247', 80)) - socket.send('GET /testwifi/index.html HTTP/1.0\r\n\r\n') - -Constructors ------------- - -.. class:: esp.socket() - - Create and return a socket object. - - -TCP Methods ------------ - -.. method:: socket.connect(addr) - - Connect to the adress and port specified in the ``addr`` tuple. - -.. method:: socket.close() - - Close the connection. - -.. method:: socket.accept() - - Accept a single connection from the connection queue. - -.. method:: socket.listen(backlog) - - Start listening for incoming connections. - - Note: Only one socket can be listening for connections at a time. - -.. method:: socket.bind(addr) - - Bind the socket to the address and port specified by the ``addr`` tuple. - -.. method:: socket.send(buf) - - Send the bytes from ``buf``. - -.. method:: socket.recv() - - Receive and return bytes from the socket. - - -UDP Methods ------------ - -.. method:: socket.sendto(data, addr) - - Placeholder for UDP support, not implemented yet. - -.. method:: socket.recvfrom(addr) - - Placeholder for UDP support, not implemented yet. - - -Callback Setter Methods ------------------------ - -.. method:: onconnect(lambda):: - - When connection is established, call the callback ``lambda``. - -.. method:: onrecv(lambda):: - - When data is received, call the callback ``lambda``. - -.. method:: onsent(lamda):: - - What data is finished sending, call the callback ``lambda``. - -.. method:: ondisconnect(lambda):: - - Call the callback ``lambda`` when the connection is closed. diff --git a/docs/library/index.rst b/docs/library/index.rst index e3d6e31575..9a105697b7 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -51,6 +51,7 @@ library. .. toctree:: :maxdepth: 1 + builtins.rst cmath.rst gc.rst math.rst @@ -74,6 +75,7 @@ library. .. toctree:: :maxdepth: 1 + builtins.rst cmath.rst gc.rst math.rst @@ -97,6 +99,7 @@ library. .. toctree:: :maxdepth: 1 + builtins.rst gc.rst select.rst sys.rst @@ -113,6 +116,7 @@ library. .. toctree:: :maxdepth: 1 + builtins.rst gc.rst math.rst sys.rst diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADC.rst index 309d070b1b..2752878ff3 100644 --- a/docs/library/machine.ADC.rst +++ b/docs/library/machine.ADC.rst @@ -1,4 +1,4 @@ -.. _machine.ADC: +.. currentmodule:: machine class ADC -- analog to digital conversion ========================================= @@ -14,7 +14,7 @@ Usage:: Constructors ------------ -.. class:: machine.ADC(id=0, \*, bits=12) +.. class:: 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. @@ -31,7 +31,7 @@ Constructors Methods ------- -.. method:: adc.channel(id, \*, pin) +.. 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 @@ -42,11 +42,11 @@ Methods apin = adc.channel(pin='GP3') apin = adc.channel(id=1, pin='GP3') -.. method:: adc.init() +.. method:: ADC.init() Enable the ADC block. -.. method:: adc.deinit() +.. method:: ADC.deinit() Disable the ADC block. diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index a7e90ca39b..b3bfa68f07 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -1,4 +1,4 @@ -.. _machine.I2C: +.. currentmodule:: machine class I2C -- a two-wire serial protocol ======================================= @@ -44,14 +44,14 @@ Constructors .. only:: port_wipy - .. class:: machine.I2C(bus, ...) + .. class:: I2C(bus, ...) Construct an I2C object on the given bus. `bus` can only be 0. If the bus is not given, the default one will be selected (0). .. only:: port_esp8266 - .. class:: machine.I2C(scl, sda, \*, freq=400000) + .. class:: I2C(scl, sda, \*, freq=400000) Construct and return a new I2C object. See the init method below for a description of the arguments. @@ -61,7 +61,7 @@ General Methods .. only:: port_wipy - .. method:: i2c.init(mode, \*, baudrate=100000, pins=(SDA, SCL)) + .. method:: I2C.init(mode, \*, baudrate=100000, pins=(SDA, SCL)) Initialise the I2C bus with the given parameters: @@ -71,7 +71,7 @@ General Methods .. only:: port_esp8266 - .. method:: i2c.init(scl, sda, \*, freq=400000) + .. method:: I2C.init(scl, sda, \*, freq=400000) Initialise the I2C bus with the given arguments: @@ -79,13 +79,13 @@ General Methods - `sda` is a pin object for the SDA line - `freq` is the SCL clock rate -.. method:: i2c.deinit() +.. method:: I2C.deinit() Turn off the I2C bus. Availability: WiPy. -.. method:: i2c.scan() +.. method:: I2C.scan() Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of those that respond. A device responds if it pulls the SDA line low after @@ -100,19 +100,19 @@ The following methods implement the primitive I2C master bus operations and can be combined to make any I2C transaction. They are provided if you need more control over the bus, otherwise the standard methods (see below) can be used. -.. method:: i2c.start() +.. method:: I2C.start() Send a start bit on the bus (SDA transitions to low while SCL is high). Availability: ESP8266. -.. method:: i2c.stop() +.. method:: I2C.stop() Send a stop bit on the bus (SDA transitions to high while SCL is high). Availability: ESP8266. -.. method:: i2c.readinto(buf) +.. method:: I2C.readinto(buf) Reads bytes from the bus and stores them into `buf`. The number of bytes read is the length of `buf`. An ACK will be sent on the bus after @@ -121,7 +121,7 @@ control over the bus, otherwise the standard methods (see below) can be used. Availability: ESP8266. -.. method:: i2c.write(buf) +.. method:: I2C.write(buf) Write all the bytes from `buf` to the bus. Checks that an ACK is received after each byte and raises an OSError if not. @@ -134,12 +134,12 @@ Standard bus operations The following methods implement the standard I2C master read and write operations that target a given slave device. -.. method:: i2c.readfrom(addr, nbytes) +.. 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) +.. method:: I2C.readfrom_into(addr, buf) Read into `buf` from the slave specified by `addr`. The number of bytes read will be the length of `buf`. @@ -147,7 +147,7 @@ operations that target a given slave device. On WiPy the return value is the number of bytes read. Otherwise the return value is `None`. -.. method:: i2c.writeto(addr, buf, \*, stop=True) +.. method:: I2C.writeto(addr, buf, \*, stop=True) Write the bytes from `buf` to the slave specified by `addr`. @@ -166,7 +166,7 @@ from and written to. In this case there are two addresses associated with an I2C transaction: the slave address and the memory address. The following methods are convenience functions to communicate with such devices. -.. method:: i2c.readfrom_mem(addr, memaddr, nbytes, \*, addrsize=8) +.. 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`. @@ -174,7 +174,7 @@ methods are convenience functions to communicate with such devices. this argument is not recognised and the address size is always 8 bits). Returns a `bytes` object with the data read. -.. method:: i2c.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8) +.. 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`. The number of bytes read is the @@ -185,7 +185,7 @@ methods are convenience functions to communicate with such devices. On WiPy the return value is the number of bytes read. Otherwise the return value is `None`. -.. method:: i2c.writeto_mem(addr, memaddr, buf, \*, addrsize=8) +.. 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`. diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index a2e97c87c2..fdada2f383 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -1,9 +1,10 @@ -.. _machine.Pin: +.. currentmodule:: machine class Pin -- control I/O pins ============================= -A pin is the basic object to control I/O pins. It has methods to set +A pin is the basic object to control I/O pins (also known as GPIO - +general-purpose input/output). 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. @@ -57,17 +58,17 @@ Usage Model: Constructors ------------ -.. class:: machine.Pin(id, ...) +.. class:: 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`. + they are used to initialise the pin. See :meth:`Pin.init`. Methods ------- .. only:: port_wipy - .. method:: pin.init(mode, pull, \*, drive, alt) + .. method:: Pin.init(mode, pull, \*, drive, alt) Initialise the pin: @@ -97,13 +98,13 @@ Methods Returns: ``None``. - .. method:: pin.id() + .. method:: Pin.id() Get the pin id. .. only:: port_esp8266 - .. method:: pin.init(mode, pull=None, \*, value) + .. method:: Pin.init(mode, pull=None, \*, value) Initialise the pin: @@ -120,7 +121,7 @@ Methods - if `value` is given then it is the output value to set the pin if it is in output mode. -.. method:: pin.value([value]) +.. method:: Pin.value([value]) Get or set the digital logic level of the pin: @@ -129,12 +130,12 @@ Methods anything that converts to a boolean. If it converts to ``True``, the pin is set high, otherwise it is set low. -.. method:: pin([value]) +.. method:: Pin.__call__([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. + See :func:`Pin.value` for more details. -.. method:: pin.alt_list() +.. 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)`` @@ -143,23 +144,23 @@ Methods .. only:: port_wipy - .. method:: pin.toggle() + .. method:: Pin.toggle() Toggle the value of the pin. - .. method:: pin.mode([mode]) + .. method:: Pin.mode([mode]) Get or set the pin mode. - .. method:: pin.pull([pull]) + .. method:: Pin.pull([pull]) Get or set the pin pull. - .. method:: pin.drive([drive]) + .. method:: Pin.drive([drive]) Get or set the pin drive strength. - .. method:: pin.irq(\*, trigger, priority=1, handler=None, wake=None) + .. method:: Pin.irq(\*, trigger, priority=1, handler=None, wake=None) Create a callback to be triggered when the input level at the pin changes. @@ -193,7 +194,7 @@ Methods .. only:: port_esp8266 - .. method:: pin.irq(\*, trigger, handler=None) + .. method:: Pin.irq(\*, trigger, handler=None) Create a callback to be triggered when the input level at the pin changes. @@ -227,28 +228,28 @@ Constants The following constants are used to configure the pin objects. Note that not all constants are available on all ports. -.. data:: IN - OUT - OPEN_DRAIN - ALT - ALT_OPEN_DRAIN +.. data:: Pin.IN + Pin.OUT + Pin.OPEN_DRAIN + Pin.ALT + Pin.ALT_OPEN_DRAIN Selects the pin mode. -.. data:: PULL_UP - PULL_DOWN +.. data:: Pin.PULL_UP + Pin.PULL_DOWN Selects the whether there is a pull up/down resistor. -.. data:: LOW_POWER - MED_POWER - HIGH_POWER +.. data:: Pin.LOW_POWER + Pin.MED_POWER + Pin.HIGH_POWER Selects the pin drive strength. -.. data:: IRQ_FALLING - IRQ_RISING - IRQ_LOW_LEVEL - IRQ_HIGH_LEVEL +.. data:: Pin.IRQ_FALLING + Pin.IRQ_RISING + Pin.IRQ_LOW_LEVEL + Pin.IRQ_HIGH_LEVEL Selects the IRQ trigger type. diff --git a/docs/library/machine.RTC.rst b/docs/library/machine.RTC.rst index c69e4781a2..b6e98e9d1f 100644 --- a/docs/library/machine.RTC.rst +++ b/docs/library/machine.RTC.rst @@ -1,4 +1,4 @@ -.. _machine.RTC: +.. currentmodule:: machine class RTC -- real time clock ============================ @@ -16,42 +16,42 @@ Example usage:: Constructors ------------ -.. class:: machine.RTC(id=0, ...) +.. class:: RTC(id=0, ...) Create an RTC object. See init for parameters of initialization. Methods ------- -.. method:: rtc.init(datetime) +.. method:: RTC.init(datetime) Initialise the RTC. Datetime is a tuple of the form: ``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])`` -.. method:: rtc.now() +.. method:: RTC.now() Get get the current datetime tuple. -.. method:: rtc.deinit() +.. 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) +.. 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) +.. method:: RTC.alarm_left(alarm_id=0) Get the number of milliseconds left before the alarm expires. -.. method:: rtc.cancel(alarm_id=0) +.. method:: RTC.cancel(alarm_id=0) Cancel a running alarm. -.. method:: rtc.irq(\*, trigger, handler=None, wake=machine.IDLE) +.. method:: RTC.irq(\*, trigger, handler=None, wake=machine.IDLE) Create an irq object triggered by a real time clock alarm. diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index da60121d07..21c28aa200 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -1,4 +1,4 @@ -.. _machine.SD: +.. currentmodule:: machine class SD -- secure digital memory card ====================================== @@ -24,18 +24,18 @@ Example usage:: Constructors ------------ -.. class:: machine.SD(id,... ) +.. class:: SD(id,... ) Create a SD card object. See ``init()`` for parameters if initialization. Methods ------- -.. method:: sd.init(id=0, pins=('GP10', 'GP11', 'GP15')) +.. method:: SD.init(id=0, pins=('GP10', 'GP11', 'GP15')) Enable the SD card. In order to initalize the card, give it a 3-tuple: ``(clk_pin, cmd_pin, dat0_pin)``. -.. method:: sd.deinit() +.. method:: SD.deinit() Disable the SD card. diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index eddd62dbdc..f3c95181dc 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -1,4 +1,4 @@ -.. _machine.SPI: +.. currentmodule:: machine class SPI -- a master-driven serial protocol ============================================ @@ -23,7 +23,7 @@ Constructors .. only:: port_wipy - .. class:: machine.SPI(id, ...) + .. class:: 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 @@ -34,7 +34,7 @@ Constructors Methods ------- -.. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO)) +.. 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: @@ -47,27 +47,27 @@ Methods - ``firstbit`` can be ``SPI.MSB`` only. - ``pins`` is an optional tupple with the pins to assign to the SPI bus. -.. method:: spi.deinit() +.. method:: SPI.deinit() Turn off the SPI bus. -.. method:: spi.write(buf) +.. method:: SPI.write(buf) Write the data contained in ``buf``. Returns the number of bytes written. -.. method:: spi.read(nbytes, *, write=0x00) +.. 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) +.. 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) +.. method:: SPI.write_readinto(write_buf, read_buf) Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the same length. diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index daf63c9b93..344d1ea86e 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -1,4 +1,4 @@ -.. _machine.Timer: +.. currentmodule:: machine class Timer -- control internal timers ====================================== @@ -59,7 +59,7 @@ class Timer -- control internal timers Constructors ------------ -.. class:: machine.Timer(id, ...) +.. class:: Timer(id, ...) .. only:: port_wipy @@ -71,7 +71,7 @@ Methods .. only:: port_wipy - .. method:: timer.init(mode, \*, width=16) + .. method:: Timer.init(mode, \*, width=16) Initialise the timer. Example:: @@ -92,14 +92,14 @@ Methods (or large periods), 32-bit timers should be used. 32-bit mode is only available for ``ONE_SHOT`` AND ``PERIODIC`` modes. -.. method:: timer.deinit() +.. 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) + .. 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). diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 7399b9b6e9..27a8801900 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -1,4 +1,4 @@ -.. _machine.UART: +.. currentmodule:: machine class UART -- duplex serial communication bus ============================================= @@ -36,7 +36,7 @@ using the standard stream methods:: uart.readinto(buf) # read and store into the given buffer uart.write('abc') # write the 3 characters -.. only:: port_machineoard +.. only:: port_pyboard Individual characters can be read/written using:: @@ -47,9 +47,6 @@ using the standard stream methods:: 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:: @@ -61,7 +58,7 @@ Constructors .. only:: port_wipy - .. class:: machine.UART(bus, ...) + .. class:: UART(bus, ...) Construct a UART object on the given bus. ``bus`` can be 0 or 1. If the bus is not given, the default one will be selected (0) or the selection @@ -72,7 +69,7 @@ Methods .. only:: port_wipy - .. method:: uart.init(baudrate=9600, bits=8, parity=None, stop=1, \*, pins=(TX, RX, RTS, CTS)) + .. method:: UART.init(baudrate=9600, bits=8, parity=None, stop=1, \*, pins=(TX, RX, RTS, CTS)) Initialise the UART bus with the given parameters: @@ -88,28 +85,28 @@ Methods .. only:: not port_esp8266 - .. method:: uart.deinit() + .. method:: UART.deinit() Turn off the UART bus. - .. method:: uart.any() + .. method:: UART.any() Return the number of characters available for reading. -.. method:: uart.read([nbytes]) +.. 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 ``None`` on timeout. -.. method:: uart.readall() +.. method:: UART.readall() Read as much data as possible. Return value: a bytes object or ``None`` on timeout. -.. method:: uart.readinto(buf[, nbytes]) +.. 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. @@ -117,13 +114,13 @@ Methods Return value: number of bytes read and stored into ``buf`` or ``None`` on timeout. -.. method:: uart.readline() +.. method:: UART.readline() Read a line, ending in a newline character. Return value: the line read or ``None`` on timeout. -.. method:: uart.write(buf) +.. method:: UART.write(buf) Write the buffer of bytes to the bus. @@ -131,7 +128,7 @@ Methods .. only:: not port_esp8266 - .. method:: uart.sendbreak() + .. method:: UART.sendbreak() Send a break condition on the bus. This drives the bus low for a duration of 13 bits. @@ -139,7 +136,7 @@ Methods .. only:: port_wipy - .. method:: uart.irq(trigger, priority=1, handler=None, wake=machine.IDLE) + .. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE) Create a callback to be triggered when data is received on the UART. diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index dca74f70f6..d7c801356e 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -1,4 +1,4 @@ -.. _machine.WDT: +.. currentmodule:: machine class WDT -- watchdog timer =========================== @@ -17,7 +17,7 @@ Example usage:: Constructors ------------ -.. class:: machine.WDT(id=0, timeout=5000) +.. class:: 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 diff --git a/docs/library/network.rst b/docs/library/network.rst index fe4eaa7525..b183ef9a4b 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -41,11 +41,11 @@ For example:: Example:: - import network - server = network.Server() - server.deinit() # disable the server - # enable the server again with new settings - server.init(login=('user', 'password'), timeout=600) + import network + server = network.Server() + server.deinit() # disable the server + # enable the server again with new settings + server.init(login=('user', 'password'), timeout=600) Constructors ------------ diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 30957c4c1a..2ffd4e16f5 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.ADC: class ADC -- analog to digital conversion @@ -35,12 +36,12 @@ Methods .. only:: port_pyboard - .. method:: adc.read() + .. method:: ADC.read() Read the value on the analog pin and return it. The returned value will be between 0 and 4095. - .. method:: adc.read_timed(buf, timer) + .. method:: ADC.read_timed(buf, timer) Read analog values into ``buf`` at a rate set by the ``timer`` object. diff --git a/docs/library/pyb.Accel.rst b/docs/library/pyb.Accel.rst index fd96ec35f9..2ae357fe70 100644 --- a/docs/library/pyb.Accel.rst +++ b/docs/library/pyb.Accel.rst @@ -1,3 +1,5 @@ +.. currentmodule:: pyb + class Accel -- accelerometer control ==================================== @@ -20,7 +22,7 @@ Constructors Methods ------- -.. method:: accel.filtered_xyz() +.. method:: Accel.filtered_xyz() Get a 3-tuple of filtered x, y and z values. @@ -29,18 +31,18 @@ Methods with the sample from the current call. Returned values are therefore 4 times the size of what they would be from the raw x(), y() and z() calls. -.. method:: accel.tilt() +.. method:: Accel.tilt() Get the tilt register. -.. method:: accel.x() +.. method:: Accel.x() Get the x-axis value. -.. method:: accel.y() +.. method:: Accel.y() Get the y-axis value. -.. method:: accel.z() +.. method:: Accel.z() Get the z-axis value. diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index e5d2b9acb1..9e71f12b06 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -1,3 +1,5 @@ +.. currentmodule:: pyb + class CAN -- controller area network communication bus ====================================================== @@ -34,7 +36,7 @@ Constructors Class Methods ------------- -.. method:: CAN.initfilterbanks(nr) +.. classmethod:: CAN.initfilterbanks(nr) Reset and disable all filter banks and assign how many banks should be available for CAN(1). @@ -46,7 +48,7 @@ Class Methods Methods ------- -.. method:: can.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) +.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) Initialise the CAN bus with the given parameters: @@ -78,11 +80,11 @@ Methods See page 680 of the STM32F405 datasheet for more details. -.. method:: can.deinit() +.. method:: CAN.deinit() Turn off the CAN bus. -.. method:: can.setfilter(bank, mode, fifo, params, \*, rtr) +.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: @@ -124,17 +126,17 @@ Methods |CAN.MASK32 |1 | +-----------+----------------------+ -.. method:: can.clearfilter(bank) +.. method:: CAN.clearfilter(bank) Clear and disables a filter bank: - ``bank`` is the filter bank that is to be cleared. -.. method:: can.any(fifo) +.. method:: CAN.any(fifo) Return ``True`` if any message waiting on the FIFO, else ``False``. -.. method:: can.recv(fifo, \*, timeout=5000) +.. method:: CAN.recv(fifo, \*, timeout=5000) Receive data on the bus: @@ -148,7 +150,7 @@ Methods - The FMI (Filter Match Index) value. - An array containing the data. -.. method:: can.send(data, id, \*, timeout=0, rtr=False) +.. method:: CAN.send(data, id, \*, timeout=0, rtr=False) Send a message on the bus: @@ -168,7 +170,7 @@ Methods Return value: ``None``. -.. method:: can.rxcallback(fifo, fun) +.. method:: CAN.rxcallback(fifo, fun) Register a function to be called when a message is accepted into a empty fifo: diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index 7b5b1a6821..4b9651e27e 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.DAC: class DAC -- digital to analog conversion @@ -62,32 +63,32 @@ Constructors Methods ------- -.. method:: dac.init(bits=8) +.. method:: DAC.init(bits=8) Reinitialise the DAC. ``bits`` can be 8 or 12. -.. method:: dac.deinit() +.. method:: DAC.deinit() De-initialise the DAC making its pin available for other uses. -.. method:: dac.noise(freq) +.. method:: DAC.noise(freq) Generate a pseudo-random noise signal. A new random sample is written to the DAC output at the given frequency. -.. method:: dac.triangle(freq) +.. method:: DAC.triangle(freq) Generate a triangle wave. The value on the DAC output changes at the given frequency, and the frequence of the repeating triangle wave itself is 2048 times smaller. -.. method:: dac.write(value) +.. method:: DAC.write(value) 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) +.. 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 in 8-bit mode, and diff --git a/docs/library/pyb.ExtInt.rst b/docs/library/pyb.ExtInt.rst index 61023ebb38..d8f4d92bb8 100644 --- a/docs/library/pyb.ExtInt.rst +++ b/docs/library/pyb.ExtInt.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.ExtInt: class ExtInt -- configure I/O pins to interrupt on external events @@ -71,7 +72,7 @@ Constructors Class methods ------------- -.. method:: ExtInt.regs() +.. classmethod:: ExtInt.regs() Dump the values of the EXTI registers. @@ -79,20 +80,20 @@ Class methods Methods ------- -.. method:: extint.disable() +.. method:: ExtInt.disable() Disable the interrupt associated with the ExtInt object. This could be useful for debouncing. -.. method:: extint.enable() +.. method:: ExtInt.enable() Enable a disabled interrupt. -.. method:: extint.line() +.. method:: ExtInt.line() Return the line number that the pin is mapped to. -.. method:: extint.swint() +.. method:: ExtInt.swint() Trigger the callback from software. diff --git a/docs/library/pyb.I2C.rst b/docs/library/pyb.I2C.rst index 9d17bb0559..210b4ccf21 100644 --- a/docs/library/pyb.I2C.rst +++ b/docs/library/pyb.I2C.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.I2C: class I2C -- a two-wire serial protocol @@ -85,13 +86,13 @@ Constructors Methods ------- -.. method:: i2c.deinit() +.. method:: I2C.deinit() Turn off the I2C bus. .. only:: port_pyboard - .. method:: i2c.init(mode, \*, addr=0x12, baudrate=400000, gencall=False) + .. method:: I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False) Initialise the I2C bus with the given parameters: @@ -100,11 +101,11 @@ Methods - ``baudrate`` is the SCL clock rate (only sensible for a master) - ``gencall`` is whether to support general call mode - .. method:: i2c.is_ready(addr) + .. method:: I2C.is_ready(addr) Check if an I2C device responds to the given address. Only valid when in master mode. - .. method:: i2c.mem_read(data, addr, memaddr, \*, timeout=5000, addr_size=8) + .. method:: I2C.mem_read(data, addr, memaddr, \*, timeout=5000, addr_size=8) Read from the memory of an I2C device: @@ -117,7 +118,7 @@ Methods Returns the read data. This is only valid in master mode. - .. method:: i2c.mem_write(data, addr, memaddr, \*, timeout=5000, addr_size=8) + .. method:: I2C.mem_write(data, addr, memaddr, \*, timeout=5000, addr_size=8) Write to the memory of an I2C device: @@ -130,7 +131,7 @@ Methods Returns ``None``. This is only valid in master mode. - .. method:: i2c.recv(recv, addr=0x00, \*, timeout=5000) + .. method:: I2C.recv(recv, addr=0x00, \*, timeout=5000) Receive data on the bus: @@ -142,7 +143,7 @@ Methods Return value: if ``recv`` is an integer then a new buffer of the bytes received, otherwise the same buffer that was passed in to ``recv``. - .. method:: i2c.send(send, addr=0x00, \*, timeout=5000) + .. method:: I2C.send(send, addr=0x00, \*, timeout=5000) Send data on the bus: @@ -152,7 +153,7 @@ Methods Return value: ``None``. -.. method:: i2c.scan() +.. 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. diff --git a/docs/library/pyb.LCD.rst b/docs/library/pyb.LCD.rst index 7555b6fb09..83cf890b63 100644 --- a/docs/library/pyb.LCD.rst +++ b/docs/library/pyb.LCD.rst @@ -1,3 +1,5 @@ +.. currentmodule:: pyb + class LCD -- LCD control for the LCD touch-sensor pyskin ======================================================== @@ -47,48 +49,48 @@ Constructors Methods ------- -.. method:: lcd.command(instr_data, buf) +.. method:: LCD.command(instr_data, buf) Send an arbitrary command to the LCD. Pass 0 for ``instr_data`` to send an instruction, otherwise pass 1 to send data. ``buf`` is a buffer with the instructions/data to send. -.. method:: lcd.contrast(value) +.. method:: LCD.contrast(value) Set the contrast of the LCD. Valid values are between 0 and 47. -.. method:: lcd.fill(colour) +.. method:: LCD.fill(colour) Fill the screen with the given colour (0 or 1 for white or black). This method writes to the hidden buffer. Use ``show()`` to show the buffer. -.. method:: lcd.get(x, y) +.. method:: LCD.get(x, y) Get the pixel at the position ``(x, y)``. Returns 0 or 1. This method reads from the visible buffer. -.. method:: lcd.light(value) +.. method:: LCD.light(value) Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off. -.. method:: lcd.pixel(x, y, colour) +.. method:: LCD.pixel(x, y, colour) Set the pixel at ``(x, y)`` to the given colour (0 or 1). This method writes to the hidden buffer. Use ``show()`` to show the buffer. -.. method:: lcd.show() +.. method:: LCD.show() Show the hidden buffer on the screen. -.. method:: lcd.text(str, x, y, colour) +.. method:: LCD.text(str, x, y, colour) Draw the given text to the position ``(x, y)`` using the given colour (0 or 1). This method writes to the hidden buffer. Use ``show()`` to show the buffer. -.. method:: lcd.write(str) +.. method:: LCD.write(str) Write the string ``str`` to the screen. It will appear immediately. diff --git a/docs/library/pyb.LED.rst b/docs/library/pyb.LED.rst index aeeb75b8f1..1ab73a69c9 100644 --- a/docs/library/pyb.LED.rst +++ b/docs/library/pyb.LED.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.LED: class LED -- LED object @@ -19,7 +20,7 @@ Constructors Methods ------- -.. method:: led.intensity([value]) +.. method:: LED.intensity([value]) Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on). If no argument is given, return the LED intensity. @@ -31,15 +32,15 @@ Methods relevant LED is set to a value between 1 and 254. Otherwise the timers are free for general purpose use. -.. method:: led.off() +.. method:: LED.off() Turn the LED off. -.. method:: led.on() +.. method:: LED.on() Turn the LED on, to maximum intensity. -.. method:: led.toggle() +.. method:: LED.toggle() Toggle the LED between on (maximum intensity) and off. If the LED is at non-zero intensity then it is considered "on" and toggle will turn it off. diff --git a/docs/library/pyb.Pin.rst b/docs/library/pyb.Pin.rst index 30440f5025..154217ebb7 100644 --- a/docs/library/pyb.Pin.rst +++ b/docs/library/pyb.Pin.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.Pin: class Pin -- control I/O pins @@ -84,20 +85,16 @@ Constructors Class methods ------------- - - .. method:: Pin.af_list() - - Returns an array of alternate functions available for this pin. - - .. method:: Pin.debug([state]) + + .. classmethod:: Pin.debug([state]) Get or set the debugging state (``True`` or ``False`` for on or off). - .. method:: Pin.dict([dict]) + .. classmethod:: Pin.dict([dict]) Get or set the pin mapper dictionary. - .. method:: Pin.mapper([fun]) + .. classmethod:: Pin.mapper([fun]) Get or set the pin mapper function. @@ -107,7 +104,7 @@ Methods .. only:: port_pyboard - .. method:: pin.init(mode, pull=Pin.PULL_NONE, af=-1) + .. method:: Pin.init(mode, pull=Pin.PULL_NONE, af=-1) Initialise the pin: @@ -131,7 +128,7 @@ Methods Returns: ``None``. -.. method:: pin.value([value]) +.. method:: Pin.value([value]) Get or set the digital logic level of the pin: @@ -142,43 +139,47 @@ Methods .. only:: port_pyboard - .. method:: pin.__str__() + .. method:: Pin.__str__() Return a string describing the pin object. - .. method:: pin.af() + .. method:: Pin.af() Returns the currently configured alternate-function of the pin. The integer returned will match one of the allowed constants for the af argument to the init function. + + .. method:: Pin.af_list() + + Returns an array of alternate functions available for this pin. - .. method:: pin.gpio() + .. method:: Pin.gpio() Returns the base address of the GPIO block associated with this pin. - .. method:: pin.mode() + .. method:: Pin.mode() Returns the currently configured mode of the pin. The integer returned will match one of the allowed constants for the mode argument to the init function. - .. method:: pin.name() + .. method:: Pin.name() Get the pin name. - .. method:: pin.names() + .. method:: Pin.names() Returns the cpu and board names for this pin. - .. method:: pin.pin() + .. method:: Pin.pin() Get the pin number. - .. method:: pin.port() + .. method:: Pin.port() Get the pin port. - -.. method:: pin.pull() + +.. method:: Pin.pull() Returns the currently configured pull of the pin. The integer returned will match one of the allowed constants for the pull argument to the init diff --git a/docs/library/pyb.RTC.rst b/docs/library/pyb.RTC.rst index 51b17deccf..383ddf20c2 100644 --- a/docs/library/pyb.RTC.rst +++ b/docs/library/pyb.RTC.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.RTC: class RTC -- real time clock @@ -24,7 +25,7 @@ Constructors Methods ------- -.. method:: rtc.datetime([datetimetuple]) +.. method:: RTC.datetime([datetimetuple]) Get or set the date and time of the RTC. @@ -44,7 +45,7 @@ Methods .. only:: port_pyboard - .. method:: rtc.wakeup(timeout, callback=None) + .. method:: RTC.wakeup(timeout, callback=None) Set the RTC wakeup timer to trigger repeatedly at every ``timeout`` milliseconds. This trigger can wake the pyboard from both the sleep @@ -55,7 +56,7 @@ Methods If ``callback`` is given then it is executed at every trigger of the wakeup timer. ``callback`` must take exactly one argument. - .. method:: rtc.info() + .. method:: RTC.info() Get information about the startup time and reset source. @@ -64,7 +65,7 @@ Methods - Bit 0x10000 is set if a power-on reset occurred. - Bit 0x20000 is set if an external reset occurred - .. method:: rtc.calibration(cal) + .. method:: RTC.calibration(cal) Get or set RTC calibration. diff --git a/docs/library/pyb.SPI.rst b/docs/library/pyb.SPI.rst index b17c804d70..54ecc65b6d 100644 --- a/docs/library/pyb.SPI.rst +++ b/docs/library/pyb.SPI.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.SPI: class SPI -- a master-driven serial protocol @@ -50,13 +51,13 @@ Constructors Methods ------- -.. method:: spi.deinit() +.. method:: SPI.deinit() Turn off the SPI bus. .. only:: port_pyboard - .. method:: spi.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) + .. method:: SPI.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) Initialise the SPI bus with the given parameters: @@ -82,7 +83,7 @@ Methods .. only:: port_pyboard - .. method:: spi.recv(recv, \*, timeout=5000) + .. method:: SPI.recv(recv, \*, timeout=5000) Receive data on the bus: @@ -93,7 +94,7 @@ Methods Return value: if ``recv`` is an integer then a new buffer of the bytes received, otherwise the same buffer that was passed in to ``recv``. - .. method:: spi.send(send, \*, timeout=5000) + .. method:: SPI.send(send, \*, timeout=5000) Send data on the bus: @@ -102,7 +103,7 @@ Methods Return value: ``None``. - .. method:: spi.send_recv(send, recv=None, \*, timeout=5000) + .. method:: SPI.send_recv(send, recv=None, \*, timeout=5000) Send and receive data on the bus at the same time: diff --git a/docs/library/pyb.Servo.rst b/docs/library/pyb.Servo.rst index cea31fd28e..b3ce71d11a 100644 --- a/docs/library/pyb.Servo.rst +++ b/docs/library/pyb.Servo.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.Servo: class Servo -- 3-wire hobby servo driver @@ -37,7 +38,7 @@ Constructors Methods ------- -.. method:: servo.angle([angle, time=0]) +.. method:: Servo.angle([angle, time=0]) If no arguments are given, this function returns the current angle. @@ -48,7 +49,7 @@ Methods angle. If omitted, then the servo moves as quickly as possible to its new position. -.. method:: servo.speed([speed, time=0]) +.. method:: Servo.speed([speed, time=0]) If no arguments are given, this function returns the current speed. @@ -58,14 +59,14 @@ Methods - ``time`` is the number of milliseconds to take to get to the specified speed. If omitted, then the servo accelerates as quickly as possible. -.. method:: servo.pulse_width([value]) +.. method:: Servo.pulse_width([value]) If no arguments are given, this function returns the current raw pulse-width value. If an argument is given, this function sets the raw pulse-width value. -.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]]) +.. method:: Servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]]) If no arguments are given, this function returns the current calibration data, as a 5-tuple. diff --git a/docs/library/pyb.Switch.rst b/docs/library/pyb.Switch.rst index daaed19420..bc62b6eee9 100644 --- a/docs/library/pyb.Switch.rst +++ b/docs/library/pyb.Switch.rst @@ -1,3 +1,5 @@ +.. currentmodule:: pyb + class Switch -- switch object ============================= @@ -27,11 +29,12 @@ Constructors Methods ------- -.. method:: switch() +.. method:: Switch.__call__() - Return the switch state: ``True`` if pressed down, ``False`` otherwise. + Call switch object directly to get its state: ``True`` if pressed down, + ``False`` otherwise. -.. method:: switch.callback(fun) +.. method:: Switch.callback(fun) Register the given function to be called when the switch is pressed down. If ``fun`` is ``None``, then it disables the callback. diff --git a/docs/library/pyb.Timer.rst b/docs/library/pyb.Timer.rst index d2a299bd29..ffb092caa3 100644 --- a/docs/library/pyb.Timer.rst +++ b/docs/library/pyb.Timer.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.Timer: class Timer -- control internal timers @@ -67,7 +68,7 @@ Methods .. only:: port_pyboard - .. method:: timer.init(\*, freq, prescaler, period) + .. method:: Timer.init(\*, freq, prescaler, period) Initialise the timer. Initialisation must be either by frequency (in Hz) or by prescaler and period:: @@ -114,7 +115,7 @@ Methods You must either specify freq or both of period and prescaler. -.. method:: timer.deinit() +.. method:: Timer.deinit() Deinitialises the timer. @@ -127,7 +128,7 @@ Methods .. only:: port_pyboard - .. method:: timer.callback(fun) + .. method:: Timer.callback(fun) Set the function to be called when the timer triggers. ``fun`` is passed 1 argument, the timer object. @@ -135,7 +136,7 @@ Methods .. only:: port_pyboard - .. method:: timer.channel(channel, mode, ...) + .. method:: Timer.channel(channel, mode, ...) If only a channel number is passed, then a previously initialized channel object is returned (or ``None`` if there is no previous channel). @@ -211,27 +212,27 @@ Methods .. only:: port_pyboard - .. method:: timer.counter([value]) + .. method:: Timer.counter([value]) Get or set the timer counter. .. only:: port_pyboard - .. method:: timer.freq([value]) + .. method:: Timer.freq([value]) Get or set the frequency for the timer (changes prescaler and period if set). .. only:: port_pyboard - .. method:: timer.period([value]) + .. method:: Timer.period([value]) Get or set the period of the timer. - .. method:: timer.prescaler([value]) + .. method:: Timer.prescaler([value]) Get or set the prescaler for the timer. - .. method:: timer.source_freq() + .. method:: Timer.source_freq() Get the frequency of the source of the timer. diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index 536b6f467d..4a692469f8 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -1,3 +1,4 @@ +.. currentmodule:: pyb .. _pyb.UART: class UART -- duplex serial communication bus @@ -76,7 +77,7 @@ Methods .. only:: port_pyboard - .. method:: uart.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64) + .. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64) Initialise the UART bus with the given parameters: @@ -100,22 +101,22 @@ Methods *Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits are supported. -.. method:: uart.deinit() +.. method:: UART.deinit() Turn off the UART bus. .. only:: port_pyboard - .. method:: uart.any() + .. method:: UART.any() Returns the number of bytes waiting (may be 0). - .. method:: uart.writechar(char) + .. method:: UART.writechar(char) Write a single character on the bus. ``char`` is an integer to write. Return value: ``None``. See note below if CTS flow control is used. -.. method:: uart.read([nbytes]) +.. method:: UART.read([nbytes]) Read characters. If ``nbytes`` is specified then read at most that many bytes. If ``nbytes`` are available in the buffer, returns immediately, otherwise returns @@ -129,19 +130,19 @@ Methods Return value: a bytes object containing the bytes read in. Returns ``None`` on timeout. -.. method:: uart.readall() +.. method:: UART.readall() Read as much data as possible. Returns after the timeout has elapsed. Return value: a bytes object or ``None`` if timeout prevents any data being read. -.. method:: uart.readchar() +.. method:: UART.readchar() Receive a single character on the bus. Return value: The character read, as an integer. Returns -1 on timeout. -.. method:: uart.readinto(buf[, nbytes]) +.. 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. @@ -149,7 +150,7 @@ Methods Return value: number of bytes read and stored into ``buf`` or ``None`` on timeout. -.. method:: uart.readline() +.. method:: UART.readline() Read a line, ending in a newline character. If such a line exists, return is immediate. If the timeout elapses, all available data is returned regardless @@ -157,7 +158,7 @@ Methods Return value: the line read or ``None`` on timeout if no data is available. -.. method:: uart.write(buf) +.. method:: UART.write(buf) .. only:: port_pyboard @@ -169,7 +170,7 @@ Methods Return value: number of bytes written. If a timeout occurs and no bytes were written returns ``None``. -.. method:: uart.sendbreak() +.. method:: UART.sendbreak() Send a break condition on the bus. This drives the bus low for a duration of 13 bits. @@ -214,14 +215,14 @@ Flow Control If CTS flow control is enabled the write behaviour is as follows: - If the Pyboard's ``uart.write(buf)`` method is called, transmission will stall for + If the Pyboard's ``UART.write(buf)`` method is called, transmission will stall for any periods when ``nCTS`` is ``False``. This will result in a timeout if the entire buffer was not transmitted in the timeout period. The method returns the number of bytes written, enabling the user to write the remainder of the data if required. In the event of a timeout, a character will remain in the UART pending ``nCTS``. The number of bytes composing this character will be included in the return value. - If ``uart.writechar()`` is called when ``nCTS`` is ``False`` the method will time + If ``UART.writechar()`` is called when ``nCTS`` is ``False`` the method will time out unless the target asserts ``nCTS`` in time. If it times out ``OSError 116`` will be raised. The character will be transmitted as soon as the target asserts ``nCTS``. diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index cc4dbe5903..4e34af2586 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -1,3 +1,5 @@ +.. currentmodule:: pyb + class USB_VCP -- USB virtual comm port ====================================== @@ -17,7 +19,7 @@ Constructors Methods ------- -.. method:: usb_vcp.setinterrupt(chr) +.. method:: USB_VCP.setinterrupt(chr) Set the character which interrupts running Python code. This is set to 3 (CTRL-C) by default, and when a CTRL-C character is received over @@ -26,20 +28,20 @@ Methods Set to -1 to disable this interrupt feature. This is useful when you want to send raw bytes over the USB VCP port. -.. method:: usb_vcp.isconnected() +.. method:: USB_VCP.isconnected() Return ``True`` if USB is connected as a serial device, else ``False``. -.. method:: usb_vcp.any() +.. method:: USB_VCP.any() Return ``True`` if any characters waiting, else ``False``. -.. method:: usb_vcp.close() +.. method:: USB_VCP.close() This method does nothing. It exists so the USB_VCP object can act as a file. -.. method:: usb_vcp.read([nbytes]) +.. method:: USB_VCP.read([nbytes]) Read at most ``nbytes`` from the serial device and return them as a bytes object. If ``nbytes`` is not specified then the method acts as @@ -47,12 +49,12 @@ Methods so if no pending data available, this method will return immediately with ``None`` value. -.. method:: usb_vcp.readall() +.. method:: USB_VCP.readall() Read all available bytes from the serial device and return them as a bytes object, or ``None`` if no pending data available. -.. method:: usb_vcp.readinto(buf, [maxlen]) +.. method:: USB_VCP.readinto(buf, [maxlen]) Read bytes from the serial device and store them into ``buf``, which should be a buffer-like object. At most ``len(buf)`` bytes are read. @@ -62,14 +64,14 @@ Methods Returns the number of bytes read and stored into ``buf`` or ``None`` if no pending data available. -.. method:: usb_vcp.readline() +.. method:: USB_VCP.readline() Read a whole line from the serial device. Returns a bytes object containing the data, including the trailing newline character or ``None`` if no pending data available. -.. method:: usb_vcp.readlines() +.. method:: USB_VCP.readlines() Read as much data as possible from the serial device, breaking it into lines. @@ -77,13 +79,13 @@ Methods Returns a list of bytes objects, each object being one of the lines. Each line will include the newline character. -.. method:: usb_vcp.write(buf) +.. method:: USB_VCP.write(buf) Write the bytes from ``buf`` to the serial device. Returns the number of bytes written. -.. method:: usb_vcp.recv(data, \*, timeout=5000) +.. method:: USB_VCP.recv(data, \*, timeout=5000) Receive data on the bus: @@ -94,7 +96,7 @@ Methods Return value: if ``data`` is an integer then a new buffer of the bytes received, otherwise the number of bytes read into ``data`` is returned. -.. method:: usb_vcp.send(data, \*, timeout=5000) +.. method:: USB_VCP.send(data, \*, timeout=5000) Send data over the USB VCP: diff --git a/docs/library/select.rst b/docs/library/select.rst index c24f010e6b..8dcd4080f1 100644 --- a/docs/library/select.rst +++ b/docs/library/select.rst @@ -61,7 +61,7 @@ Methods list of (``obj``, ``event``, ...) tuples, ``event`` element specifies which events happened with a stream and is a combination of `select.POLL*` constants described above. There may be other elements in tuple, depending - on platform and version, so don't assume that its size is 2. In case of + on a platform and version, so don't assume that its size is 2. In case of timeout, an empty list is returned. Timeout is in milliseconds. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index b5a9138c07..1d7579754f 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -21,7 +21,12 @@ Functions .. admonition:: Difference to CPython :class: attention - This function appears in the ``traceback`` module in CPython. + This is simplified version of a function which appears in the + ``traceback`` module in CPython. Unlike ``traceback.print_exception()``, + this function takes just exception value instead of exception type, + exception value, and traceback object; `file` argument should be + positional; further arguments are not supported. CPython-compatible + ``traceback`` module can be found in micropython-lib. Constants --------- diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 9a7f85edcd..630a3a36fb 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -1,97 +1,106 @@ -:mod:`uctypes` -- access C structures -===================================== +:mod:`uctypes` -- access binary data in a structured way +======================================================== .. module:: uctypes - :synopsis: access C structures + :synopsis: access binary data in a structured way This module implements "foreign data interface" for MicroPython. The idea -behind it is similar to CPython's ``ctypes`` modules, but actual API is -different, streamlined and optimized for small size. +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and the access it using familiar dot-syntax to reference +sub-fields. + +.. seealso:: + + Module :mod:`ustruct` + Standard Python way to access binary data structures (doesn't scale + well to large and complex structures). Defining structure layout ------------------------- Structure layout is defined by a "descriptor" - a Python dictionary which encodes field names as keys and other properties required to access them as -an associated values. Currently, uctypes requires explicit specification of -offsets for each field. Offset are given in bytes from structure start. +associated values. Currently, uctypes requires explicit specification of +offsets for each field. Offset are given in bytes from a structure start. Following are encoding examples for various field types: - Scalar types:: +* Scalar types:: "field_name": uctypes.UINT32 | 0 - in other words, value is scalar type identifier ORed with field offset - (in bytes) from the start of the structure. + in other words, value is scalar type identifier ORed with field offset + (in bytes) from the start of the structure. - Recursive structures:: +* Recursive structures:: "sub": (2, { "b0": uctypes.UINT8 | 0, "b1": uctypes.UINT8 | 1, }) - i.e. value is a 2-tuple, first element of which is offset, and second is - a structure descriptor dictionary (note: offsets in recursive descriptors - are relative to a structure it defines). + i.e. value is a 2-tuple, first element of which is offset, and second is + a structure descriptor dictionary (note: offsets in recursive descriptors + are relative to a structure it defines). - Arrays of primitive types:: +* Arrays of primitive types:: "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), - i.e. value is a 2-tuple, first element of which is ARRAY flag ORed - with offset, and second is scalar element type ORed number of elements - in array. + i.e. value is a 2-tuple, first element of which is ARRAY flag ORed + with offset, and second is scalar element type ORed number of elements + in array. - Arrays of aggregate types:: +* Arrays of aggregate types:: "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), - i.e. value is a 3-tuple, first element of which is ARRAY flag ORed - with offset, second is a number of elements in array, and third is - descriptor of element type. + i.e. value is a 3-tuple, first element of which is ARRAY flag ORed + with offset, second is a number of elements in array, and third is + descriptor of element type. - Pointer to a primitive type:: +* Pointer to a primitive type:: "ptr": (uctypes.PTR | 0, uctypes.UINT8), - i.e. value is a 2-tuple, first element of which is PTR flag ORed - with offset, and second is scalar element type. + i.e. value is a 2-tuple, first element of which is PTR flag ORed + with offset, and second is scalar element type. - Pointer to aggregate type:: +* Pointer to an aggregate type:: "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), - i.e. value is a 2-tuple, first element of which is PTR flag ORed - with offset, second is descriptor of type pointed to. + i.e. value is a 2-tuple, first element of which is PTR flag ORed + with offset, second is descriptor of type pointed to. - Bitfields:: +* Bitfields:: "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, - i.e. value is type of scalar value containing given bitfield (typenames are - similar to scalar types, but prefixes with "BF"), ORed with offset for - scalar value containing the bitfield, and further ORed with values for - bit offset and bit length of the bitfield within scalar value, shifted by - BF_POS and BF_LEN positions, respectively. Bitfield position is counted - from the least significant bit, and is the number of right-most bit of a - field (in other words, it's a number of bits a scalar needs to be shifted - right to extra the bitfield). - - In the example above, first UINT16 value will be extracted at offset 0 - (this detail may be important when accessing hardware registers, where - particular access size and alignment are required), and then bitfield - whose rightmost bit is least-significant bit of this UINT16, and length - is 8 bits, will be extracted - effectively, this will access - least-significant byte of UINT16. - - Note that bitfield operations are independent of target byte endianness, - in particular, example above will access least-significant byte of UINT16 - in both little- and big-endian structures. But it depends on the least - significant bit being numbered 0. Some targets may use different - numbering in their native ABI, but ``uctypes`` always uses normalized - numbering described above. + i.e. value is type of scalar value containing given bitfield (typenames are + similar to scalar types, but prefixes with "BF"), ORed with offset for + scalar value containing the bitfield, and further ORed with values for + bit offset and bit length of the bitfield within scalar value, shifted by + BF_POS and BF_LEN positions, respectively. Bitfield position is counted + from the least significant bit, and is the number of right-most bit of a + field (in other words, it's a number of bits a scalar needs to be shifted + right to extra the bitfield). + + In the example above, first UINT16 value will be extracted at offset 0 + (this detail may be important when accessing hardware registers, where + particular access size and alignment are required), and then bitfield + whose rightmost bit is least-significant bit of this UINT16, and length + is 8 bits, will be extracted - effectively, this will access + least-significant byte of UINT16. + + Note that bitfield operations are independent of target byte endianness, + in particular, example above will access least-significant byte of UINT16 + in both little- and big-endian structures. But it depends on the least + significant bit being numbered 0. Some targets may use different + numbering in their native ABI, but ``uctypes`` always uses normalized + numbering described above. Module contents --------------- @@ -103,17 +112,18 @@ Module contents .. data:: LITTLE_ENDIAN - Little-endian packed structure. (Packed means that every field occupies - exactly as many bytes as defined in the descriptor, i.e. alignment is 1). + Layout type for a little-endian packed structure. (Packed means that every + field occupies exactly as many bytes as defined in the descriptor, i.e. + the alignment is 1). .. data:: BIG_ENDIAN - Big-endian packed structure. + Layour type for a big-endian packed structure. .. data:: NATIVE - Native structure - with data endianness and alignment conforming to - the ABI of the system on which MicroPython runs. + Layout type for a native structure - with data endianness and alignment + conforming to the ABI of the system on which MicroPython runs. .. function:: sizeof(struct) @@ -145,33 +155,55 @@ Structure descriptors and instantiating structure objects Given a structure descriptor dictionary and its layout type, you can instantiate a specific structure instance at a given memory address -using uctypes.struct() constructor. Memory address usually comes from +using :class:`uctypes.struct()` constructor. Memory address usually comes from following sources: * Predefined address, when accessing hardware registers on a baremetal system. Lookup these addresses in datasheet for a particular MCU/SoC. -* As return value from a call to some FFI (Foreign Function Interface) +* As a return value from a call to some FFI (Foreign Function Interface) function. -* From uctypes.addressof(), when you want to pass arguments to FFI +* From uctypes.addressof(), when you want to pass arguments to an FFI function, or alternatively, to access some data for I/O (for example, - data read from file or network socket). + data read from a file or network socket). Structure objects ----------------- Structure objects allow accessing individual fields using standard dot -notation: ``my_struct.field1``. If a field is of scalar type, getting -it will produce primitive value (Python integer or float) corresponding -to value contained in a field. Scalar field can also be assigned to. +notation: ``my_struct.substruct1.field1``. If a field is of scalar type, +getting it will produce a primitive value (Python integer or float) +corresponding to the value contained in a field. A scalar field can also +be assigned to. If a field is an array, its individual elements can be accessed with -standard subscript operator - both read and assigned to. +the standard subscript operator ``[]`` - both read and assigned to. If a field is a pointer, it can be dereferenced using ``[0]`` syntax (corresponding to C ``*`` operator, though ``[0]`` works in C too). -Subscripting pointer with other integer values but 0 are supported too, +Subscripting a pointer with other integer values but 0 are supported too, with the same semantics as in C. Summing up, accessing structure fields generally follows C syntax, -except for pointer derefence, you need to use ``[0]`` operator instead -of ``*``. +except for pointer derefence, when you need to use ``[0]`` operator +instead of ``*``. + +Limitations +----------- + +Accessing non-scalar fields leads to allocation of intermediate objects +to represent them. This means that special care should be taken to +layout a structure which needs to be accessed when memory allocation +is disabled (e.g. from an interrupt). The recommendations are: + +* Avoid nested structures. For example, instead of + ``mcu_registers.peripheral_a.register1``, define separate layout + descriptors for each peripheral, to be accessed as + ``peripheral_a.register1``. +* Avoid other non-scalar data, like array. For example, instead of + ``peripheral_a.register[0]`` use ``peripheral_a.register0``. + +Note that these recommendations will lead to decreased readability +and conciseness of layouts, so they should be used only if the need +to access structure fields without allocation is anticipated (it's +even possible to define 2 parallel layouts - one for normal usage, +and a restricted one to use when memory allocation is prohibited). diff --git a/docs/library/ure.rst b/docs/library/ure.rst index f20dff6f39..ee360bcc47 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -32,7 +32,7 @@ Supported operators are: ``'+?'`` -Counted repetitions (``{m,n}``), more advanced assertions, names groups, +Counted repetitions (``{m,n}``), more advanced assertions, named groups, etc. are not supported. diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index d31e4d2fc9..9b279e5ba7 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -74,6 +74,7 @@ Constants .. data:: socket.IPPROTO_UDP .. data:: socket.IPPROTO_TCP .. only:: port_wipy + .. data:: socket.IPPROTO_SEC protocol numbers @@ -100,7 +101,7 @@ Methods 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 + that the system will allow before refusing new connections. If not specified, a default reasonable value is chosen. .. method:: socket.accept() diff --git a/docs/sphinx_selective_exclude/LICENSE b/docs/sphinx_selective_exclude/LICENSE new file mode 100644 index 0000000000..0b47ced8a1 --- /dev/null +++ b/docs/sphinx_selective_exclude/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2016 by the sphinx_selective_exclude authors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/sphinx_selective_exclude/README.md b/docs/sphinx_selective_exclude/README.md new file mode 100644 index 0000000000..cc9725c21c --- /dev/null +++ b/docs/sphinx_selective_exclude/README.md @@ -0,0 +1,138 @@ +Sphinx eager ".. only::" directive and other selective rendition extensions +=========================================================================== + +Project home page: https://github.com/pfalcon/sphinx_selective_exclude + +The implementation of ".. only::" directive in Sphinx documentation +generation tool is known to violate principles of least user surprise +and user expectations in general. Instead of excluding content early +in the pipeline (pre-processor style), Sphinx defers exclusion until +output phase, and what's the worst, various stages processing ignore +"only" blocks and their exclusion status, so they may leak unexpected +information into ToC, indexes, etc. + +There's multiple issues submitted upstream on this matter: + +* https://github.com/sphinx-doc/sphinx/issues/2150 +* https://github.com/sphinx-doc/sphinx/issues/1717 +* https://github.com/sphinx-doc/sphinx/issues/1488 +* etc. + +They are largely ignored by Sphinx maintainers. + +This projects tries to rectify situation on users' side. It actually +changes the way Sphinx processes "only" directive, but does this +without forking the project, and instead is made as a standard +Sphinx extension, which a user may add to their documentation config. +Unlike normal extensions, extensions provided in this package +monkey-patch Sphinx core to work in a way expected by users. + +eager_only +---------- + +The core extension provided by the package is called `eager_only` and +is based on the idea by Andrea Cassioli (see bugreports above) to +process "only" directive as soon as possible during parsing phase. +This approach has some drawbacks, like producing warnings like +"WARNING: document isn't included in any toctree" if "only" is used +to shape up a toctree, or the fact that changing a documentation +builder (html/latex/etc.) will almost certainly require complete +rebuild of documentation. But these are relatively minor issues +comparing to completely broken way "only" works in upstream Sphinx. + +modindex_exclude +---------------- + +"only" directive allows for fine-grained conditional exclusion, but +sometimes you may want to exclude entire module(s) at once. Even if +you wrap an entire module description in "only" directive, like: + + .. only: option1 + .. module:: my_module + + ... + +You will still have an HTML page generated, albeit empty. It may also +go into indexes, so will be discoverable by users, leading to less +than ideal experience. `modindex_exclude` extension is design to +resolve this issue, by making sure that any reference of a module +is excluded from Python module index ("modindex"), as well as +general cross-reference index ("genindex"). In the latter case, +any symbol belong to a module will be excluded. Unlike `eager_only` +extension which appear to have issued with "latexpdf" builder, +`modindex_exclude` is useful for PDF, and allows to get cleaner +index for PDF, just the same as for HTML. + +search_auto_exclude +------------------- + +Even if you exclude soem documents from toctree:: using only:: +directive, they will be indexed for full-text search, so user may +find them and get confused. This plugin follows very simple idea +that if you didn't include some documents in the toctree, then +you didn't want them to be accessible (e.g. for a particular +configuration), and so will make sure they aren't indexed either. + +This extension depends on `eager_only` and won't work without it. +Note that Sphinx will issue warnings, as usual, for any documents +not included in a toctree. This is considered a feature, and gives +you a chance to check that document exclusions are indeed right +for a particular configuration you build (and not that you forgot +to add something to a toctree). + +Summary +------- + +Based on the above, sphinx_selective_exclude offers extension to let +you: + +* Make "only::" directive work in an expected, intuitive manner, using + `eager_only` extension. +* However, if you apply only:: to toctree::, excluded documents will + still be available via full-text search, so you need to use + `search_auto_exclude` for that to work as expected. +* Similar to search, indexes may also require special treatment, hence + there's the `modindex_exclude` extension. + +Most likely, you will want to use all 3 extensions together - if you +really want build subsets of docimentation covering sufficiently different +configurations from a single doctree. However, if one of them is enough +to cover your usecase, that's OK to (and why they were separated into +3 extensions, to follow KISS and "least surprise" principles and to +not make people deal with things they aren't interested in). In this case, +however remember there're other extensions, if you later hit a usecase +when they're needed. + +Usage +----- + +To use these extensions, add https://github.com/pfalcon/sphinx_selective_exclude +as a git submodule to your project, in documentation folder (where +Sphinx conf.py is located). Alternatively, commit sphinx_selective_exclude +directory instead of making it a submodule (you will need to pick up +any project updates manually then). + +Add following lines to "extensions" settings in your conf.py (you +likely already have some standard Sphinx extensions enabled): + + extensions = [ + ... + 'sphinx_selective_exclude.eager_only', + 'sphinx_selective_exclude.search_auto_exclude', + 'sphinx_selective_exclude.modindex_exclude', + ] + +As discussed above, you may enable all extensions, or one by one. + +Please note that to make sure these extensions work well and avoid producing +output docs with artifacts, it is IMPERATIVE to remove cached doctree if +you rebuild documentation with another builder (i.e. with different output +format). Also, to stay on safe side, it's recommended to remove old doctree +anyway before generating production-ready documentation for publishing. To +do that, run something like: + + rm -rf _build/doctrees/ + +A typical artificat when not following these simple rules is that content +of some sections may be missing. If you face anything like that, just +remember what's written above and remove cached doctrees. diff --git a/docs/sphinx_selective_exclude/__init__.py b/docs/sphinx_selective_exclude/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/docs/sphinx_selective_exclude/__init__.py diff --git a/docs/sphinx_selective_exclude/eager_only.py b/docs/sphinx_selective_exclude/eager_only.py new file mode 100644 index 0000000000..82766c2e64 --- /dev/null +++ b/docs/sphinx_selective_exclude/eager_only.py @@ -0,0 +1,45 @@ +# +# This is a Sphinx documentation tool extension which makes .only:: +# directives be eagerly processed early in the parsing stage. This +# makes sure that content in .only:: blocks gets actually excluded +# as a typical user expects, instead of bits of information in +# these blocks leaking to documentation in various ways (e.g., +# indexes containing entries for functions which are actually in +# .only:: blocks and thus excluded from documentation, etc.) +# Note that with this extension, you may need to completely +# rebuild a doctree when switching builders (i.e. completely +# remove _build/doctree dir between generation of HTML vs PDF +# documentation). +# +# This extension works by monkey-patching Sphinx core, so potentially +# may not work with untested Sphinx versions. It tested to work with +# 1.2.2 and 1.4.2 +# +# Copyright (c) 2016 Paul Sokolovsky +# Based on idea by Andrea Cassioli: +# https://github.com/sphinx-doc/sphinx/issues/2150#issuecomment-171912290 +# Licensed under the terms of BSD license, see LICENSE file. +# +import sphinx +from docutils.parsers.rst import directives + + +class EagerOnly(sphinx.directives.other.Only): + + def run(self, *args): + # Evaluate the condition eagerly, and if false return no nodes right away + env = self.state.document.settings.env + env.app.builder.tags.add('TRUE') + #print(repr(self.arguments[0])) + if not env.app.builder.tags.eval_condition(self.arguments[0]): + return [] + + # Otherwise, do the usual processing + nodes = super(EagerOnly, self).run() + if len(nodes) == 1: + nodes[0]['expr'] = 'TRUE' + return nodes + + +def setup(app): + directives.register_directive('only', EagerOnly) diff --git a/docs/sphinx_selective_exclude/modindex_exclude.py b/docs/sphinx_selective_exclude/modindex_exclude.py new file mode 100644 index 0000000000..18b49cc80f --- /dev/null +++ b/docs/sphinx_selective_exclude/modindex_exclude.py @@ -0,0 +1,75 @@ +# +# This is a Sphinx documentation tool extension which allows to +# exclude some Python modules from the generated indexes. Modules +# are excluded both from "modindex" and "genindex" index tables +# (in the latter case, all members of a module are exlcuded). +# To control exclusion, set "modindex_exclude" variable in Sphinx +# conf.py to the list of modules to exclude. Note: these should be +# modules (as defined by py:module directive, not just raw filenames). +# This extension works by monkey-patching Sphinx core, so potentially +# may not work with untested Sphinx versions. It tested to work with +# 1.2.2 and 1.4.2 +# +# Copyright (c) 2016 Paul Sokolovsky +# Licensed under the terms of BSD license, see LICENSE file. +# +import sphinx + + +#org_PythonModuleIndex_generate = None +org_PyObject_add_target_and_index = None +org_PyModule_run = None + +EXCLUDES = {} + +# No longer used, PyModule_run() monkey-patch does all the job +def PythonModuleIndex_generate(self, docnames=None): + docnames = [] + excludes = self.domain.env.config['modindex_exclude'] + for modname, (docname, synopsis, platforms, deprecated) in self.domain.data['modules'].items(): + #print(docname) + if modname not in excludes: + docnames.append(docname) + + return org_PythonModuleIndex_generate(self, docnames) + + +def PyObject_add_target_and_index(self, name_cls, sig, signode): + if hasattr(self.env, "ref_context"): + # Sphinx 1.4 + ref_context = self.env.ref_context + else: + # Sphinx 1.2 + ref_context = self.env.temp_data + modname = self.options.get( + 'module', ref_context.get('py:module')) + #print("*", modname, name_cls) + if modname in self.env.config['modindex_exclude']: + return None + return org_PyObject_add_target_and_index(self, name_cls, sig, signode) + + +def PyModule_run(self): + env = self.state.document.settings.env + modname = self.arguments[0].strip() + excl = env.config['modindex_exclude'] + if modname in excl: + self.options['noindex'] = True + EXCLUDES.setdefault(modname, []).append(env.docname) + return org_PyModule_run(self) + + +def setup(app): + app.add_config_value('modindex_exclude', [], 'html') + +# global org_PythonModuleIndex_generate +# org_PythonModuleIndex_generate = sphinx.domains.python.PythonModuleIndex.generate +# sphinx.domains.python.PythonModuleIndex.generate = PythonModuleIndex_generate + + global org_PyObject_add_target_and_index + org_PyObject_add_target_and_index = sphinx.domains.python.PyObject.add_target_and_index + sphinx.domains.python.PyObject.add_target_and_index = PyObject_add_target_and_index + + global org_PyModule_run + org_PyModule_run = sphinx.domains.python.PyModule.run + sphinx.domains.python.PyModule.run = PyModule_run diff --git a/docs/sphinx_selective_exclude/search_auto_exclude.py b/docs/sphinx_selective_exclude/search_auto_exclude.py new file mode 100644 index 0000000000..b8b326dd2c --- /dev/null +++ b/docs/sphinx_selective_exclude/search_auto_exclude.py @@ -0,0 +1,34 @@ +# +# This is a Sphinx documentation tool extension which allows to +# automatically exclude from full-text search index document +# which are not referenced via toctree::. It's intended to be +# used with toctrees conditional on only:: directive, with the +# idea being that if you didn't include it in the ToC, you don't +# want the docs being findable by search either (for example, +# because these docs contain information not pertinent to a +# particular product configuration). +# +# This extension depends on "eager_only" extension and won't work +# without it. +# +# Copyright (c) 2016 Paul Sokolovsky +# Licensed under the terms of BSD license, see LICENSE file. +# +import sphinx + + +org_StandaloneHTMLBuilder_index_page = None + + +def StandaloneHTMLBuilder_index_page(self, pagename, doctree, title): + if pagename not in self.env.files_to_rebuild: + if pagename != self.env.config.master_doc and 'orphan' not in self.env.metadata[pagename]: + print("Excluding %s from full-text index because it's not referenced in ToC" % pagename) + return + return org_StandaloneHTMLBuilder_index_page(self, pagename, doctree, title) + + +def setup(app): + global org_StandaloneHTMLBuilder_index_page + org_StandaloneHTMLBuilder_index_page = sphinx.builders.html.StandaloneHTMLBuilder.index_page + sphinx.builders.html.StandaloneHTMLBuilder.index_page = StandaloneHTMLBuilder_index_page diff --git a/docs/templates/versions.html b/docs/templates/versions.html index 6323024ecb..198630dd77 100644 --- a/docs/templates/versions.html +++ b/docs/templates/versions.html @@ -17,14 +17,12 @@ <dd><a href="{{ url }}">{{ slug }}</a></dd> {% endfor %} </dl> - <!-- <dl> <dt>Downloads</dt> {% for type, url in downloads %} <dd><a href="{{ url }}">{{ type }}</a></dd> {% endfor %} </dl> - --> <hr/> <dl> <dt>External links</dt> diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index 3bccf72dae..34dca769e9 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -25,8 +25,8 @@ SET_CHARGE_PUMP = const(0x8d) class SSD1306: - def __init__(self, height, external_vcc): - self.width = 128 + def __init__(self, width, height, external_vcc): + self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 @@ -73,9 +73,15 @@ class SSD1306: self.write_cmd(SET_NORM_INV | (invert & 1)) def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 self.write_cmd(SET_COL_ADDR) - self.write_cmd(0) - self.write_cmd(self.width - 1) + self.write_cmd(x0) + self.write_cmd(x1) self.write_cmd(SET_PAGE_ADDR) self.write_cmd(0) self.write_cmd(self.pages - 1) @@ -95,11 +101,11 @@ class SSD1306: class SSD1306_I2C(SSD1306): - def __init__(self, height, i2c, addr=0x3c, external_vcc=False): + def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): self.i2c = i2c self.addr = addr self.temp = bytearray(2) - super().__init__(height, external_vcc) + super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.temp[0] = 0x80 # Co=1, D/C#=0 @@ -119,7 +125,7 @@ class SSD1306_I2C(SSD1306): class SSD1306_SPI(SSD1306): - def __init__(self, height, spi, dc, res, cs, external_vcc=False): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): self.rate = 10 * 1024 * 1024 dc.init(dc.OUT, value=0) res.init(res.OUT, value=0) @@ -128,7 +134,7 @@ class SSD1306_SPI(SSD1306): self.dc = dc self.res = res self.cs = cs - super().__init__(height, external_vcc) + super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) diff --git a/esp8266/Makefile b/esp8266/Makefile index 65093d819b..00826cfe46 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -8,9 +8,12 @@ MICROPY_PY_USSL = 1 # include py core make definitions include ../py/py.mk +MPY_CROSS = ../mpy-cross/mpy-cross +MPY_TOOL = ../tools/mpy-tool.py MAKE_FROZEN = ../tools/make-frozen.py SCRIPTDIR = scripts +FROZEN_MPY_DIR = modules PORT ?= /dev/ttyACM0 BAUD ?= 115200 CROSS_COMPILE = xtensa-lx106-elf- @@ -131,6 +134,9 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -139,6 +145,7 @@ OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) +OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o #OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction @@ -163,11 +170,22 @@ $(BUILD)/frozen.c: $(wildcard $(SCRIPTDIR)/*) $(CONFVARS_FILE) $(ECHO) "Generating $@" $(Q)$(MAKE_FROZEN) $(SCRIPTDIR) > $@ +# to build .mpy files from .py files +$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ + +# to build frozen_mpy.c from all .mpy files +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ + .PHONY: deploy deploy: $(BUILD)/firmware-combined.bin $(ECHO) "Writing $< to the board" - $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $< + $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=8m 0 $< #$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $(BUILD)/firmware.elf-0x00000.bin 0x9000 $(BUILD)/firmware.elf-0x0[1-f]000.bin reset: diff --git a/esp8266/README.md b/esp8266/README.md index 0509a3799b..b9162e9585 100644 --- a/esp8266/README.md +++ b/esp8266/README.md @@ -1,12 +1,12 @@ MicroPython port to ESP8266 =========================== -This is a highly experimental port of MicroPython for the WiFi modules based +This is an experimental port of MicroPython for the WiFi modules based on Espressif ESP8266 chip. -WARNING: The port is highly experimental and any APIs are subject to change. +WARNING: The port is experimental and many APIs are subject to change. -Currently implemented features include: +Supported features include: - REPL (Python prompt) over UART0. - Garbage collector, exceptions. - Unicode support. @@ -19,6 +19,8 @@ Currently implemented features include: - 1-Wire and WS2812 (aka Neopixel) protocols support. - Internal filesystem using the flash. - WebREPL over WiFi from a browser (clients at https://github.com/micropython/webrepl). +- Modules for HTTP, MQTT, many other formats and protocols via + https://github.com/micropython/micropython-lib . Work-in-progress documentation is available at http://docs.micropython.org/en/latest/esp8266/ . @@ -39,6 +41,12 @@ $ git submodule update --init See the README in the repository root for more information about external dependencies. +The MicroPython cross-compiler must be built to pre-compile some of the +built-in scripts to bytecode. This can be done using: +```bash +$ make -C mpy-cross +``` + Then, to build MicroPython for the ESP8266, just run: ```bash $ cd esp8266 diff --git a/esp8266/eagle.rom.addr.v6.ld b/esp8266/eagle.rom.addr.v6.ld index 30e238f5a5..ce071a3bb9 100644 --- a/esp8266/eagle.rom.addr.v6.ld +++ b/esp8266/eagle.rom.addr.v6.ld @@ -47,25 +47,25 @@ PROVIDE ( _NMIExceptionVector = 0x40000020 ); PROVIDE ( _ResetHandler = 0x400000a4 ); PROVIDE ( _ResetVector = 0x40000080 ); PROVIDE ( _UserExceptionVector = 0x40000050 ); -PROVIDE ( __adddf3 = 0x4000c538 ); -PROVIDE ( __addsf3 = 0x4000c180 ); -PROVIDE ( __divdf3 = 0x4000cb94 ); +__adddf3 = 0x4000c538; +__addsf3 = 0x4000c180; +__divdf3 = 0x4000cb94; __divdi3 = 0x4000ce60; __divsi3 = 0x4000dc88; -PROVIDE ( __extendsfdf2 = 0x4000cdfc ); -PROVIDE ( __fixdfsi = 0x4000ccb8 ); -PROVIDE ( __fixunsdfsi = 0x4000cd00 ); -PROVIDE ( __fixunssfsi = 0x4000c4c4 ); -PROVIDE ( __floatsidf = 0x4000e2f0 ); -PROVIDE ( __floatsisf = 0x4000e2ac ); -PROVIDE ( __floatunsidf = 0x4000e2e8 ); -PROVIDE ( __floatunsisf = 0x4000e2a4 ); -PROVIDE ( __muldf3 = 0x4000c8f0 ); +__extendsfdf2 = 0x4000cdfc; +__fixdfsi = 0x4000ccb8; +__fixunsdfsi = 0x4000cd00; +__fixunssfsi = 0x4000c4c4; +__floatsidf = 0x4000e2f0; +__floatsisf = 0x4000e2ac; +__floatunsidf = 0x4000e2e8; +__floatunsisf = 0x4000e2a4; +__muldf3 = 0x4000c8f0; __muldi3 = 0x40000650; -PROVIDE ( __mulsf3 = 0x4000c3dc ); -PROVIDE ( __subdf3 = 0x4000c688 ); -PROVIDE ( __subsf3 = 0x4000c268 ); -PROVIDE ( __truncdfsf2 = 0x4000cd5c ); +__mulsf3 = 0x4000c3dc; +__subdf3 = 0x4000c688; +__subsf3 = 0x4000c268; +__truncdfsf2 = 0x4000cd5c; __udivdi3 = 0x4000d310; __udivsi3 = 0x4000e21c; __umoddi3 = 0x4000d770; diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c index 9f090a0973..3cc4610825 100644 --- a/esp8266/esp_mphal.c +++ b/esp8266/esp_mphal.c @@ -161,21 +161,21 @@ static int call_dupterm_read(void) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_obj_t read_m[3]; - mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_read, read_m); - read_m[2] = MP_OBJ_NEW_SMALL_INT(1); - mp_obj_t res = mp_call_method_n_kw(1, 0, read_m); + mp_obj_t readinto_m[3]; + mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_readinto, readinto_m); + readinto_m[2] = MP_STATE_PORT(dupterm_arr_obj); + mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m); if (res == mp_const_none) { nlr_pop(); return -2; } - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ); - if (bufinfo.len == 0) { + if (res == MP_OBJ_NEW_SMALL_INT(0)) { mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL); nlr_pop(); return -1; } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ); nlr_pop(); if (*(byte*)bufinfo.buf == interrupt_char) { mp_keyboard_interrupt(); diff --git a/esp8266/fatfs_port.c b/esp8266/fatfs_port.c index c62ae2e7dc..b87906f789 100644 --- a/esp8266/fatfs_port.c +++ b/esp8266/fatfs_port.c @@ -1,6 +1,43 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" #include "lib/fatfs/ff.h" -#include "lib/fatfs/diskio.h" +#include "timeutils.h" +#include "modpybrtc.h" DWORD get_fattime(void) { - return 0; + + // TODO: Optimize division (there's no HW division support on ESP8266, + // so it's expensive). + uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(secs, &tm); + + return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | + ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); } diff --git a/esp8266/main.c b/esp8266/main.c index 9cc955e44c..21bb6e0e0f 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -34,6 +34,7 @@ #include "py/stackctrl.h" #include "py/mphal.h" #include "py/gc.h" +#include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "gccollect.h" #include "user_interface.h" @@ -56,7 +57,9 @@ STATIC void mp_reset(void) { #endif MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); MP_STATE_PORT(term_obj) = MP_OBJ_NULL; + MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL; pin_init0(); + readline_init0(); #if MICROPY_MODULE_FROZEN pyexec_frozen_module("_boot.py"); pyexec_file("boot.py"); diff --git a/esp8266/modesp.c b/esp8266/modesp.c index 0c6cc423e1..99f063a756 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -46,6 +46,7 @@ #include "espneopixel.h" #include "espapa102.h" #include "modpyb.h" +#include "modpybrtc.h" #define MODESP_ESPCONN (0) @@ -540,8 +541,11 @@ STATIC mp_obj_t esp_sleep_type(mp_uint_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_sleep_type_obj, 0, 1, esp_sleep_type); STATIC mp_obj_t esp_deepsleep(mp_uint_t n_args, const mp_obj_t *args) { + uint32_t sleep_us = n_args > 0 ? mp_obj_get_int(args[0]) : 0; + // prepare for RTC reset at wake up + rtc_prepare_deepsleep(sleep_us); system_deep_sleep_set_option(n_args > 1 ? mp_obj_get_int(args[1]) : 0); - system_deep_sleep(n_args > 0 ? mp_obj_get_int(args[0]) : 0); + system_deep_sleep(sleep_us); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_deepsleep_obj, 0, 2, esp_deepsleep); diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 36872c9dff..80ae7ac2a0 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -103,6 +103,8 @@ STATIC mp_obj_t machine_deepsleep(void) { } } + // prepare for RTC reset at wake up + rtc_prepare_deepsleep(sleep_us); // put the device in a deep-sleep state system_deep_sleep_set_option(0); // default power down mode; TODO check this system_deep_sleep(sleep_us); diff --git a/esp8266/modnetwork.c b/esp8266/modnetwork.c index c0763ce0eb..7cfa3ff77a 100644 --- a/esp8266/modnetwork.c +++ b/esp8266/modnetwork.c @@ -142,7 +142,13 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) { struct bss_info *bs; STAILQ_FOREACH(bs, si->pbss, next) { mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + #if 1 + // struct bss_info::ssid_len is not documented in SDK API Guide, + // but is present in SDK headers since 1.4.0 + t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len); + #else t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid)); + #endif t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid)); t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel); t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi); diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c index 484d0d82fd..9685248034 100644 --- a/esp8266/modpybrtc.c +++ b/esp8266/modpybrtc.c @@ -120,6 +120,12 @@ uint64_t pyb_rtc_get_us_since_2000() { return (((uint64_t)rtc_ticks * cal) >> 12) + delta; }; +void rtc_prepare_deepsleep(uint64_t sleep_us) { + // RTC time will reset at wake up. Let's be preared for this. + int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us; + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); +} + STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 1) { // Get time diff --git a/esp8266/modpybrtc.h b/esp8266/modpybrtc.h index b4ca780712..5b9d9fc766 100644 --- a/esp8266/modpybrtc.h +++ b/esp8266/modpybrtc.h @@ -30,3 +30,5 @@ extern uint64_t pyb_rtc_alarm0_expiry; void pyb_rtc_set_us_since_2000(uint64_t nowus); uint64_t pyb_rtc_get_us_since_2000(); + +void rtc_prepare_deepsleep(uint64_t sleep_us); diff --git a/esp8266/modpybuart.c b/esp8266/modpybuart.c index 5971ffecec..f27ee4e2d2 100644 --- a/esp8266/modpybuart.c +++ b/esp8266/modpybuart.c @@ -36,32 +36,39 @@ #include "py/mperrno.h" #include "modpyb.h" -// baudrate is currently fixed to this value -#define UART_BAUDRATE (115200) +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; typedef struct _pyb_uart_obj_t { mp_obj_base_t base; uint8_t uart_id; + uint8_t bits; + uint8_t parity; + uint8_t stop; + uint32_t baudrate; uint16_t timeout; // timeout waiting for first char (in ms) uint16_t timeout_char; // timeout waiting between chars (in ms) } pyb_uart_obj_t; +STATIC const char *_parity_name[] = {"None", "1", "0"}; + /******************************************************************************/ // MicroPython bindings for UART STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "UART(%u, baudrate=%u, timeout=%u, timeout_char=%u)", - self->uart_id, UART_BAUDRATE, self->timeout, self->timeout_char); + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, timeout=%u, timeout_char=%u)", + self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], + self->stop, self->timeout, self->timeout_char); } STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_timeout, ARG_timeout_char }; + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_timeout_char }; static const mp_arg_t allowed_args[] = { - //{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, - //{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, - //{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - //{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, //{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, //{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, @@ -70,16 +77,84 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // set baudrate + if (args[ARG_baudrate].u_int > 0) { + self->baudrate = args[ARG_baudrate].u_int; + UartDev.baut_rate = self->baudrate; // Sic! + } + + // set data bits + switch (args[ARG_bits].u_int) { + case 0: + break; + case 5: + UartDev.data_bits = UART_FIVE_BITS; + self->bits = 5; + break; + case 6: + UartDev.data_bits = UART_SIX_BITS; + self->bits = 6; + break; + case 7: + UartDev.data_bits = UART_SEVEN_BITS; + self->bits = 7; + break; + case 8: + UartDev.data_bits = UART_EIGHT_BITS; + self->bits = 8; + break; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid data bits")); + break; + } + + // set parity + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + UartDev.parity = UART_NONE_BITS; + self->parity = 0; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + if (parity & 1) { + UartDev.parity = UART_ODD_BITS; + self->parity = 1; + } else { + UartDev.parity = UART_EVEN_BITS; + self->parity = 2; + } + } + } + + // set stop bits + switch (args[ARG_stop].u_int) { + case 0: + break; + case 1: + UartDev.stop_bits = UART_ONE_STOP_BIT; + self->stop = 1; + break; + case 2: + UartDev.stop_bits = UART_TWO_STOP_BIT; + self->stop = 2; + break; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid stop bits")); + break; + } + // set timeout self->timeout = args[ARG_timeout].u_int; // set timeout_char // make sure it is at least as long as a whole character (13 bits to be safe) self->timeout_char = args[ARG_timeout_char].u_int; - uint32_t min_timeout_char = 13000 / UART_BAUDRATE + 1; + uint32_t min_timeout_char = 13000 / self->baudrate + 1; if (self->timeout_char < min_timeout_char) { self->timeout_char = min_timeout_char; } + + // setup + uart_setup(self->uart_id); } STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -95,6 +170,12 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size pyb_uart_obj_t *self = m_new_obj(pyb_uart_obj_t); self->base.type = &pyb_uart_type; self->uart_id = uart_id; + self->baudrate = 115200; + self->bits = 8; + self->parity = 0; + self->stop = 1; + self->timeout = 0; + self->timeout_char = 0; // init the peripheral mp_map_t kw_args; @@ -191,6 +272,6 @@ const mp_obj_type_t pyb_uart_type = { .make_new = pyb_uart_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &uart_stream_p, + .protocol = &uart_stream_p, .locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict, }; diff --git a/esp8266/scripts/_boot.py b/esp8266/modules/_boot.py index c950de6758..2cacb56760 100644 --- a/esp8266/scripts/_boot.py +++ b/esp8266/modules/_boot.py @@ -1,3 +1,4 @@ +import gc import uos from flashbdev import bdev @@ -7,3 +8,5 @@ try: except OSError: import inisetup vfs = inisetup.setup() + +gc.collect() diff --git a/esp8266/scripts/flashbdev.py b/esp8266/modules/flashbdev.py index 07ed966020..07ed966020 100644 --- a/esp8266/scripts/flashbdev.py +++ b/esp8266/modules/flashbdev.py diff --git a/esp8266/scripts/webrepl.py b/esp8266/modules/webrepl.py index da3e70c595..da3e70c595 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/modules/webrepl.py diff --git a/esp8266/scripts/webrepl_setup.py b/esp8266/modules/webrepl_setup.py index d0bf8465d5..d0bf8465d5 100644 --- a/esp8266/scripts/webrepl_setup.py +++ b/esp8266/modules/webrepl_setup.py diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 544edc408f..90dbc00098 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -74,7 +74,9 @@ #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_FROZEN_STR (1) +#define MICROPY_MODULE_FROZEN_MPY (1) #define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32 +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool #define MICROPY_FATFS_ENABLE_LFN (1) #define MICROPY_FATFS_RPATH (2) diff --git a/esp8266/scripts/inisetup.py b/esp8266/scripts/inisetup.py index 461690b162..7d8f6fa0a8 100644 --- a/esp8266/scripts/inisetup.py +++ b/esp8266/scripts/inisetup.py @@ -40,7 +40,9 @@ def setup(): with open("/boot.py", "w") as f: f.write("""\ # This file is executed on every boot (including wake-boot from deepsleep) +import gc #import webrepl #webrepl.start() +gc.collect() """) return vfs diff --git a/esp8266/scripts/websocket_helper.py b/esp8266/scripts/websocket_helper.py index 22ac28592d..9c06db5023 100644 --- a/esp8266/scripts/websocket_helper.py +++ b/esp8266/scripts/websocket_helper.py @@ -36,21 +36,20 @@ def server_handshake(sock): if DEBUG: print("Sec-WebSocket-Key:", webkey, len(webkey)) - respkey = webkey + b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - respkey = hashlib.sha1(respkey).digest() + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) - resp = b"""\ + sock.send(b"""\ HTTP/1.1 101 Switching Protocols\r Upgrade: websocket\r Connection: Upgrade\r -Sec-WebSocket-Accept: %s\r -\r -""" % respkey - - if DEBUG: - print(resp) - sock.send(resp) +Sec-WebSocket-Accept: """) + sock.send(respkey) + sock.send("\r\n\r\n") # Very simplified client handshake, works for MicroPython's diff --git a/esp8266/uart.c b/esp8266/uart.c index 1c317a1cb6..d724331c41 100644 --- a/esp8266/uart.c +++ b/esp8266/uart.c @@ -237,6 +237,12 @@ void ICACHE_FLASH_ATTR uart_reattach() { uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880); } +void ICACHE_FLASH_ATTR uart_setup(uint8 uart) { + ETS_UART_INTR_DISABLE(); + uart_config(uart); + ETS_UART_INTR_ENABLE(); +} + // Task-based UART interface #include "py/obj.h" diff --git a/esp8266/uart.h b/esp8266/uart.h index 8e09beea58..21894d3fa6 100644 --- a/esp8266/uart.h +++ b/esp8266/uart.h @@ -96,5 +96,6 @@ int uart_rx_char(void); void uart_tx_one_char(uint8 uart, uint8 TxChar); void uart_flush(uint8 uart); void uart_os_config(int uart); +void uart_setup(uint8 uart); #endif // _INCLUDED_UART_H_ diff --git a/examples/unix/ffi_example.py b/examples/unix/ffi_example.py index bc3919d40a..f650e33708 100644 --- a/examples/unix/ffi_example.py +++ b/examples/unix/ffi_example.py @@ -5,9 +5,9 @@ print("libc:", libc) print() # Declare few functions -perror = libc.func("v", "perror", ["s"]) +perror = libc.func("v", "perror", "s") time = libc.func("i", "time", "p") -open = libc.func("i", "open", ["s", "i"]) +open = libc.func("i", "open", "si") qsort = libc.func("v", "qsort", "piip") # And one variable errno = libc.var("i", "errno") @@ -18,8 +18,8 @@ print() perror("ffi before error") open("somethingnonexistent__", 0) -print(errno) -print(errno.get()) +print("errno object:", errno) +print("errno value:", errno.get()) perror("ffi after error") print() @@ -32,8 +32,7 @@ def cmp(pa, pb): cmp_c = ffi.callback("i", cmp, "pp") print("callback:", cmp_c) -# TODO: violates Py semantics, pass bytearray -s = "foobar" +s = bytearray(b"foobar") print("org string:", s) qsort(s, len(s), 1, cmp_c) -print("qsort'ed:", s) +print("qsort'ed string:", s) diff --git a/extmod/machine_pinbase.c b/extmod/machine_pinbase.c new file mode 100644 index 0000000000..3c1f094834 --- /dev/null +++ b/extmod/machine_pinbase.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_MACHINE + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/virtpin.h" + +// PinBase class + +// As this is abstract class, its instance is null. +// But there should be an instance, as the rest of instance code +// expects that there will be concrete object for inheritance. +typedef struct _mp_pinbase_t { + mp_obj_base_t base; +} mp_pinbase_t; + +STATIC const mp_obj_type_t pinbase_type; + +STATIC mp_pinbase_t pinbase_singleton = { + .base = { &pinbase_type }, +}; + +STATIC mp_obj_t pinbase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)args; + return MP_OBJ_FROM_PTR(&pinbase_singleton); +} + +mp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); +mp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + switch (request) { + case MP_PIN_READ: { + mp_obj_t dest[2]; + mp_load_method(obj, MP_QSTR_value, dest); + return mp_obj_get_int(mp_call_method_n_kw(0, 0, dest)); + } + case MP_PIN_WRITE: { + mp_obj_t dest[3]; + mp_load_method(obj, MP_QSTR_value, dest); + dest[2] = (arg == 0 ? mp_const_false : mp_const_true); + mp_call_method_n_kw(1, 0, dest); + return 0; + } + } + return -1; +} + +STATIC const mp_pin_p_t pinbase_pin_p = { + .ioctl = pinbase_ioctl, +}; + +const mp_obj_type_t machine_pinbase_type = { + { &mp_type_type }, + .name = MP_QSTR_PinBase, + .make_new = pinbase_make_new, + .protocol = &pinbase_pin_p, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/extmod/machine_pinbase.h b/extmod/machine_pinbase.h new file mode 100644 index 0000000000..ece3384cc6 --- /dev/null +++ b/extmod/machine_pinbase.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef __MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H__ +#define __MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H__ + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pinbase_type; + +#endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H__ diff --git a/extmod/modbtree.c b/extmod/modbtree.c new file mode 100644 index 0000000000..0a0c5271c0 --- /dev/null +++ b/extmod/modbtree.c @@ -0,0 +1,353 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include "py/nlr.h" +#include "py/runtime.h" + +#if MICROPY_PY_BTREE + +#include <db.h> +#include <../../btree/btree.h> + +typedef struct _mp_obj_btree_t { + mp_obj_base_t base; + DB *db; + mp_obj_t start_key; + mp_obj_t end_key; + #define FLAG_END_KEY_INCL 1 + #define FLAG_DESC 2 + #define FLAG_ITER_TYPE_MASK 0xc0 + #define FLAG_ITER_KEYS 0x40 + #define FLAG_ITER_VALUES 0x80 + #define FLAG_ITER_ITEMS 0xc0 + byte flags; + byte next_flags; +} mp_obj_btree_t; + +STATIC const mp_obj_type_t btree_type; + +#define CHECK_ERROR(res) \ + if (res == RET_ERROR) { \ + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno))); \ + } + +void __dbpanic(DB *db) { + printf("__dbpanic(%p)\n", db); +} + +STATIC mp_obj_btree_t *btree_new(DB *db) { + mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t); + o->base.type = &btree_type; + o->db = db; + o->start_key = mp_const_none; + o->end_key = mp_const_none; + o->next_flags = 0; + return o; +} + +STATIC void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<btree %p>", self->db); +} + +STATIC mp_obj_t btree_close(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_close_obj, btree_close); + +STATIC mp_obj_t btree_put(size_t n_args, const mp_obj_t *args) { + (void)n_args; + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + DBT key, val; + // Different ports may have different type sizes + mp_uint_t v; + key.data = (void*)mp_obj_str_get_data(args[1], &v); + key.size = v; + val.data = (void*)mp_obj_str_get_data(args[2], &v); + val.size = v; + return MP_OBJ_NEW_SMALL_INT(__bt_put(self->db, &key, &val, 0)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_put_obj, 3, 4, btree_put); + +STATIC mp_obj_t btree_get(size_t n_args, const mp_obj_t *args) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + DBT key, val; + // Different ports may have different type sizes + mp_uint_t v; + key.data = (void*)mp_obj_str_get_data(args[1], &v); + key.size = v; + int res = __bt_get(self->db, &key, &val, 0); + if (res == RET_SPECIAL) { + if (n_args > 2) { + return args[2]; + } else { + return mp_const_none; + } + } + CHECK_ERROR(res); + return mp_obj_new_bytes(val.data, val.size); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_get_obj, 2, 3, btree_get); + +STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + int flags = MP_OBJ_SMALL_INT_VALUE(args[1]); + DBT key, val; + if (n_args > 2) { + // Different ports may have different type sizes + mp_uint_t v; + key.data = (void*)mp_obj_str_get_data(args[2], &v); + key.size = v; + } + + int res = __bt_seq(self->db, &key, &val, flags); + if (res == RET_SPECIAL) { + return mp_const_none; + } + + mp_obj_t pair_o = mp_obj_new_tuple(2, NULL); + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o); + pair->items[0] = mp_obj_new_bytes(key.data, key.size); + pair->items[1] = mp_obj_new_bytes(val.data, val.size); + return pair_o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_seq_obj, 2, 4, btree_seq); + +STATIC mp_obj_t btree_init_iter(size_t n_args, const mp_obj_t *args, byte type) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + self->next_flags = type; + self->start_key = mp_const_none; + self->end_key = mp_const_none; + if (n_args > 1) { + self->start_key = args[1]; + if (n_args > 2) { + self->end_key = args[2]; + if (n_args > 3) { + self->next_flags = type | MP_OBJ_SMALL_INT_VALUE(args[3]); + } + } + } + return args[0]; +} + +STATIC mp_obj_t btree_keys(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_KEYS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_keys_obj, 1, 4, btree_keys); + +STATIC mp_obj_t btree_values(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_VALUES); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_values_obj, 1, 4, btree_values); + +STATIC mp_obj_t btree_items(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_ITEMS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_items_obj, 1, 4, btree_items); + +STATIC mp_obj_t btree_getiter(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + if (self->next_flags != 0) { + // If we're called immediately after keys(), values(), or items(), + // use their setup for iteration. + self->flags = self->next_flags; + self->next_flags = 0; + } else { + // Otherwise, iterate over all keys. + self->flags = FLAG_ITER_KEYS; + self->start_key = mp_const_none; + self->end_key = mp_const_none; + } + + return self_in; +} + +STATIC mp_obj_t btree_iternext(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + DBT key, val; + int res; + // Different ports may have different type sizes + mp_uint_t v; + bool desc = self->flags & FLAG_DESC; + if (self->start_key != MP_OBJ_NULL) { + int flags = R_FIRST; + if (self->start_key != mp_const_none) { + key.data = (void*)mp_obj_str_get_data(self->start_key, &v); + key.size = v; + flags = R_CURSOR; + } else if (desc) { + flags = R_LAST; + } + res = __bt_seq(self->db, &key, &val, flags); + self->start_key = MP_OBJ_NULL; + } else { + res = __bt_seq(self->db, &key, &val, desc ? R_PREV : R_NEXT); + } + + if (res == RET_SPECIAL) { + return MP_OBJ_STOP_ITERATION; + } + CHECK_ERROR(res); + + if (self->end_key != mp_const_none) { + DBT end_key; + end_key.data = (void*)mp_obj_str_get_data(self->end_key, &v); + end_key.size = v; + BTREE *t = self->db->internal; + int cmp = t->bt_cmp(&key, &end_key); + if (desc) { + cmp = -cmp; + } + if (self->flags & FLAG_END_KEY_INCL) { + cmp--; + } + if (cmp >= 0) { + self->end_key = MP_OBJ_NULL; + return MP_OBJ_STOP_ITERATION; + } + } + + switch (self->flags & FLAG_ITER_TYPE_MASK) { + case FLAG_ITER_KEYS: + return mp_obj_new_bytes(key.data, key.size); + case FLAG_ITER_VALUES: + return mp_obj_new_bytes(val.data, val.size); + default: { + mp_obj_t pair_o = mp_obj_new_tuple(2, NULL); + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o); + pair->items[0] = mp_obj_new_bytes(key.data, key.size); + pair->items[1] = mp_obj_new_bytes(val.data, val.size); + return pair_o; + } + } +} + +STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + // Different ports may have different type sizes + mp_uint_t v; + if (value == MP_OBJ_NULL) { + // delete + DBT key; + key.data = (void*)mp_obj_str_get_data(index, &v); + key.size = v; + int res = __bt_delete(self->db, &key, 0); + if (res == RET_SPECIAL) { + nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + } + CHECK_ERROR(res); + return mp_const_none; + } else if (value == MP_OBJ_SENTINEL) { + // load + DBT key, val; + key.data = (void*)mp_obj_str_get_data(index, &v); + key.size = v; + int res = __bt_get(self->db, &key, &val, 0); + if (res == RET_SPECIAL) { + nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + } + CHECK_ERROR(res); + return mp_obj_new_bytes(val.data, val.size); + } else { + // store + DBT key, val; + key.data = (void*)mp_obj_str_get_data(index, &v); + key.size = v; + val.data = (void*)mp_obj_str_get_data(value, &v); + val.size = v; + int res = __bt_put(self->db, &key, &val, 0); + CHECK_ERROR(res); + return mp_const_none; + } +} + +STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&btree_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&btree_put_obj) }, + { MP_ROM_QSTR(MP_QSTR_seq), MP_ROM_PTR(&btree_seq_obj) }, + { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&btree_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&btree_values_obj) }, + { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&btree_items_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table); + +STATIC const mp_obj_type_t btree_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_btree, + .print = btree_print, + .getiter = btree_getiter, + .iternext = btree_iternext, + .subscr = btree_subscr, + .locals_dict = (void*)&btree_locals_dict, +}; + +STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + const char *fname = NULL; + if (pos_args[0] != mp_const_none) { + fname = mp_obj_str_get_str(pos_args[0]); + } + + struct { + mp_arg_val_t server_side; + } args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + DB *db = __bt_open(fname, /*flags*/O_CREAT | O_RDWR, /*mode*/0770, /*openinfo*/NULL, /*dflags*/0); + return MP_OBJ_FROM_PTR(btree_new(db)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open); + +STATIC const mp_rom_map_elem_t mp_module_btree_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_btree) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_btree_open_obj) }, + { MP_ROM_QSTR(MP_QSTR_INCL), MP_ROM_INT(FLAG_END_KEY_INCL) }, + { MP_ROM_QSTR(MP_QSTR_DESC), MP_ROM_INT(FLAG_DESC) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_table); + +const mp_obj_module_t mp_module_btree = { + .base = { &mp_type_module }, + .name = MP_QSTR_btree, + .globals = (mp_obj_dict_t*)&mp_module_btree_globals, +}; + +#endif // MICROPY_PY_BTREE diff --git a/extmod/modlwip.c b/extmod/modlwip.c index cb7cc6596f..80df662647 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -239,7 +239,7 @@ typedef struct _lwip_socket_obj_t { byte peer[4]; mp_uint_t peer_port; mp_uint_t timeout; - uint16_t leftover_count; + uint16_t recv_offset; uint8_t domain; uint8_t type; @@ -354,11 +354,17 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err socket->state = STATE_PEER_CLOSED; exec_user_callback(socket); return ERR_OK; - } else if (socket->incoming.pbuf != NULL) { - // No room in the inn, let LWIP know it's still responsible for delivery later + } + + if (socket->incoming.pbuf == NULL) { + socket->incoming.pbuf = p; + } else { + #ifdef SOCKET_SINGLE_PBUF return ERR_BUF; + #else + pbuf_cat(socket->incoming.pbuf, p); + #endif } - socket->incoming.pbuf = p; exec_user_callback(socket); @@ -536,22 +542,28 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ struct pbuf *p = socket->incoming.pbuf; - if (socket->leftover_count == 0) { - socket->leftover_count = p->tot_len; + mp_uint_t remaining = p->len - socket->recv_offset; + if (len > remaining) { + len = remaining; } - u16_t result = pbuf_copy_partial(p, buf, ((socket->leftover_count >= len) ? len : socket->leftover_count), (p->tot_len - socket->leftover_count)); - if (socket->leftover_count > len) { - // More left over... - socket->leftover_count -= len; - } else { + memcpy(buf, (byte*)p->payload + socket->recv_offset, len); + + remaining -= len; + if (remaining == 0) { + socket->incoming.pbuf = p->next; + // If we don't ref here, free() will free the entire chain, + // if we ref, it does what we need: frees 1st buf, and decrements + // next buf's refcount back to 1. + pbuf_ref(p->next); pbuf_free(p); - socket->incoming.pbuf = NULL; - socket->leftover_count = 0; + socket->recv_offset = 0; + } else { + socket->recv_offset += len; } + tcp_recved(socket->pcb.tcp, len); - tcp_recved(socket->pcb.tcp, result); - return (mp_uint_t) result; + return len; } /*******************************************************************************/ @@ -561,8 +573,8 @@ STATIC const mp_obj_type_t lwip_socket_type; STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { lwip_socket_obj_t *self = self_in; - mp_printf(print, "<socket state=%d timeout=%d incoming=%p remaining=%d>", self->state, self->timeout, - self->incoming.pbuf, self->leftover_count); + mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout, + self->incoming.pbuf, self->recv_offset); } // FIXME: Only supports two arguments at present @@ -612,7 +624,7 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args socket->incoming.pbuf = NULL; socket->timeout = -1; socket->state = STATE_NEW; - socket->leftover_count = 0; + socket->recv_offset = 0; return socket; } @@ -749,7 +761,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { socket2->incoming.pbuf = NULL; socket2->timeout = socket->timeout; socket2->state = STATE_CONNECTED; - socket2->leftover_count = 0; + socket2->recv_offset = 0; socket2->callback = MP_OBJ_NULL; tcp_arg(socket2->pcb.tcp, (void*)socket2); tcp_err(socket2->pcb.tcp, _lwip_tcp_error); @@ -1148,7 +1160,7 @@ STATIC const mp_obj_type_t lwip_socket_type = { .name = MP_QSTR_socket, .print = lwip_socket_print, .make_new = lwip_socket_make_new, - .stream_p = &lwip_socket_stream_p, + .protocol = &lwip_socket_stream_p, .locals_dict = (mp_obj_t)&lwip_socket_locals_dict, }; diff --git a/extmod/moduos_dupterm.c b/extmod/moduos_dupterm.c index 4c9f9e4940..d888099dff 100644 --- a/extmod/moduos_dupterm.c +++ b/extmod/moduos_dupterm.c @@ -31,6 +31,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/objtuple.h" +#include "py/objarray.h" #include "py/stream.h" #if MICROPY_PY_OS_DUPTERM @@ -51,8 +52,16 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { if (nlr_push(&nlr) == 0) { mp_obj_t write_m[3]; mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_write, write_m); - write_m[2] = mp_obj_new_bytearray_by_ref(len, (char*)str); + + mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + void *org_items = arr->items; + arr->items = (void*)str; + arr->len = len; + write_m[2] = MP_STATE_PORT(dupterm_arr_obj); mp_call_method_n_kw(1, 0, write_m); + arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + arr->items = org_items; + arr->len = 1; nlr_pop(); } else { mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); @@ -69,9 +78,12 @@ STATIC mp_obj_t mp_uos_dupterm(mp_uint_t n_args, const mp_obj_t *args) { } } else { if (args[0] == mp_const_none) { - MP_STATE_PORT(term_obj) = NULL; + MP_STATE_PORT(term_obj) = MP_OBJ_NULL; } else { MP_STATE_PORT(term_obj) = args[0]; + if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) { + MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); + } } return mp_const_none; } diff --git a/extmod/modussl.c b/extmod/modussl.c index 567033cf48..4a3e297e1e 100644 --- a/extmod/modussl.c +++ b/extmod/modussl.c @@ -156,7 +156,7 @@ STATIC const mp_obj_type_t ussl_socket_type = { .print = socket_print, .getiter = NULL, .iternext = NULL, - .stream_p = &ussl_socket_stream_p, + .protocol = &ussl_socket_stream_p, .locals_dict = (void*)&ussl_socket_locals_dict, }; @@ -202,7 +202,8 @@ int mp_stream_errno; ssize_t mp_stream_posix_write(void *sock_obj, const void *buf, size_t len) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)sock_obj; - mp_uint_t out_sz = o->type->stream_p->write(o, buf, len, &mp_stream_errno); + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->write(o, buf, len, &mp_stream_errno); if (out_sz == MP_STREAM_ERROR) { return -1; } else { @@ -212,7 +213,8 @@ ssize_t mp_stream_posix_write(void *sock_obj, const void *buf, size_t len) { ssize_t mp_stream_posix_read(void *sock_obj, void *buf, size_t len) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)sock_obj; - mp_uint_t out_sz = o->type->stream_p->read(o, buf, len, &mp_stream_errno); + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->read(o, buf, len, &mp_stream_errno); if (out_sz == MP_STREAM_ERROR) { return -1; } else { diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 8ecab922aa..4f7b924e07 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -303,6 +303,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password) STATIC const mp_map_elem_t webrepl_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&webrepl_close_obj }, }; @@ -317,7 +318,7 @@ STATIC const mp_obj_type_t webrepl_type = { { &mp_type_type }, .name = MP_QSTR__webrepl, .make_new = webrepl_make_new, - .stream_p = &webrepl_stream_p, + .protocol = &webrepl_stream_p, .locals_dict = (mp_obj_t)&webrepl_locals_dict, }; diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index fc5e29a05e..6354633af4 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -282,6 +282,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); STATIC const mp_map_elem_t websocket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&mp_stream_ioctl_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&websocket_close_obj }, @@ -298,7 +299,7 @@ STATIC const mp_obj_type_t websocket_type = { { &mp_type_type }, .name = MP_QSTR_websocket, .make_new = websocket_make_new, - .stream_p = &websocket_stream_p, + .protocol = &websocket_stream_p, .locals_dict = (mp_obj_t)&websocket_locals_dict, }; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index a4a81370f9..df5cbb0d62 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -186,7 +186,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { if (path_equal(path, "/")) { // stat root directory fno.fsize = 0; - fno.fdate = 0; + fno.fdate = 0x2821; // Jan 1, 2000 fno.ftime = 0; fno.fattrib = AM_DIR; } else { @@ -196,7 +196,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { if (vfs != NULL && path_equal(path, vfs->str)) { // stat mounted device directory fno.fsize = 0; - fno.fdate = 0; + fno.fdate = 0x2821; // Jan 1, 2000 fno.ftime = 0; fno.fattrib = AM_DIR; res = FR_OK; diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 857cd1f470..0cd61e4605 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -259,7 +259,7 @@ const mp_obj_type_t mp_type_fileio = { .make_new = file_obj_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &fileio_stream_p, + .protocol = &fileio_stream_p, .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, }; #endif @@ -278,7 +278,7 @@ const mp_obj_type_t mp_type_textio = { .make_new = file_obj_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &textio_stream_p, + .protocol = &textio_stream_p, .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, }; diff --git a/extmod/virtpin.c b/extmod/virtpin.c index a5817ab4d0..dbfa21d669 100644 --- a/extmod/virtpin.c +++ b/extmod/virtpin.c @@ -28,12 +28,12 @@ int mp_virtual_pin_read(mp_obj_t pin) { mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); - mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol; return pin_p->ioctl(pin, MP_PIN_READ, 0, NULL); } void mp_virtual_pin_write(mp_obj_t pin, int value) { mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); - mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol; pin_p->ioctl(pin, MP_PIN_WRITE, value, NULL); } diff --git a/lib/berkeley-db-1.xx b/lib/berkeley-db-1.xx new file mode 160000 +Subproject 7b31cae3c0892a7fca2089cb0354a4920c98c41 diff --git a/lib/fatfs/option/ccsbcs.c b/lib/fatfs/option/ccsbcs.c index 3d1a785b86..e35e15cd91 100644 --- a/lib/fatfs/option/ccsbcs.c +++ b/lib/fatfs/option/ccsbcs.c @@ -493,10 +493,7 @@ const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */ #endif
-#if !_TBLDEF || !_USE_LFN
-#error This file is not needed in current configuration. Remove from the project.
-#endif
-
+#if _TBLDEF && _USE_LFN
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR chr, /* Character code to be converted */
@@ -571,3 +568,5 @@ WCHAR ff_wtoupper ( /* Upper converted character */ return tbl_lower[i] ? tbl_upper[i] : chr;
}
+
+#endif
diff --git a/lib/libm/kf_rem_pio2.c b/lib/libm/kf_rem_pio2.c index 48b1547203..e267b65f9a 100644 --- a/lib/libm/kf_rem_pio2.c +++ b/lib/libm/kf_rem_pio2.c @@ -86,7 +86,8 @@ twon8 = 3.9062500000e-03; /* 0x3b800000 */ /* compute q[0],q[1],...q[jk] */ for (i=0;i<=jk;i++) { - for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; } jz = jk; diff --git a/lib/libm/sf_cos.c b/lib/libm/sf_cos.c index 5776ef46bb..33cde50e28 100644 --- a/lib/libm/sf_cos.c +++ b/lib/libm/sf_cos.c @@ -25,12 +25,6 @@ #include "fdlibm.h" #ifdef __STDC__ -static const float one=1.0; -#else -static float one=1.0; -#endif - -#ifdef __STDC__ float cosf(float x) #else float cosf(x) diff --git a/mpy-cross/gccollect.c b/mpy-cross/gccollect.c index 4e7e5178a7..75891a2fb5 100644 --- a/mpy-cross/gccollect.c +++ b/mpy-cross/gccollect.c @@ -142,7 +142,7 @@ void gc_collect(void) { gc_helper_get_regs(regs); // GC stack (and regs because we captured them) void **regs_ptr = (void**)(void*)®s; - gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t)); + gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t)); #if MICROPY_EMIT_NATIVE mp_unix_mark_exec(); #endif diff --git a/pic16bit/main.c b/pic16bit/main.c index b8e9b46ead..fcc51b6617 100644 --- a/pic16bit/main.c +++ b/pic16bit/main.c @@ -64,7 +64,7 @@ soft_reset: // init MicroPython runtime int stack_dummy; - MP_STATE_VM(stack_top) = (char*)&stack_dummy; + MP_STATE_THREAD(stack_top) = (char*)&stack_dummy; gc_init(heap, heap + sizeof(heap)); mp_init(); mp_hal_init(); @@ -93,7 +93,7 @@ void gc_collect(void) { void *dummy; gc_collect_start(); // Node: stack is ascending - gc_collect_root(&dummy, ((mp_uint_t)&dummy - (mp_uint_t)MP_STATE_VM(stack_top)) / sizeof(mp_uint_t)); + gc_collect_root(&dummy, ((mp_uint_t)&dummy - (mp_uint_t)MP_STATE_THREAD(stack_top)) / sizeof(mp_uint_t)); gc_collect_end(); } diff --git a/py/builtin.h b/py/builtin.h index 5d79d2835e..cd1be3ab88 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -94,6 +94,7 @@ extern const mp_obj_module_t mp_module_micropython; extern const mp_obj_module_t mp_module_ustruct; extern const mp_obj_module_t mp_module_sys; extern const mp_obj_module_t mp_module_gc; +extern const mp_obj_module_t mp_module_thread; extern const mp_obj_dict_t mp_module_builtins_globals; @@ -113,6 +114,7 @@ extern const mp_obj_module_t mp_module_lwip; extern const mp_obj_module_t mp_module_websocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; +extern const mp_obj_module_t mp_module_btree; // extmod functions MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj); diff --git a/py/builtinimport.c b/py/builtinimport.c index d3670858e5..ef3545d653 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -462,7 +462,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { vstr_add_str(&path, "__init__.py"); if (mp_import_stat_any(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py - mp_warning("%s is imported as namespace package", vstr_str(&path)); + //mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { do_load(module_obj, &path); vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py @@ -94,6 +94,14 @@ #define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0) #endif +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +#define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1) +#define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex)) +#else +#define GC_ENTER() +#define GC_EXIT() +#endif + // TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool void gc_init(void *start, void *end) { // align end pointer on block boundary @@ -144,6 +152,10 @@ void gc_init(void *start, void *end) { // allow auto collection MP_STATE_MEM(gc_auto_collect_enabled) = 1; + #if MICROPY_PY_THREAD + mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); + #endif + DEBUG_printf("GC layout:\n"); DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); #if MICROPY_ENABLE_FINALISER @@ -153,11 +165,15 @@ void gc_init(void *start, void *end) { } void gc_lock(void) { + GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; + GC_EXIT(); } void gc_unlock(void) { + GC_ENTER(); MP_STATE_MEM(gc_lock_depth)--; + GC_EXIT(); } bool gc_is_locked(void) { @@ -236,6 +252,10 @@ STATIC void gc_sweep(void) { case AT_HEAD: #if MICROPY_ENABLE_FINALISER if (FTB_GET(block)) { + #if MICROPY_PY_THREAD + // TODO need to think about reentrancy with finaliser code + assert(!"finaliser with threading not implemented"); + #endif mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block); if (obj->type != NULL) { // if the object has a type then see if it has a __del__ method @@ -272,14 +292,15 @@ STATIC void gc_sweep(void) { } void gc_collect_start(void) { - gc_lock(); + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, // dict_globals, then the root pointer section of mp_state_vm. void **ptrs = (void**)(void*)&mp_state_ctx; - gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(void*)); + gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*)); } void gc_collect_root(void **ptrs, size_t len) { @@ -294,31 +315,26 @@ void gc_collect_end(void) { gc_deal_with_stack_overflow(); gc_sweep(); MP_STATE_MEM(gc_last_free_atb_index) = 0; - gc_unlock(); + MP_STATE_MEM(gc_lock_depth)--; + GC_EXIT(); } void gc_info(gc_info_t *info) { + GC_ENTER(); info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start); info->used = 0; info->free = 0; + info->max_free = 0; info->num_1block = 0; info->num_2block = 0; info->max_block = 0; - for (size_t block = 0, len = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { + bool finish = false; + for (size_t block = 0, len = 0, len_free = 0; !finish;) { size_t kind = ATB_GET_KIND(block); - if (kind == AT_FREE || kind == AT_HEAD) { - if (len == 1) { - info->num_1block += 1; - } else if (len == 2) { - info->num_2block += 1; - } - if (len > info->max_block) { - info->max_block = len; - } - } switch (kind) { case AT_FREE: info->free += 1; + len_free += 1; len = 0; break; @@ -336,23 +352,51 @@ void gc_info(gc_info_t *info) { // shouldn't happen break; } + + block++; + finish = (block == MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); + // Get next block type if possible + if (!finish) { + kind = ATB_GET_KIND(block); + } + + if (finish || kind == AT_FREE || kind == AT_HEAD) { + if (len == 1) { + info->num_1block += 1; + } else if (len == 2) { + info->num_2block += 1; + } + if (len > info->max_block) { + info->max_block = len; + } + if (finish || kind == AT_HEAD) { + if (len_free > info->max_free) { + info->max_free = len_free; + } + len_free = 0; + } + } } info->used *= BYTES_PER_BLOCK; info->free *= BYTES_PER_BLOCK; + GC_EXIT(); } void *gc_alloc(size_t n_bytes, bool has_finaliser) { size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK; DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks); - // check if GC is locked - if (MP_STATE_MEM(gc_lock_depth) > 0) { + // check for 0 allocation + if (n_blocks == 0) { return NULL; } - // check for 0 allocation - if (n_blocks == 0) { + GC_ENTER(); + + // check if GC is locked + if (MP_STATE_MEM(gc_lock_depth) > 0) { + GC_EXIT(); return NULL; } @@ -372,6 +416,7 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser) { if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; } } + GC_EXIT(); // nothing found! if (collected) { return NULL; @@ -379,6 +424,7 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser) { DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes); gc_collect(); collected = 1; + GC_ENTER(); } // found, ending at block i inclusive @@ -406,9 +452,12 @@ found: } // get pointer to first block + // we must create this pointer before unlocking the GC so a collection can find it void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK); DEBUG_printf("gc_alloc(%p)\n", ret_ptr); + GC_EXIT(); + // zero out the additional bytes of the newly allocated blocks // This is needed because the blocks may have previously held pointers // to the heap and will not be set to something else if the caller @@ -421,7 +470,9 @@ found: // clear type pointer in case it is never set ((mp_obj_base_t*)ret_ptr)->type = NULL; // set mp_obj flag only if it has a finaliser + GC_ENTER(); FTB_SET(start_block); + GC_EXIT(); } #else (void)has_finaliser; @@ -447,8 +498,10 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) { // force the freeing of a piece of memory // TODO: freeing here does not call finaliser void gc_free(void *ptr) { + GC_ENTER(); if (MP_STATE_MEM(gc_lock_depth) > 0) { // TODO how to deal with this error? + GC_EXIT(); return; } @@ -471,18 +524,25 @@ void gc_free(void *ptr) { block += 1; } while (ATB_GET_KIND(block) == AT_TAIL); + GC_EXIT(); + #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif } else { + GC_EXIT(); assert(!"bad free"); } } else if (ptr != NULL) { + GC_EXIT(); assert(!"bad free"); + } else { + GC_EXIT(); } } size_t gc_nbytes(const void *ptr) { + GC_ENTER(); if (VERIFY_PTR(ptr)) { size_t block = BLOCK_FROM_PTR(ptr); if (ATB_GET_KIND(block) == AT_HEAD) { @@ -491,11 +551,13 @@ size_t gc_nbytes(const void *ptr) { do { n_blocks += 1; } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL); + GC_EXIT(); return n_blocks * BYTES_PER_BLOCK; } } // invalid pointer + GC_EXIT(); return 0; } @@ -529,10 +591,6 @@ void *gc_realloc(void *ptr, mp_uint_t n_bytes) { #else // Alternative gc_realloc impl void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { - if (MP_STATE_MEM(gc_lock_depth) > 0) { - return NULL; - } - // check for pure allocation if (ptr_in == NULL) { return gc_alloc(n_bytes, false); @@ -554,8 +612,16 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { // get first block size_t block = BLOCK_FROM_PTR(ptr); + GC_ENTER(); + // sanity check the ptr is pointing to the head of a block if (ATB_GET_KIND(block) != AT_HEAD) { + GC_EXIT(); + return NULL; + } + + if (MP_STATE_MEM(gc_lock_depth) > 0) { + GC_EXIT(); return NULL; } @@ -590,6 +656,7 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { // return original ptr if it already has the requested number of blocks if (new_blocks == n_blocks) { + GC_EXIT(); return ptr_in; } @@ -605,6 +672,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB; } + GC_EXIT(); + #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); #endif @@ -620,6 +689,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { ATB_FREE_TO_TAIL(bl); } + GC_EXIT(); + // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc) memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes); @@ -630,19 +701,21 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { return ptr_in; } + #if MICROPY_ENABLE_FINALISER + bool ftb_state = FTB_GET(block); + #else + bool ftb_state = false; + #endif + + GC_EXIT(); + if (!allow_move) { // not allowed to move memory block so return failure return NULL; } // can't resize inplace; try to find a new contiguous chain - void *ptr_out = gc_alloc(n_bytes, -#if MICROPY_ENABLE_FINALISER - FTB_GET(block) -#else - false -#endif - ); + void *ptr_out = gc_alloc(n_bytes, ftb_state); // check that the alloc succeeded if (ptr_out == NULL) { @@ -661,11 +734,12 @@ void gc_dump_info(void) { gc_info(&info); mp_printf(&mp_plat_print, "GC: total: %u, used: %u, free: %u\n", (uint)info.total, (uint)info.used, (uint)info.free); - mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u\n", - (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block); + mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n", + (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free); } void gc_dump_alloc_table(void) { + GC_ENTER(); static const size_t DUMP_BYTES_PER_LINE = 64; #if !EXTENSIVE_HEAP_PROFILING // When comparing heap output we don't want to print the starting @@ -713,7 +787,7 @@ void gc_dump_alloc_table(void) { } if (c == 'h') { ptrs = (void**)&c; - len = ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t); + len = ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t); for (mp_uint_t i = 0; i < len; i++) { mp_uint_t ptr = (mp_uint_t)ptrs[i]; if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) { @@ -771,6 +845,7 @@ void gc_dump_alloc_table(void) { mp_printf(&mp_plat_print, "%c", c); } mp_print_str(&mp_plat_print, "\n"); + GC_EXIT(); } #if DEBUG_PRINT @@ -54,6 +54,7 @@ typedef struct _gc_info_t { size_t total; size_t used; size_t free; + size_t max_free; size_t num_1block; size_t num_2block; size_t max_block; diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 194d901d26..69aaefb3e6 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -30,7 +30,7 @@ def process_file(f): m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) assert m is not None fname = m.group(1) - if fname[0] == "/" or not fname.endswith(".c"): + if not fname.endswith(".c"): continue if fname != last_fname: write_out(last_fname, output) diff --git a/py/mkrules.mk b/py/mkrules.mk index 3ed4afec19..b77f8d600f 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -49,7 +49,7 @@ $(BUILD)/%.o: %.c # List all native flags since the current build system doesn't have # the micropython configuration available. However, these flags are # needed to extract all qstrings -QSTR_GEN_EXTRA_CFLAGS += -D__QSTR_EXTRACT -DN_X64 -DN_X86 -DN_THUMB -DN_ARM +QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp vpath %.c . $(TOP) @@ -115,9 +115,6 @@ ifndef DEBUG endif $(Q)$(SIZE) $(PROG) -lib: $(OBJ) - $(AR) rcs libmicropython.a $^ - clean: clean-prog clean-prog: $(RM) -f $(PROG) @@ -126,6 +123,9 @@ clean-prog: .PHONY: clean-prog endif +lib: $(OBJ) + $(AR) rcs libmicropython.a $^ + clean: $(RM) -rf $(BUILD) .PHONY: clean diff --git a/py/modio.c b/py/modio.c index 2fbe6bc1e1..f8826c71a7 100644 --- a/py/modio.c +++ b/py/modio.c @@ -124,7 +124,7 @@ STATIC const mp_obj_type_t bufwriter_type = { { &mp_type_type }, .name = MP_QSTR_BufferedWriter, .make_new = bufwriter_make_new, - .stream_p = &bufwriter_stream_p, + .protocol = &bufwriter_stream_p, .locals_dict = (mp_obj_t)&bufwriter_locals_dict, }; #endif // MICROPY_PY_IO_BUFFEREDWRITER diff --git a/py/modmicropython.c b/py/modmicropython.c index 1ff5e25bd0..805bda51d2 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -60,7 +60,7 @@ mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) { (mp_uint_t)m_get_total_bytes_allocated(), (mp_uint_t)m_get_current_bytes_allocated(), (mp_uint_t)m_get_peak_bytes_allocated()); #endif #if MICROPY_STACK_CHECK - mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " INT_FMT "\n", mp_stack_usage(), MP_STATE_VM(stack_limit)); + mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " INT_FMT "\n", mp_stack_usage(), MP_STATE_THREAD(stack_limit)); #else mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_stack_usage()); #endif diff --git a/py/modthread.c b/py/modthread.c new file mode 100644 index 0000000000..6c8340c928 --- /dev/null +++ b/py/modthread.c @@ -0,0 +1,301 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include "py/runtime.h" +#include "py/stackctrl.h" + +#if MICROPY_PY_THREAD + +#include "py/mpthread.h" + +#if 0 // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +/****************************************************************/ +// Lock object +// Note: with the GIL enabled we can easily synthesise a lock object + +STATIC const mp_obj_type_t mp_type_thread_lock; + +typedef struct _mp_obj_thread_lock_t { + mp_obj_base_t base; + #if !MICROPY_PY_THREAD_GIL + mp_thread_mutex_t mutex; + #endif + volatile bool locked; +} mp_obj_thread_lock_t; + +STATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) { + mp_obj_thread_lock_t *self = m_new_obj(mp_obj_thread_lock_t); + self->base.type = &mp_type_thread_lock; + #if !MICROPY_PY_THREAD_GIL + mp_thread_mutex_init(&self->mutex); + #endif + self->locked = false; + return self; +} + +STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]); + bool wait = true; + if (n_args > 1) { + wait = mp_obj_get_int(args[1]); + // TODO support timeout arg + } + #if MICROPY_PY_THREAD_GIL + if (self->locked) { + if (!wait) { + return mp_const_false; + } + do { + MP_THREAD_GIL_EXIT(); + MP_THREAD_GIL_ENTER(); + } while (self->locked); + } + self->locked = true; + return mp_const_true; + #else + int ret = mp_thread_mutex_lock(&self->mutex, wait); + if (ret == 0) { + return mp_const_false; + } else if (ret == 1) { + self->locked = true; + return mp_const_true; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-ret))); + } + #endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire); + +STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); + // TODO check if already unlocked + self->locked = false; + #if !MICROPY_PY_THREAD_GIL + mp_thread_mutex_unlock(&self->mutex); + #endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release); + +STATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->locked); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked); + +STATIC mp_obj_t thread_lock___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; // unused + return thread_lock_release(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock___exit___obj, 4, 4, thread_lock___exit__); + +STATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) }, + { MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) }, + { MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&thread_lock_acquire_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&thread_lock___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table); + +STATIC const mp_obj_type_t mp_type_thread_lock = { + { &mp_type_type }, + .name = MP_QSTR_lock, + .locals_dict = (mp_obj_dict_t*)&thread_lock_locals_dict, +}; + +/****************************************************************/ +// _thread module + +STATIC size_t thread_stack_size = 0; + +STATIC mp_obj_t mod_thread_get_ident(void) { + return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident); + +STATIC mp_obj_t mod_thread_stack_size(size_t n_args, const mp_obj_t *args) { + mp_obj_t ret = mp_obj_new_int_from_uint(thread_stack_size); + if (n_args == 0) { + thread_stack_size = 0; + } else { + thread_stack_size = mp_obj_get_int(args[0]); + } + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_stack_size_obj, 0, 1, mod_thread_stack_size); + +typedef struct _thread_entry_args_t { + size_t stack_size; + mp_obj_t fun; + size_t n_args; + size_t n_kw; + mp_obj_t args[]; +} thread_entry_args_t; + +STATIC void *thread_entry(void *args_in) { + // Execution begins here for a new thread. We do not have the GIL. + + thread_entry_args_t *args = (thread_entry_args_t*)args_in; + + mp_state_thread_t ts; + mp_thread_set_state(&ts); + + mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan + mp_stack_set_limit(args->stack_size); + + MP_THREAD_GIL_ENTER(); + + // signal that we are set up and running + mp_thread_start(); + + // TODO set more thread-specific state here: + // mp_pending_exception? (root pointer) + // cur_exception (root pointer) + // dict_locals? (root pointer) uPy doesn't make a new locals dict for functions, just for classes, so it's different to CPy + + DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top)); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args); + nlr_pop(); + } else { + // uncaught exception + // check for SystemExit + mp_obj_base_t *exc = (mp_obj_base_t*)nlr.ret_val; + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + // swallow exception silently + } else { + // print exception out + mp_printf(&mp_plat_print, "Unhandled exception in thread started by "); + mp_obj_print_helper(&mp_plat_print, args->fun, PRINT_REPR); + mp_printf(&mp_plat_print, "\n"); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(exc)); + } + } + + DEBUG_printf("[thread] finish ts=%p\n", &ts); + + // signal that we are finished + mp_thread_finish(); + + MP_THREAD_GIL_EXIT(); + + return NULL; +} + +STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) { + // This structure holds the Python function and arguments for thread entry. + // We copy all arguments into this structure to keep ownership of them. + // We must be very careful about root pointers because this pointer may + // disappear from our address space before the thread is created. + thread_entry_args_t *th_args; + + // get positional arguments + mp_uint_t pos_args_len; + mp_obj_t *pos_args_items; + mp_obj_get_array(args[1], &pos_args_len, &pos_args_items); + + // check for keyword arguments + if (n_args == 2) { + // just position arguments + th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len); + th_args->n_kw = 0; + } else { + // positional and keyword arguments + if (mp_obj_get_type(args[2]) != &mp_type_dict) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting a dict for keyword args")); + } + mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; + th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); + th_args->n_kw = map->used; + // copy across the keyword arguments + for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + th_args->args[n++] = map->table[i].key; + th_args->args[n++] = map->table[i].value; + } + } + } + + // copy agross the positional arguments + th_args->n_args = pos_args_len; + memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t)); + + // set the stack size to use + th_args->stack_size = thread_stack_size; + + // set the function for thread entry + th_args->fun = args[0]; + + // spawn the thread! + mp_thread_create(thread_entry, th_args, &th_args->stack_size); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread); + +STATIC mp_obj_t mod_thread_exit(void) { + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit); + +STATIC mp_obj_t mod_thread_allocate_lock(void) { + return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock); + +STATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) }, + { MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) }, + { MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) }, + { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) }, + { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table); + +const mp_obj_module_t mp_module_thread = { + .base = { &mp_type_module }, + .name = MP_QSTR__thread, + .globals = (mp_obj_dict_t*)&mp_module_thread_globals, +}; + +#endif // MICROPY_PY_THREAD diff --git a/py/mpconfig.h b/py/mpconfig.h index 084fc246f5..aec5d40826 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -824,6 +824,17 @@ typedef double mp_float_t; #define MICROPY_PY_UERRNO (0) #endif +// Whether to provide "_thread" module +#ifndef MICROPY_PY_THREAD +#define MICROPY_PY_THREAD (0) +#endif + +// Whether to make the VM/runtime thread-safe using a global lock +// If not enabled then thread safety must be provided at the Python level +#ifndef MICROPY_PY_THREAD_GIL +#define MICROPY_PY_THREAD_GIL (MICROPY_PY_THREAD) +#endif + // Extended modules #ifndef MICROPY_PY_UCTYPES @@ -888,6 +899,10 @@ typedef double mp_float_t; #define MICROPY_PY_FRAMEBUF (0) #endif +#ifndef MICROPY_PY_BTREE +#define MICROPY_PY_BTREE (0) +#endif + /*****************************************************************************/ /* Hooks for a port to add builtins */ @@ -1031,6 +1046,11 @@ typedef double mp_float_t; #define MP_WEAK __attribute__((weak)) #endif +// Modifier for functions which should be never inlined +#ifndef MP_NOINLINE +#define MP_NOINLINE __attribute__((noinline)) +#endif + // Condition is likely to be true, to help branch prediction #ifndef MP_LIKELY #define MP_LIKELY(x) __builtin_expect((x), 1) diff --git a/py/mphal.h b/py/mphal.h index aacd02ebd8..54a45b0240 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -73,6 +73,7 @@ mp_uint_t mp_hal_ticks_us(void); #define mp_hal_get_pin_obj(pin) (pin) #define mp_hal_pin_read(pin) mp_virtual_pin_read(pin) #define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v) +#include "extmod/virtpin.h" #endif #endif // __MICROPY_INCLUDED_PY_MPHAL_H__ diff --git a/py/mpstate.h b/py/mpstate.h index 0e77e65833..281795773f 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -29,6 +29,7 @@ #include <stdint.h> #include "py/mpconfig.h" +#include "py/mpthread.h" #include "py/misc.h" #include "py/nlr.h" #include "py/obj.h" @@ -80,6 +81,11 @@ typedef struct _mp_state_mem_t { #if MICROPY_PY_GC_COLLECT_RETVAL size_t gc_collected; #endif + + #if MICROPY_PY_THREAD + // This is a global mutex used to make the GC thread-safe. + mp_thread_mutex_t gc_mutex; + #endif } mp_state_mem_t; // This structure hold runtime and VM information. It includes a section @@ -91,9 +97,6 @@ typedef struct _mp_state_vm_t { // this must start at the start of this structure // - // Note: nlr asm code has the offset of this hard-coded - nlr_buf_t *nlr_top; - qstr_pool_t *last_pool; // non-heap memory for creating an exception if we can't allocate RAM @@ -140,6 +143,7 @@ typedef struct _mp_state_vm_t { #if MICROPY_PY_OS_DUPTERM mp_obj_t term_obj; + mp_obj_t dupterm_arr_obj; #endif #if MICROPY_PY_LWIP_SLIP @@ -161,12 +165,9 @@ typedef struct _mp_state_vm_t { size_t qstr_last_alloc; size_t qstr_last_used; - // Stack top at the start of program - // Note: this entry is used to locate the end of the root pointer section. - char *stack_top; - - #if MICROPY_STACK_CHECK - mp_uint_t stack_limit; + #if MICROPY_PY_THREAD + // This is a global mutex used to make qstr interning thread-safe. + mp_thread_mutex_t qstr_mutex; #endif mp_uint_t mp_optimise_value; @@ -175,9 +176,29 @@ typedef struct _mp_state_vm_t { #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0 mp_int_t mp_emergency_exception_buf_size; #endif + + #if MICROPY_PY_THREAD_GIL + // This is a global mutex used to make the VM/runtime thread-safe. + mp_thread_mutex_t gil_mutex; + #endif } mp_state_vm_t; -// This structure combines the above 2 structures, and adds the local +// This structure holds state that is specific to a given thread. +// Everything in this structure is scanned for root pointers. +typedef struct _mp_state_thread_t { + // Note: nlr asm code has the offset of this hard-coded + nlr_buf_t *nlr_top; // ROOT POINTER + + // Stack top at the start of program + // Note: this entry is used to locate the end of the root pointer section. + char *stack_top; + + #if MICROPY_STACK_CHECK + size_t stack_limit; + #endif +} mp_state_thread_t; + +// This structure combines the above 3 structures, and adds the local // and global dicts. // Note: if this structure changes then revisit all nlr asm code since they // have the offset of nlr_top hard-coded. @@ -185,7 +206,8 @@ typedef struct _mp_state_ctx_t { // these must come first for root pointer scanning in GC to work mp_obj_dict_t *dict_locals; mp_obj_dict_t *dict_globals; - // this must come next for root pointer scanning in GC to work + // these must come next in this order for root pointer scanning in GC to work + mp_state_thread_t thread; mp_state_vm_t vm; mp_state_mem_t mem; } mp_state_ctx_t; @@ -196,4 +218,11 @@ extern mp_state_ctx_t mp_state_ctx; #define MP_STATE_VM(x) (mp_state_ctx.vm.x) #define MP_STATE_MEM(x) (mp_state_ctx.mem.x) +#if MICROPY_PY_THREAD +extern mp_state_thread_t *mp_thread_get_state(void); +#define MP_STATE_THREAD(x) (mp_thread_get_state()->x) +#else +#define MP_STATE_THREAD(x) (mp_state_ctx.thread.x) +#endif + #endif // __MICROPY_INCLUDED_PY_MPSTATE_H__ diff --git a/py/mpthread.h b/py/mpthread.h new file mode 100644 index 0000000000..04d4f19684 --- /dev/null +++ b/py/mpthread.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __MICROPY_INCLUDED_PY_MPTHREAD_H__ +#define __MICROPY_INCLUDED_PY_MPTHREAD_H__ + +#include "py/mpconfig.h" + +#if MICROPY_PY_THREAD + +#ifdef MICROPY_MPTHREADPORT_H +#include MICROPY_MPTHREADPORT_H +#else +#include <mpthreadport.h> +#endif + +struct _mp_state_thread_t; + +struct _mp_state_thread_t *mp_thread_get_state(void); +void mp_thread_set_state(void *state); +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size); +void mp_thread_start(void); +void mp_thread_finish(void); +void mp_thread_mutex_init(mp_thread_mutex_t *mutex); +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait); +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex); + +#endif // MICROPY_PY_THREAD + +#if MICROPY_PY_THREAD && MICROPY_PY_THREAD_GIL +#include "py/mpstate.h" +#define MP_THREAD_GIL_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(gil_mutex), 1) +#define MP_THREAD_GIL_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(gil_mutex)) +#else +#define MP_THREAD_GIL_ENTER() +#define MP_THREAD_GIL_EXIT() +#endif + +#endif // __MICROPY_INCLUDED_PY_MPTHREAD_H__ @@ -70,8 +70,8 @@ struct _nlr_buf_t { NORETURN void nlr_setjmp_jump(void *val); // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ((buf)->prev = MP_STATE_VM(nlr_top), MP_STATE_VM(nlr_top) = (buf), setjmp((buf)->jmpbuf)) -#define nlr_pop() { MP_STATE_VM(nlr_top) = MP_STATE_VM(nlr_top)->prev; } +#define nlr_push(buf) ((buf)->prev = MP_STATE_THREAD(nlr_top), MP_STATE_THREAD(nlr_top) = (buf), setjmp((buf)->jmpbuf)) +#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } #define nlr_jump(val) nlr_setjmp_jump(val) #else unsigned int nlr_push(nlr_buf_t *); @@ -91,7 +91,7 @@ void nlr_jump_fail(void *val); #include "mpstate.h" #define nlr_raise(val) \ do { \ - /*printf("nlr_raise: nlr_top=%p\n", MP_STATE_VM(nlr_top)); \ + /*printf("nlr_raise: nlr_top=%p\n", MP_STATE_THREAD(nlr_top)); \ fflush(stdout);*/ \ void *_val = MP_OBJ_TO_PTR(val); \ assert(_val != NULL); \ @@ -101,11 +101,11 @@ void nlr_jump_fail(void *val); #if !MICROPY_NLR_SETJMP #define nlr_push(val) \ - assert(MP_STATE_VM(nlr_top) != val),nlr_push(val) + assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) /* #define nlr_push(val) \ - printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_VM(nlr_top), val),assert(MP_STATE_VM(nlr_top) != val),nlr_push(val) + printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) #endif */ #endif diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 661b650c5c..43a13156f2 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -29,8 +29,8 @@ #if MICROPY_NLR_SETJMP void nlr_setjmp_jump(void *val) { - nlr_buf_t *buf = MP_STATE_VM(nlr_top); - MP_STATE_VM(nlr_top) = buf->prev; + nlr_buf_t *buf = MP_STATE_THREAD(nlr_top); + MP_STATE_THREAD(nlr_top) = buf->prev; buf->ret_val = val; longjmp(buf->jmpbuf, 1); } diff --git a/py/nlrthumb.S b/py/nlrthumb.S deleted file mode 100644 index 624275e8ed..0000000000 --- a/py/nlrthumb.S +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013-2015 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) - -// We only need the functions here if we are on arm/thumb, and we are not -// using setjmp/longjmp. -// -// For reference, arm/thumb callee save regs are: -// r4-r11, r13=sp - -// the offset of nlr_top within mp_state_ctx_t -#define NLR_TOP_OFFSET (2 * 4) - - .syntax unified - /*.cpu cortex-m4*/ - /*.thumb*/ - .text - .align 2 - -/**************************************/ -// mp_uint_t nlr_push(r0=nlr_buf_t *nlr) - - .global nlr_push -#if defined(__thumb2__) - .thumb - .thumb_func -#endif - .type nlr_push, %function -nlr_push: - str r4, [r0, #12] @ store r4 into nlr_buf - str r5, [r0, #16] @ store r5 into nlr_buf - str r6, [r0, #20] @ store r6 into nlr_buf - str r7, [r0, #24] @ store r7 into nlr_buf - -#if defined(__ARM_ARCH_6M__) - mov r1, r8 - str r1, [r0, #28] @ store r8 into nlr_buf - mov r1, r9 - str r1, [r0, #32] @ store r9 into nlr_buf - mov r1, r10 - str r1, [r0, #36] @ store r10 into nlr_buf - mov r1, r11 - str r1, [r0, #40] @ store r11 into nlr_buf - mov r1, r13 - str r1, [r0, #44] @ store r13=sp into nlr_buf - mov r1, lr - str r1, [r0, #8] @ store lr into nlr_buf -#else - str r8, [r0, #28] @ store r8 into nlr_buf - str r9, [r0, #32] @ store r9 into nlr_buf - str r10, [r0, #36] @ store r10 into nlr_buf - str r11, [r0, #40] @ store r11 into nlr_buf - str r13, [r0, #44] @ store r13=sp into nlr_buf - str lr, [r0, #8] @ store lr into nlr_buf -#endif - - ldr r3, nlr_top_addr @ load addr of nlr_top - ldr r2, [r3] @ load nlr_top - str r2, [r0] @ store nlr_top into nlr_buf - str r0, [r3] @ store nlr_buf into nlr_top (to link list) - - movs r0, #0 @ return 0, normal return - bx lr @ return - .size nlr_push, .-nlr_push - -/**************************************/ -// void nlr_pop() - - .global nlr_pop -#if defined(__thumb2__) - .thumb - .thumb_func -#endif - .type nlr_pop, %function -nlr_pop: - ldr r3, nlr_top_addr @ load addr of nlr_top - ldr r2, [r3] @ load nlr_top - ldr r2, [r2] @ load prev nlr_buf - str r2, [r3] @ store prev nlr_buf to nlr_top (to unlink list) - bx lr @ return - .size nlr_pop, .-nlr_pop - -/**************************************/ -// void nlr_jump(r0=mp_uint_t val) - - .global nlr_jump -#if defined(__thumb2__) - .thumb - .thumb_func -#endif - .type nlr_jump, %function -nlr_jump: - ldr r3, nlr_top_addr @ load addr of nlr_top - ldr r2, [r3] @ load nlr_top - cmp r2, #0 @ test if nlr_top is NULL -#if defined(__ARM_ARCH_6M__) - bne nlr_jump_non_null @ if nlr_top is NULL, transfer control to nlr_jump_fail - bl nlr_jump_fail -nlr_jump_non_null: -#else - beq nlr_jump_fail @ if nlr_top is NULL, transfer control to nlr_jump_fail -#endif - str r0, [r2, #4] @ store return value - ldr r0, [r2] @ load prev nlr_buf - str r0, [r3] @ store prev nol_buf into nlr_top (to unlink list) - - ldr r4, [r2, #12] @ load r4 from nlr_buf - ldr r5, [r2, #16] @ load r5 from nlr_buf - ldr r6, [r2, #20] @ load r6 from nlr_buf - ldr r7, [r2, #24] @ load r7 from nlr_buf -#if defined(__ARM_ARCH_6M__) - ldr r1, [r2, #28] @ load r8 from nlr_buf - mov r8, r1 - ldr r1, [r2, #32] @ load r9 from nlr_buf - mov r9, r1 - ldr r1, [r2, #36] @ load r10 from nlr_buf - mov r10, r1 - ldr r1, [r2, #40] @ load r11 from nlr_buf - mov r11, r1 - ldr r1, [r2, #44] @ load r13=sp from nlr_buf - mov r13, r1 - ldr r1, [r2, #8] @ load lr from nlr_buf - mov lr, r1 -#else - ldr r8, [r2, #28] @ load r8 from nlr_buf - ldr r9, [r2, #32] @ load r9 from nlr_buf - ldr r10, [r2, #36] @ load r10 from nlr_buf - ldr r11, [r2, #40] @ load r11 from nlr_buf - ldr r13, [r2, #44] @ load r13=sp from nlr_buf - ldr lr, [r2, #8] @ load lr from nlr_buf -#endif - - movs r0, #1 @ return 1, non-local return - bx lr @ return - .size nlr_jump, .-nlr_jump - - .align 2 -nlr_top_addr: - .word mp_state_ctx + NLR_TOP_OFFSET - -#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) diff --git a/py/nlrthumb.c b/py/nlrthumb.c new file mode 100644 index 0000000000..a61c73c036 --- /dev/null +++ b/py/nlrthumb.c @@ -0,0 +1,134 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" +#include "py/nlr.h" + +#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) + +// We only need the functions here if we are on arm/thumb, and we are not +// using setjmp/longjmp. +// +// For reference, arm/thumb callee save regs are: +// r4-r11, r13=sp + +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm volatile ( + "str r4, [r0, #12] \n" // store r4 into nlr_buf + "str r5, [r0, #16] \n" // store r5 into nlr_buf + "str r6, [r0, #20] \n" // store r6 into nlr_buf + "str r7, [r0, #24] \n" // store r7 into nlr_buf + +#if defined(__ARM_ARCH_6M__) + "mov r1, r8 \n" + "str r1, [r0, #28] \n" // store r8 into nlr_buf + "mov r1, r9 \n" + "str r1, [r0, #32] \n" // store r9 into nlr_buf + "mov r1, r10 \n" + "str r1, [r0, #36] \n" // store r10 into nlr_buf + "mov r1, r11 \n" + "str r1, [r0, #40] \n" // store r11 into nlr_buf + "mov r1, r13 \n" + "str r1, [r0, #44] \n" // store r13=sp into nlr_buf + "mov r1, lr \n" + "str r1, [r0, #8] \n" // store lr into nlr_buf +#else + "str r8, [r0, #28] \n" // store r8 into nlr_buf + "str r9, [r0, #32] \n" // store r9 into nlr_buf + "str r10, [r0, #36] \n" // store r10 into nlr_buf + "str r11, [r0, #40] \n" // store r11 into nlr_buf + "str r13, [r0, #44] \n" // store r13=sp into nlr_buf + "str lr, [r0, #8] \n" // store lr into nlr_buf +#endif + + "b nlr_push_tail \n" // do the rest in C + ); + + return 0; // needed to silence compiler warning +} + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} + +NORETURN __attribute__((naked)) void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + + top->ret_val = val; + *top_ptr = top->prev; + + __asm volatile ( + "mov r0, %0 \n" // r0 points to nlr_buf + "ldr r4, [r0, #12] \n" // load r4 from nlr_buf + "ldr r5, [r0, #16] \n" // load r5 from nlr_buf + "ldr r6, [r0, #20] \n" // load r6 from nlr_buf + "ldr r7, [r0, #24] \n" // load r7 from nlr_buf + +#if defined(__ARM_ARCH_6M__) + "ldr r1, [r0, #28] \n" // load r8 from nlr_buf + "mov r8, r1 \n" + "ldr r1, [r0, #32] \n" // load r9 from nlr_buf + "mov r9, r1 \n" + "ldr r1, [r0, #36] \n" // load r10 from nlr_buf + "mov r10, r1 \n" + "ldr r1, [r0, #40] \n" // load r11 from nlr_buf + "mov r11, r1 \n" + "ldr r1, [r0, #44] \n" // load r13=sp from nlr_buf + "mov r13, r1 \n" + "ldr r1, [r0, #8] \n" // load lr from nlr_buf + "mov lr, r1 \n" +#else + "ldr r8, [r0, #28] \n" // load r8 from nlr_buf + "ldr r9, [r0, #32] \n" // load r9 from nlr_buf + "ldr r10, [r0, #36] \n" // load r10 from nlr_buf + "ldr r11, [r0, #40] \n" // load r11 from nlr_buf + "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf + "ldr lr, [r0, #8] \n" // load lr from nlr_buf +#endif + "movs r0, #1 \n" // return 1, non-local return + "bx lr \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers + ); + + for (;;); // needed to silence compiler warning +} + +#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) diff --git a/py/nlrx64.S b/py/nlrx64.S index 8dda025cad..ad2b66fdb2 100644 --- a/py/nlrx64.S +++ b/py/nlrx64.S @@ -41,6 +41,9 @@ #define NLR_TOP (mp_state_ctx + NLR_TOP_OFFSET) #endif +// offset of nlr_top within mp_state_thread_t structure +#define NLR_TOP_TH_OFF (0) + #if defined(_WIN32) || defined(__CYGWIN__) #define NLR_OS_WINDOWS #endif @@ -77,9 +80,20 @@ _nlr_push: movq %r13, 56(%rdi) # store %r13 into nlr_buf movq %r14, 64(%rdi) # store %r14 into nlr_buf movq %r15, 72(%rdi) # store %r15 into nlr_buf + +#if !MICROPY_PY_THREAD movq NLR_TOP(%rip), %rax # get last nlr_buf movq %rax, (%rdi) # store it movq %rdi, NLR_TOP(%rip) # stor new nlr_buf (to make linked list) +#else + movq %rdi, %rbp # since we make a call, must save rdi in rbp + callq mp_thread_get_state # get mp_state_thread ptr into rax + movq NLR_TOP_TH_OFF(%rax), %rsi # get thread.nlr_top (last nlr_buf) + movq %rsi, (%rbp) # store it + movq %rbp, NLR_TOP_TH_OFF(%rax) # store new nlr_buf (to make linked list) + movq 24(%rbp), %rbp # restore rbp +#endif + xorq %rax, %rax # return 0, normal return ret # return #if !(defined(__APPLE__) && defined(__MACH__)) @@ -97,9 +111,18 @@ nlr_pop: .globl _nlr_pop _nlr_pop: #endif + +#if !MICROPY_PY_THREAD movq NLR_TOP(%rip), %rax # get nlr_top into %rax movq (%rax), %rax # load prev nlr_buf movq %rax, NLR_TOP(%rip) # store prev nlr_buf (to unlink list) +#else + callq mp_thread_get_state # get mp_state_thread ptr into rax + movq NLR_TOP_TH_OFF(%rax), %rdi # get thread.nlr_top (last nlr_buf) + movq (%rdi), %rdi # load prev nlr_buf + movq %rdi, NLR_TOP_TH_OFF(%rax) # store prev nlr_buf (to unlink list) +#endif + ret # return #if !(defined(__APPLE__) && defined(__MACH__)) .size nlr_pop, .-nlr_pop @@ -116,6 +139,8 @@ nlr_jump: .globl _nlr_jump _nlr_jump: #endif + +#if !MICROPY_PY_THREAD movq %rdi, %rax # put return value in %rax movq NLR_TOP(%rip), %rdi # get nlr_top into %rdi test %rdi, %rdi # check for nlr_top being NULL @@ -123,6 +148,19 @@ nlr_jump: movq %rax, 8(%rdi) # store return value movq (%rdi), %rax # load prev nlr_buf movq %rax, NLR_TOP(%rip) # store prev nlr_buf (to unlink list) +#else + movq %rdi, %rbp # put return value in rbp + callq mp_thread_get_state # get thread ptr in rax + movq %rax, %rsi # put thread ptr in rsi + movq %rbp, %rax # put return value to rax (for je .fail) + movq NLR_TOP_TH_OFF(%rsi), %rdi # get thread.nlr_top in rdi + test %rdi, %rdi # check for nlr_top being NULL + je .fail # fail if nlr_top is NULL + movq %rax, 8(%rdi) # store return value + movq (%rdi), %rax # load prev nlr_buf + movq %rax, NLR_TOP_TH_OFF(%rsi) # store prev nlr_buf (to unlink list) +#endif + movq 72(%rdi), %r15 # load saved %r15 movq 64(%rdi), %r14 # load saved %r14 movq 56(%rdi), %r13 # load saved %r13 diff --git a/py/nlrx86.S b/py/nlrx86.S index a6ec4b73c7..8a96af81ce 100644 --- a/py/nlrx86.S +++ b/py/nlrx86.S @@ -42,6 +42,9 @@ #define NLR_TOP (mp_state_ctx + NLR_TOP_OFFSET) #endif +// offset of nlr_top within mp_state_thread_t structure +#define NLR_TOP_TH_OFF (0) + .file "nlr.s" .text @@ -65,9 +68,20 @@ nlr_push: mov %ebx, 20(%edx) # store %bx into nlr_buf+20 mov %edi, 24(%edx) # store %di into nlr_buf mov %esi, 28(%edx) # store %si into nlr_buf + +#if !MICROPY_PY_THREAD mov NLR_TOP, %eax # load nlr_top mov %eax, (%edx) # store it mov %edx, NLR_TOP # stor new nlr_buf (to make linked list) +#else + // to check: stack is aligned to 16-byte boundary before this call + call mp_thread_get_state # get mp_state_thread ptr into eax + mov 4(%esp), %edx # load nlr_buf argument into edx (edx clobbered by call) + mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) + mov %ecx, (%edx) # store it + mov %edx, NLR_TOP_TH_OFF(%eax) # store new nlr_buf (to make linked list) +#endif + xor %eax, %eax # return 0, normal return ret # return #if !defined(NLR_OS_WINDOWS) @@ -86,9 +100,18 @@ _nlr_pop: .type nlr_pop, @function nlr_pop: #endif + +#if !MICROPY_PY_THREAD mov NLR_TOP, %eax # load nlr_top mov (%eax), %eax # load prev nlr_buf mov %eax, NLR_TOP # store nlr_top (to unlink list) +#else + call mp_thread_get_state # get mp_state_thread ptr into eax + mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) + mov (%ecx), %ecx # load prev nlr_buf + mov %ecx, NLR_TOP_TH_OFF(%eax) # store prev nlr_buf (to unlink list) +#endif + ret # return #if !defined(NLR_OS_WINDOWS) .size nlr_pop, .-nlr_pop @@ -106,6 +129,8 @@ _nlr_jump: .type nlr_jump, @function nlr_jump: #endif + +#if !MICROPY_PY_THREAD mov NLR_TOP, %edx # load nlr_top test %edx, %edx # check for nlr_top being NULL #if defined(NLR_OS_WINDOWS) @@ -117,6 +142,21 @@ nlr_jump: mov %eax, 4(%edx) # store return value mov (%edx), %eax # load prev nlr_top mov %eax, NLR_TOP # store nlr_top (to unlink list) +#else + call mp_thread_get_state # get mp_state_thread ptr into eax + mov NLR_TOP_TH_OFF(%eax), %edx # get thread.nlr_top (last nlr_buf) + test %edx, %edx # check for nlr_top being NULL +#if defined(NLR_OS_WINDOWS) + je _nlr_jump_fail # fail if nlr_top is NULL +#else + je nlr_jump_fail # fail if nlr_top is NULL +#endif + mov 4(%esp), %ecx # load return value + mov %ecx, 4(%edx) # store return value + mov (%edx), %ecx # load prev nlr_top + mov %ecx, NLR_TOP_TH_OFF(%eax) # store nlr_top (to unlink list) +#endif + mov 28(%edx), %esi # load saved %si mov 24(%edx), %edi # load saved %di mov 20(%edx), %ebx # load saved %bx @@ -484,7 +484,8 @@ struct _mp_obj_type_t { mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args) mp_buffer_p_t buffer_p; - const mp_stream_p_t *stream_p; + // One of disjoint protocols (interfaces), like mp_stream_p_t, etc. + const void *protocol; // these are for dynamically created types (classes) struct _mp_obj_tuple_t *bases_tuple; diff --git a/py/objarray.c b/py/objarray.c index bafba7623f..2cd0fef6b6 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -34,6 +34,7 @@ #include "py/runtime.h" #include "py/binary.h" #include "py/objstr.h" +#include "py/objarray.h" #if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW @@ -58,16 +59,6 @@ #define TYPECODE_MASK (~(mp_uint_t)0) #endif -typedef struct _mp_obj_array_t { - mp_obj_base_t base; - mp_uint_t typecode : 8; - // free is number of unused elements after len used elements - // alloc size = len + free - mp_uint_t free : (8 * sizeof(mp_uint_t) - 8); - mp_uint_t len; // in elements - void *items; -} mp_obj_array_t; - STATIC mp_obj_t array_iterator_new(mp_obj_t array_in); STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg); STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in); diff --git a/py/objarray.h b/py/objarray.h new file mode 100644 index 0000000000..013ac5be9b --- /dev/null +++ b/py/objarray.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_PY_OBJARRAY_H__ +#define __MICROPY_INCLUDED_PY_OBJARRAY_H__ + +#include "py/obj.h" + +typedef struct _mp_obj_array_t { + mp_obj_base_t base; + mp_uint_t typecode : 8; + // free is number of unused elements after len used elements + // alloc size = len + free + mp_uint_t free : (8 * sizeof(mp_uint_t) - 8); + mp_uint_t len; // in elements + void *items; +} mp_obj_array_t; + +#endif // __MICROPY_INCLUDED_PY_OBJARRAY_H__ diff --git a/py/objdict.c b/py/objdict.c index 04da2bf624..91d5b75e2b 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -119,8 +119,16 @@ STATIC mp_obj_t dict_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_EQUAL: { #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_UNLIKELY(MP_OBJ_IS_TYPE(lhs_in, &mp_type_ordereddict) && MP_OBJ_IS_TYPE(rhs_in, &mp_type_ordereddict))) { - //TODO: implement - return MP_OBJ_NULL; + // Iterate through both dictionaries simultaneously and compare keys and values. + mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); + mp_uint_t c1 = 0, c2 = 0; + mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2); + for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) { + if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) { + return mp_const_false; + } + } + return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false; } else #endif if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { diff --git a/py/objmodule.c b/py/objmodule.c index c7cb644488..dc2ce787b4 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -160,6 +160,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_GC && MICROPY_ENABLE_GC { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) }, #endif +#if MICROPY_PY_THREAD + { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) }, +#endif // extmod modules @@ -205,6 +208,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_FRAMEBUF { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) }, #endif +#if MICROPY_PY_BTREE + { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, +#endif // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES diff --git a/py/objstringio.c b/py/objstringio.c index 5fd2ca9d3b..abd4e835e8 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -174,7 +174,7 @@ const mp_obj_type_t mp_type_stringio = { .make_new = stringio_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &stringio_stream_p, + .protocol = &stringio_stream_p, .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, }; @@ -186,7 +186,7 @@ const mp_obj_type_t mp_type_bytesio = { .make_new = stringio_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &bytesio_stream_p, + .protocol = &bytesio_stream_p, .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, }; #endif diff --git a/py/objtype.c b/py/objtype.c index 2f14c387db..907308a757 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -914,7 +914,13 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->getiter = instance_getiter; //o->iternext = ; not implemented o->buffer_p.get_buffer = instance_get_buffer; - //o->stream_p = ; not implemented + // Inherit protocol from a base class. This allows to define an + // abstract base class which would translate C-level protocol to + // Python method calls, and any subclass inheriting from it will + // support this feature. + if (len > 0) { + o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol; + } o->bases_tuple = MP_OBJ_TO_PTR(bases_tuple); o->locals_dict = MP_OBJ_TO_PTR(locals_dict); diff --git a/py/parse.c b/py/parse.c index 7da484c497..1ec995cd8f 100644 --- a/py/parse.c +++ b/py/parse.c @@ -461,6 +461,8 @@ STATIC const mp_rom_map_elem_t mp_constants_table[] = { STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif +STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args); + #if MICROPY_COMP_CONST_FOLDING STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 @@ -587,6 +589,15 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args assert(elem->value == MP_OBJ_NULL); elem->value = MP_OBJ_NEW_SMALL_INT(value); + // If the constant starts with an underscore then treat it as a private + // variable and don't emit any code to store the value to the id. + if (qstr_str(id)[0] == '_') { + pop_result(parser); // pop const(value) + pop_result(parser); // pop id + push_result_rule(parser, 0, rules[RULE_pass_stmt], 0); // replace with "pass" + return true; + } + // replace const(value) with value pop_result(parser); push_result_node(parser, pn_value); @@ -16,6 +16,7 @@ endif # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 +INC += -I../lib INC += -I../lib/netutils ifeq ($(MICROPY_PY_USSL),1) @@ -63,6 +64,30 @@ SRC_MOD += $(LWIP_DIR)/netif/slipif.c endif endif +ifeq ($(MICROPY_PY_BTREE),1) +BTREE_DIR = lib/berkeley-db-1.xx +CFLAGS_MOD += -D__DBINTERFACE_PRIVATE=1 +INC += -I../$(BTREE_DIR)/PORT/include +SRC_MOD += extmod/modbtree.c +SRC_MOD += $(addprefix $(BTREE_DIR)/,\ +btree/bt_close.c \ +btree/bt_conv.c \ +btree/bt_debug.c \ +btree/bt_delete.c \ +btree/bt_get.c \ +btree/bt_open.c \ +btree/bt_overflow.c \ +btree/bt_page.c \ +btree/bt_put.c \ +btree/bt_search.c \ +btree/bt_seq.c \ +btree/bt_split.c \ +btree/bt_utils.c \ +mpool/mpool.c \ + ) +CFLAGS_MOD += -DMICROPY_PY_BTREE=1 +endif + # py object files PY_O_BASENAME = \ mpstate.o \ @@ -161,6 +186,7 @@ PY_O_BASENAME = \ modstruct.o \ modsys.o \ moduerrno.o \ + modthread.o \ vm.o \ bc.o \ showbc.o \ @@ -176,6 +202,7 @@ PY_O_BASENAME = \ ../extmod/modubinascii.o \ ../extmod/virtpin.o \ ../extmod/machine_mem.o \ + ../extmod/machine_pinbase.o \ ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ ../extmod/modussl.o \ @@ -72,6 +72,14 @@ #error unimplemented qstr length decoding #endif +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +#define QSTR_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1) +#define QSTR_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(qstr_mutex)) +#else +#define QSTR_ENTER() +#define QSTR_EXIT() +#endif + // this must match the equivalent function in makeqstrdata.py mp_uint_t qstr_compute_hash(const byte *data, size_t len) { // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html @@ -93,7 +101,7 @@ const qstr_pool_t mp_qstr_const_pool = { 10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below) MP_QSTRnumber_of, // corresponds to number of strings in array just below { -#ifndef __QSTR_EXTRACT +#ifndef NO_QSTR #define QDEF(id, str) str, #include "genhdr/qstrdefs.generated.h" #undef QDEF @@ -111,6 +119,10 @@ extern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL; void qstr_init(void) { MP_STATE_VM(last_pool) = (qstr_pool_t*)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left MP_STATE_VM(qstr_last_chunk) = NULL; + + #if MICROPY_PY_THREAD + mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex)); + #endif } STATIC const byte *find_qstr(qstr q) { @@ -125,12 +137,17 @@ STATIC const byte *find_qstr(qstr q) { return 0; } +// qstr_mutex must be taken while in this function STATIC qstr qstr_add(const byte *q_ptr) { DEBUG_printf("QSTR: add hash=%d len=%d data=%.*s\n", Q_GET_HASH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_DATA(q_ptr)); // make sure we have room in the pool for a new qstr if (MP_STATE_VM(last_pool)->len >= MP_STATE_VM(last_pool)->alloc) { - qstr_pool_t *pool = m_new_obj_var(qstr_pool_t, const char*, MP_STATE_VM(last_pool)->alloc * 2); + qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char*, MP_STATE_VM(last_pool)->alloc * 2); + if (pool == NULL) { + QSTR_EXIT(); + m_malloc_fail(MP_STATE_VM(last_pool)->alloc * 2); + } pool->prev = MP_STATE_VM(last_pool); pool->total_prev_len = MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len; pool->alloc = MP_STATE_VM(last_pool)->alloc * 2; @@ -169,6 +186,7 @@ qstr qstr_from_str(const char *str) { qstr qstr_from_strn(const char *str, size_t len) { assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); + QSTR_ENTER(); qstr q = qstr_find_strn(str, len); if (q == 0) { // qstr does not exist in interned pool so need to add it @@ -198,7 +216,11 @@ qstr qstr_from_strn(const char *str, size_t len) { MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, al); if (MP_STATE_VM(qstr_last_chunk) == NULL) { // failed to allocate a large chunk so try with exact size - MP_STATE_VM(qstr_last_chunk) = m_new(byte, n_bytes); + MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, n_bytes); + if (MP_STATE_VM(qstr_last_chunk) == NULL) { + QSTR_EXIT(); + m_malloc_fail(n_bytes); + } al = n_bytes; } MP_STATE_VM(qstr_last_alloc) = al; @@ -217,6 +239,7 @@ qstr qstr_from_strn(const char *str, size_t len) { q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; q = qstr_add(q_ptr); } + QSTR_EXIT(); return q; } @@ -228,6 +251,7 @@ byte *qstr_build_start(size_t len, byte **q_ptr) { } qstr qstr_build_end(byte *q_ptr) { + QSTR_ENTER(); qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr)); if (q == 0) { size_t len = Q_GET_LENGTH(q_ptr); @@ -238,6 +262,7 @@ qstr qstr_build_end(byte *q_ptr) { } else { m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr)); } + QSTR_EXIT(); return q; } @@ -263,6 +288,7 @@ const byte *qstr_data(qstr q, size_t *len) { } void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes) { + QSTR_ENTER(); *n_pool = 0; *n_qstr = 0; *n_str_data_bytes = 0; @@ -280,14 +306,17 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si #endif } *n_total_bytes += *n_str_data_bytes; + QSTR_EXIT(); } #if MICROPY_PY_MICROPYTHON_MEM_INFO void qstr_dump_data(void) { + QSTR_ENTER(); for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) { for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { mp_printf(&mp_plat_print, "Q(%s)\n", Q_GET_DATA(*q)); } } + QSTR_EXIT(); } #endif @@ -37,7 +37,7 @@ // first entry in enum will be MP_QSTR_NULL=0, which indicates invalid/no qstr enum { -#ifndef __QSTR_EXTRACT +#ifndef NO_QSTR #define QDEF(id, str) id, #include "genhdr/qstrdefs.generated.h" #undef QDEF diff --git a/py/runtime.c b/py/runtime.c index 7f28abbf4f..f88c92be63 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -91,6 +91,12 @@ void mp_init(void) { // start with no extensions to builtins MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif + + #if MICROPY_PY_THREAD_GIL + mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); + #endif + + MP_THREAD_GIL_ENTER(); } void mp_deinit(void) { diff --git a/py/stackctrl.c b/py/stackctrl.c index 14d1fd0429..1843e7339e 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -32,23 +32,23 @@ void mp_stack_ctrl_init(void) { volatile int stack_dummy; - MP_STATE_VM(stack_top) = (char*)&stack_dummy; + MP_STATE_THREAD(stack_top) = (char*)&stack_dummy; } void mp_stack_set_top(void *top) { - MP_STATE_VM(stack_top) = top; + MP_STATE_THREAD(stack_top) = top; } mp_uint_t mp_stack_usage(void) { // Assumes descending stack volatile int stack_dummy; - return MP_STATE_VM(stack_top) - (char*)&stack_dummy; + return MP_STATE_THREAD(stack_top) - (char*)&stack_dummy; } #if MICROPY_STACK_CHECK void mp_stack_set_limit(mp_uint_t limit) { - MP_STATE_VM(stack_limit) = limit; + MP_STATE_THREAD(stack_limit) = limit; } void mp_exc_recursion_depth(void) { @@ -57,7 +57,7 @@ void mp_exc_recursion_depth(void) { } void mp_stack_check(void) { - if (mp_stack_usage() >= MP_STATE_VM(stack_limit)) { + if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { mp_exc_recursion_depth(); } } diff --git a/py/stream.c b/py/stream.c index ebdbe26b45..4fcc151dca 100644 --- a/py/stream.c +++ b/py/stream.c @@ -58,10 +58,11 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); io_func_t io_func; + const mp_stream_p_t *stream_p = s->type->protocol; if (flags & MP_STREAM_RW_WRITE) { - io_func = (io_func_t)s->type->stream_p->write; + io_func = (io_func_t)stream_p->write; } else { - io_func = s->type->stream_p->read; + io_func = stream_p->read; } *errcode = 0; @@ -94,7 +95,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); - const mp_stream_p_t *stream_p = o->type->stream_p; + const mp_stream_p_t *stream_p = o->type->protocol; if (stream_p == NULL || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) @@ -1263,6 +1263,10 @@ pending_exception_check: RAISE(obj); } + // TODO make GIL release more efficient + MP_THREAD_GIL_EXIT(); + MP_THREAD_GIL_ENTER(); + } // for loop } else { diff --git a/qemu-arm/Makefile b/qemu-arm/Makefile index 31ba6baa26..d09282a1e8 100644 --- a/qemu-arm/Makefile +++ b/qemu-arm/Makefile @@ -53,6 +53,9 @@ OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ_TEST += $(BUILD)/tinytest.o +# we can't use LTO for nlrthumb.c because it contains inline assembler +$(PY_BUILD)/nlrthumb.o: CFLAGS += -fno-lto + all: run run: $(BUILD)/firmware.elf diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c index 6b935bbab0..ae2beabcd0 100644 --- a/qemu-arm/test_main.c +++ b/qemu-arm/test_main.c @@ -73,7 +73,7 @@ void gc_collect(void) { void *sp = (void*)&dummy; // trace the stack, including the registers (since they live on the stack in this function) - gc_collect_root((void**)sp, ((uint32_t)MP_STATE_VM(stack_top) - (uint32_t)sp) / sizeof(uint32_t)); + gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - (uint32_t)sp) / sizeof(uint32_t)); gc_collect_end(); } diff --git a/stmhal/boards/OLIMEX_E407/mpconfigboard.h b/stmhal/boards/OLIMEX_E407/mpconfigboard.h new file mode 100644 index 0000000000..4d1f7ff834 --- /dev/null +++ b/stmhal/boards/OLIMEX_E407/mpconfigboard.h @@ -0,0 +1,87 @@ +#define STM32E407 + +#define MICROPY_HW_BOARD_NAME "OLIMEX STM32-E407" +#define MICROPY_HW_MCU_NAME "STM32F407" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LIS3DSH (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_CAN (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#if MICROPY_HW_HAS_SWITCH == 0 +#define MICROPY_HW_UART1_PORT (GPIOB) +#define MICROPY_HW_UART1_PINS (GPIO_PIN_6 | GPIO_PIN_7) +#endif + +#define MICROPY_HW_UART2_PORT (GPIOA) +#define MICROPY_HW_UART2_PINS (GPIO_PIN_2 | GPIO_PIN_3) +#define MICROPY_HW_UART2_RTS (GPIO_PIN_1) +#define MICROPY_HW_UART2_CTS (GPIO_PIN_0) + +#define MICROPY_HW_UART3_PORT (GPIOD) +#define MICROPY_HW_UART3_PINS (GPIO_PIN_8 | GPIO_PIN_9) +#define MICROPY_HW_UART3_RTS (GPIO_PIN_12) +#define MICROPY_HW_UART3_CTS (GPIO_PIN_11) + +#if MICROPY_HW_HAS_SWITCH == 0 +// NOTE: A0 also connects to the user switch. To use UART4 you should +// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back +// of the board near the USER switch). +#define MICROPY_HW_UART4_PORT (GPIOA) +#define MICROPY_HW_UART4_PINS (GPIO_PIN_0 | GPIO_PIN_1) +#endif + +#define MICROPY_HW_UART6_PORT (GPIOC) +#define MICROPY_HW_UART6_PINS (GPIO_PIN_6 | GPIO_PIN_7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_C13) +#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) +#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C11) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/stmhal/boards/OLIMEX_E407/mpconfigboard.mk b/stmhal/boards/OLIMEX_E407/mpconfigboard.mk new file mode 100644 index 0000000000..ece09caa13 --- /dev/null +++ b/stmhal/boards/OLIMEX_E407/mpconfigboard.mk @@ -0,0 +1,4 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F407xx +AF_FILE = boards/stm32f405_af.csv +LD_FILE = boards/stm32f405.ld diff --git a/stmhal/boards/OLIMEX_E407/pins.csv b/stmhal/boards/OLIMEX_E407/pins.csv new file mode 100644 index 0000000000..6b91f74ae4 --- /dev/null +++ b/stmhal/boards/OLIMEX_E407/pins.csv @@ -0,0 +1,85 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PC4,PC4 +PC5,PC5 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +LED_GREEN,PC13 +PC14,PC14 +PC15,PC15 +PH0,PH0 +PH1,PH1 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PA0,PA0 + diff --git a/stmhal/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/stmhal/boards/OLIMEX_E407/stm32f4xx_hal_conf.h new file mode 100644 index 0000000000..de2e5f7e7e --- /dev/null +++ b/stmhal/boards/OLIMEX_E407/stm32f4xx_hal_conf.h @@ -0,0 +1,407 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +#define USE_USB_FS + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)0x0500) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/stmhal/can.c b/stmhal/can.c index 262c487f62..88d66b6530 100644 --- a/stmhal/can.c +++ b/stmhal/can.c @@ -888,7 +888,7 @@ const mp_obj_type_t pyb_can_type = { .name = MP_QSTR_CAN, .print = pyb_can_print, .make_new = pyb_can_make_new, - .stream_p = &can_stream_p, + .protocol = &can_stream_p, .locals_dict = (mp_obj_t)&pyb_can_locals_dict, }; diff --git a/stmhal/dma.c b/stmhal/dma.c index 9f3e87fb9e..218d0fbef2 100644 --- a/stmhal/dma.c +++ b/stmhal/dma.c @@ -267,8 +267,10 @@ const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, DMA_PERIPH_TO_M const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_dac }; const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_spi_i2c }; */ -#if MICROPY_HW_HAS_SDCARD +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +// defined twice as L4 HAL only needs one channel and can correctly switch direction but sdcard.c needs two channels const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel4, DMA_REQUEST_7, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_sdio }; +const dma_descr_t dma_SDIO_0_RX= { DMA2_Channel4, DMA_REQUEST_7, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_sdio }; #endif /* not preferred streams const dma_descr_t dma_ADC_3_RX = { DMA2_Channel5, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_11, NULL }; diff --git a/stmhal/dma.h b/stmhal/dma.h index 5880029f3d..5199bd3721 100644 --- a/stmhal/dma.h +++ b/stmhal/dma.h @@ -73,7 +73,8 @@ extern const dma_descr_t dma_I2C_1_TX; extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; extern const dma_descr_t dma_SPI_3_TX; -extern const dma_descr_t dma_SDIO_1_TX; +extern const dma_descr_t dma_SDIO_0_TX; +extern const dma_descr_t dma_SDIO_0_RX; #endif diff --git a/stmhal/hal/HALCOMMITS b/stmhal/hal/HALCOMMITS index e16d23ed2c..7e8feb62b2 100644 --- a/stmhal/hal/HALCOMMITS +++ b/stmhal/hal/HALCOMMITS @@ -4,6 +4,9 @@ should be separate from any other changes and should be listed here, most recent commit at the top of the list. This makes it easier to upgrade to a new HAL version. +daa279a3a1b38bc7a8218e2c6186e63483c7cfc3 +stmhal: Port of f4 hal commit 1d7fb82 to l4 hal + d4c33499579eb8f4febec2f5f01f5021f719fdaf stmhal: L4: Adapt UART HAL to avoid 64-bit integer division. diff --git a/stmhal/hal/l4/inc/stm32l4xx_hal_sd.h b/stmhal/hal/l4/inc/stm32l4xx_hal_sd.h index 3735978cf6..1baa66a9d2 100644 --- a/stmhal/hal/l4/inc/stm32l4xx_hal_sd.h +++ b/stmhal/hal/l4/inc/stm32l4xx_hal_sd.h @@ -643,8 +643,9 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd); * @{ */ /* Blocking mode: Polling */ -HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); -HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +// dpgeorge: read/write functions renamed to emphasise that address is given by block number +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks); HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr); /* Non-Blocking mode: Interrupt */ @@ -659,8 +660,9 @@ void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd); void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd); /* Non-Blocking mode: DMA */ -HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); -HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +// dpgeorge: read/write functions renamed to emphasise that address is given by block number +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks); HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); /** diff --git a/stmhal/hal/l4/src/stm32l4xx_hal_sd.c b/stmhal/hal/l4/src/stm32l4xx_hal_sd.c index 6956fb925d..10d4e8b0e5 100644 --- a/stmhal/hal/l4/src/stm32l4xx_hal_sd.c +++ b/stmhal/hal/l4/src/stm32l4xx_hal_sd.c @@ -459,13 +459,13 @@ __weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) * is managed by polling mode. * @param hsd: SD handle * @param pReadBuffer: pointer to the buffer that will contain the received data - * @param ReadAddr: Address from where data is to be read + * @param BlockNumber: Block number from where data is to be read (byte address = BlockNumber * BlockSize) * @param BlockSize: SD card Data block size * @note BlockSize must be 512 bytes. * @param NumberOfBlocks: Number of SD blocks to read * @retval SD Card error state */ -HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks) { SDMMC_CmdInitTypeDef sdmmc_cmdinitstructure; SDMMC_DataInitTypeDef sdmmc_datainitstructure; @@ -475,10 +475,16 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff /* Initialize data control register */ hsd->Instance->DCTRL = 0; + uint32_t ReadAddr; if (hsd->CardType == HIGH_CAPACITY_SD_CARD) { BlockSize = 512; - ReadAddr /= 512; + ReadAddr = BlockNumber; + } + else + { + // should not overflow for standard-capacity cards + ReadAddr = BlockNumber * BlockSize; } /* Set Block Size for Card */ @@ -517,7 +523,7 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; } - sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + sdmmc_cmdinitstructure.Argument = ReadAddr; SDMMC_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); /* Read block(s) in polling mode */ @@ -635,13 +641,13 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff * transfer is managed by polling mode. * @param hsd: SD handle * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit - * @param WriteAddr: Address from where data is to be written + * @param BlockNumber: Block number to where data is to be written (byte address = BlockNumber * BlockSize) * @param BlockSize: SD card Data block size * @note BlockSize must be 512 bytes. * @param NumberOfBlocks: Number of SD blocks to write * @retval SD Card error state */ -HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks) { SDMMC_CmdInitTypeDef sdmmc_cmdinitstructure; SDMMC_DataInitTypeDef sdmmc_datainitstructure; @@ -653,10 +659,16 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu /* Initialize data control register */ hsd->Instance->DCTRL = 0; + uint32_t WriteAddr; if (hsd->CardType == HIGH_CAPACITY_SD_CARD) { BlockSize = 512; - WriteAddr /= 512; + WriteAddr = BlockNumber; + } + else + { + // should not overflow for standard-capacity cards + WriteAddr = BlockNumber * BlockSize; } /* Set Block Size for Card */ @@ -686,7 +698,7 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK; } - sdmmc_cmdinitstructure.Argument = (uint32_t)WriteAddr; + sdmmc_cmdinitstructure.Argument = WriteAddr; SDMMC_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); /* Check for error conditions */ @@ -845,13 +857,13 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu * to check the completion of the read process * @param hsd: SD handle * @param pReadBuffer: Pointer to the buffer that will contain the received data - * @param ReadAddr: Address from where data is to be read + * @param BlockNumber: Block number from where data is to be read (byte address = BlockNumber * BlockSize) * @param BlockSize: SD card Data block size * @note BlockSize must be 512 bytes. * @param NumberOfBlocks: Number of blocks to read. * @retval SD Card error state */ -HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks) { SDMMC_CmdInitTypeDef sdmmc_cmdinitstructure; SDMMC_DataInitTypeDef sdmmc_datainitstructure; @@ -895,10 +907,16 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead /* Enable the DMA Channel */ HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)&hsd->Instance->FIFO, (uint32_t)pReadBuffer, (uint32_t)(BlockSize * NumberOfBlocks)/4); + uint32_t ReadAddr; if (hsd->CardType == HIGH_CAPACITY_SD_CARD) { BlockSize = 512; - ReadAddr /= 512; + ReadAddr = BlockNumber; + } + else + { + // should not overflow for standard-capacity cards + ReadAddr = BlockNumber * BlockSize; } /* Set Block Size for Card */ @@ -938,7 +956,7 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; } - sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + sdmmc_cmdinitstructure.Argument = ReadAddr; SDMMC_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); /* Check for error conditions */ @@ -965,13 +983,13 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead * to check the completion of the write process (by SD current status polling). * @param hsd: SD handle * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit - * @param WriteAddr: Address from where data is to be read + * @param @param BlockNumber: Block number to where data is to be written (byte address = BlockNumber * BlockSize) * @param BlockSize: the SD card Data block size * @note BlockSize must be 512 bytes. * @param NumberOfBlocks: Number of blocks to write * @retval SD Card error state */ -HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks) { SDMMC_CmdInitTypeDef sdmmc_cmdinitstructure; SDMMC_DataInitTypeDef sdmmc_datainitstructure; @@ -1015,10 +1033,16 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWri /* Enable SDMMC DMA transfer */ __HAL_SD_SDMMC_DMA_ENABLE(hsd); + uint32_t WriteAddr; if (hsd->CardType == HIGH_CAPACITY_SD_CARD) { BlockSize = 512; - WriteAddr /= 512; + WriteAddr = BlockNumber; + } + else + { + // should not overflow for standard-capacity cards + WriteAddr = BlockNumber * BlockSize; } /* Set Block Size for Card */ diff --git a/stmhal/moduselect.c b/stmhal/moduselect.c index e87478ae62..92e77e6ca8 100644 --- a/stmhal/moduselect.c +++ b/stmhal/moduselect.c @@ -53,12 +53,13 @@ STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_ if (elem->value == NULL) { // object not found; get its ioctl and add it to the poll list mp_obj_type_t *type = mp_obj_get_type(obj[i]); - if (type->stream_p == NULL || type->stream_p->ioctl == NULL) { + const mp_stream_p_t *stream_p = type->protocol; + if (stream_p == NULL || stream_p->ioctl == NULL) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "object with stream.ioctl required")); } poll_obj_t *poll_obj = m_new_obj(poll_obj_t); poll_obj->obj = obj[i]; - poll_obj->ioctl = type->stream_p->ioctl; + poll_obj->ioctl = stream_p->ioctl; poll_obj->flags = flags; poll_obj->flags_ret = 0; elem->value = poll_obj; diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c index 9cc1f3314a..fbd1196446 100644 --- a/stmhal/modusocket.c +++ b/stmhal/modusocket.c @@ -376,7 +376,7 @@ STATIC const mp_obj_type_t socket_type = { { &mp_type_type }, .name = MP_QSTR_socket, .make_new = socket_make_new, - .stream_p = &socket_stream_p, + .protocol = &socket_stream_p, .locals_dict = (mp_obj_t)&socket_locals_dict, }; diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index 352b7c10c2..cf31f53acf 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -123,7 +123,7 @@ STATIC const mp_obj_type_t stdio_obj_type = { .print = stdio_obj_print, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &stdio_obj_stream_p, + .protocol = &stdio_obj_stream_p, .locals_dict = (mp_obj_t)&stdio_locals_dict, }; @@ -156,7 +156,7 @@ STATIC const mp_obj_type_t stdio_buffer_obj_type = { .print = stdio_obj_print, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &stdio_buffer_obj_stream_p, + .protocol = &stdio_buffer_obj_stream_p, .locals_dict = (mp_obj_t)&stdio_locals_dict, }; diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index 32c9df60a2..caf6dc8d5d 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -40,9 +40,9 @@ #if MICROPY_HW_HAS_SDCARD -#if defined(MCU_SERIES_F7) +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) -// The F7 series calls the peripheral SDMMC rather than SDIO, so provide some +// The F7 & L4 series calls the peripheral SDMMC rather than SDIO, so provide some // #defines for backwards compatability. #define SDIO SDMMC1 @@ -65,11 +65,6 @@ #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV -#elif defined(MCU_SERIES_L4) - -// The L4 series is not supported -#error Unsupported Processor - #endif // TODO: Since SDIO is fundamentally half-duplex, we really only need to diff --git a/stmhal/uart.c b/stmhal/uart.c index 210330e81a..cbcb7c059b 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -933,6 +933,6 @@ const mp_obj_type_t pyb_uart_type = { .make_new = pyb_uart_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &uart_stream_p, + .protocol = &uart_stream_p, .locals_dict = (mp_obj_t)&pyb_uart_locals_dict, }; diff --git a/stmhal/usb.c b/stmhal/usb.c index b786fb7584..4ef6bfa500 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -530,7 +530,7 @@ const mp_obj_type_t pyb_usb_vcp_type = { .make_new = pyb_usb_vcp_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &pyb_usb_vcp_stream_p, + .protocol = &pyb_usb_vcp_stream_p, .locals_dict = (mp_obj_t)&pyb_usb_vcp_locals_dict, }; @@ -614,7 +614,7 @@ const mp_obj_type_t pyb_usb_hid_type = { { &mp_type_type }, .name = MP_QSTR_USB_HID, .make_new = pyb_usb_hid_make_new, - .stream_p = &pyb_usb_hid_stream_p, + .protocol = &pyb_usb_hid_stream_p, .locals_dict = (mp_obj_t)&pyb_usb_hid_locals_dict, }; diff --git a/teensy/README.md b/teensy/README.md index 14a5e4a713..3e4a75b9ed 100644 --- a/teensy/README.md +++ b/teensy/README.md @@ -56,3 +56,17 @@ include Makefile GNUmakefile is not checked into the source code control system, so it will retain your settings when updating your source tree. You can also add additional Makefile customizations this way. + +### Tips for OSX + +Set the ARDUINO environment variable to the location where Arduino with TeensyDuino is installed. +```bash +export ARDUINO=~/Downloads/Arduino.app/Contents/Java/ +``` + +Search /dev/ for USB port name, which will be cu.usbmodem followed by a few numbers. The name of the port maybe different depending on the version of OSX. +To access the Python prompt type: + +```bash +screen <devicename> 115200 +``` diff --git a/tests/basics/ordereddict_eq.py b/tests/basics/ordereddict_eq.py new file mode 100644 index 0000000000..2746608772 --- /dev/null +++ b/tests/basics/ordereddict_eq.py @@ -0,0 +1,44 @@ +try: + from collections import OrderedDict +except ImportError: + try: + from ucollections import OrderedDict + except ImportError: + print("SKIP") + import sys + sys.exit() + +x = OrderedDict() +y = OrderedDict() +x['a'] = 1 +x['b'] = 2 +y['a'] = 1 +y['b'] = 2 +print(x) +print(y) +print(x == y) + +z = OrderedDict() +z['b'] = 2 +z['a'] = 1 +print(y) +print(z) +print(y == z) + +del z['b'] +z['b'] = 2 +print(y) +print(z) +print(y == z) + +del x['a'] +del y['a'] +print(x) +print(y) +print(x == y) + +del z['b'] +del y['b'] +print(y) +print(z) +print(y == z) diff --git a/tests/basics/ordereddict_eq.py.exp b/tests/basics/ordereddict_eq.py.exp new file mode 100644 index 0000000000..892ba0e3bd --- /dev/null +++ b/tests/basics/ordereddict_eq.py.exp @@ -0,0 +1,15 @@ +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'a': 1, 'b': 2}) +True +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'b': 2, 'a': 1}) +False +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'a': 1, 'b': 2}) +True +OrderedDict({'b': 2}) +OrderedDict({'b': 2}) +True +OrderedDict({}) +OrderedDict({'a': 1}) +False diff --git a/tests/bench/bytealloc-1-bytes_n.py b/tests/bench/bytealloc-1-bytes_n.py new file mode 100644 index 0000000000..4a4bbc6fae --- /dev/null +++ b/tests/bench/bytealloc-1-bytes_n.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num // 1000)): + bytes(10000) + +bench.run(test) diff --git a/tests/bench/bytealloc-2-repeat.py b/tests/bench/bytealloc-2-repeat.py new file mode 100644 index 0000000000..786a804622 --- /dev/null +++ b/tests/bench/bytealloc-2-repeat.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num // 1000)): + b"\0" * 10000 + +bench.run(test) diff --git a/tests/extmod/btree1.py b/tests/extmod/btree1.py new file mode 100644 index 0000000000..11acd7c98f --- /dev/null +++ b/tests/extmod/btree1.py @@ -0,0 +1,59 @@ +try: + import btree +except ImportError: + print("SKIP") + import sys + sys.exit() + +db = btree.open(None) +db[b"foo3"] = b"bar3" +db[b"foo1"] = b"bar1" +db[b"foo2"] = b"bar2" +db[b"bar1"] = b"foo1" + +print(db[b"foo2"]) +try: + print(db[b"foo"]) +except KeyError: + print("KeyError") +print(db.get(b"foo")) +print(db.get(b"foo", b"dflt")) + +del db[b"foo2"] +try: + del db[b"foo"] +except KeyError: + print("KeyError") + +for k, v in db.items(): + print((k, v)) + +print("---") +for k, v in db.items(None, None): + print((k, v)) + +print("---") +for k, v in db.items(b"f"): + print((k, v)) + +print("---") +for k, v in db.items(b"f", b"foo3"): + print((k, v)) + +print("---") +for k, v in db.items(None, b"foo3"): + print((k, v)) + +print("---") +for k, v in db.items(b"f", b"foo3", btree.INCL): + print((k, v)) + +print("---") +for k, v in db.items(None, None, btree.DESC): + print((k, v)) + +print(list(db.keys())) +print(list(db.values())) + +for k in db: + print(k) diff --git a/tests/extmod/btree1.py.exp b/tests/extmod/btree1.py.exp new file mode 100644 index 0000000000..a266d7acfc --- /dev/null +++ b/tests/extmod/btree1.py.exp @@ -0,0 +1,32 @@ +b'bar2' +KeyError +None +b'dflt' +KeyError +(b'bar1', b'foo1') +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'bar1', b'foo1') +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo1', b'bar1') +--- +(b'bar1', b'foo1') +(b'foo1', b'bar1') +--- +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo3', b'bar3') +(b'foo1', b'bar1') +(b'bar1', b'foo1') +[b'bar1', b'foo1', b'foo3'] +[b'foo1', b'bar1', b'bar3'] +b'bar1' +b'foo1' +b'foo3' diff --git a/tests/extmod/machine_pinbase.py b/tests/extmod/machine_pinbase.py new file mode 100644 index 0000000000..07a489a596 --- /dev/null +++ b/tests/extmod/machine_pinbase.py @@ -0,0 +1,25 @@ +try: + from umachine import PinBase +except ImportError: + from machine import PinBase + + +class MyPin(PinBase): + + def __init__(self): + print("__init__") + self.v = False + + def value(self, v=None): + print("value:", v) + if v is None: + self.v = not self.v + return int(self.v) + +p = MyPin() + +print(p.value()) +print(p.value()) +print(p.value()) +p.value(1) +p.value(0) diff --git a/tests/extmod/machine_pinbase.py.exp b/tests/extmod/machine_pinbase.py.exp new file mode 100644 index 0000000000..b31cd98308 --- /dev/null +++ b/tests/extmod/machine_pinbase.py.exp @@ -0,0 +1,9 @@ +__init__ +value: None +1 +value: None +0 +value: None +1 +value: 1 +value: 0 diff --git a/tests/micropython/const.py b/tests/micropython/const.py index 457365c50a..09717fd147 100644 --- a/tests/micropython/const.py +++ b/tests/micropython/const.py @@ -9,3 +9,15 @@ def f(): print(X, Y + 1) f() + +_X = const(12) +_Y = const(_X + 34) + +print(_X, _Y) + +class A: + Z = const(1) + _Z = const(2) + print(Z, _Z) + +print(hasattr(A, 'Z'), hasattr(A, '_Z')) diff --git a/tests/micropython/const.py.exp b/tests/micropython/const.py.exp index c447aaf8c1..ece6a5cb2e 100644 --- a/tests/micropython/const.py.exp +++ b/tests/micropython/const.py.exp @@ -1,2 +1,5 @@ 123 580 123 580 +12 46 +1 2 +True False diff --git a/tests/micropython/meminfo.py.exp b/tests/micropython/meminfo.py.exp index c1a662ae6b..a229a7fa4c 100644 --- a/tests/micropython/meminfo.py.exp +++ b/tests/micropython/meminfo.py.exp @@ -1,11 +1,11 @@ mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ - No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ - No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ GC memory layout; from \[0-9a-f\]\+: ######## qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+ diff --git a/tests/misc/recursive_iternext.py b/tests/misc/recursive_iternext.py index 376c45b3c7..025fa425b5 100644 --- a/tests/misc/recursive_iternext.py +++ b/tests/misc/recursive_iternext.py @@ -5,7 +5,7 @@ try: # large stack/heap, eg unix [0] * 80000 - N = 2000 + N = 2400 except: try: # medium, eg pyboard diff --git a/tests/run-tests b/tests/run-tests index 649f1789fa..02791896b5 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -201,6 +201,13 @@ def run_tests(pyb, tests, args): skip_tests.add('float/true_value.py') skip_tests.add('float/types.py') + # Some tests shouldn't be run on a PC + if pyb is None: + # unix build does not have the GIL so can't run thread mutation tests + for t in tests: + if t.startswith('thread/mutate_'): + skip_tests.add(t) + # Some tests shouldn't be run on pyboard if pyb is not None: skip_tests.add('basics/exception_chain.py') # warning is not printed diff --git a/tests/thread/mutate_bytearray.py b/tests/thread/mutate_bytearray.py new file mode 100644 index 0000000000..f3276f1b2d --- /dev/null +++ b/tests/thread/mutate_bytearray.py @@ -0,0 +1,45 @@ +# test concurrent mutating access to a shared bytearray object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared bytearray +ba = bytearray() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + l = len(ba) + ba.append(i) + assert len(ba) >= l + 1 + + l = len(ba) + ba.extend(bytearray([i])) + assert len(ba) >= l + 1 + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 +n_repeat = 4 # use 40 for more stressful test (uses more heap) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (n_repeat, i * 256 // n_thread, (i + 1) * 256 // n_thread)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check bytearray has correct contents +print(len(ba)) +count = [0 for _ in range(256)] +for b in ba: + count[b] += 1 +print(count) + diff --git a/tests/thread/mutate_dict.py b/tests/thread/mutate_dict.py new file mode 100644 index 0000000000..c57d332d51 --- /dev/null +++ b/tests/thread/mutate_dict.py @@ -0,0 +1,42 @@ +# test concurrent mutating access to a shared dict object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared dict +di = {'a':'A', 'b':'B', 'c':'C', 'd':'D'} + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + di[i] = repeat + i + assert di[i] == repeat + i + + del di[i] + assert i not in di + + di[i] = repeat + i + assert di[i] == repeat + i + + assert di.pop(i) == repeat + i + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (30, i * 300, (i + 1) * 300)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check dict has correct contents +print(sorted(di.items())) diff --git a/tests/thread/mutate_instance.py b/tests/thread/mutate_instance.py new file mode 100644 index 0000000000..a1ae428b54 --- /dev/null +++ b/tests/thread/mutate_instance.py @@ -0,0 +1,43 @@ +# test concurrent mutating access to a shared user instance +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared user class and instance +class User: + def __init__(self): + self.a = 'A' + self.b = 'B' + self.c = 'C' +user = User() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + setattr(user, 'attr_%u' % i, repeat + i) + assert getattr(user, 'attr_%u' % i) == repeat + i + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_repeat = 30 +n_range = 50 # 300 for stressful test (uses more heap) +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (n_repeat, i * n_range, (i + 1) * n_range)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check user instance has correct contents +print(user.a, user.b, user.c) +for i in range(n_thread * n_range): + assert getattr(user, 'attr_%u' % i) == n_repeat - 1 + i diff --git a/tests/thread/mutate_list.py b/tests/thread/mutate_list.py new file mode 100644 index 0000000000..764a9bd99e --- /dev/null +++ b/tests/thread/mutate_list.py @@ -0,0 +1,44 @@ +# test concurrent mutating access to a shared list object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared list +li = list() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + li.append(i) + assert li.count(i) == repeat + 1 + + li.extend([i, i]) + assert li.count(i) == repeat + 3 + + li.remove(i) + assert li.count(i) == repeat + 2 + + li.remove(i) + assert li.count(i) == repeat + 1 + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (4, i * 60, (i + 1) * 60)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check list has correct contents +li.sort() +print(li) diff --git a/tests/thread/mutate_set.py b/tests/thread/mutate_set.py new file mode 100644 index 0000000000..5492d86313 --- /dev/null +++ b/tests/thread/mutate_set.py @@ -0,0 +1,37 @@ +# test concurrent mutating access to a shared set object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared set +se = set([-1, -2, -3, -4]) + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + se.add(i) + assert i in se + + se.remove(i) + assert i not in se + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (50, i * 500, (i + 1) * 500)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check set has correct contents +print(sorted(se)) diff --git a/tests/thread/stress_aes.py b/tests/thread/stress_aes.py new file mode 100644 index 0000000000..ecc963c925 --- /dev/null +++ b/tests/thread/stress_aes.py @@ -0,0 +1,255 @@ +# Stress test for threads using AES encryption routines. +# +# AES was chosen because it is integer based and inplace so doesn't use the +# heap. It is therefore a good test of raw performance and correctness of the +# VM/runtime. It can be used to measure threading performance (concurrency is +# in principle possible) and correctness (it's non trivial for the encryption/ +# decryption to give the correct answer). +# +# The AES code comes first (code originates from a C version authored by D.P.George) +# and then the test harness at the bottom. It can be tuned to be more/less +# agressive by changing the amount of data to encrypt, the number of loops and +# the number of threads. +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +################################################################## +# discrete arithmetic routines, mostly from a precomputed table + +# non-linear, invertible, substitution box +aes_s_box_table = bytes(( + 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16, +)) + +# multiplication of polynomials modulo x^8 + x^4 + x^3 + x + 1 = 0x11b +def aes_gf8_mul_2(x): + if x & 0x80: + return (x << 1) ^ 0x11b + else: + return x << 1 + +def aes_gf8_mul_3(x): + return x ^ aes_gf8_mul_2(x) + +# non-linear, invertible, substitution box +def aes_s_box(a): + return aes_s_box_table[a & 0xff] + +# return 0x02^(a-1) in GF(2^8) +def aes_r_con(a): + ans = 1 + while a > 1: + ans <<= 1; + if ans & 0x100: + ans ^= 0x11b + a -= 1 + return ans + +################################################################## +# basic AES algorithm; see FIPS-197 +# +# Think of it as a pseudo random number generator, with each +# symbol in the sequence being a 16 byte block (the state). The +# key is a parameter of the algorithm and tells which particular +# sequence of random symbols you want. The initial vector, IV, +# sets the start of the sequence. The idea of a strong cipher +# is that it's very difficult to guess the key even if you know +# a large part of the sequence. The basic AES algorithm simply +# provides such a sequence. En/de-cryption is implemented here +# using OCB, where the sequence is xored against the plaintext. +# Care must be taken to (almost) always choose a different IV. + +# all inputs must be size 16 +def aes_add_round_key(state, w): + for i in range(16): + state[i] ^= w[i] + +# combined sub_bytes, shift_rows, mix_columns, add_round_key +# all inputs must be size 16 +def aes_sb_sr_mc_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = aes_gf8_mul_2(x0) ^ aes_gf8_mul_3(x1) ^ x2 ^ x3 ^ w[w_idx] + temp[temp_idx + 1] = x0 ^ aes_gf8_mul_2(x1) ^ aes_gf8_mul_3(x2) ^ x3 ^ w[w_idx + 1] + temp[temp_idx + 2] = x0 ^ x1 ^ aes_gf8_mul_2(x2) ^ aes_gf8_mul_3(x3) ^ w[w_idx + 2] + temp[temp_idx + 3] = aes_gf8_mul_3(x0) ^ x1 ^ x2 ^ aes_gf8_mul_2(x3) ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# combined sub_bytes, shift_rows, add_round_key +# all inputs must be size 16 +def aes_sb_sr_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = x0 ^ w[w_idx] + temp[temp_idx + 1] = x1 ^ w[w_idx + 1] + temp[temp_idx + 2] = x2 ^ w[w_idx + 2] + temp[temp_idx + 3] = x3 ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# take state as input and change it to the next state in the sequence +# state and temp have size 16, w has size 16 * (Nr + 1), Nr >= 1 +def aes_state(state, w, temp, nr): + aes_add_round_key(state, w) + w_idx = 16 + for i in range(nr - 1): + aes_sb_sr_mc_ark(state, w, w_idx, temp) + w_idx += 16 + aes_sb_sr_ark(state, w, w_idx, temp) + +# expand 'key' to 'w' for use with aes_state +# key has size 4 * Nk, w has size 16 * (Nr + 1), temp has size 16 +def aes_key_expansion(key, w, temp, nk, nr): + for i in range(4 * nk): + w[i] = key[i] + w_idx = 4 * nk - 4 + for i in range(nk, 4 * (nr + 1)): + t = temp + t_idx = 0 + if i % nk == 0: + t[0] = aes_s_box(w[w_idx + 1]) ^ aes_r_con(i // nk) + for j in range(1, 4): + t[j] = aes_s_box(w[w_idx + (j + 1) % 4]) + elif nk > 6 and i % nk == 4: + for j in range(0, 4): + t[j] = aes_s_box(w[w_idx + j]) + else: + t = w + t_idx = w_idx + w_idx += 4 + for j in range(4): + w[w_idx + j] = w[w_idx + j - 4 * nk] ^ t[t_idx + j] + +################################################################## +# simple use of AES algorithm, using output feedback (OFB) mode + +class AES: + def __init__(self, keysize): + if keysize == 128: + self.nk = 4 + self.nr = 10 + elif keysize == 192: + self.nk = 6 + self.nr = 12 + else: + assert keysize == 256 + self.nk = 8 + self.nr = 14 + + self.state = bytearray(16) + self.w = bytearray(16 * (self.nr + 1)) + self.temp = bytearray(16) + self.state_pos = 16 + + def set_key(self, key): + aes_key_expansion(key, self.w, self.temp, self.nk, self.nr) + self.state_pos = 16 + + def set_iv(self, iv): + for i in range(16): + self.state[i] = iv[i] + self.state_pos = 16; + + def get_some_state(self, n_needed): + if self.state_pos >= 16: + aes_state(self.state, self.w, self.temp, self.nr) + self.state_pos = 0 + n = 16 - self.state_pos + if n > n_needed: + n = n_needed + return n + + def apply_to(self, data): + idx = 0 + n = len(data) + while n > 0: + ln = self.get_some_state(n) + n -= ln + for i in range(ln): + data[idx + i] ^= self.state[self.state_pos + i] + idx += ln + self.state_pos += n + +################################################################## +# test code + +try: + import utime as time +except ImportError: + import time +import _thread + +class LockedCounter: + def __init__(self): + self.lock = _thread.allocate_lock() + self.value = 0 + + def add(self, val): + self.lock.acquire() + self.value += val + self.lock.release() + +count = LockedCounter() + +def thread_entry(): + global count + + aes = AES(256) + key = bytearray(256 // 8) + iv = bytearray(16) + data = bytearray(128) + # from now on we don't use the heap + + for loop in range(5): + # encrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(8): + aes.apply_to(data) + + # decrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(8): + aes.apply_to(data) + + # verify + for i in range(len(data)): + assert data[i] == 0 + + count.add(1) + +if __name__ == '__main__': + n_thread = 20 + for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + while count.value < n_thread: + time.sleep(1) diff --git a/tests/thread/stress_heap.py b/tests/thread/stress_heap.py new file mode 100644 index 0000000000..ac3ebe0491 --- /dev/null +++ b/tests/thread/stress_heap.py @@ -0,0 +1,42 @@ +# stress test for the heap by allocating lots of objects within threads +# allocates about 5mb on the heap +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def last(l): + return l[-1] + +def thread_entry(n): + # allocate a bytearray and fill it + data = bytearray(i for i in range(256)) + + # run a loop which allocates a small list and uses it each iteration + lst = 8 * [0] + sum = 0 + for i in range(n): + sum += last(lst) + lst = [0, 0, 0, 0, 0, 0, 0, i + 1] + + # check that the bytearray still has the right data + for i, b in enumerate(data): + assert i == b + + # print the result of the loop and indicate we are finished + with lock: + print(sum, lst[-1]) + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 10 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10000,)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass diff --git a/tests/thread/stress_recurse.py b/tests/thread/stress_recurse.py new file mode 100644 index 0000000000..68367c4dd7 --- /dev/null +++ b/tests/thread/stress_recurse.py @@ -0,0 +1,25 @@ +# test hitting the function recursion limit within a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(): + foo() + +def thread_entry(): + try: + foo() + except RuntimeError: + print('RuntimeError') + global finished + finished = True + +finished = False + +_thread.start_new_thread(thread_entry, ()) + +# busy wait for thread to finish +while not finished: + pass +print('done') diff --git a/tests/thread/thread_exc1.py b/tests/thread/thread_exc1.py new file mode 100644 index 0000000000..10fb94b4fb --- /dev/null +++ b/tests/thread/thread_exc1.py @@ -0,0 +1,30 @@ +# test raising and catching an exception within a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(): + raise ValueError + +def thread_entry(): + try: + foo() + except ValueError: + pass + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print('done') diff --git a/tests/thread/thread_exit1.py b/tests/thread/thread_exit1.py new file mode 100644 index 0000000000..88cdd165c7 --- /dev/null +++ b/tests/thread/thread_exit1.py @@ -0,0 +1,19 @@ +# test _thread.exit() function +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(): + _thread.exit() + +_thread.start_new_thread(thread_entry, ()) +_thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/tests/thread/thread_exit2.py b/tests/thread/thread_exit2.py new file mode 100644 index 0000000000..368a11bba4 --- /dev/null +++ b/tests/thread/thread_exit2.py @@ -0,0 +1,19 @@ +# test raising SystemExit to finish a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(): + raise SystemExit + +_thread.start_new_thread(thread_entry, ()) +_thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/tests/thread/thread_gc1.py b/tests/thread/thread_gc1.py new file mode 100644 index 0000000000..8dcbf7e07a --- /dev/null +++ b/tests/thread/thread_gc1.py @@ -0,0 +1,34 @@ +# test that we can run the garbage collector within threads +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import gc +import _thread + +def thread_entry(n): + # allocate a bytearray and fill it + data = bytearray(i for i in range(256)) + + # do some work and call gc.collect() a few times + for i in range(n): + for i in range(len(data)): + data[i] = data[i] + gc.collect() + + # print whether the data remains intact and indicate we are finished + with lock: + print(list(data) == list(range(256))) + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10,)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass diff --git a/tests/thread/thread_ident1.py b/tests/thread/thread_ident1.py new file mode 100644 index 0000000000..217fce73b1 --- /dev/null +++ b/tests/thread/thread_ident1.py @@ -0,0 +1,21 @@ +# test _thread.get_ident() function +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def thread_entry(): + tid = _thread.get_ident() + print('thread', type(tid) == int, tid != 0, tid != tid_main) + global finished + finished = True + +tid_main = _thread.get_ident() +print('main', type(tid_main) == int, tid_main != 0) + +finished = False +_thread.start_new_thread(thread_entry, ()) + +while not finished: + pass +print('done') diff --git a/tests/thread/thread_lock1.py b/tests/thread/thread_lock1.py new file mode 100644 index 0000000000..ca585ffbb9 --- /dev/null +++ b/tests/thread/thread_lock1.py @@ -0,0 +1,40 @@ +# test _thread lock object using a single thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# create lock +lock = _thread.allocate_lock() + +print(type(lock) == _thread.LockType) + +# should be unlocked +print(lock.locked()) + +# basic acquire and release +print(lock.acquire()) +print(lock.locked()) +lock.release() +print(lock.locked()) + +# try acquire twice (second should fail) +print(lock.acquire()) +print(lock.locked()) +print(lock.acquire(0)) +print(lock.locked()) +lock.release() +print(lock.locked()) + +# test with capabilities of lock +with lock: + print(lock.locked()) + +# test that lock is unlocked if an error is rasied +try: + with lock: + print(lock.locked()) + raise KeyError +except KeyError: + print('KeyError') + print(lock.locked()) diff --git a/tests/thread/thread_lock2.py b/tests/thread/thread_lock2.py new file mode 100644 index 0000000000..405f10b0b6 --- /dev/null +++ b/tests/thread/thread_lock2.py @@ -0,0 +1,24 @@ +# test _thread lock objects with multiple threads +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +lock = _thread.allocate_lock() + +def thread_entry(): + lock.acquire() + print('have it') + lock.release() + +# spawn the threads +for i in range(4): + _thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/tests/thread/thread_lock3.py b/tests/thread/thread_lock3.py new file mode 100644 index 0000000000..607898dad8 --- /dev/null +++ b/tests/thread/thread_lock3.py @@ -0,0 +1,27 @@ +# test thread coordination using a lock object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +lock = _thread.allocate_lock() +n_thread = 10 +n_finished = 0 + +def thread_entry(idx): + global n_finished + while True: + with lock: + if n_finished == idx: + break + print('my turn:', idx) + with lock: + n_finished += 1 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (i,)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass diff --git a/tests/thread/thread_lock4.py b/tests/thread/thread_lock4.py new file mode 100644 index 0000000000..d77aa24ee8 --- /dev/null +++ b/tests/thread/thread_lock4.py @@ -0,0 +1,46 @@ +# test using lock to coordinate access to global mutable objects +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def fac(n): + x = 1 + for i in range(1, n + 1): + x *= i + return x + +def thread_entry(): + while True: + with jobs_lock: + try: + f, arg = jobs.pop(0) + except IndexError: + return + ans = f(arg) + with output_lock: + output.append((arg, ans)) + +# create a list of jobs +jobs = [(fac, i) for i in range(20, 80)] +jobs_lock = _thread.allocate_lock() +n_jobs = len(jobs) + +# create a list to store the results +output = [] +output_lock = _thread.allocate_lock() + +# spawn threads to do the jobs +for i in range(4): + _thread.start_new_thread(thread_entry, ()) + +# wait for the jobs to complete +while True: + with jobs_lock: + if len(output) == n_jobs: + break + +# sort and print the results +output.sort(key=lambda x: x[0]) +for arg, ans in output: + print(arg, ans) diff --git a/tests/thread/thread_qstr1.py b/tests/thread/thread_qstr1.py new file mode 100644 index 0000000000..c0256316e5 --- /dev/null +++ b/tests/thread/thread_qstr1.py @@ -0,0 +1,35 @@ +# test concurrent interning of strings +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# function to check the interned string +def check(s, val): + assert type(s) == str + assert int(s) == val + +# main thread function +def th(base, n): + for i in range(n): + # this will intern the string and check it + exec("check('%u', %u)" % (base + i, base + i)) + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 +n_qstr_per_thread = 100 # make 1000 for a more stressful test (uses more heap) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (i * n_qstr_per_thread, n_qstr_per_thread)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +print('pass') diff --git a/tests/thread/thread_shared1.py b/tests/thread/thread_shared1.py new file mode 100644 index 0000000000..13c6651cc4 --- /dev/null +++ b/tests/thread/thread_shared1.py @@ -0,0 +1,31 @@ +# test capability for threads to access a shared immutable data structure +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(i): + pass + +def thread_entry(n, tup): + for i in tup: + foo(i) + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# the shared data structure +tup = (1, 2, 3, 4) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (100, tup)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print(tup) diff --git a/tests/thread/thread_shared2.py b/tests/thread/thread_shared2.py new file mode 100644 index 0000000000..e4bfe78022 --- /dev/null +++ b/tests/thread/thread_shared2.py @@ -0,0 +1,32 @@ +# test capability for threads to access a shared mutable data structure +# (without contention because they access different parts of the structure) +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(lst, i): + lst[i] += 1 + +def thread_entry(n, lst, idx): + for i in range(n): + foo(lst, idx) + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# the shared data structure +lst = [0, 0] + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ((i + 1) * 10, lst, i)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print(lst) diff --git a/tests/thread/thread_sleep1.py b/tests/thread/thread_sleep1.py new file mode 100644 index 0000000000..032ec17543 --- /dev/null +++ b/tests/thread/thread_sleep1.py @@ -0,0 +1,31 @@ +# test threads sleeping +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime + sleep_ms = utime.sleep_ms +except ImportError: + import time + sleep_ms = lambda t: time.sleep(t / 1000) + +import _thread + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +def thread_entry(t): + global n_finished + sleep_ms(t) + sleep_ms(2 * t) + with lock: + n_finished += 1 + +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10 * i,)) + +# wait for threads to finish +while n_finished < n_thread: + sleep_ms(100) +print('done', n_thread) diff --git a/tests/thread/thread_stacksize1.py b/tests/thread/thread_stacksize1.py new file mode 100644 index 0000000000..e62899631f --- /dev/null +++ b/tests/thread/thread_stacksize1.py @@ -0,0 +1,44 @@ +# test setting the thread stack size +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import sys +import _thread + +# different implementations have different minimum sizes +if sys.implementation.name == 'micropython': + sz = 2 * 1024 +else: + sz = 32 * 1024 + +def foo(): + pass + +def thread_entry(): + foo() + with lock: + global n_finished + n_finished += 1 + +# reset stack size to default +_thread.stack_size() + +# test set/get of stack size +print(_thread.stack_size()) +print(_thread.stack_size(sz)) +print(_thread.stack_size() == sz) +print(_thread.stack_size()) + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# set stack size and spawn a few threads +_thread.stack_size(sz) +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print('done') diff --git a/tests/thread/thread_start1.py b/tests/thread/thread_start1.py new file mode 100644 index 0000000000..d23a74aa21 --- /dev/null +++ b/tests/thread/thread_start1.py @@ -0,0 +1,23 @@ +# test basic capability to start a new thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def foo(): + pass + +def thread_entry(n): + for i in range(n): + foo() + +_thread.start_new_thread(thread_entry, (10,)) +_thread.start_new_thread(thread_entry, (20,)) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/tests/thread/thread_start2.py b/tests/thread/thread_start2.py new file mode 100644 index 0000000000..4efa808eb9 --- /dev/null +++ b/tests/thread/thread_start2.py @@ -0,0 +1,19 @@ +# test capability to start a thread with keyword args +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(a0, a1, a2, a3): + print('thread', a0, a1, a2, a3) + +# spawn thread using kw args +_thread.start_new_thread(thread_entry, (10, 20), {'a2': 0, 'a3': 1}) + +# wait for thread to finish +time.sleep(1) +print('done') diff --git a/unix/Makefile b/unix/Makefile index 90653e88e8..2e0cbfd35a 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -28,7 +28,7 @@ ifdef DEBUG CFLAGS += -g COPT = -O0 else -COPT = -Os #-DNDEBUG +COPT = -Os -fdata-sections -ffunction-sections #-DNDEBUG # _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra # security for detecting buffer overflows. Some distros (Ubuntu at the very least) # have it enabled by default. @@ -63,10 +63,10 @@ endif ifeq ($(UNAME_S),Darwin) CC = clang # Use clang syntax for map file -LDFLAGS_ARCH = -Wl,-map,$@.map +LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip else # Use gcc syntax for map file -LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref +LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections endif LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) @@ -85,16 +85,6 @@ INC += -I../lib/mp-readline CFLAGS_MOD += -DMICROPY_USE_READLINE=1 LIB_SRC_C_EXTRA += mp-readline/readline.c endif -ifeq ($(MICROPY_USE_READLINE),2) -CFLAGS_MOD += -DMICROPY_USE_READLINE=2 -LDFLAGS_MOD += -lreadline -# the following is needed for BSD -#LDFLAGS_MOD += -ltermcap -endif -ifeq ($(MICROPY_PY_TIME),1) -CFLAGS_MOD += -DMICROPY_PY_TIME=1 -SRC_MOD += modtime.c -endif ifeq ($(MICROPY_PY_TERMIOS),1) CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 SRC_MOD += modtermios.c @@ -103,6 +93,10 @@ ifeq ($(MICROPY_PY_SOCKET),1) CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 SRC_MOD += modsocket.c endif +ifeq ($(MICROPY_PY_THREAD),1) +CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0 +LDFLAGS_MOD += -lpthread +endif ifeq ($(MICROPY_PY_FFI),1) @@ -138,10 +132,12 @@ SRC_C = \ main.c \ gccollect.c \ unix_mphal.c \ + mpthreadport.c \ input.c \ file.c \ modmachine.c \ modos.c \ + modtime.c \ moduselect.c \ alloc.c \ coverage.c \ @@ -162,9 +158,13 @@ endif LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ utils/printf.c \ + timeutils/timeutils.c \ + ) + +# FatFS VFS support +LIB_SRC_C += $(addprefix lib/,\ fatfs/ff.c \ fatfs/option/ccsbcs.c \ - timeutils/timeutils.c \ ) OBJ = $(PY_O) @@ -235,7 +235,11 @@ fast: # build a minimal interpreter minimal: - $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_minimal.h>"' BUILD=build-minimal PROG=micropython_minimal MICROPY_PY_TIME=0 MICROPY_PY_TERMIOS=0 MICROPY_PY_SOCKET=0 MICROPY_PY_FFI=0 MICROPY_USE_READLINE=0 + $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_minimal.h>"' \ + BUILD=build-minimal PROG=micropython_minimal \ + MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_SOCKET=0 MICROPY_PY_THREAD=0 \ + MICROPY_PY_TERMIOS=0 MICROPY_PY_USSL=0 \ + MICROPY_USE_READLINE=0 MICROPY_FATFS=0 # build interpreter with nan-boxing as object model nanbox: @@ -260,7 +264,7 @@ freedos: # build an interpreter for coverage testing and do the testing coverage: - $(MAKE) COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_coverage.h>" -fprofile-arcs -ftest-coverage -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wuninitialized -Wunused-parameter -DMICROPY_UNIX_COVERAGE' LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' BUILD=build-coverage PROG=micropython_coverage + $(MAKE) COPT="-O0" MICROPY_PY_BTREE=0 CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_coverage.h>" -fprofile-arcs -ftest-coverage -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wuninitialized -Wunused-parameter -DMICROPY_UNIX_COVERAGE' LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' BUILD=build-coverage PROG=micropython_coverage coverage_test: coverage $(eval DIRNAME=$(notdir $(CURDIR))) @@ -301,7 +305,7 @@ libffi: cd ../lib/libffi; git clean -d -x -f cd ../lib/libffi; ./autogen.sh mkdir -p ../lib/libffi/build_dir; cd ../lib/libffi/build_dir; \ - ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ + ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \ make install-exec-recursive; make -C include install-data-am axtls: ../lib/axtls/README diff --git a/unix/alloc.c b/unix/alloc.c index a0676a0aef..04c635ee97 100644 --- a/unix/alloc.c +++ b/unix/alloc.c @@ -33,7 +33,7 @@ #include "py/mpstate.h" #include "py/gc.h" -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) #if defined(__OpenBSD__) || defined(__MACH__) #define MAP_ANONYMOUS MAP_ANON @@ -85,4 +85,23 @@ void mp_unix_mark_exec(void) { } } -#endif // MICROPY_EMIT_NATIVE +#if MICROPY_FORCE_PLAT_ALLOC_EXEC +// Provide implementation of libffi ffi_closure_* functions in terms +// of the functions above. On a normal Linux system, this save a lot +// of code size. +void *ffi_closure_alloc(size_t size, void **code); +void ffi_closure_free(void *ptr); + +void *ffi_closure_alloc(size_t size, void **code) { + mp_uint_t dummy; + mp_unix_alloc_exec(size, code, &dummy); + return *code; +} + +void ffi_closure_free(void *ptr) { + (void)ptr; + // TODO +} +#endif + +#endif // MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) diff --git a/unix/file.c b/unix/file.c index 33acdccd06..a7620e079e 100644 --- a/unix/file.c +++ b/unix/file.c @@ -88,6 +88,14 @@ STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in } #endif mp_int_t r = write(o->fd, buf, size); + while (r == -1 && errno == EINTR) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + r = write(o->fd, buf, size); + } if (r == -1) { *errcode = errno; return MP_STREAM_ERROR; @@ -242,7 +250,7 @@ const mp_obj_type_t mp_type_fileio = { .make_new = fdfile_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &fileio_stream_p, + .protocol = &fileio_stream_p, .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, }; #endif @@ -261,7 +269,7 @@ const mp_obj_type_t mp_type_textio = { .make_new = fdfile_make_new, .getiter = mp_identity, .iternext = mp_stream_unbuffered_iter, - .stream_p = &textio_stream_p, + .protocol = &textio_stream_p, .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, }; diff --git a/unix/gccollect.c b/unix/gccollect.c index 125c273a30..397c4ffe1c 100644 --- a/unix/gccollect.c +++ b/unix/gccollect.c @@ -136,15 +136,25 @@ STATIC void gc_helper_get_regs(regs_t arr) { #endif // MICROPY_GCREGS_SETJMP -void gc_collect(void) { - //gc_dump_info(); +// this function is used by mpthreadport.c +void gc_collect_regs_and_stack(void); - gc_collect_start(); +void gc_collect_regs_and_stack(void) { regs_t regs; gc_helper_get_regs(regs); // GC stack (and regs because we captured them) void **regs_ptr = (void**)(void*)®s; - gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_VM(stack_top) - (uintptr_t)®s) / sizeof(uintptr_t)); + gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)®s) / sizeof(uintptr_t)); +} + +void gc_collect(void) { + //gc_dump_info(); + + gc_collect_start(); + gc_collect_regs_and_stack(); + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif #if MICROPY_EMIT_NATIVE mp_unix_mark_exec(); #endif diff --git a/unix/main.c b/unix/main.c index dedee28e7f..a1c057400f 100644 --- a/unix/main.c +++ b/unix/main.c @@ -45,6 +45,7 @@ #include "py/gc.h" #include "py/stackctrl.h" #include "py/mphal.h" +#include "py/mpthread.h" #include "extmod/misc.h" #include "genhdr/mpversion.h" #include "input.h" @@ -292,7 +293,7 @@ STATIC int usage(char **argv) { "-v : verbose (trace various operations); can be multiple\n" "-O[N] : apply bytecode optimizations of level N\n" "\n" -"Implementation specific options:\n", argv[0] +"Implementation specific options (-X):\n", argv[0] ); int impl_opts_cnt = 0; printf( @@ -302,7 +303,7 @@ STATIC int usage(char **argv) { impl_opts_cnt++; #if MICROPY_ENABLE_GC printf( -" heapsize=<n> -- set the heap size for the GC (default %ld)\n" +" heapsize=<n>[w][K|M] -- set the heap size for the GC (default %ld)\n" , heap_size); impl_opts_cnt++; #endif @@ -350,12 +351,20 @@ STATIC void pre_process_options(int argc, char **argv) { heap_size *= 1024; } else if ((*end | 0x20) == 'm') { heap_size *= 1024 * 1024; + } else { + // Compensate for ++ below + --end; + } + if (*++end != 0) { + goto invalid_arg; } if (word_adjust) { heap_size = heap_size * BYTES_PER_WORD / 4; } #endif } else { +invalid_arg: + printf("Invalid option\n"); exit(usage(argv)); } a++; @@ -379,6 +388,9 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) { MP_NOINLINE int main_(int argc, char **argv); int main(int argc, char **argv) { + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif // We should capture stack top ASAP after start, and it should be // captured guaranteedly before any other stack variables are allocated. // For this, actual main (renamed main_) should not be inlined into @@ -432,10 +444,12 @@ MP_NOINLINE int main_(int argc, char **argv) { } if (p[0] == '~' && p[1] == '/' && home != NULL) { // Expand standalone ~ to $HOME - CHECKBUF(buf, PATH_MAX); - CHECKBUF_APPEND(buf, home, strlen(home)); - CHECKBUF_APPEND(buf, p + 1, (size_t)(p1 - p - 1)); - path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(buf, CHECKBUF_LEN(buf))); + int home_l = strlen(home); + vstr_t vstr; + vstr_init(&vstr, home_l + (p1 - p - 1) + 1); + vstr_add_strn(&vstr, home, home_l); + vstr_add_strn(&vstr, p + 1, p1 - p - 1); + path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } else { path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p)); } diff --git a/unix/modmachine.c b/unix/modmachine.c index 5c032c3466..166d47712d 100644 --- a/unix/modmachine.c +++ b/unix/modmachine.c @@ -31,6 +31,8 @@ #include "py/obj.h" #include "extmod/machine_mem.h" +#include "extmod/machine_pinbase.h" +#include "extmod/machine_pulse.h" #if MICROPY_PLAT_DEV_MEM #include <errno.h> @@ -78,6 +80,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PinBase), MP_ROM_PTR(&machine_pinbase_type) }, + #if MICROPY_PY_MACHINE_PULSE + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/unix/modsocket.c b/unix/modsocket.c index 8e0d86fc79..cd68b20a45 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -381,7 +381,7 @@ STATIC const mp_obj_type_t usocket_type = { .make_new = socket_make_new, .getiter = NULL, .iternext = NULL, - .stream_p = &usocket_stream_p, + .protocol = &usocket_stream_p, .locals_dict = (mp_obj_dict_t*)&usocket_locals_dict, }; diff --git a/unix/modtime.c b/unix/modtime.c index d3b780790c..6843238cf3 100644 --- a/unix/modtime.c +++ b/unix/modtime.c @@ -24,6 +24,9 @@ * THE SOFTWARE. */ +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME + #include <unistd.h> #include <errno.h> #include <string.h> @@ -118,7 +121,9 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { tv.tv_sec = ipart; int res; while (1) { + MP_THREAD_GIL_EXIT(); res = sleep_select(0, NULL, NULL, NULL, &tv); + MP_THREAD_GIL_ENTER(); #if MICROPY_SELECT_REMAINING_TIME // TODO: This assumes Linux behavior of modifying tv to the remaining // time. @@ -136,20 +141,26 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { RAISE_ERRNO(res, errno); #else // TODO: Handle EINTR + MP_THREAD_GIL_EXIT(); sleep(mp_obj_get_int(arg)); + MP_THREAD_GIL_ENTER(); #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); STATIC mp_obj_t mod_time_sleep_ms(mp_obj_t arg) { + MP_THREAD_GIL_EXIT(); usleep(mp_obj_get_int(arg) * 1000); + MP_THREAD_GIL_ENTER(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_ms_obj, mod_time_sleep_ms); STATIC mp_obj_t mod_time_sleep_us(mp_obj_t arg) { + MP_THREAD_GIL_EXIT(); usleep(mp_obj_get_int(arg)); + MP_THREAD_GIL_ENTER(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_us_obj, mod_time_sleep_us); @@ -190,3 +201,5 @@ const mp_obj_module_t mp_module_time = { .name = MP_QSTR_utime, .globals = (mp_obj_dict_t*)&mp_module_time_globals, }; + +#endif // MICROPY_PY_UTIME diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 9601673a74..06c4edc1e2 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -103,6 +103,7 @@ #define MICROPY_STACKLESS_STRICT (0) #define MICROPY_PY_OS_STATVFS (1) +#define MICROPY_PY_UTIME (1) #define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UZLIB (1) @@ -119,6 +120,7 @@ #define MICROPY_PY_USELECT (1) #endif #define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr #define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr @@ -129,8 +131,8 @@ #define MICROPY_FATFS_VOLUMES (3) #define MICROPY_FATFS_MAX_SS (4096) #define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ -#define MICROPY_FSUSERMOUNT (1) -#define MICROPY_VFS_FAT (1) +#define MICROPY_FSUSERMOUNT (0) +#define MICROPY_VFS_FAT (0) // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. // names in exception messages (may require more RAM). @@ -170,10 +172,10 @@ extern const struct _mp_obj_module_t mp_module_jni; #else #define MICROPY_PY_JNI_DEF #endif -#if MICROPY_PY_TIME -#define MICROPY_PY_TIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, +#if MICROPY_PY_UTIME +#define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, #else -#define MICROPY_PY_TIME_DEF +#define MICROPY_PY_UTIME_DEF #endif #if MICROPY_PY_TERMIOS #define MICROPY_PY_TERMIOS_DEF { MP_ROM_QSTR(MP_QSTR_termios), MP_ROM_PTR(&mp_module_termios) }, @@ -194,7 +196,7 @@ extern const struct _mp_obj_module_t mp_module_jni; #define MICROPY_PORT_BUILTIN_MODULES \ MICROPY_PY_FFI_DEF \ MICROPY_PY_JNI_DEF \ - MICROPY_PY_TIME_DEF \ + MICROPY_PY_UTIME_DEF \ MICROPY_PY_SOCKET_DEF \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ @@ -233,9 +235,10 @@ void mp_unix_free_exec(void *ptr, mp_uint_t size); void mp_unix_mark_exec(void); #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size) #define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size) - -#ifndef MP_NOINLINE -#define MP_NOINLINE __attribute__((noinline)) +#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC +// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI +// (overriding libffi own implementation) +#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1) #endif #if MICROPY_PY_OS_DUPTERM diff --git a/unix/mpconfigport.mk b/unix/mpconfigport.mk index 88bd749a71..9f826661a9 100644 --- a/unix/mpconfigport.mk +++ b/unix/mpconfigport.mk @@ -6,11 +6,16 @@ MICROPY_FORCE_32BIT = 0 # This variable can take the following values: # 0 - no readline, just simple input # 1 - use MicroPython version of readline -# 2 - use GNU readline (causes binary to be licensed under GPL) MICROPY_USE_READLINE = 1 -# Subset of CPython time module -MICROPY_PY_TIME = 1 +# Whether to enable FatFs VFS +MICROPY_FATFS = 1 + +# btree module using Berkeley DB 1.xx +MICROPY_PY_BTREE = 1 + +# _thread module using pthreads +MICROPY_PY_THREAD = 1 # Subset of CPython termios module MICROPY_PY_TERMIOS = 1 diff --git a/unix/mpconfigport_coverage.h b/unix/mpconfigport_coverage.h index e5d5fd7a47..f9a6fbd9dd 100644 --- a/unix/mpconfigport_coverage.h +++ b/unix/mpconfigport_coverage.h @@ -31,3 +31,7 @@ #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) +#undef MICROPY_FSUSERMOUNT +#undef MICROPY_VFS_FAT +#define MICROPY_FSUSERMOUNT (1) +#define MICROPY_VFS_FAT (1) diff --git a/unix/mpconfigport_minimal.h b/unix/mpconfigport_minimal.h index cffc9a6250..2ab95c67af 100644 --- a/unix/mpconfigport_minimal.h +++ b/unix/mpconfigport_minimal.h @@ -26,6 +26,12 @@ // options to control how Micro Python is built +#define MICROPY_ALLOC_QSTR_CHUNK_INIT (64) +#define MICROPY_ALLOC_PARSE_RULE_INIT (8) +#define MICROPY_ALLOC_PARSE_RULE_INC (8) +#define MICROPY_ALLOC_PARSE_RESULT_INIT (8) +#define MICROPY_ALLOC_PARSE_RESULT_INC (8) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) #define MICROPY_ALLOC_PATH_MAX (PATH_MAX) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_FINALISER (0) @@ -38,6 +44,7 @@ #define MICROPY_ENABLE_SOURCE_LINE (0) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_WARNINGS (0) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_STREAMS_NON_BLOCK (0) @@ -76,6 +83,7 @@ #define MICROPY_PY_SYS_STDFILES (0) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UTIME (0) #define MICROPY_PY_UZLIB (0) #define MICROPY_PY_UJSON (0) #define MICROPY_PY_URE (0) @@ -83,6 +91,18 @@ #define MICROPY_PY_UHASHLIB (0) #define MICROPY_PY_UBINASCII (0) +extern const struct _mp_obj_module_t mp_module_os; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \ + +#define MICROPY_PORT_ROOT_POINTERS \ + mp_obj_t keyboard_interrupt_obj; + +////////////////////////////////////////// +// Do not change anything beyond this line +////////////////////////////////////////// + // Define to 1 to use undertested inefficient GC helper implementation // (if more efficient arch-specific one is not available). #ifndef MICROPY_GCREGS_SETJMP @@ -93,13 +113,6 @@ #endif #endif -#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) - -extern const struct _mp_obj_module_t mp_module_os; - -#define MICROPY_PORT_BUILTIN_MODULES \ - { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \ - // type definitions for the specific machine #ifdef __LP64__ @@ -124,9 +137,6 @@ typedef long mp_off_t; typedef void *machine_ptr_t; // must be of pointer size typedef const void *machine_const_ptr_t; // must be of pointer size -#define MICROPY_PORT_ROOT_POINTERS \ - mp_obj_t keyboard_interrupt_obj; - // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include <stdlib.h> diff --git a/unix/mpthreadport.c b/unix/mpthreadport.c new file mode 100644 index 0000000000..e5cfe7a669 --- /dev/null +++ b/unix/mpthreadport.c @@ -0,0 +1,223 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "py/mpstate.h" +#include "py/mpthread.h" +#include "py/gc.h" + +#if MICROPY_PY_THREAD + +#include <signal.h> +#include <sched.h> + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + pthread_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + struct _thread_t *next; +} thread_t; + +STATIC pthread_key_t tls_key; + +// the mutex controls access to the linked list +STATIC pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; +STATIC thread_t *thread; + +// this is used to synchronise the signal handler of the thread +// it's needed because we can't use any pthread calls in a signal handler +STATIC volatile int thread_signal_done; + +// this signal handler is used to scan the regs and stack of a thread +STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { + (void)info; // unused + (void)context; // unused + if (signo == SIGUSR1) { + void gc_collect_regs_and_stack(void); + gc_collect_regs_and_stack(); + // We have access to the context (regs, stack) of the thread but it seems + // that we don't need the extra information, enough is captured by the + // gc_collect_regs_and_stack function above + //gc_collect_root((void**)context, sizeof(ucontext_t) / sizeof(uintptr_t)); + thread_signal_done = 1; + } +} + +void mp_thread_init(void) { + pthread_key_create(&tls_key, NULL); + pthread_setspecific(tls_key, &mp_state_ctx.thread); + + // create first entry in linked list of all threads + thread = malloc(sizeof(thread_t)); + thread->id = pthread_self(); + thread->ready = 1; + thread->arg = NULL; + thread->next = NULL; + + // enable signal handler for garbage collection + struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = mp_thread_gc; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR1, &sa, NULL); +} + +// This function scans all pointers that are external to the current thread. +// It does this by signalling all other threads and getting them to scan their +// own registers and stack. Note that there may still be some edge cases left +// with race conditions and root-pointer scanning: a given thread may manipulate +// the global root pointers (in mp_state_ctx) while another thread is doing a +// garbage collection and tracing these pointers. +void mp_thread_gc_others(void) { + pthread_mutex_lock(&thread_mutex); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root(&th->arg, 1); + if (th->id == pthread_self()) { + continue; + } + if (!th->ready) { + continue; + } + thread_signal_done = 0; + pthread_kill(th->id, SIGUSR1); + while (thread_signal_done == 0) { + sched_yield(); + } + } + pthread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return (mp_state_thread_t*)pthread_getspecific(tls_key); +} + +void mp_thread_set_state(void *state) { + pthread_setspecific(tls_key, state); +} + +void mp_thread_start(void) { + pthread_mutex_lock(&thread_mutex); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == pthread_self()) { + th->ready = 1; + break; + } + } + pthread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + // default stack size is 8k machine-words, minimum is 2k + if (*stack_size == 0) { + *stack_size = 8192 * BYTES_PER_WORD; + } else if (*stack_size < 2048 * BYTES_PER_WORD) { + *stack_size = 2048 * BYTES_PER_WORD; + } + + // set thread attributes + pthread_attr_t attr; + int ret = pthread_attr_init(&attr); + if (ret != 0) { + goto er; + } + ret = pthread_attr_setstacksize(&attr, *stack_size); + if (ret != 0) { + goto er; + } + + pthread_mutex_lock(&thread_mutex); + + // create thread + pthread_t id; + ret = pthread_create(&id, &attr, entry, arg); + if (ret != 0) { + pthread_mutex_unlock(&thread_mutex); + goto er; + } + + // adjust stack_size to provide room to recover from hitting the limit + *stack_size -= 1024 * BYTES_PER_WORD; + + // add thread to linked list of all threads + thread_t *th = malloc(sizeof(thread_t)); + th->id = id; + th->ready = 0; + th->arg = arg; + th->next = thread; + thread = th; + + pthread_mutex_unlock(&thread_mutex); + + return; + +er: + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ret))); +} + +void mp_thread_finish(void) { + pthread_mutex_lock(&thread_mutex); + // TODO unlink from list + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == pthread_self()) { + th->ready = 0; + break; + } + } + pthread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + pthread_mutex_init(mutex, NULL); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + int ret; + if (wait) { + ret = pthread_mutex_lock(mutex); + if (ret == 0) { + return 1; + } + } else { + ret = pthread_mutex_trylock(mutex); + if (ret == 0) { + return 1; + } else if (ret == EBUSY) { + return 0; + } + } + return -ret; +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + pthread_mutex_unlock(mutex); + // TODO check return value +} + +#endif // MICROPY_PY_THREAD diff --git a/unix/mpthreadport.h b/unix/mpthreadport.h new file mode 100644 index 0000000000..51cf8d7860 --- /dev/null +++ b/unix/mpthreadport.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __MICROPY_INCLUDED_UNIX_MPTHREADPORT_H__ +#define __MICROPY_INCLUDED_UNIX_MPTHREADPORT_H__ + +#include <pthread.h> + +typedef pthread_mutex_t mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); + +#endif // __MICROPY_INCLUDED_UNIX_MPTHREADPORT_H__ diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 51d4697e4d..a860c2e322 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_UTIME (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) @@ -157,6 +158,7 @@ extern const struct _mp_obj_module_t mp_module_os; extern const struct _mp_obj_module_t mp_module_time; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&mp_module_time }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&mp_module_machine }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \ #if MICROPY_USE_READLINE == 1 diff --git a/windows/mpconfigport.mk b/windows/mpconfigport.mk index 3a2c6a6b1a..87001d464f 100644 --- a/windows/mpconfigport.mk +++ b/windows/mpconfigport.mk @@ -6,8 +6,5 @@ MICROPY_FORCE_32BIT = 0 # Linking with GNU readline causes binary to be licensed under GPL MICROPY_USE_READLINE = 1 -# Subset of CPython time module -MICROPY_PY_TIME = 1 - # ffi module requires libffi (libffi-dev Debian package) MICROPY_PY_FFI = 0 diff --git a/windows/msvc/genhdr.targets b/windows/msvc/genhdr.targets index ba0681f554..8c2ba8eb21 100644 --- a/windows/msvc/genhdr.targets +++ b/windows/msvc/genhdr.targets @@ -47,7 +47,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { <Target Name="MakeQstrDefs" DependsOnTargets="MakeDestDir" Inputs="@(ClCompile)" Outputs="$(QstrDefsCollected)"> <ItemGroup> <PyIncDirs Include="$(PyIncDirs)"/> - <PreProcDefs Include="%(ClCompile.PreProcessorDefinitions);__QSTR_EXTRACT;N_X64;N_X86;N_THUMB;N_ARM"/> + <PreProcDefs Include="%(ClCompile.PreProcessorDefinitions);NO_QSTR;N_X64;N_X86;N_THUMB;N_ARM"/> <PyQstrSourceFiles Include="@(ClCompile)"> <OutFile>$([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '$(DestDir)qstr\'))</OutFile> </PyQstrSourceFiles> diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props index b1065bdfe4..569f24c76b 100644 --- a/windows/msvc/sources.props +++ b/windows/msvc/sources.props @@ -14,6 +14,7 @@ <ClCompile Include="$(PyBaseDir)unix\modtime.c"/> <ClCompile Include="$(PyBaseDir)unix\modmachine.c" /> <ClCompile Include="$(PyBaseDir)extmod\machine_mem.c" /> + <ClCompile Include="$(PyBaseDir)extmod\machine_pinbase.c" /> <ClCompile Include="$(PyBaseDir)extmod\modubinascii.c" /> <ClCompile Include="$(PyBaseDir)extmod\moductypes.c" /> <ClCompile Include="$(PyBaseDir)extmod\moduhashlib.c" /> |