Merge remote-tracking branch 'upstream/master'

This commit is contained in:
BruceHsu 2017-10-03 01:35:25 +08:00
commit 56ba21c081
299 changed files with 16208 additions and 13185 deletions

2
.gitmodules vendored
View file

@ -1,6 +1,6 @@
[submodule "lwip/lwip"] [submodule "lwip/lwip"]
path = lwip/lwip path = lwip/lwip
url = https://github.com/SuperHouse/esp-lwip.git url = https://github.com/ourairquality/lwip.git
[submodule "extras/mbedtls/mbedtls"] [submodule "extras/mbedtls/mbedtls"]
path = extras/mbedtls/mbedtls path = extras/mbedtls/mbedtls
url = https://github.com/ARMmbed/mbedtls.git url = https://github.com/ARMmbed/mbedtls.git

View file

@ -2,7 +2,7 @@ language: c
sudo: false sudo: false
env: env:
# Target commit for https://github.com/pfalcon/esp-open-sdk/ # Target commit for https://github.com/pfalcon/esp-open-sdk/
OPENSDK_COMMIT=a48b12f OPENSDK_COMMIT=b069537
CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}" CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}"
CROSS_BINDIR="${CROSS_ROOT}/bin" CROSS_BINDIR="${CROSS_ROOT}/bin"
CROSS="ccache xtensa-lx106-elf-" CROSS="ccache xtensa-lx106-elf-"
@ -29,12 +29,14 @@ addons:
- libncurses5-dev - libncurses5-dev
- libexpat1-dev - libexpat1-dev
- python - python
- python-serial - python-pip
- sed - sed
- git - git
- help2man
- vim-common - vim-common
before_install: before_install:
- pip install --user pyserial
- travis_wait 30 utils/travis_build/install_toolchain.sh - travis_wait 30 utils/travis_build/install_toolchain.sh
script: script:

View file

@ -1,65 +1,61 @@
The FreeRTOS.org source code is licensed by the *modified* GNU General Public The FreeRTOS open source license covers the FreeRTOS source files,
License (GPL), text provided below. A special exception to the GPL is which are located in the /FreeRTOS/Source directory of the official FreeRTOS
included to allow you to distribute a combined work that includes FreeRTOS download. It also covers most of the source files in the demo application
without being obliged to provide the source code for any proprietary projects, which are located in the /FreeRTOS/Demo directory of the official
components. See the licensing section of http://www.FreeRTOS.org for full FreeRTOS download. The demo projects may also include third party software that
details. The exception text is also included at the bottom of this file. 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.
The FreeRTOS download also includes demo application source code, some of ----------------------------------------------------------------------------
which is provided by third parties AND IS LICENSED SEPARATELY FROM FREERTOS.
For the avoidance of any doubt refer to the comment included at the top NOTE: The modification to the GPL is included to allow you to distribute a
of each source and header file for license and copyright information. combined work that includes FreeRTOS without being obliged to provide the source
code for proprietary components.
This is a list of files for which Real Time Engineers Ltd are not the ----------------------------------------------------------------------------
copyright owner and are NOT COVERED BY THE GPL.
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,
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
a module which is not derived from or based on FreeRTOS.
Clause 1:
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 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.
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).
1) Various header files provided by silicon manufacturers and tool vendors
that define processor specific memory addresses and utility macros.
Permission has been granted by the various copyright holders for these
files to be included in the FreeRTOS download. Users must ensure license
conditions are adhered to for any use other than compilation of the
FreeRTOS demo applications.
2) The uIP TCP/IP stack the copyright of which is held by Adam Dunkels.
Users must ensure the open source license conditions stated at the top
of each uIP source file is understood and adhered to.
3) The lwIP TCP/IP stack the copyright of which is held by the Swedish
Institute of Computer Science. Users must ensure the open source license
conditions stated at the top of each lwIP source file is understood and
adhered to.
4) Various peripheral driver source files and binaries provided by silicon
manufacturers and tool vendors. Permission has been granted by the
various copyright holders for these files to be included in the FreeRTOS
download. Users must ensure license conditions are adhered to for any
use other than compilation of the FreeRTOS demo applications.
5) The files contained within FreeRTOS\Demo\WizNET_DEMO_TERN_186\tern_code,
which are slightly modified versions of code provided by and copyright to
Tern Inc.
Errors and omissions should be reported to Richard Barry, contact details for
whom can be obtained from http://www.FreeRTOS.org.
The GPL license text follows.
A special exception 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 any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details. The exception text is also
included at the bottom of this file.
-------------------------------------------------------------------- --------------------------------------------------------------------
The standard GPL V2 text:
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
@ -401,40 +397,3 @@ consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.
----------------------------------------------------------------------------
The FreeRTOS GPL Exception Text:
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
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.
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
+ 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.
+ The combined work is not itself an RTOS, scheduler, kernel or related product.
+ 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).

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -139,6 +139,16 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
/* A StaticEventGroup_t object must be provided. */ /* A StaticEventGroup_t object must be provided. */
configASSERT( pxEventGroupBuffer ); configASSERT( pxEventGroupBuffer );
#if( configASSERT_DEFINED == 1 )
{
/* Sanity check that the size of the structure used to declare a
variable of type StaticEventGroup_t equals the size of the real
event group structure. */
volatile size_t xSize = sizeof( StaticEventGroup_t );
configASSERT( xSize == sizeof( EventGroup_t ) );
}
#endif /* configASSERT_DEFINED */
/* The user has provided a statically allocated event group - use it. */ /* 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(). */ pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
@ -602,7 +612,7 @@ BaseType_t xMatchFound = pdFALSE;
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
that is was unblocked due to its required bits matching, rather that is was unblocked due to its required bits matching, rather
than because it timed out. */ than because it timed out. */
( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
} }
/* Move onto the next list item. Note pxListItem->pxNext is not /* Move onto the next list item. Note pxListItem->pxNext is not
@ -634,8 +644,8 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
{ {
/* Unblock the task, returning 0 as the event list is being deleted /* Unblock the task, returning 0 as the event list is being deleted
and cannot therefore have any bits set. */ and cannot therefore have any bits set. */
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
} }
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -126,6 +126,10 @@ extern "C" {
#error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details.
#endif #endif
#if configMAX_PRIORITIES < 1
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
#endif
#ifndef configUSE_PREEMPTION #ifndef configUSE_PREEMPTION
#error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif #endif
@ -142,10 +146,6 @@ extern "C" {
#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. #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 #endif
#ifndef configMAX_PRIORITIES
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
#endif
#ifndef configUSE_CO_ROUTINES #ifndef configUSE_CO_ROUTINES
#define configUSE_CO_ROUTINES 0 #define configUSE_CO_ROUTINES 0
#endif #endif
@ -408,6 +408,14 @@ extern "C" {
#define configCHECK_FOR_STACK_OVERFLOW 0 #define configCHECK_FOR_STACK_OVERFLOW 0
#endif #endif
#ifndef configRECORD_STACK_HIGH_ADDRESS
#define configRECORD_STACK_HIGH_ADDRESS 0
#endif
#ifndef configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 0
#endif
/* The following event macros are embedded in the kernel API calls. */ /* The following event macros are embedded in the kernel API calls. */
#ifndef traceMOVED_TASK_TO_READY_STATE #ifndef traceMOVED_TASK_TO_READY_STATE
@ -708,6 +716,10 @@ extern "C" {
#define configUSE_TICKLESS_IDLE 0 #define configUSE_TICKLESS_IDLE 0
#endif #endif
#ifndef configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING
#define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( x )
#endif
#ifndef configPRE_SLEEP_PROCESSING #ifndef configPRE_SLEEP_PROCESSING
#define configPRE_SLEEP_PROCESSING( x ) #define configPRE_SLEEP_PROCESSING( x )
#endif #endif
@ -724,6 +736,10 @@ extern "C" {
#define portTASK_USES_FLOATING_POINT() #define portTASK_USES_FLOATING_POINT()
#endif #endif
#ifndef portTASK_CALLS_SECURE_FUNCTIONS
#define portTASK_CALLS_SECURE_FUNCTIONS()
#endif
#ifndef configUSE_TIME_SLICING #ifndef configUSE_TIME_SLICING
#define configUSE_TIME_SLICING 1 #define configUSE_TIME_SLICING 1
#endif #endif
@ -782,6 +798,12 @@ extern "C" {
#define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1
#endif #endif
#ifndef configSTACK_DEPTH_TYPE
/* Defaults to uint16_t for backward compatibility, but can be overridden
in FreeRTOSConfig.h if uint16_t is too restrictive. */
#define configSTACK_DEPTH_TYPE uint16_t
#endif
/* Sanity check the configuration. */ /* Sanity check the configuration. */
#if( configUSE_TICKLESS_IDLE != 0 ) #if( configUSE_TICKLESS_IDLE != 0 )
#if( INCLUDE_vTaskSuspend != 1 ) #if( INCLUDE_vTaskSuspend != 1 )
@ -797,6 +819,10 @@ extern "C" {
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes #error configUSE_MUTEXES must be set to 1 to use recursive mutexes
#endif #endif
#ifndef configINITIAL_TICK_COUNT
#define configINITIAL_TICK_COUNT 0
#endif
#if( portTICK_TYPE_IS_ATOMIC == 0 ) #if( portTICK_TYPE_IS_ATOMIC == 0 )
/* Either variables of tick type cannot be read atomically, or /* Either variables of tick type cannot be read atomically, or
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
@ -917,7 +943,7 @@ typedef struct xSTATIC_TCB
UBaseType_t uxDummy5; UBaseType_t uxDummy5;
void *pxDummy6; void *pxDummy6;
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
#if ( portSTACK_GROWTH > 0 ) #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
void *pxDummy8; void *pxDummy8;
#endif #endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #if ( portCRITICAL_NESTING_IN_TCB == 1 )
@ -945,10 +971,14 @@ typedef struct xSTATIC_TCB
uint32_t ulDummy18; uint32_t ulDummy18;
uint8_t ucDummy19; uint8_t ucDummy19;
#endif #endif
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) #if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
uint8_t uxDummy20; uint8_t uxDummy20;
#endif #endif
#if( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDummy21;
#endif
} StaticTask_t; } StaticTask_t;
/* /*

View file

@ -1,15 +1,38 @@
/* Default esp-open-sdk FreeRTOSConfig file. /*
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved
You can override settings in here by creating your own VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
FreeRTOSConfig.h file in your program directory.
You could just copy this file there and edit it, but it's This file is part of the FreeRTOS distribution.
recommended you instead define whatever you want to override and
then use #include_next<FreeRTOSConfig.h> to pick up these defaults.
The "blink" example in "examples/blink" provides an example of how FreeRTOS is free software; you can redistribute it and/or modify it under
to do this. 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
For esp-open-rtos, you can override settings in here by creating your own
FreeRTOSConfig.h file in your program directory. You could just copy this
file there and edit it, but it's recommended you instead define whatever you
want to override and then use #include_next<FreeRTOSConfig.h> to pick up
these defaults. The "blink" example in "examples/blink" provides an example
of how to do this.
1 tab == 4 spaces!
*/ */
#ifndef __DEFAULT_FREERTOS_CONFIG_H #ifndef __DEFAULT_FREERTOS_CONFIG_H
#define __DEFAULT_FREERTOS_CONFIG_H #define __DEFAULT_FREERTOS_CONFIG_H
@ -47,7 +70,7 @@
#define configTICK_RATE_HZ ( ( TickType_t ) 100 ) #define configTICK_RATE_HZ ( ( TickType_t ) 100 )
#endif #endif
#ifndef configMAX_PRIORITIES #ifndef configMAX_PRIORITIES
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 ) #define configMAX_PRIORITIES ( 15 )
#endif #endif
#ifndef configMINIMAL_STACK_SIZE #ifndef configMINIMAL_STACK_SIZE
#define configMINIMAL_STACK_SIZE ( ( unsigned short )256 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short )256 )
@ -108,6 +131,10 @@
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#endif #endif
#ifndef configUSE_NEWLIB_REENTRANT
#define configUSE_NEWLIB_REENTRANT 1
#endif
/* Set the following definitions to 1 to include the API function, or zero /* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */ to exclude the API function. */
#ifndef INCLUDE_vTaskPrioritySet #ifndef INCLUDE_vTaskPrioritySet
@ -144,5 +171,10 @@ to exclude the API function. */
#define configENABLE_BACKWARD_COMPATIBILITY 0 #define configENABLE_BACKWARD_COMPATIBILITY 0
#endif #endif
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
void vAssertCalled(const char * pcFile, unsigned long ulLine);
#define configASSERT(x) if((x) == 0) vAssertCalled(__FILE__, __LINE__);
#endif /* __DEFAULT_FREERTOS_CONFIG_H */ #endif /* __DEFAULT_FREERTOS_CONFIG_H */

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t;
typedef struct xLIST typedef struct xLIST
{ {
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ 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; 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 (). */ 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. */ 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. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -83,6 +83,7 @@
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 ); 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 ); 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 ); BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
void MPU_vTaskDelay( const TickType_t xTicksToDelay ); void MPU_vTaskDelay( const TickType_t xTicksToDelay );
@ -124,7 +125,9 @@ BaseType_t MPU_xTaskGetSchedulerState( void );
/* MPU versions of queue.h API function. */ /* 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_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 ); BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait );
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
void MPU_vQueueDelete( QueueHandle_t xQueue ); void MPU_vQueueDelete( QueueHandle_t xQueue );

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -130,7 +130,9 @@ only for ports that are using the MPU. */
/* Map standard queue.h API functions to the MPU equivalents. */ /* Map standard queue.h API functions to the MPU equivalents. */
#define xQueueGenericSend MPU_xQueueGenericSend #define xQueueGenericSend MPU_xQueueGenericSend
#define xQueueGenericReceive MPU_xQueueGenericReceive #define xQueueReceive MPU_xQueueReceive
#define xQueuePeek MPU_xQueuePeek
#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
#define vQueueDelete MPU_vQueueDelete #define vQueueDelete MPU_vQueueDelete
@ -177,8 +179,11 @@ only for ports that are using the MPU. */
#define xEventGroupSync MPU_xEventGroupSync #define xEventGroupSync MPU_xEventGroupSync
#define vEventGroupDelete MPU_vEventGroupDelete #define vEventGroupDelete MPU_vEventGroupDelete
/* Remove the privileged function macro. */ /* Remove the privileged function macro, but keep the PRIVILEGED_DATA
macro so applications can place data in privileged access sections
(useful when using statically allocated objects). */
#define PRIVILEGED_FUNCTION #define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -696,12 +696,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ
* <pre> * <pre>
BaseType_t xQueuePeek( BaseType_t xQueuePeek(
QueueHandle_t xQueue, QueueHandle_t xQueue,
void *pvBuffer, void * const pvBuffer,
TickType_t xTicksToWait TickType_t xTicksToWait
);</pre> );</pre>
* *
* This is a macro that calls the xQueueGenericReceive() function.
*
* Receive an item from a queue without removing the item from the queue. * Receive an item from a queue without removing the item from the queue.
* The item is received by copy so a buffer of adequate size must be * The item is received by copy so a buffer of adequate size must be
* provided. The number of bytes copied into the buffer was defined when * provided. The number of bytes copied into the buffer was defined when
@ -782,10 +780,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ
// ... Rest of task code. // ... Rest of task code.
} }
</pre> </pre>
* \defgroup xQueueReceive xQueueReceive * \defgroup xQueuePeek xQueuePeek
* \ingroup QueueManagement * \ingroup QueueManagement
*/ */
#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/** /**
* queue. h * queue. h
@ -829,8 +827,6 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
TickType_t xTicksToWait TickType_t xTicksToWait
);</pre> );</pre>
* *
* This is a macro that calls the xQueueGenericReceive() function.
*
* Receive an item from a queue. The item is received by copy so a buffer of * Receive an item from a queue. The item is received by copy so a buffer of
* adequate size must be provided. The number of bytes copied into the buffer * adequate size must be provided. The number of bytes copied into the buffer
* was defined when the queue was created. * was defined when the queue was created.
@ -911,106 +907,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
* \defgroup xQueueReceive xQueueReceive * \defgroup xQueueReceive xQueueReceive
* \ingroup QueueManagement * \ingroup QueueManagement
*/ */
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* queue. h
* <pre>
BaseType_t xQueueGenericReceive(
QueueHandle_t xQueue,
void *pvBuffer,
TickType_t xTicksToWait
BaseType_t xJustPeek
);</pre>
*
* It is preferred that the macro xQueueReceive() be used rather than calling
* this function directly.
*
* Receive an item from a queue. The item is received by copy so a buffer of
* adequate size must be provided. The number of bytes copied into the buffer
* was defined when the queue was created.
*
* This function must not be used in an interrupt service routine. See
* xQueueReceiveFromISR for an alternative that can.
*
* @param xQueue The handle to the queue from which the item is to be
* received.
*
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
*
* @param xTicksToWait The maximum amount of time the task should block
* waiting for an item to receive should the queue be empty at the time
* of the call. The time is defined in tick periods so the constant
* portTICK_PERIOD_MS should be used to convert to real time if this is required.
* xQueueGenericReceive() will return immediately if the queue is empty and
* xTicksToWait is 0.
*
* @param xJustPeek When set to true, the item received from the queue is not
* actually removed from the queue - meaning a subsequent call to
* xQueueReceive() will return the same item. When set to false, the item
* being received from the queue is also removed from the queue.
*
* @return pdTRUE if an item was successfully received from the queue,
* otherwise pdFALSE.
*
* Example usage:
<pre>
struct AMessage
{
char ucMessageID;
char ucData[ 20 ];
} xMessage;
QueueHandle_t xQueue;
// Task to create a queue and post a value.
void vATask( void *pvParameters )
{
struct AMessage *pxMessage;
// Create a queue capable of containing 10 pointers to AMessage structures.
// These should be passed by pointer as they contain a lot of data.
xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
if( xQueue == 0 )
{
// Failed to create the queue.
}
// ...
// Send a pointer to a struct AMessage object. Don't block if the
// queue is already full.
pxMessage = & xMessage;
xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
// ... Rest of task code.
}
// Task to receive from the queue.
void vADifferentTask( void *pvParameters )
{
struct AMessage *pxRxedMessage;
if( xQueue != 0 )
{
// Receive a message on the created queue. Block for 10 ticks if a
// message is not immediately available.
if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
{
// pcRxedMessage now points to the struct AMessage variable posted
// by vATask.
}
}
// ... Rest of task code.
}
</pre>
* \defgroup xQueueReceive xQueueReceive
* \ingroup QueueManagement
*/
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ) PRIVILEGED_FUNCTION;
/** /**
* queue. h * queue. h
@ -1560,7 +1457,9 @@ QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION
QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) 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 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; QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
/* /*
* For internal use only. Use xSemaphoreTakeMutexRecursive() or * For internal use only. Use xSemaphoreTakeMutexRecursive() or

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -328,7 +328,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* \defgroup xSemaphoreTake xSemaphoreTake * \defgroup xSemaphoreTake xSemaphoreTake
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) #define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
/** /**
* semphr. h * semphr. h
@ -1154,6 +1154,17 @@ typedef QueueHandle_t SemaphoreHandle_t;
*/ */
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) #define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
/**
* semphr.h
* <pre>TaskHandle_t xSemaphoreGetMutexHolderFromISR( SemaphoreHandle_t xMutex );</pre>
*
* If xMutex is indeed a mutex type semaphore, return the current mutex holder.
* If xMutex is not a mutex type semaphore, or the mutex is available (not held
* by a task), return NULL.
*
*/
#define xSemaphoreGetMutexHolderFromISR( xSemaphore ) xQueueGetMutexHolderFromISR( ( xSemaphore ) )
/** /**
* semphr.h * semphr.h
* <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre> * <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre>

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -160,6 +160,9 @@ typedef struct xTASK_PARAMETERS
UBaseType_t uxPriority; UBaseType_t uxPriority;
StackType_t *puxStackBuffer; StackType_t *puxStackBuffer;
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
StaticTask_t * const pxTaskBuffer;
#endif
} TaskParameters_t; } TaskParameters_t;
/* Used with the uxTaskGetSystemState() function to return the state of each task /* Used with the uxTaskGetSystemState() function to return the state of each task
@ -269,7 +272,7 @@ is used in assert() statements. */
BaseType_t xTaskCreate( BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode, TaskFunction_t pvTaskCode,
const char * const pcName, const char * const pcName,
uint16_t usStackDepth, configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters, void *pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t *pvCreatedTask TaskHandle_t *pvCreatedTask
@ -358,11 +361,11 @@ is used in assert() statements. */
*/ */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint16_t usStackDepth, const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif #endif
/** /**
@ -474,12 +477,12 @@ is used in assert() statements. */
*/ */
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth, const uint32_t ulStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
StackType_t * const puxStackBuffer, StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/** /**
@ -487,6 +490,8 @@ is used in assert() statements. */
*<pre> *<pre>
BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre> BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre>
* *
* Only available when configSUPPORT_DYNAMIC_ALLOCATION is set to 1.
*
* xTaskCreateRestricted() should only be used in systems that include an MPU * xTaskCreateRestricted() should only be used in systems that include an MPU
* implementation. * implementation.
* *
@ -494,6 +499,9 @@ is used in assert() statements. */
* The function parameters define the memory regions and associated access * The function parameters define the memory regions and associated access
* permissions allocated to the task. * permissions allocated to the task.
* *
* See xTaskCreateRestrictedStatic() for a version that does not use any
* dynamic memory allocation.
*
* @param pxTaskDefinition Pointer to a structure that contains a member * @param pxTaskDefinition Pointer to a structure that contains a member
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
* documentation) plus an optional stack buffer and the memory region * documentation) plus an optional stack buffer and the memory region
@ -553,6 +561,94 @@ TaskHandle_t xHandle;
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif #endif
/**
* task. h
*<pre>
BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre>
*
* Only available when configSUPPORT_STATIC_ALLOCATION is set to 1.
*
* xTaskCreateRestrictedStatic() should only be used in systems that include an
* MPU implementation.
*
* 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
* xTaskCreateRestricted() then the stack is provided by the application writer,
* and the memory used to hold the task's data structure is automatically
* dynamically allocated inside the xTaskCreateRestricted() function. If a task
* is created using xTaskCreateRestrictedStatic() then the application writer
* must provide the memory used to hold the task's data structures too.
* xTaskCreateRestrictedStatic() therefore allows a memory protected task to be
* created without using any dynamic memory allocation.
*
* @param pxTaskDefinition Pointer to a structure that contains a member
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
* documentation) plus an optional stack buffer and the memory region
* definitions. If configSUPPORT_STATIC_ALLOCATION is set to 1 the structure
* contains an additional member, which is used to point to a variable of type
* StaticTask_t - which is then used to hold the task's data structure.
*
* @param pxCreatedTask Used to pass back a handle by which the created task
* can be referenced.
*
* @return pdPASS if the task was successfully created and added to a ready
* list, otherwise an error code defined in the file projdefs.h
*
* Example usage:
<pre>
// Create an TaskParameters_t structure that defines the task to be created.
// The StaticTask_t variable is only included in the structure when
// configSUPPORT_STATIC_ALLOCATION is set to 1. The PRIVILEGED_DATA macro can
// be used to force the variable into the RTOS kernel's privileged data area.
static PRIVILEGED_DATA StaticTask_t xTaskBuffer;
static const TaskParameters_t xCheckTaskParameters =
{
vATask, // pvTaskCode - the function that implements the task.
"ATask", // pcName - just a text name for the task to assist debugging.
100, // usStackDepth - the stack size DEFINED IN WORDS.
NULL, // pvParameters - passed into the task function as the function parameters.
( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
// xRegions - Allocate up to three separate memory regions for access by
// the task, with appropriate access permissions. Different processors have
// different memory alignment requirements - refer to the FreeRTOS documentation
// for full information.
{
// Base address Length Parameters
{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
}
&xTaskBuffer; // Holds the task's data structure.
};
int main( void )
{
TaskHandle_t xHandle;
// Create a task from the const structure defined above. The task handle
// is requested (the second parameter is not NULL) but in this case just for
// demonstration purposes as its not actually used.
xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
// Start the scheduler.
vTaskStartScheduler();
// Will only get here if there was insufficient memory to create the idle
// and/or timer task.
for( ;; );
}
</pre>
* \defgroup xTaskCreateRestrictedStatic xTaskCreateRestrictedStatic
* \ingroup Tasks
*/
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif
/** /**
* task. h * task. h
*<pre> *<pre>
@ -2141,14 +2237,14 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
* Removes a task from both the specified event list and the list of blocked * Removes a task from both the specified event list and the list of blocked
* tasks, and places it on a ready queue. * tasks, and places it on a ready queue.
* *
* xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called * xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called
* if either an event occurs to unblock a task, or the block timeout period * if either an event occurs to unblock a task, or the block timeout period
* expires. * expires.
* *
* xTaskRemoveFromEventList() is used when the event list is in task priority * xTaskRemoveFromEventList() is used when the event list is in task priority
* order. It removes the list item from the head of the event list as that will * order. It removes the list item from the head of the event list as that will
* have the highest priority owning task of all the tasks on the event list. * have the highest priority owning task of all the tasks on the event list.
* xTaskRemoveFromUnorderedEventList() is used when the event list is not * vTaskRemoveFromUnorderedEventList() is used when the event list is not
* ordered and the event list items hold something other than the owning tasks * ordered and the event list items hold something other than the owning tasks
* priority. In this case the event list item value is updated to the value * priority. In this case the event list item value is updated to the value
* passed in the xItemValue parameter. * passed in the xItemValue parameter.
@ -2157,7 +2253,7 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
* making the call, otherwise pdFALSE. * making the call, otherwise pdFALSE.
*/ */
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION; BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION; void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
/* /*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
@ -2207,7 +2303,7 @@ BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
* Raises the priority of the mutex holder to that of the calling task should * Raises the priority of the mutex holder to that of the calling task should
* the mutex holder have a priority less than the calling task. * the mutex holder have a priority less than the calling task.
*/ */
void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
/* /*
* Set the priority of a task back to its proper priority in the case that it * Set the priority of a task back to its proper priority in the case that it
@ -2215,6 +2311,16 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO
*/ */
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
/*
* If a higher priority task attempting to obtain a mutex caused a lower
* priority task to inherit the higher priority task's priority - but the higher
* priority task then timed out without obtaining the mutex, then the lower
* priority task will disinherit the priority again - but only down as far as
* the highest priority task that is still waiting for the mutex (if there were
* more than one task waiting for the mutex).
*/
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION;
/* /*
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter. * Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
*/ */
@ -2258,6 +2364,13 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION;
*/ */
void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
/*
* For internal use only. Same as vTaskSetTimeOutState(), but without a critial
* section.
*/
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -75,10 +75,10 @@
#error "include FreeRTOS.h must appear in source files before include timers.h" #error "include FreeRTOS.h must appear in source files before include timers.h"
#endif #endif
/*lint -e537 This headers are only multiply included if the application code /*lint -save -e537 This headers are only multiply included if the application code
happens to also be including task.h. */ happens to also be including task.h. */
#include "task.h" #include "task.h"
/*lint +e537 */ /*lint -restore */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -266,11 +266,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
* @endverbatim * @endverbatim
*/ */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
TimerHandle_t xTimerCreate( const char * const pcTimerName, TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION;
#endif #endif
/** /**
@ -396,12 +396,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
* @endverbatim * @endverbatim
*/ */
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction, TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION;
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/** /**

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -73,10 +73,12 @@
#include <malloc.h> #include <malloc.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <xtensa_ops.h> #include <xtensa_ops.h>
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "queue.h"
#include "xtensa_rtos.h" #include "xtensa_rtos.h"
unsigned cpu_sr; unsigned cpu_sr;
@ -91,6 +93,13 @@ char level1_int_disabled;
*/ */
void *xPortSupervisorStackPointer; void *xPortSupervisorStackPointer;
void vAssertCalled(const char * pcFile, unsigned long ulLine)
{
printf("rtos assert %s %lu\n", pcFile, ulLine);
abort();
//for (;;);
}
/* /*
* Stack initialization * Stack initialization
*/ */
@ -100,7 +109,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
portSTACK_TYPE *sp, *tp; portSTACK_TYPE *sp, *tp;
/* Create interrupt stack frame aligned to 16 byte boundary */ /* Create interrupt stack frame aligned to 16 byte boundary */
sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf); sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack + 1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
/* Clear the entire frame (do not use memset() because we don't depend on C library) */ /* Clear the entire frame (do not use memset() because we don't depend on C library) */
for (tp = sp; tp <= pxTopOfStack; ++tp) for (tp = sp; tp <= pxTopOfStack; ++tp)
@ -121,30 +130,29 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
static int pending_soft_sv; static int pending_soft_sv;
static int pending_maclayer_sv; static int pending_maclayer_sv;
/* PendSV is called in place of vPortYield() to request a supervisor /*
call. * The portYIELD macro calls PendSV with SVC_Software to set a pending interrupt
* service callback that allows a task switch, and this occur when interrupts
The portYIELD macro calls pendSV if it's a software request. * are enabled which might be after exiting the critical region below.
*
The libpp and libudhcp libraries also call this function, assuming * The wdev NMI calls this function from pp_post() with SVC_MACLayer to set a
always with arg==2 (but maybe sometimes with arg==1?) * pending interrupt service callback which flushs the queue of messages that
* the NMI stashes away. This interrupt will be triggered after the return from
In the original esp_iot_rtos_sdk implementation, arg was a char. Using an * the NMI and when interrupts are enabled. The NMI can not touch the FreeRTOS
enum is ABI-compatible, though. * queues itself. The NMI must not touch the interrupt masks so that path must
*/ * not call vPortEnterCritical and vPortExitCritical.
*/
void IRAM PendSV(enum SVC_ReqType req) void IRAM PendSV(enum SVC_ReqType req)
{ {
if (req == SVC_Software) {
vPortEnterCritical(); vPortEnterCritical();
if(req == SVC_Software)
{
pending_soft_sv = 1; pending_soft_sv = 1;
}
else if(req == SVC_MACLayer)
pending_maclayer_sv= 1;
WSR(BIT(INUM_SOFT), interrupt); WSR(BIT(INUM_SOFT), interrupt);
vPortExitCritical(); vPortExitCritical();
} else if (req == SVC_MACLayer) {
pending_maclayer_sv= 1;
WSR(BIT(INUM_SOFT), interrupt);
}
} }
/* This MAC layer ISR handler is defined in libpp.a, and is called /* This MAC layer ISR handler is defined in libpp.a, and is called
@ -153,16 +161,14 @@ void IRAM PendSV(enum SVC_ReqType req)
*/ */
extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void); extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void);
void IRAM SV_ISR(void) void IRAM SV_ISR(void *arg)
{ {
portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE ; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE ;
if(pending_maclayer_sv) if (pending_maclayer_sv) {
{
xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl(); xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
pending_maclayer_sv = 0; pending_maclayer_sv = 0;
} }
if( xHigherPriorityTaskWoken || pending_soft_sv) if (xHigherPriorityTaskWoken || pending_soft_sv) {
{
sdk__xt_timer_int1(); sdk__xt_timer_int1();
pending_soft_sv = 0; pending_soft_sv = 0;
} }
@ -170,14 +176,9 @@ void IRAM SV_ISR(void)
void xPortSysTickHandle (void) void xPortSysTickHandle (void)
{ {
//CloseNMI(); if (xTaskIncrementTick() != pdFALSE) {
{
if(xTaskIncrementTick() !=pdFALSE )
{
vTaskSwitchContext(); vTaskSwitchContext();
} }
}
//OpenNMI();
} }
/* /*
@ -185,11 +186,11 @@ void xPortSysTickHandle (void)
*/ */
portBASE_TYPE xPortStartScheduler( void ) portBASE_TYPE xPortStartScheduler( void )
{ {
_xt_isr_attach(INUM_SOFT, SV_ISR); _xt_isr_attach(INUM_SOFT, SV_ISR, NULL);
_xt_isr_unmask(BIT(INUM_SOFT)); _xt_isr_unmask(BIT(INUM_SOFT));
/* Initialize system tick timer interrupt and schedule the first tick. */ /* Initialize system tick timer interrupt and schedule the first tick. */
_xt_isr_attach(INUM_TICK, sdk__xt_timer_int); _xt_isr_attach(INUM_TICK, sdk__xt_timer_int, NULL);
_xt_isr_unmask(BIT(INUM_TICK)); _xt_isr_unmask(BIT(INUM_TICK));
sdk__xt_tick_timer_init(); sdk__xt_tick_timer_init();
@ -221,8 +222,10 @@ size_t xPortGetFreeHeapSize( void )
uint32_t brk_val = (uint32_t) sbrk(0); uint32_t brk_val = (uint32_t) sbrk(0);
intptr_t sp = (intptr_t)xPortSupervisorStackPointer; intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
if(sp == 0) /* scheduler not started */ if (sp == 0) {
/* scheduler not started */
SP(sp); SP(sp);
}
return sp - brk_val + mi.fordblks; return sp - brk_val + mi.fordblks;
} }
@ -233,8 +236,6 @@ void vPortEndScheduler( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static unsigned portBASE_TYPE uxCriticalNesting = 0; static unsigned portBASE_TYPE uxCriticalNesting = 0;
/* These nested vPortEnter/ExitCritical macros are called by SDK /* These nested vPortEnter/ExitCritical macros are called by SDK
@ -243,26 +244,42 @@ static unsigned portBASE_TYPE uxCriticalNesting = 0;
* It may be possible to replace the global nesting count variable * It may be possible to replace the global nesting count variable
* with a save/restore of interrupt level, although it's difficult as * with a save/restore of interrupt level, although it's difficult as
* the functions have no return value. * the functions have no return value.
*
* These should not be called from the NMI in regular operation and
* the NMI must not touch the interrupt mask, but that might occur in
* exceptional paths such as aborts and debug code.
*/ */
void IRAM vPortEnterCritical( void ) void IRAM vPortEnterCritical(void) {
{
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
uxCriticalNesting++; uxCriticalNesting++;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void IRAM vPortExitCritical( void ) void IRAM vPortExitCritical(void) {
{
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if (uxCriticalNesting == 0)
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
} }
/* Backward compatibility with libmain.a and libpp.a and can remove when these are open. */ /* Backward compatibility, for the sdk library. */
signed portBASE_TYPE xTaskGenericCreate( TaskFunction_t pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, TaskHandle_t *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const MemoryRegion_t * const xRegions )
{ signed portBASE_TYPE xTaskGenericCreate(TaskFunction_t pxTaskCode,
(void)puxStackBuffer; (void)xRegions; const signed char * const pcName,
return xTaskCreate( pxTaskCode, (const char * const)pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); unsigned short usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
TaskHandle_t *pxCreatedTask,
portSTACK_TYPE *puxStackBuffer,
const MemoryRegion_t * const xRegions) {
(void)puxStackBuffer;
(void)xRegions;
return xTaskCreate(pxTaskCode, (const char * const)pcName, usStackDepth,
pvParameters, uxPriority, pxCreatedTask);
} }
BaseType_t xQueueGenericReceive(QueueHandle_t xQueue, void * const pvBuffer,
TickType_t xTicksToWait, const BaseType_t xJustPeeking) {
configASSERT(xJustPeeking == 0);
return xQueueReceive(xQueue, pvBuffer, xTicksToWait);
}

View file

@ -1,65 +1,29 @@
/* /*
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 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. This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under 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 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 >>! NOTE: The modification to the GPL is included to allow you to !<<
>>! the source code for proprietary components outside of the FreeRTOS >>! distribute a combined work that includes FreeRTOS without being !<<
>>! kernel. >>! 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 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 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 link: http://www.freertos.org/a00114.html
1 tab == 4 spaces! 1 tab == 4 spaces!
***************************************************************************
* *
* Having a problem? Start by reading the FAQ "My application does *
* not run, what could be wrong?" *
* *
* http://www.FreeRTOS.org/FAQHelp.html *
* *
***************************************************************************
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd. contact details.
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.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!
*/ */
@ -92,16 +56,15 @@ extern "C" {
#define portDOUBLE double #define portDOUBLE double
#define portLONG long #define portLONG long
#define portSHORT short #define portSHORT short
#define portSTACK_TYPE unsigned portLONG #define portSTACK_TYPE uint32_t
#define portBASE_TYPE long #define portBASE_TYPE long
#define portPOINTER_SIZE_TYPE unsigned portLONG
typedef portSTACK_TYPE StackType_t; typedef portSTACK_TYPE StackType_t;
typedef portBASE_TYPE BaseType_t; typedef portBASE_TYPE BaseType_t;
typedef unsigned portBASE_TYPE UBaseType_t; typedef unsigned portBASE_TYPE UBaseType_t;
typedef uint32_t TickType_t; typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffff #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* Architecture specifics. */ /* Architecture specifics. */
#define portSTACK_GROWTH ( -1 ) #define portSTACK_GROWTH ( -1 )
@ -156,6 +119,9 @@ extern unsigned cpu_sr;
prefer to _xt_disable_interrupts & _xt_enable_interrupts and store prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
the ps value in a local variable - that approach is recursive-safe the ps value in a local variable - that approach is recursive-safe
and generally better. and generally better.
The NMI must not touch the interrupt mask and it should not in
regular operation, but there is a guard here just in case.
*/ */
inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void) inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void)
{ {
@ -185,6 +151,10 @@ not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/* FreeRTOS API functions should not be called from the NMI handler. */
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT(sdk_NMIIrqIsOn == 0)
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -0,0 +1,20 @@
Each real time kernel port consists of three files that contain the core kernel
components and are common to every port, and one or more files that are
specific to a particular microcontroller and/or compiler.
+ The FreeRTOS/Source/Portable/MemMang directory contains the five sample
memory allocators as described on the http://www.FreeRTOS.org WEB site.
+ The other directories each contain files specific to a particular
microcontroller or compiler, where the directory name denotes the compiler
specific files the directory contains.
For example, if you are interested in the [compiler] port for the [architecture]
microcontroller, then the port specific files are contained in
FreeRTOS/Source/Portable/[compiler]/[architecture] directory. If this is the
only port you are interested in then all the other directories can be
ignored.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
#endif #endif
#if( configUSE_MUTEXES == 1 )
/*
* If a task waiting for a mutex causes the mutex holder to inherit a
* priority, but the waiting task times out, then the holder should
* disinherit the priority - but only down to the highest priority of any
* other tasks that are waiting for the same mutex. This function returns
* that priority.
*/
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
#endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -374,6 +384,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
} }
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
}
return pxNewQueue; return pxNewQueue;
} }
@ -422,6 +436,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
} }
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
}
return pxNewQueue; return pxNewQueue;
} }
@ -567,6 +585,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) )
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore )
{
void *pxReturn;
configASSERT( xSemaphore );
/* Mutexes cannot be used in interrupt service routines, so the mutex
holder should not change in an ISR, and therefore a critical section is
not required here. */
if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )
{
pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder;
}
else
{
pxReturn = NULL;
}
return pxReturn;
} /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */
#endif
/*-----------------------------------------------------------*/
#if ( configUSE_RECURSIVE_MUTEXES == 1 ) #if ( configUSE_RECURSIVE_MUTEXES == 1 )
BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
@ -643,7 +687,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
} }
else else
{ {
xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait );
/* pdPASS will only be returned if the mutex was successfully /* pdPASS will only be returned if the mutex was successfully
obtained. The calling task may have entered the Blocked state obtained. The calling task may have entered the Blocked state
@ -855,7 +899,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{ {
/* The queue was full and a block time was specified so /* The queue was full and a block time was specified so
configure the timeout structure. */ configure the timeout structure. */
vTaskSetTimeOutState( &xTimeOut ); vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE; xEntryTimeSet = pdTRUE;
} }
else else
@ -1127,7 +1171,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
can be assumed there is no mutex holder and no need to determine if can be assumed there is no mutex holder and no need to determine if
priority disinheritance is needed. Simply increase the count of priority disinheritance is needed. Simply increase the count of
messages (semaphores) available. */ messages (semaphores) available. */
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
/* The event list is not altered if the queue is locked. This will /* The event list is not altered if the queue is locked. This will
be done when the queue is unlocked later. */ be done when the queue is unlocked later. */
@ -1234,21 +1278,27 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking ) BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
{ {
BaseType_t xEntryTimeSet = pdFALSE; BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut; TimeOut_t xTimeOut;
int8_t *pcOriginalReadPosition;
Queue_t * const pxQueue = ( Queue_t * ) xQueue; Queue_t * const pxQueue = ( Queue_t * ) xQueue;
configASSERT( pxQueue ); /* Check the pointer is not NULL. */
configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); configASSERT( ( pxQueue ) );
/* The buffer into which data is received can only be NULL if the data size
is zero (so no data is copied into the buffer. */
configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{ {
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
} }
#endif #endif
/* This function relaxes the coding standard somewhat to allow return /* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest statements within the function itself. This is done in the interest
of execution time efficiency. */ of execution time efficiency. */
@ -1263,34 +1313,14 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
must be the highest priority task wanting to access the queue. */ must be the highest priority task wanting to access the queue. */
if( uxMessagesWaiting > ( UBaseType_t ) 0 ) if( uxMessagesWaiting > ( UBaseType_t ) 0 )
{ {
/* Remember the read position in case the queue is only being /* Data available, remove one item. */
peeked. */
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
prvCopyDataFromQueue( pxQueue, pvBuffer ); prvCopyDataFromQueue( pxQueue, pvBuffer );
if( xJustPeeking == pdFALSE )
{
traceQUEUE_RECEIVE( pxQueue ); traceQUEUE_RECEIVE( pxQueue );
pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
/* Actually removing data, not just peeking. */ /* There is now space in the queue, were any tasks waiting to
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; post to the queue? If so, unblock the highest priority waiting
task. */
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
/* Record the information required to implement
priority inheritance should it become necessary. */
pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{ {
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
@ -1306,34 +1336,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
}
else
{
traceQUEUE_PEEK( pxQueue );
/* The data is not being removed, so reset the 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 )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority than this task. */
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
return pdPASS; return pdPASS;
@ -1352,7 +1354,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{ {
/* The queue was empty and a block time was specified so /* The queue was empty and a block time was specified so
configure the timeout structure. */ configure the timeout structure. */
vTaskSetTimeOutState( &xTimeOut ); vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE; xEntryTimeSet = pdTRUE;
} }
else else
@ -1373,6 +1375,182 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
/* Update the timeout state to see if it has expired yet. */ /* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{ {
/* The timeout has not expired. If the queue is still empty place
the task on the list of tasks waiting to receive from the queue. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* The queue contains data again. Loop back to try and read the
data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else
{
/* Timed out. If there is no data in the queue exit, otherwise loop
back and attempt to read the data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
/*-----------------------------------------------------------*/
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
#if( configUSE_MUTEXES == 1 )
BaseType_t xInheritanceOccurred = pdFALSE;
#endif
/* Check the queue pointer is not NULL. */
configASSERT( ( pxQueue ) );
/* Check this really is a semaphore, in which case the item size will be
0. */
configASSERT( pxQueue->uxItemSize == 0 );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
/* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest
of execution time efficiency. */
for( ;; )
{
taskENTER_CRITICAL();
{
/* Semaphores are queues with an item size of 0, and where the
number of messages in the queue is the semaphore's count value. */
const UBaseType_t uxSemaphoreCount = 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( uxSemaphoreCount > ( UBaseType_t ) 0 )
{
traceQUEUE_RECEIVE( pxQueue );
/* Semaphores are queues with a data size of zero and where the
messages waiting is the semaphore's count. Reduce the count. */
pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
/* Record the information required to implement
priority inheritance should it become necessary. */
pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
/* Check to see if other tasks are blocked waiting to give the
semaphore, and if so, unblock the highest priority such task. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
/* For inheritance to have occurred there must have been an
initial timeout, and an adjusted timeout cannot become 0, as
if it were 0 the function would have exited. */
#if( configUSE_MUTEXES == 1 )
{
configASSERT( xInheritanceOccurred == pdFALSE );
}
#endif /* configUSE_MUTEXES */
/* The semaphore count was 0 and no block time is specified
(or the block time has expired) so exit now. */
taskEXIT_CRITICAL();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
/* The semaphore count was 0 and a block time was specified
so configure the timeout structure ready to block. */
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
else
{
/* Entry time was already set. */
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL();
/* Interrupts and other tasks can give to and take from the semaphore
now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
/* A block time is specified and not expired. If the semaphore
count is 0 then enter the Blocked state to wait for a semaphore to
become available. As semaphores are implemented with queues the
queue being empty is equivalent to the semaphore count being 0. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{ {
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
@ -1383,7 +1561,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{ {
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
} }
@ -1407,13 +1585,193 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
} }
else else
{ {
/* Try again. */ /* There was no timeout and the semaphore count was not 0, so
attempt to take the semaphore again. */
prvUnlockQueue( pxQueue ); prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll(); ( void ) xTaskResumeAll();
} }
} }
else else
{ {
/* Timed out. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
/* If the semaphore count is 0 exit now as the timeout has
expired. Otherwise return to attempt to take the semaphore that is
known to be available. As semaphores are implemented by queues the
queue being empty is equivalent to the semaphore count being 0. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
#if ( configUSE_MUTEXES == 1 )
{
/* xInheritanceOccurred could only have be set if
pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to
test the mutex type again to check it is actually a mutex. */
if( xInheritanceOccurred != pdFALSE )
{
taskENTER_CRITICAL();
{
UBaseType_t uxHighestWaitingPriority;
/* This task blocking on the mutex caused another
task to inherit this task's priority. Now this task
has timed out the priority should be disinherited
again, but only as low as the next highest priority
task that is waiting for the same mutex. */
uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
}
taskEXIT_CRITICAL();
}
}
#endif /* configUSE_MUTEXES */
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
/*-----------------------------------------------------------*/
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
int8_t *pcOriginalReadPosition;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
/* Check the pointer is not NULL. */
configASSERT( ( pxQueue ) );
/* The buffer into which data is received can only be NULL if the data size
is zero (so no data is copied into the buffer. */
configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
/* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest
of execution time efficiency. */
for( ;; )
{
taskENTER_CRITICAL();
{
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 so it can be reset after the data
is read from the queue as this function is only peeking the
data, not removing it. */
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
prvCopyDataFromQueue( pxQueue, pvBuffer );
traceQUEUE_PEEK( pxQueue );
/* The data is not being removed, so reset the 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 )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority than this task. */
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
/* The queue was empty and no block time is specified (or
the block time has expired) so leave now. */
taskEXIT_CRITICAL();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
/* The queue was empty and a block time was specified so
configure the timeout structure ready to enter the blocked
state. */
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
else
{
/* Entry time was already set. */
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL();
/* Interrupts and other tasks can send to and receive from the queue
now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
/* Timeout has not expired yet, check to see if there is data in the
queue now, and if not enter the Blocked state to wait for data. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* There is data in the queue now, so don't enter the blocked
state, instead return to try and obtain the data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else
{
/* The timeout has expired. If there is still no data in the queue
exit, otherwise go back and try to read the data again. */
prvUnlockQueue( pxQueue ); prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll(); ( void ) xTaskResumeAll();
@ -1468,7 +1826,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
prvCopyDataFromQueue( pxQueue, pvBuffer ); prvCopyDataFromQueue( pxQueue, pvBuffer );
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
/* If the queue is locked the event list will not be modified. /* If the queue is locked the event list will not be modified.
Instead update the lock count so the task that unlocks the queue Instead update the lock count so the task that unlocks the queue
@ -1694,6 +2052,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
#endif /* configUSE_TRACE_FACILITY */ #endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_MUTEXES == 1 )
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue )
{
UBaseType_t uxHighestPriorityOfWaitingTasks;
/* If a task waiting for a mutex causes the mutex holder to inherit a
priority, but the waiting task times out, then the holder should
disinherit the priority - but only down to the highest priority of any
other tasks that are waiting for the same mutex. For this purpose,
return the priority of the highest priority task that is waiting for the
mutex. */
if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 )
{
uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) );
}
else
{
uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;
}
return uxHighestPriorityOfWaitingTasks;
}
#endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
{ {
BaseType_t xReturn = pdFALSE; BaseType_t xReturn = pdFALSE;
@ -1767,7 +2152,7 @@ UBaseType_t uxMessagesWaiting;
} }
} }
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
return xReturn; return xReturn;
} }
@ -2316,7 +2701,7 @@ BaseType_t xReturn;
} }
return pcReturn; return pcReturn;
} } /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */
#endif /* configQUEUE_REGISTRY_SIZE */ #endif /* configQUEUE_REGISTRY_SIZE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -2395,7 +2780,7 @@ BaseType_t xReturn;
{ {
QueueSetHandle_t pxQueue; QueueSetHandle_t pxQueue;
pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET ); pxQueue = xQueueGenericCreate( uxEventQueueLength, ( UBaseType_t ) sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
return pxQueue; return pxQueue;
} }
@ -2478,7 +2863,7 @@ BaseType_t xReturn;
{ {
QueueSetMemberHandle_t xReturn = NULL; QueueSetMemberHandle_t xReturn = NULL;
( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ ( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait ); /*lint !e961 Casting from one typedef to another is not redundant. */
return xReturn; return xReturn;
} }

View file

@ -1,17 +1,20 @@
Each real time kernel port consists of three files that contain the core kernel Each real time kernel port consists of three files that contain the core kernel
components and are common to every port, and one or more files that are components and are common to every port, and one or more files that are
specific to a particular microcontroller and or compiler. specific to a particular microcontroller and/or compiler.
+ The FreeRTOS/Source directory contains the three files that are common to
every port - list.c, queue.c and tasks.c. The kernel is contained within these
three files. croutine.c implements the optional co-routine functionality - which
is normally only used on very memory limited systems.
+ The FreeRTOS/Source/Portable directory contains the files that are specific to + The FreeRTOS/Source/Portable/MemMang directory contains the five sample
a particular microcontroller and or compiler. memory allocators as described on the http://www.FreeRTOS.org WEB site.
+ The FreeRTOS/Source/include directory contains the real time kernel header + The other directories each contain files specific to a particular
files. microcontroller or compiler, where the directory name denotes the compiler
specific files the directory contains.
For example, if you are interested in the [compiler] port for the [architecture]
microcontroller, then the port specific files are contained in
FreeRTOS/Source/Portable/[compiler]/[architecture] directory. If this is the
only port you are interested in then all the other directories can be
ignored.
See the readme file in the FreeRTOS/Source/Portable directory for more
information.

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -131,12 +131,23 @@ made to free the RAM that was allocated statically.
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a 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 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 that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
a statically allocated stack and a dynamically allocated TCB. */ 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 ) ) !!!NOTE!!! If the definition of tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is
changed then the definition of StaticTask_t must also be updated. */
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) #define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) #define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) #define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
/* If any of the following are set then task stacks are filled with a known
value so the high water mark can be determined. If none of the following are
set then don't fill the stack so there is no unnecessary dependency on memset. */
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
#else
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
#endif
/* /*
* Macros used by vListTask to indicate which state a task is in. * Macros used by vListTask to indicate which state a task is in.
*/ */
@ -153,6 +164,12 @@ a statically allocated stack and a dynamically allocated TCB. */
#define static #define static
#endif #endif
/* The name allocated to the Idle task. This can be overridden by defining
configIDLE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configIDLE_TASK_NAME
#define configIDLE_TASK_NAME "IDLE"
#endif
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
@ -304,8 +321,8 @@ typedef struct tskTaskControlBlock
StackType_t *pxStack; /*< Points to the start of the stack. */ 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. */ 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 ) #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif #endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #if ( portCRITICAL_NESTING_IN_TCB == 1 )
@ -352,7 +369,7 @@ typedef struct tskTaskControlBlock
/* See the comments above the definition of /* See the comments above the definition of
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif #endif
@ -366,8 +383,8 @@ typedef struct tskTaskControlBlock
below to enable the use of older kernel aware debuggers. */ below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t; typedef tskTCB TCB_t;
/*lint -e956 A manual analysis and inspection has been used to determine which /*lint -save -e956 A manual analysis and inspection has been used to determine
static variables must be declared volatile. */ which static variables must be declared volatile. */
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
@ -394,7 +411,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r
/* Other file private variables. --------------------------------*/ /* Other file private variables. --------------------------------*/
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
@ -421,21 +438,27 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
#endif #endif
/*lint +e956 */ /*lint -restore */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Callback function prototypes. --------------------------*/ /* Callback function prototypes. --------------------------*/
#if( configCHECK_FOR_STACK_OVERFLOW > 0 ) #if( configCHECK_FOR_STACK_OVERFLOW > 0 )
extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
#endif #endif
#if( configUSE_TICK_HOOK > 0 ) #if( configUSE_TICK_HOOK > 0 )
extern void vApplicationTickHook( void ); extern void vApplicationTickHook( void );
#endif #endif
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
#endif #endif
/* File private functions. --------------------------------*/ /* File private functions. --------------------------------*/
@ -446,7 +469,9 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
* is in any other state. * is in any other state.
*/ */
#if ( INCLUDE_vTaskSuspend == 1 ) #if ( INCLUDE_vTaskSuspend == 1 )
static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
#endif /* INCLUDE_vTaskSuspend */ #endif /* INCLUDE_vTaskSuspend */
/* /*
@ -565,13 +590,13 @@ static void prvResetNextTaskUnblockTime( void );
* dynamically to fill in the structure's members. * dynamically to fill in the structure's members.
*/ */
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth, const uint32_t ulStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask, TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB, TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
/* /*
* Called after a new task has been created and initialised to place the task * Called after a new task has been created and initialised to place the task
@ -579,17 +604,28 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
*/ */
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
/*
* freertos_tasks_c_additions_init() should only be called if the user definable
* macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
* called by the function.
*/
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION;
#endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth, const uint32_t ulStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
StackType_t * const puxStackBuffer, StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ StaticTask_t * const pxTaskBuffer )
{ {
TCB_t *pxNewTCB; TCB_t *pxNewTCB;
TaskHandle_t xReturn; TaskHandle_t xReturn;
@ -597,6 +633,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
configASSERT( puxStackBuffer != NULL ); configASSERT( puxStackBuffer != NULL );
configASSERT( pxTaskBuffer != NULL ); configASSERT( pxTaskBuffer != NULL );
#if( configASSERT_DEFINED == 1 )
{
/* Sanity check that the size of the structure used to declare a
variable of type StaticTask_t equals the size of the real task
structure. */
volatile size_t xSize = sizeof( StaticTask_t );
configASSERT( xSize == sizeof( TCB_t ) );
}
#endif /* configASSERT_DEFINED */
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
{ {
/* The memory used for the task's TCB and stack are passed into this /* The memory used for the task's TCB and stack are passed into this
@ -604,7 +651,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
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 = ( 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; pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
{ {
/* Tasks can be created statically or dynamically, so note this /* Tasks can be created statically or dynamically, so note this
task was created statically in case the task is later deleted. */ task was created statically in case the task is later deleted. */
@ -626,7 +673,53 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
#endif /* SUPPORT_STATIC_ALLOCATION */ #endif /* SUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( portUSING_MPU_WRAPPERS == 1 ) #if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
{
TCB_t *pxNewTCB;
BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
configASSERT( pxTaskDefinition->puxStackBuffer != NULL );
configASSERT( pxTaskDefinition->pxTaskBuffer != NULL );
if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != 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 * ) pxTaskDefinition->pxTaskBuffer;
/* Store the stack location in the TCB. */
pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
/* 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;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
pxTaskDefinition->pcName,
( uint32_t ) pxTaskDefinition->usStackDepth,
pxTaskDefinition->pvParameters,
pxTaskDefinition->uxPriority,
pxCreatedTask, pxNewTCB,
pxTaskDefinition->xRegions );
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
return xReturn;
}
#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/*-----------------------------------------------------------*/
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) )
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
{ {
@ -674,11 +767,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint16_t usStackDepth, const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ TaskHandle_t * const pxCreatedTask )
{ {
TCB_t *pxNewTCB; TCB_t *pxNewTCB;
BaseType_t xReturn; BaseType_t xReturn;
@ -741,7 +834,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
if( pxNewTCB != NULL ) if( pxNewTCB != NULL )
{ {
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
{ {
/* Tasks can be created statically or dynamically, so note this /* Tasks can be created statically or dynamically, so note this
task was created dynamically in case it is later deleted. */ task was created dynamically in case it is later deleted. */
@ -765,13 +858,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth, const uint32_t ulStackDepth,
void * const pvParameters, void * const pvParameters,
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask, TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB, TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const MemoryRegion_t * const xRegions )
{ {
StackType_t *pxTopOfStack; StackType_t *pxTopOfStack;
UBaseType_t x; UBaseType_t x;
@ -791,12 +884,12 @@ UBaseType_t x;
#endif /* portUSING_MPU_WRAPPERS == 1 */ #endif /* portUSING_MPU_WRAPPERS == 1 */
/* Avoid dependency on memset() if it is not required. */ /* Avoid dependency on memset() if it is not required. */
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) #if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
{ {
/* Fill the stack with a known value to assist debugging. */ /* Fill the stack with a known value to assist debugging. */
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); ( 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 ) ) ) */ #endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
/* Calculate the top of stack address. This depends on whether the stack /* 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. grows from high memory to low (as per the 80x86) or vice versa.
@ -809,6 +902,14 @@ UBaseType_t x;
/* Check the alignment of the calculated top of stack is correct. */ /* Check the alignment of the calculated top of stack is correct. */
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
#if( configRECORD_STACK_HIGH_ADDRESS == 1 )
{
/* Also record the stack's high address, which may assist
debugging. */
pxNewTCB->pxEndOfStack = pxTopOfStack;
}
#endif /* configRECORD_STACK_HIGH_ADDRESS */
} }
#else /* portSTACK_GROWTH */ #else /* portSTACK_GROWTH */
{ {
@ -1515,14 +1616,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
} }
/* If the task is in the blocked or suspended list we need do /* If the task is in the blocked or suspended list we need do
nothing more than change it's priority variable. However, if nothing more than change its priority variable. However, if
the task is in a ready list it needs to be removed and placed the task is in a ready list it needs to be removed and placed
in the list appropriate to its new priority. */ in the list appropriate to its new priority. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
{ {
/* The task is currently in its ready list - remove before adding /* The task is currently in its ready list - remove before
it to it's new ready list. As we are in a critical section we adding it to it's new ready list. As we are in a critical
can do this even if the scheduler is suspended. */ section we can do this even if the scheduler is suspended. */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{ {
/* It is known that the task is in its ready list so /* It is known that the task is in its ready list so
@ -1597,6 +1698,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
} }
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
#if( configUSE_TASK_NOTIFICATIONS == 1 )
{
if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
{
/* The task was blocked to wait for a notification, but is
now suspended, so no notification was received. */
pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
}
#endif
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
@ -1672,7 +1784,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{ {
/* Is it in the suspended list because it is in the Suspended /* Is it in the suspended list because it is in the Suspended
state, or because is is blocked with no timeout? */ state, or because is is blocked with no timeout? */
if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
} }
@ -1716,12 +1828,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{ {
traceTASK_RESUME( pxTCB ); traceTASK_RESUME( pxTCB );
/* As we are in a critical section we can access the ready /* The ready list can be accessed even if the scheduler is
lists even if the scheduler is suspended. */ suspended because this is inside a critical section. */
( void ) uxListRemove( &( pxTCB->xStateListItem ) ); ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB ); prvAddTaskToReadyList( pxTCB );
/* We may have just resumed a higher priority task. */ /* A higher priority task may have just been resumed. */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{ {
/* This yield may not cause the task just resumed to run, /* This yield may not cause the task just resumed to run,
@ -1838,9 +1950,9 @@ BaseType_t xReturn;
address of the RAM then create the idle task. */ address of the RAM then create the idle task. */
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
"IDLE", configIDLE_TASK_NAME,
ulIdleTaskStackSize, ulIdleTaskStackSize,
( void * ) NULL, ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
pxIdleTaskStackBuffer, pxIdleTaskStackBuffer,
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
@ -1858,7 +1970,8 @@ BaseType_t xReturn;
{ {
/* The Idle task is being created using dynamically allocated RAM. */ /* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreate( prvIdleTask, xReturn = xTaskCreate( prvIdleTask,
"IDLE", configMINIMAL_STACK_SIZE, configIDLE_TASK_NAME,
configMINIMAL_STACK_SIZE,
( void * ) NULL, ( void * ) NULL,
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
@ -1880,6 +1993,15 @@ BaseType_t xReturn;
if( xReturn == pdPASS ) if( xReturn == pdPASS )
{ {
/* freertos_tasks_c_additions_init() should only be called if the user
definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
the only macro called by the function. */
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
{
freertos_tasks_c_additions_init();
}
#endif
/* Interrupts are turned off here, to ensure a tick does not occur /* Interrupts are turned off here, to ensure a tick does not occur
before or during the call to xPortStartScheduler(). The stacks of before or during the call to xPortStartScheduler(). The stacks of
the created tasks contain a status word with interrupts switched on the created tasks contain a status word with interrupts switched on
@ -1901,7 +2023,10 @@ BaseType_t xReturn;
/* If configGENERATE_RUN_TIME_STATS is defined then the following /* If configGENERATE_RUN_TIME_STATS is defined then the following
macro must be defined to configure the timer/counter used to generate macro must be defined to configure the timer/counter used to generate
the run time counter time base. */ the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS
is set to 0 and the following line fails to build then ensure you do not
have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
FreeRTOSConfig.h file. */
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
/* Setting up the timer tick is hardware specific and thus in the /* Setting up the timer tick is hardware specific and thus in the
@ -2427,7 +2552,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
{ {
TCB_t *pxTCB = ( TCB_t * ) xTask; TCB_t *pxTCB = ( TCB_t * ) xTask;
BaseType_t xReturn = pdFALSE; BaseType_t xReturn;
configASSERT( pxTCB ); configASSERT( pxTCB );
@ -2437,6 +2562,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
it is actually in the Blocked state. */ it is actually in the Blocked state. */
if( eTaskGetState( xTask ) == eBlocked ) if( eTaskGetState( xTask ) == eBlocked )
{ {
xReturn = pdPASS;
/* Remove the reference to the task from the blocked list. An /* Remove the reference to the task from the blocked list. An
interrupt won't touch the xStateListItem because the interrupt won't touch the xStateListItem because the
scheduler is suspended. */ scheduler is suspended. */
@ -2485,10 +2612,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
} }
else else
{ {
mtCOVERAGE_TEST_MARKER(); xReturn = pdFAIL;
} }
} }
xTaskResumeAll(); ( void ) xTaskResumeAll();
return xReturn; return xReturn;
} }
@ -2510,13 +2637,13 @@ BaseType_t xSwitchRequired = pdFALSE;
{ {
/* Minor optimisation. The tick count cannot change in this /* Minor optimisation. The tick count cannot change in this
block. */ block. */
const TickType_t xConstTickCount = xTickCount + 1; const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
/* Increment the RTOS tick, switching the delayed and overflowed /* Increment the RTOS tick, switching the delayed and overflowed
delayed lists if it wraps to 0. */ delayed lists if it wraps to 0. */
xTickCount = xConstTickCount; xTickCount = xConstTickCount;
if( xConstTickCount == ( TickType_t ) 0U ) if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
{ {
taskSWITCH_DELAYED_LISTS(); taskSWITCH_DELAYED_LISTS();
} }
@ -2959,10 +3086,9 @@ BaseType_t xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
{ {
TCB_t *pxUnblockedTCB; TCB_t *pxUnblockedTCB;
BaseType_t xReturn;
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
the event flags implementation. */ the event flags implementation. */
@ -2985,28 +3111,30 @@ BaseType_t xReturn;
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
{ {
/* Return true if the task removed from the event list has /* The unblocked task has a priority above that of the calling task, so
a higher priority than the calling task. This allows a context switch is required. This function is called with the
the calling task to know if it should force a context scheduler suspended so xYieldPending is set so the context switch
switch now. */ occurs immediately that the scheduler is resumed (unsuspended). */
xReturn = pdTRUE;
/* Mark that a yield is pending in case the user is not using the
"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
xYieldPending = pdTRUE; xYieldPending = pdTRUE;
} }
else
{
xReturn = pdFALSE;
}
return xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
{ {
configASSERT( pxTimeOut ); configASSERT( pxTimeOut );
taskENTER_CRITICAL();
{
pxTimeOut->xOverflowCount = xNumOfOverflows;
pxTimeOut->xTimeOnEntering = xTickCount;
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
{
/* For internal use only as it does not use a critical section. */
pxTimeOut->xOverflowCount = xNumOfOverflows; pxTimeOut->xOverflowCount = xNumOfOverflows;
pxTimeOut->xTimeOnEntering = xTickCount; pxTimeOut->xTimeOnEntering = xTickCount;
} }
@ -3023,6 +3151,7 @@ BaseType_t xReturn;
{ {
/* Minor optimisation. The tick count cannot change in this block. */ /* Minor optimisation. The tick count cannot change in this block. */
const TickType_t xConstTickCount = xTickCount; const TickType_t xConstTickCount = xTickCount;
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
#if( INCLUDE_xTaskAbortDelay == 1 ) #if( INCLUDE_xTaskAbortDelay == 1 )
if( pxCurrentTCB->ucDelayAborted != pdFALSE ) if( pxCurrentTCB->ucDelayAborted != pdFALSE )
@ -3055,11 +3184,11 @@ BaseType_t xReturn;
was called. */ was called. */
xReturn = pdTRUE; xReturn = pdTRUE;
} }
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. */ else if( xElapsedTime < *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. */ /* Not a genuine timeout. Adjust parameters for time remaining. */
*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); *pxTicksToWait -= xElapsedTime;
vTaskSetTimeOutState( pxTimeOut ); vTaskInternalSetTimeOutState( pxTimeOut );
xReturn = pdFALSE; xReturn = pdFALSE;
} }
else else
@ -3136,6 +3265,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
SCHEDULER IS STARTED. **/ SCHEDULER IS STARTED. **/
/* In case a task that has a secure context deletes itself, in which case
the idle task is responsible for deleting the task's secure context, if
any. */
portTASK_CALLS_SECURE_FUNCTIONS();
for( ;; ) for( ;; )
{ {
/* See if any tasks have deleted themselves - if so then the idle task /* See if any tasks have deleted themselves - if so then the idle task
@ -3212,6 +3346,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
configASSERT( xNextTaskUnblockTime >= xTickCount ); configASSERT( xNextTaskUnblockTime >= xTickCount );
xExpectedIdleTime = prvGetExpectedIdleTime(); xExpectedIdleTime = prvGetExpectedIdleTime();
/* Define the following macro to set xExpectedIdleTime to 0
if the application does not want
portSUPPRESS_TICKS_AND_SLEEP() to be called. */
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{ {
traceLOW_POWER_IDLE_BEGIN(); traceLOW_POWER_IDLE_BEGIN();
@ -3368,23 +3507,13 @@ static void prvCheckTasksWaitingTermination( void )
/** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
#if ( INCLUDE_vTaskDelete == 1 ) #if ( INCLUDE_vTaskDelete == 1 )
{
BaseType_t xListIsEmpty;
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */
while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
{
vTaskSuspendAll();
{
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
}
( void ) xTaskResumeAll();
if( xListIsEmpty == pdFALSE )
{ {
TCB_t *pxTCB; TCB_t *pxTCB;
/* uxDeletedTasksWaitingCleanUp is used to prevent vTaskSuspendAll()
being called too often in the idle task. */
while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
{
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
@ -3396,11 +3525,6 @@ static void prvCheckTasksWaitingTermination( void )
prvDeleteTCB( pxTCB ); prvDeleteTCB( pxTCB );
} }
else
{
mtCOVERAGE_TEST_MARKER();
}
}
} }
#endif /* INCLUDE_vTaskDelete */ #endif /* INCLUDE_vTaskDelete */
} }
@ -3421,25 +3545,6 @@ static void prvCheckTasksWaitingTermination( void )
pxTaskStatus->pxStackBase = pxTCB->pxStack; pxTaskStatus->pxStackBase = pxTCB->pxStack;
pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
#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( pxTaskStatus->eCurrentState == eSuspended )
{
vTaskSuspendAll();
{
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
pxTaskStatus->eCurrentState = eBlocked;
}
}
xTaskResumeAll();
}
}
#endif /* INCLUDE_vTaskSuspend */
#if ( configUSE_MUTEXES == 1 ) #if ( configUSE_MUTEXES == 1 )
{ {
pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
@ -3460,12 +3565,38 @@ static void prvCheckTasksWaitingTermination( void )
} }
#endif #endif
/* Obtaining the task state is a little fiddly, so is only done if the value /* Obtaining the task state is a little fiddly, so is only done if the
of eState passed into this function is eInvalid - otherwise the state is value of eState passed into this function is eInvalid - otherwise the
just set to whatever is passed in. */ state is just set to whatever is passed in. */
if( eState != eInvalid ) if( eState != eInvalid )
{
if( pxTCB == pxCurrentTCB )
{
pxTaskStatus->eCurrentState = eRunning;
}
else
{ {
pxTaskStatus->eCurrentState = eState; pxTaskStatus->eCurrentState = eState;
#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 )
{
vTaskSuspendAll();
{
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
pxTaskStatus->eCurrentState = eBlocked;
}
}
( void ) xTaskResumeAll();
}
}
#endif /* INCLUDE_vTaskSuspend */
}
} }
else else
{ {
@ -3499,7 +3630,7 @@ static void prvCheckTasksWaitingTermination( void )
static UBaseType_t prvListTasksWithinSingleList( 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; configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;
UBaseType_t uxTask = 0; UBaseType_t uxTask = 0;
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
@ -3600,7 +3731,7 @@ static void prvCheckTasksWaitingTermination( void )
vPortFree( pxTCB->pxStack ); vPortFree( pxTCB->pxStack );
vPortFree( pxTCB ); vPortFree( pxTCB );
} }
#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
{ {
/* The task could have been allocated statically or dynamically, so /* The task could have been allocated statically or dynamically, so
check what was statically allocated before trying to free the check what was statically allocated before trying to free the
@ -3622,7 +3753,7 @@ static void prvCheckTasksWaitingTermination( void )
{ {
/* Neither the stack nor the TCB were allocated dynamically, so /* Neither the stack nor the TCB were allocated dynamically, so
nothing needs to be freed. */ nothing needs to be freed. */
configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
@ -3703,25 +3834,27 @@ TCB_t *pxTCB;
#if ( configUSE_MUTEXES == 1 ) #if ( configUSE_MUTEXES == 1 )
void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
{ {
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;
BaseType_t xReturn = pdFALSE;
/* If the mutex was given back by an interrupt while the queue was /* If the mutex was given back by an interrupt while the queue was
locked then the mutex holder might now be NULL. */ locked then the mutex holder might now be NULL. _RB_ Is this still
needed as interrupts can no longer use mutexes? */
if( pxMutexHolder != NULL ) if( pxMutexHolder != NULL )
{ {
/* If the holder of the mutex has a priority below the priority of /* If the holder of the mutex has a priority below the priority of
the task attempting to obtain the mutex then it will temporarily the task attempting to obtain the mutex then it will temporarily
inherit the priority of the task attempting to obtain the mutex. */ inherit the priority of the task attempting to obtain the mutex. */
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
{ {
/* Adjust the mutex holder state to account for its new /* Adjust the mutex holder state to account for its new
priority. Only reset the event list item value if the value is priority. Only reset the event list item value if the value is
not being used for anything else. */ not being used for anything else. */
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
{ {
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
} }
else else
{ {
@ -3730,11 +3863,11 @@ TCB_t *pxTCB;
/* If the task being modified is in the ready state it will need /* If the task being modified is in the ready state it will need
to be moved into a new list. */ to be moved into a new list. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
{ {
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{ {
taskRESET_READY_PRIORITY( pxTCB->uxPriority ); taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
} }
else else
{ {
@ -3742,26 +3875,45 @@ TCB_t *pxTCB;
} }
/* Inherit the priority before being moved into the new list. */ /* Inherit the priority before being moved into the new list. */
pxTCB->uxPriority = pxCurrentTCB->uxPriority; pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
prvAddTaskToReadyList( pxTCB ); prvAddTaskToReadyList( pxMutexHolderTCB );
} }
else else
{ {
/* Just inherit the priority. */ /* Just inherit the priority. */
pxTCB->uxPriority = pxCurrentTCB->uxPriority; pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
} }
traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );
/* Inheritance occurred. */
xReturn = pdTRUE;
}
else
{
if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )
{
/* The base priority of the mutex holder is lower than the
priority of the task attempting to take the mutex, but the
current priority of the mutex holder is not lower than the
priority of the task attempting to take the mutex.
Therefore the mutex holder must have already inherited a
priority, but inheritance would have occurred if that had
not been the case. */
xReturn = pdTRUE;
} }
else else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
}
else else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
return xReturn;
} }
#endif /* configUSE_MUTEXES */ #endif /* configUSE_MUTEXES */
@ -3781,7 +3933,6 @@ TCB_t *pxTCB;
interrupt, and if a mutex is given by the holding task then it must interrupt, and if a mutex is given by the holding task then it must
be the running state task. */ be the running state task. */
configASSERT( pxTCB == pxCurrentTCB ); configASSERT( pxTCB == pxCurrentTCB );
configASSERT( pxTCB->uxMutexesHeld ); configASSERT( pxTCB->uxMutexesHeld );
( pxTCB->uxMutexesHeld )--; ( pxTCB->uxMutexesHeld )--;
@ -3848,6 +3999,108 @@ TCB_t *pxTCB;
#endif /* configUSE_MUTEXES */ #endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configUSE_MUTEXES == 1 )
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )
{
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
if( pxMutexHolder != NULL )
{
/* If pxMutexHolder is not NULL then the holder must hold at least
one mutex. */
configASSERT( pxTCB->uxMutexesHeld );
/* Determine the priority to which the priority of the task that
holds the mutex should be set. This will be the greater of the
holding task's base priority and the priority of the highest
priority task that is waiting to obtain the mutex. */
if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )
{
uxPriorityToUse = uxHighestPriorityWaitingTask;
}
else
{
uxPriorityToUse = pxTCB->uxBasePriority;
}
/* Does the priority need to change? */
if( pxTCB->uxPriority != uxPriorityToUse )
{
/* Only disinherit if no other mutexes are held. This is a
simplification in the priority inheritance implementation. If
the task that holds the mutex is also holding other mutexes then
the other mutexes may have caused the priority inheritance. */
if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )
{
/* If a task has timed out because it already holds the
mutex it was trying to obtain then it cannot of inherited
its own priority. */
configASSERT( pxTCB != pxCurrentTCB );
/* Disinherit the priority, remembering the previous
priority to facilitate determining the subject task's
state. */
traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
uxPriorityUsedOnEntry = pxTCB->uxPriority;
pxTCB->uxPriority = uxPriorityToUse;
/* Only reset the event list item value if the value is not
being used for anything else. */
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
{
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* If the running task is not the task that holds the mutex
then the task that holds the mutex could be in either the
Ready, Blocked or Suspended states. Only remove the task
from its current state list if it is in the Ready state as
the task's priority is going to change and there is one
Ready list per priority. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
{
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
prvAddTaskToReadyList( pxTCB );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #if ( portCRITICAL_NESTING_IN_TCB == 1 )
void vTaskEnterCritical( void ) void vTaskEnterCritical( void )
@ -3937,7 +4190,7 @@ TCB_t *pxTCB;
#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ #endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
void vTaskList( char * pcWriteBuffer ) void vTaskList( char * pcWriteBuffer )
{ {
@ -4029,10 +4282,10 @@ TCB_t *pxTCB;
} }
} }
#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
/*----------------------------------------------------------*/ /*----------------------------------------------------------*/
#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
void vTaskGetRunTimeStats( char *pcWriteBuffer ) void vTaskGetRunTimeStats( char *pcWriteBuffer )
{ {
@ -4156,7 +4409,7 @@ TCB_t *pxTCB;
} }
} }
#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ #endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
TickType_t uxTaskResetEventItemValue( void ) TickType_t uxTaskResetEventItemValue( void )
@ -4240,7 +4493,7 @@ TickType_t uxReturn;
} }
else else
{ {
pxCurrentTCB->ulNotifiedValue = ulReturn - 1; pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
} }
} }
else else
@ -4315,7 +4568,7 @@ TickType_t uxReturn;
blocked state (because a notification was already pending) or the blocked state (because a notification was already pending) or the
task unblocked because of a notification. Otherwise the task task unblocked because of a notification. Otherwise the task
unblocked because of a timeout. */ unblocked because of a timeout. */
if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
{ {
/* A notification was not received. */ /* A notification was not received. */
xReturn = pdFALSE; xReturn = pdFALSE;
@ -4800,8 +5053,24 @@ const TickType_t xConstTickCount = xTickCount;
#endif /* INCLUDE_vTaskSuspend */ #endif /* INCLUDE_vTaskSuspend */
} }
/* Code below here allows additional code to be inserted into this source file,
especially where access to file scope functions and data is needed (for example
when performing module tests). */
#ifdef FREERTOS_MODULE_TEST #ifdef FREERTOS_MODULE_TEST
#include "tasks_test_access_functions.h" #include "tasks_test_access_functions.h"
#endif #endif
#if( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 )
#include "freertos_tasks_c_additions.h"
static void freertos_tasks_c_additions_init( void )
{
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
FREERTOS_TASKS_C_ADDITIONS_INIT();
#endif
}
#endif

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -100,6 +100,12 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
/* Misc definitions. */ /* Misc definitions. */
#define tmrNO_DELAY ( TickType_t ) 0U #define tmrNO_DELAY ( TickType_t ) 0U
/* The name assigned to the timer service task. This can be overridden by
defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configTIMER_SERVICE_TASK_NAME
#define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
#endif
/* The definition of the timers themselves. */ /* The definition of the timers themselves. */
typedef struct tmrTimerControl typedef struct tmrTimerControl
{ {
@ -158,8 +164,8 @@ typedef struct tmrTimerQueueMessage
} u; } u;
} DaemonTaskMessage_t; } DaemonTaskMessage_t;
/*lint -e956 A manual analysis and inspection has been used to determine which /*lint -save -e956 A manual analysis and inspection has been used to determine
static variables must be declared volatile. */ which static variables must be declared volatile. */
/* The list in which active timers are stored. Timers are referenced in expire /* The list in which active timers are stored. Timers are referenced in expire
time order, with the nearest expiry time at the front of the list. Only the time order, with the nearest expiry time at the front of the list. Only the
@ -173,7 +179,7 @@ PRIVILEGED_DATA static List_t *pxOverflowTimerList;
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
/*lint +e956 */ /*lint -restore */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -248,12 +254,12 @@ static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseTy
* Called after a Timer_t structure has been allocated either statically or * Called after a Timer_t structure has been allocated either statically or
* dynamically to fill in the structure's members. * dynamically to fill in the structure's members.
*/ */
static void prvInitialiseNewTimer( const char * const pcTimerName, static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction, TimerCallbackFunction_t pxCallbackFunction,
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xTimerCreateTimerTask( void ) BaseType_t xTimerCreateTimerTask( void )
@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
"Tmr Svc", configTIMER_SERVICE_TASK_NAME,
ulTimerTaskStackSize, ulTimerTaskStackSize,
NULL, NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
#else #else
{ {
xReturn = xTaskCreate( prvTimerTask, xReturn = xTaskCreate( prvTimerTask,
"Tmr Svc", configTIMER_SERVICE_TASK_NAME,
configTIMER_TASK_STACK_DEPTH, configTIMER_TASK_STACK_DEPTH,
NULL, NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
@ -311,11 +317,11 @@ BaseType_t xReturn = pdFAIL;
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
TimerHandle_t xTimerCreate( const char * const pcTimerName, TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ TimerCallbackFunction_t pxCallbackFunction )
{ {
Timer_t *pxNewTimer; Timer_t *pxNewTimer;
@ -343,12 +349,12 @@ BaseType_t xReturn = pdFAIL;
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction, TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ StaticTimer_t *pxTimerBuffer )
{ {
Timer_t *pxNewTimer; Timer_t *pxNewTimer;
@ -356,7 +362,7 @@ BaseType_t xReturn = pdFAIL;
{ {
/* Sanity check that the size of the structure used to declare a /* Sanity check that the size of the structure used to declare a
variable of type StaticTimer_t equals the size of the real timer variable of type StaticTimer_t equals the size of the real timer
structures. */ structure. */
volatile size_t xSize = sizeof( StaticTimer_t ); volatile size_t xSize = sizeof( StaticTimer_t );
configASSERT( xSize == sizeof( Timer_t ) ); configASSERT( xSize == sizeof( Timer_t ) );
} }
@ -385,12 +391,12 @@ BaseType_t xReturn = pdFAIL;
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvInitialiseNewTimer( const char * const pcTimerName, static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const TickType_t xTimerPeriodInTicks, const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload, const UBaseType_t uxAutoReload,
void * const pvTimerID, void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction, TimerCallbackFunction_t pxCallbackFunction,
Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ Timer_t *pxNewTimer )
{ {
/* 0 is not a valid value for xTimerPeriodInTicks. */ /* 0 is not a valid value for xTimerPeriodInTicks. */
configASSERT( ( xTimerPeriodInTicks > 0 ) ); configASSERT( ( xTimerPeriodInTicks > 0 ) );
@ -760,7 +766,7 @@ TickType_t xTimeNow;
software timer. */ software timer. */
pxTimer = xMessage.u.xTimerParameters.pxTimer; pxTimer = xMessage.u.xTimerParameters.pxTimer;
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
{ {
/* The timer is in a list, remove it. */ /* The timer is in a list, remove it. */
( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
@ -945,10 +951,10 @@ static void prvCheckForValidListAndQueue( void )
{ {
/* The timer queue is allocated statically in case /* The timer queue is allocated statically in case
configSUPPORT_DYNAMIC_ALLOCATION is 0. */ configSUPPORT_DYNAMIC_ALLOCATION is 0. */
static StaticQueue_t xStaticTimerQueue; static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
} }
#else #else
{ {
@ -991,7 +997,7 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer;
/* Checking to see if it is in the NULL list in effect checks to see if /* Checking to see if it is in the NULL list in effect checks to see if
it is referenced from either the current or the overflow timer lists in it is referenced from either the current or the overflow timer lists in
one go, but the logic has to be reversed, hence the '!'. */ one go, but the logic has to be reversed, hence the '!'. */
xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); /*lint !e961. Cast is only redundant when NULL is passed into the macro. */
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();

View file

@ -78,8 +78,8 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
## Open Source Components ## Open Source Components
* [FreeRTOS](http://www.freertos.org/) V9.0.0 * [FreeRTOS](http://www.freertos.org/) V9.0.0
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v1.4.1, modified via the [esp-lwip project](https://github.com/kadamski/esp-lwip) by @kadamski. * [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v2.0.3, with [some modifications](https://github.com/ourairquality/lwip/).
* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS. * [newlib](https://github.com/ourairquality/newlib) v2.5.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries). For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries).

View file

@ -160,6 +160,26 @@ endif
-include $$($(1)_OBJ_FILES:.o=.d) -include $$($(1)_OBJ_FILES:.o=.d)
endef endef
# Remove comment lines from libgcc.remove file
$(BUILD_DIR)libgcc.remove: $(ROOT)lib/libgcc.remove | $(BUILD_DIR)
$(Q) grep -v "^#" $< | cat > $@
# Remove unwanted object files listed in libgcc.remove
$(BUILD_DIR)libgcc.a: $(ROOT)lib/libgcc.a $(BUILD_DIR)libgcc.remove | $(BUILD_DIR)
@echo "Removing unwanted objects from $<"
$(Q) cat $< > $@
$(Q) $(AR) d $@ @$(word 2,$^)
# Remove comment lines from libc.remove file
$(BUILD_DIR)libc.remove: $(ROOT)libc/libc.remove | $(BUILD_DIR)
$(Q) grep -v "^#" $< | cat > $@
# Remove unwanted object files listed in libgcc.remove
$(BUILD_DIR)libc.a: $(ROOT)libc/xtensa-lx106-elf/lib/libc.a $(BUILD_DIR)libc.remove | $(BUILD_DIR)
@echo "Removing unwanted objects from $<"
$(Q) cat $< > $@
$(Q) $(AR) d $@ @$(word 2,$^)
## Linking rules for SDK libraries ## Linking rules for SDK libraries
## SDK libraries are preprocessed to: ## SDK libraries are preprocessed to:
# - remove object files named in <libname>.remove # - remove object files named in <libname>.remove
@ -208,9 +228,9 @@ $(foreach component,$(COMPONENTS), \
) )
# final linking step to produce .elf # final linking step to produce .elf
$(PROGRAM_OUT): $(WHOLE_ARCHIVES) $(COMPONENT_ARS) $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS) $(PROGRAM_OUT): $(WHOLE_ARCHIVES) $(COMPONENT_ARS) $(BUILD_DIR)libgcc.a $(BUILD_DIR)libc.a $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS)
$(vecho) "LD $@" $(vecho) "LD $@"
$(Q) $(LD) $(LDFLAGS) -Wl,--whole-archive $(WHOLE_ARCHIVES) -Wl,--no-whole-archive -Wl,--start-group $(COMPONENT_ARS) $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@ $(Q) $(LD) $(LDFLAGS) -Wl,--whole-archive $(WHOLE_ARCHIVES) -Wl,--no-whole-archive -Wl,--start-group $(COMPONENT_ARS) $(BUILD_DIR)libgcc.a $(BUILD_DIR)libc.a $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@
$(BUILD_DIR) $(FIRMWARE_DIR) $(BUILD_DIR)sdklib: $(BUILD_DIR) $(FIRMWARE_DIR) $(BUILD_DIR)sdklib:
$(Q) mkdir -p $@ $(Q) mkdir -p $@

View file

@ -214,8 +214,8 @@ void IRAM sdk_user_start(void) {
memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st)); memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
// By default, put the sysparam region just below the config sectors at the // By default, put the sysparam region just below the config sectors at the
// top of the flash space // top of the flash space, and allowing one extra sector spare.
sysparam_addr = flash_size - (4 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size; sysparam_addr = flash_size - (5 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
status = sysparam_init(sysparam_addr, flash_size); status = sysparam_init(sysparam_addr, flash_size);
if (status == SYSPARAM_NOTFOUND) { if (status == SYSPARAM_NOTFOUND) {
status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false); status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false);
@ -236,12 +236,12 @@ void IRAM vApplicationStackOverflowHook(TaskHandle_t task, char *task_name) {
} }
// .text+0x3d8 // .text+0x3d8
void IRAM vApplicationIdleHook(void) { void __attribute__((weak)) IRAM vApplicationIdleHook(void) {
printf("idle %u\n", WDEV.SYS_TIME); printf("idle %u\n", WDEV.SYS_TIME);
} }
// .text+0x404 // .text+0x404
void IRAM vApplicationTickHook(void) { void __attribute__((weak)) IRAM vApplicationTickHook(void) {
printf("tick %u\n", WDEV.SYS_TIME); printf("tick %u\n", WDEV.SYS_TIME);
} }
@ -311,8 +311,8 @@ static void init_g_ic(void) {
if (sdk_g_ic.s._unknown310 > 4) { if (sdk_g_ic.s._unknown310 > 4) {
sdk_g_ic.s._unknown310 = 4; sdk_g_ic.s._unknown310 = 4;
} }
if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) { if (sdk_g_ic.s.sta_ssid.ssid_length == 0xffffffff) {
bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4)); bzero(&sdk_g_ic.s.sta_ssid, sizeof(sdk_g_ic.s.sta_ssid));
bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password)); bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password));
} }
sdk_g_ic.s.wifi_led_enable = 0; sdk_g_ic.s.wifi_led_enable = 0;

View file

@ -22,6 +22,7 @@
#include "esp/dport_regs.h" #include "esp/dport_regs.h"
#include "espressif/esp_common.h" #include "espressif/esp_common.h"
#include "esplibs/libmain.h" #include "esplibs/libmain.h"
#include "user_exception.h"
/* Forward declarations */ /* Forward declarations */
static void IRAM fatal_handler_prelude(void); static void IRAM fatal_handler_prelude(void);
@ -33,6 +34,8 @@ static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_in
static IRAM_DATA fatal_exception_handler_fn fatal_exception_handler_inner = standard_fatal_exception_handler_inner; static IRAM_DATA fatal_exception_handler_fn fatal_exception_handler_inner = standard_fatal_exception_handler_inner;
static void (*user_exception_handler)(void) = NULL;
/* fatal_exception_handler called from any unhandled user exception /* fatal_exception_handler called from any unhandled user exception
* *
* (similar to a hard fault on other processor architectures) * (similar to a hard fault on other processor architectures)
@ -157,6 +160,10 @@ static void IRAM fatal_handler_prelude(void) {
} }
Cache_Read_Disable(); Cache_Read_Disable();
Cache_Read_Enable(0, 0, 1); Cache_Read_Enable(0, 0, 1);
if (user_exception_handler != NULL) {
user_exception_handler();
}
} }
/* Main part of fatal exception handler, is run from flash to save /* Main part of fatal exception handler, is run from flash to save
@ -230,3 +237,9 @@ static void abort_handler_inner(uint32_t *caller, uint32_t *sp) {
dump_heapinfo(); dump_heapinfo();
post_crash_reset(); post_crash_reset();
} }
void set_user_exception_handler(void (*fn)(void))
{
user_exception_handler = fn;
}

View file

@ -58,17 +58,17 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 }; static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 };
void __attribute__((weak)) IRAM gpio_interrupt_handler(void) void __attribute__((weak)) IRAM gpio_interrupt_handler(void *arg)
{ {
uint32_t status_reg = GPIO.STATUS; uint32_t status_reg = GPIO.STATUS;
GPIO.STATUS_CLEAR = status_reg; GPIO.STATUS_CLEAR = status_reg;
uint8_t gpio_idx; uint8_t gpio_idx;
while((gpio_idx = __builtin_ffs(status_reg))) while ((gpio_idx = __builtin_ffs(status_reg)))
{ {
gpio_idx--; gpio_idx--;
status_reg &= ~BIT(gpio_idx); status_reg &= ~BIT(gpio_idx);
if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) { if (FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx]; gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx];
if (handler) { if (handler) {
handler(gpio_idx); handler(gpio_idx);
@ -82,8 +82,8 @@ void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, g
gpio_interrupt_handlers[gpio_num] = handler; gpio_interrupt_handlers[gpio_num] = handler;
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type); GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
if(int_type != GPIO_INTTYPE_NONE) { if (int_type != GPIO_INTTYPE_NONE) {
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler, NULL);
_xt_isr_unmask(1<<INUM_GPIO); _xt_isr_unmask(1<<INUM_GPIO);
} }
} }

View file

@ -10,8 +10,13 @@
#include <esp/wdev_regs.h> #include <esp/wdev_regs.h>
#include <string.h> #include <string.h>
/* Return a random 32-bit number */ /* Return a random 32-bit number.
uint32_t hwrand(void) *
* This is also used as a substitute for rand() called from
* lmac.a:sdk_lmacTxFrame to avoid touching the newlib reent structures within
* the NMI and the NMI code needs to be in IRAM.
*/
uint32_t IRAM hwrand(void)
{ {
return WDEV.HWRNG; return WDEV.HWRNG;
} }

View file

@ -7,13 +7,19 @@
*/ */
#include <esp/interrupts.h> #include <esp/interrupts.h>
_xt_isr isr[16]; typedef struct _xt_isr_entry_ {
_xt_isr handler;
void *arg;
} _xt_isr_entry;
_xt_isr_entry isr[16];
bool esp_in_isr; bool esp_in_isr;
void IRAM _xt_isr_attach(uint8_t i, _xt_isr func) void IRAM _xt_isr_attach(uint8_t i, _xt_isr func, void *arg)
{ {
isr[i] = func; isr[i].handler = func;
isr[i].arg = arg;
} }
/* Generic ISR handler. /* Generic ISR handler.
@ -25,17 +31,20 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset)
esp_in_isr = true; esp_in_isr = true;
/* WDT has highest priority (occasional WDT resets otherwise) */ /* WDT has highest priority (occasional WDT resets otherwise) */
if(intset & BIT(INUM_WDT)) { if (intset & BIT(INUM_WDT)) {
_xt_clear_ints(BIT(INUM_WDT)); _xt_clear_ints(BIT(INUM_WDT));
isr[INUM_WDT](); isr[INUM_WDT].handler(NULL);
intset -= BIT(INUM_WDT); intset -= BIT(INUM_WDT);
} }
while(intset) { while (intset) {
uint8_t index = __builtin_ffs(intset) - 1; uint8_t index = __builtin_ffs(intset) - 1;
uint16_t mask = BIT(index); uint16_t mask = BIT(index);
_xt_clear_ints(mask); _xt_clear_ints(mask);
isr[index](); _xt_isr handler = isr[index].handler;
if (handler) {
handler(isr[index].arg);
}
intset -= mask; intset -= mask;
} }

View file

@ -159,6 +159,22 @@ inline static void _start(uint8_t bus)
SPI(bus).CMD |= SPI_CMD_USR; SPI(bus).CMD |= SPI_CMD_USR;
} }
inline static void _store_data(uint8_t bus, const void *data, size_t len)
{
uint8_t words = len / 4;
uint8_t tail = len % 4;
memcpy((void *)SPI(bus).W, data, len - tail);
if (!tail) return;
uint32_t last = 0;
uint8_t *offs = (uint8_t *)data + len - tail;
for (uint8_t i = 0; i < tail; i++)
last = last | (offs[i] << (i * 8));
SPI(bus).W[words] = last;
}
inline static uint32_t _swap_bytes(uint32_t value) inline static uint32_t _swap_bytes(uint32_t value)
{ {
return (value << 24) | ((value << 8) & 0x00ff0000) | ((value >> 8) & 0x0000ff00) | (value >> 24); return (value << 24) | ((value << 8) & 0x00ff0000) | ((value >> 8) & 0x0000ff00) | (value >> 24);
@ -189,7 +205,7 @@ static void _spi_buf_transfer(uint8_t bus, const void *out_data, void *in_data,
_wait(bus); _wait(bus);
size_t bytes = len * (uint8_t)word_size; size_t bytes = len * (uint8_t)word_size;
_set_size(bus, bytes); _set_size(bus, bytes);
memcpy((void *)SPI(bus).W, out_data, bytes); _store_data(bus, out_data, bytes);
_spi_buf_prepare(bus, len, e, word_size); _spi_buf_prepare(bus, len, e, word_size);
_start(bus); _start(bus);
_wait(bus); _wait(bus);
@ -221,23 +237,36 @@ uint32_t spi_transfer_32(uint8_t bus, uint32_t data)
return res; return res;
} }
static void _rearm_extras_bit(uint8_t bus, bool arm) { static void _rearm_extras_bit(uint8_t bus, bool arm)
{
if(!_minimal_pins[bus]) return ; if (!_minimal_pins[bus]) return;
static uint8_t status[2] ; static uint8_t status[2];
if (arm) if (arm)
{ {
if (status[bus] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR) ; if (status[bus] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR);
if (status[bus] & 0x02) SPI(bus).USER0 |= (SPI_USER0_COMMAND) ; if (status[bus] & 0x02) SPI(bus).USER0 |= (SPI_USER0_COMMAND);
if (status[bus] & 0x04) SPI(bus).USER0 |= (SPI_USER0_DUMMY | SPI_USER0_MISO); if (status[bus] & 0x04)
SPI(bus).USER0 |= (SPI_USER0_DUMMY | SPI_USER0_MISO);
status[bus] = 0; status[bus] = 0;
} }
else else
{ {
if (SPI(bus).USER0 & SPI_USER0_ADDR) { SPI(bus).USER0 &= ~(SPI_USER0_ADDR) ; status[bus] |= 0x01 ; } if (SPI(bus).USER0 & SPI_USER0_ADDR)
if (SPI(bus).USER0 & SPI_USER0_COMMAND) { SPI(bus).USER0 &= ~(SPI_USER0_COMMAND) ; status[bus] |= 0x02 ; } {
if (SPI(bus).USER0 & SPI_USER0_DUMMY) { SPI(bus).USER0 &= ~(SPI_USER0_DUMMY | SPI_USER0_MISO); status[bus] |= 0x04 ; } SPI(bus).USER0 &= ~(SPI_USER0_ADDR);
status[bus] |= 0x01;
}
if (SPI(bus).USER0 & SPI_USER0_COMMAND)
{
SPI(bus).USER0 &= ~(SPI_USER0_COMMAND);
status[bus] |= 0x02;
}
if (SPI(bus).USER0 & SPI_USER0_DUMMY)
{
SPI(bus).USER0 &= ~(SPI_USER0_DUMMY | SPI_USER0_MISO);
status[bus] |= 0x04;
}
} }
} }
@ -254,7 +283,7 @@ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len
size_t offset = i * _SPI_BUF_SIZE; size_t offset = i * _SPI_BUF_SIZE;
_spi_buf_transfer(bus, (const uint8_t *)out_data + offset, _spi_buf_transfer(bus, (const uint8_t *)out_data + offset,
in_data ? (uint8_t *)in_data + offset : NULL, buf_size, e, word_size); in_data ? (uint8_t *)in_data + offset : NULL, buf_size, e, word_size);
if (blocks) _rearm_extras_bit(bus, false) ; _rearm_extras_bit(bus, false);
} }
uint8_t tail = len % buf_size; uint8_t tail = len % buf_size;
@ -264,41 +293,42 @@ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len
in_data ? (uint8_t *)in_data + blocks * _SPI_BUF_SIZE : NULL, tail, e, word_size); in_data ? (uint8_t *)in_data + blocks * _SPI_BUF_SIZE : NULL, tail, e, word_size);
} }
if (blocks) _rearm_extras_bit(bus, true) ; if (blocks) _rearm_extras_bit(bus, true);
return len; return len;
} }
static void _repeat_send(uint8_t bus, uint32_t* dword,int32_t* repeats,spi_word_size_t size) static void _repeat_send(uint8_t bus, uint32_t *dword, int32_t *repeats,
spi_word_size_t size)
{ {
uint8_t i = 0 ; uint8_t i = 0;
while(*repeats > 0) while (*repeats > 0)
{ {
uint16_t bytes_to_transfer = __min(*repeats * size , _SPI_BUF_SIZE); uint16_t bytes_to_transfer = __min(*repeats * size, _SPI_BUF_SIZE);
_wait(bus); _wait(bus);
if (i) _rearm_extras_bit(bus, false) ; if (i) _rearm_extras_bit(bus, false);
_set_size(bus,bytes_to_transfer); _set_size(bus, bytes_to_transfer);
for(i = 0; i < (bytes_to_transfer + 3) / 4;i++) for (i = 0; i < (bytes_to_transfer + 3) / 4; i++)
SPI(bus).W[i] = *dword; //need test with memcpy ! SPI(bus).W[i] = *dword; //need test with memcpy !
_start(bus); _start(bus);
*repeats -= (bytes_to_transfer / size ) ; *repeats -= (bytes_to_transfer / size);
} }
_wait(bus); _wait(bus);
_rearm_extras_bit(bus, true) ; _rearm_extras_bit(bus, true);
} }
void spi_repeat_send_8(uint8_t bus, uint8_t data,int32_t repeats) void spi_repeat_send_8(uint8_t bus, uint8_t data, int32_t repeats)
{ {
uint32_t dword = data << 24 | data << 16 | data << 8 | data; uint32_t dword = data << 24 | data << 16 | data << 8 | data;
_repeat_send(bus,&dword,&repeats, SPI_8BIT); _repeat_send(bus, &dword, &repeats, SPI_8BIT);
} }
void spi_repeat_send_16(uint8_t bus, uint16_t data,int32_t repeats) void spi_repeat_send_16(uint8_t bus, uint16_t data, int32_t repeats)
{ {
uint32_t dword = data << 16 | data; uint32_t dword = data << 16 | data;
_repeat_send(bus,&dword,&repeats, SPI_16BIT); _repeat_send(bus, &dword, &repeats, SPI_16BIT);
} }
void spi_repeat_send_32(uint8_t bus, uint32_t data,int32_t repeats) void spi_repeat_send_32(uint8_t bus, uint32_t data, int32_t repeats)
{ {
_repeat_send(bus,&data,&repeats, SPI_32BIT); _repeat_send(bus, &data, &repeats, SPI_32BIT);
} }

View file

@ -150,7 +150,7 @@ typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num);
* *
* Example: * Example:
* *
* void IRAM gpio_interrupt_handler(void) { * void IRAM gpio_interrupt_handler(void *arg) {
* // check GPIO.STATUS * // check GPIO.STATUS
* // write GPIO.STATUS_CLEAR * // write GPIO.STATUS_CLEAR
* // Do something when GPIO changes * // Do something when GPIO changes

View file

@ -35,19 +35,37 @@ typedef enum {
INUM_TIMER_FRC2 = 10, INUM_TIMER_FRC2 = 10,
} xt_isr_num_t; } xt_isr_num_t;
void sdk__xt_int_exit (void); void sdk__xt_int_exit(void);
void _xt_user_exit (void); void _xt_user_exit(void);
void sdk__xt_tick_timer_init (void); void sdk__xt_tick_timer_init(void);
void sdk__xt_timer_int(void); void sdk__xt_timer_int(void *);
void sdk__xt_timer_int1(void); void sdk__xt_timer_int1(void);
/* The normal running level is 0.
* The system tick isr, timer frc2_isr, sv_isr etc run at level 1.
* Debug exceptions run at level 2?
* The wdev nmi runs at level 3.
*/
static inline uint32_t _xt_get_intlevel(void) static inline uint32_t _xt_get_intlevel(void)
{ {
uint32_t level; uint32_t level;
__asm__ volatile("rsr %0, intlevel" : "=a"(level)); __asm__ volatile("rsr %0, ps" : "=a"(level));
return level; return level & 0xf;
} }
/*
* There are conflicting definitions for XCHAL_EXCM_LEVEL. Newlib
* defines it to be 1 and xtensa_rtos.h defines it to be 3. Don't want
* 3 as that is for the NMI and might want to check that the OS apis
* are not entered in level 3. Setting the interrupt level to 3 does
* not disable the NMI anyway. So set the level to 2.
*/
#ifdef XCHAL_EXCM_LEVEL
#undef XCHAL_EXCM_LEVEL
#define XCHAL_EXCM_LEVEL 2
#endif
/* Disable interrupts and return the old ps value, to pass into /* Disable interrupts and return the old ps value, to pass into
_xt_restore_interrupts later. _xt_restore_interrupts later.
@ -68,25 +86,27 @@ static inline void _xt_restore_interrupts(uint32_t new_ps)
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps)); __asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
} }
/* ESPTODO: the mask/unmask functions aren't thread safe */ static inline uint32_t _xt_isr_unmask(uint32_t unmask)
static inline void _xt_isr_unmask(uint32_t unmask)
{ {
uint32_t old_level = _xt_disable_interrupts();
uint32_t intenable; uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable)); asm volatile ("rsr %0, intenable" : "=a" (intenable));
intenable |= unmask; asm volatile ("wsr %0, intenable;" :: "a" (intenable | unmask));
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable)); _xt_restore_interrupts(old_level);
return intenable;
} }
static inline void _xt_isr_mask (uint32_t mask) static inline uint32_t _xt_isr_mask(uint32_t mask)
{ {
uint32_t old_level = _xt_disable_interrupts();
uint32_t intenable; uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable)); asm volatile ("rsr %0, intenable" : "=a" (intenable));
intenable &= ~mask; asm volatile ("wsr %0, intenable;" :: "a" (intenable & ~mask));
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable)); _xt_restore_interrupts(old_level);
return intenable;
} }
static inline uint32_t _xt_read_ints (void) static inline uint32_t _xt_read_ints(void)
{ {
uint32_t interrupt; uint32_t interrupt;
asm volatile ("rsr %0, interrupt" : "=a" (interrupt)); asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
@ -98,9 +118,7 @@ static inline void _xt_clear_ints(uint32_t mask)
asm volatile ("wsr %0, intclear; esync" :: "a" (mask)); asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
} }
typedef void (* _xt_isr)(void); typedef void (* _xt_isr)(void *arg);
/* This function is implemeneted in FreeRTOS port.c at the moment, void _xt_isr_attach (uint8_t i, _xt_isr func, void *arg);
should be moved or converted to an inline */
void _xt_isr_attach (uint8_t i, _xt_isr func);
#endif #endif

View file

@ -36,4 +36,6 @@ typedef struct {
uint32_t status_mask; uint32_t status_mask;
} sdk_flashchip_t; } sdk_flashchip_t;
extern sdk_flashchip_t sdk_flashchip;
#endif /* _FLASHCHIP_H */ #endif /* _FLASHCHIP_H */

View file

@ -14,25 +14,25 @@
// 'info' is declared in app_main.o at .bss+0x4 // 'info' is declared in app_main.o at .bss+0x4
struct sdk_info_st { struct sdk_info_st {
ip_addr_t softap_ipaddr; // 0x00 ip4_addr_t softap_ipaddr; // 0x00
ip_addr_t softap_netmask; // 0x04 ip4_addr_t softap_netmask; // 0x04
ip_addr_t softap_gw; // 0x08 ip4_addr_t softap_gw; // 0x08
ip_addr_t sta_ipaddr; // 0x0c ip4_addr_t sta_ipaddr; // 0x0c
ip_addr_t sta_netmask; // 0x10 ip4_addr_t sta_netmask; // 0x10
ip_addr_t sta_gw; // 0x14 ip4_addr_t sta_gw; // 0x14
uint8_t softap_mac_addr[6]; // 0x18 uint8_t softap_mac_addr[6]; // 0x18
uint8_t sta_mac_addr[6]; // 0x1e uint8_t sta_mac_addr[6]; // 0x1e
}; };
struct _unknown_info1 { struct wl_channel {
uint8_t _unknown00; uint8_t _unknown00;
uint8_t _unknown01; uint8_t _unknown01;
uint8_t _unknown02; uint8_t _unknown02;
uint8_t _unknown03; uint8_t _unknown03;
uint8_t _unknown04; uint8_t _unknown04;
uint8_t _unknown05; uint8_t _unknown05;
uint8_t channel; // eagle_auth_done uint8_t num; // eagle_auth_done
}; };
@ -83,7 +83,7 @@ struct _unknown_wpa1 {
}; };
struct sdk_netif_conninfo { struct sdk_cnx_node {
uint8_t mac_addr[6]; uint8_t mac_addr[6];
uint8_t _unknown07[2]; uint8_t _unknown07[2];
@ -98,17 +98,19 @@ struct sdk_netif_conninfo {
uint32_t _unknown1c[23]; uint32_t _unknown1c[23];
struct _unknown_info1 *_unknown78; // eagle_auth_done struct wl_channel *channel; // 0x78 eagle_auth_done
uint32_t _unknown7c[8]; uint32_t _unknown7c[8];
uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called. uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called.
uint16_t _unknown9e; uint16_t _unknown9e;
uint32_t _unknowna0[18]; uint32_t _unknowna0[17];
int8_t _unknowne8; // void *_unknowne4;
int8_t _unknowne9; // ppInstallKey
uint8_t _unknowne8; //
uint8_t _unknowne9; // ppInstallKey
int8_t _unknownea; int8_t _unknownea;
int8_t _unknowneb; int8_t _unknowneb;
@ -128,9 +130,9 @@ struct sdk_g_ic_netif_info {
uint32_t _unknown48; // 0x48 uint32_t _unknown48; // 0x48
uint8_t _unknown4c; // 0x4c uint8_t _unknown4c; // 0x4c
uint8_t _unknown4d[59]; // 0x4d - 0x88 uint8_t _unknown4d[59]; // 0x4d - 0x88
struct sdk_netif_conninfo *_unknown88; // 0x88 struct sdk_cnx_node *_unknown88; // 0x88
uint32_t _unknown8c; // 0x8c uint32_t _unknown8c; // 0x8c
struct sdk_netif_conninfo *conninfo[6]; // 0x90 - 0xa8 struct sdk_cnx_node *cnx_nodes[6]; // 0x90 - 0xa8
uint8_t _unknowna8[12]; // 0xa8 - 0xb4 uint8_t _unknowna8[12]; // 0xa8 - 0xb4
struct _unknown_softap1 *_unknownb4; struct _unknown_softap1 *_unknownb4;
uint8_t statusb8; // 0xb8 (arg of sta_status_set) uint8_t statusb8; // 0xb8 (arg of sta_status_set)
@ -206,10 +208,9 @@ struct sdk_g_ic_volatile_st {
}; };
struct sdk_g_ic_unk0_st { struct sdk_g_ic_ssid_with_length {
uint16_t _unknown1e4; // sdk_wpa_config_profile uint32_t ssid_length; // 0x1e4 sdk_wpa_config_profile
uint16_t _unknown1e6; // sdk_wpa_config_profile uint8_t ssid[32]; // 0x1e8 Station ssid. Null terminated string.
uint8_t sta_ssid[32]; // 0x1e8 Station ssid. Null terminated string.
}; };
// This is the portion of g_ic which is loaded/saved to the flash ROM, and thus // This is the portion of g_ic which is loaded/saved to the flash ROM, and thus
@ -224,7 +225,8 @@ struct sdk_g_ic_saved_st {
uint8_t wifi_led_gpio; uint8_t wifi_led_gpio;
uint8_t wifi_led_state; // 0 or 1. uint8_t wifi_led_state; // 0 or 1.
struct sdk_g_ic_unk0_st _unknown1e4; // Current station ap config ssid and length.
struct sdk_g_ic_ssid_with_length sta_ssid; // 0x1e4
uint8_t _unknown208; uint8_t _unknown208;
uint8_t _unknown209; // sdk_wpa_config_profile uint8_t _unknown209; // sdk_wpa_config_profile
@ -260,7 +262,7 @@ struct sdk_g_ic_saved_st {
uint8_t _unknown30d; // result of ieee80211_chan2ieee uint8_t _unknown30d; // result of ieee80211_chan2ieee
uint8_t _unknown30e; uint8_t _unknown30e;
uint8_t _unknown30f; uint8_t _unknown30f;
uint8_t _unknown310; // count of entries in the softap conninfo array, less two. uint8_t _unknown310; // count of entries in the softap cnx_node array, less two.
uint8_t _unknown311[3]; uint8_t _unknown311[3];
@ -320,7 +322,7 @@ struct esf_buf {
_Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!"); _Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!");
_Static_assert(offsetof(struct sdk_info_st, sta_mac_addr) == 0x1e, "bad struct"); _Static_assert(offsetof(struct sdk_info_st, sta_mac_addr) == 0x1e, "bad struct");
_Static_assert(offsetof(struct _unknown_info1, channel) == 0x06, "bad struct"); _Static_assert(offsetof(struct wl_channel, num) == 0x06, "bad struct");
_Static_assert(sizeof(struct _unknown_softap2) == 0xcc, "_unknown_softap2 is the wrong size!"); _Static_assert(sizeof(struct _unknown_softap2) == 0xcc, "_unknown_softap2 is the wrong size!");
_Static_assert(offsetof(struct _unknown_softap2, _unknownb8) == 0xb8, "bad struct"); _Static_assert(offsetof(struct _unknown_softap2, _unknownb8) == 0xb8, "bad struct");
@ -331,8 +333,8 @@ _Static_assert(offsetof(struct _unknown_softap1, _unknown18) == 0x18, "bad struc
_Static_assert(sizeof(struct _unknown_wpa1) == 0x4c, "_unknown_wpa1 is the wrong size!"); _Static_assert(sizeof(struct _unknown_wpa1) == 0x4c, "_unknown_wpa1 is the wrong size!");
_Static_assert(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct"); _Static_assert(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct");
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown78) == 0x78, "bad struct"); _Static_assert(offsetof(struct sdk_cnx_node, channel) == 0x78, "bad struct");
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown108) == 0x108, "bad struct"); _Static_assert(offsetof(struct sdk_cnx_node, _unknown108) == 0x108, "bad struct");
_Static_assert(offsetof(struct sdk_g_ic_netif_info, started) == 0xbb, "bad struct"); _Static_assert(offsetof(struct sdk_g_ic_netif_info, started) == 0xbb, "bad struct");
@ -340,7 +342,7 @@ _Static_assert(sizeof(struct sdk_g_ic_volatile_st) == 0x1d8, "sdk_g_ic_volatile_
_Static_assert(offsetof(struct sdk_g_ic_volatile_st, _unknown1d5) == 0x1d5, "bad struct"); _Static_assert(offsetof(struct sdk_g_ic_volatile_st, _unknown1d5) == 0x1d5, "bad struct");
_Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!"); _Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!");
_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown1e4) == 0x1e4 - 0x1d8, "bad struct"); _Static_assert(offsetof(struct sdk_g_ic_saved_st, sta_ssid) == 0x1e4 - 0x1d8, "bad struct");
_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown546) == 0x546 - 0x1d8, "bad struct"); _Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown546) == 0x546 - 0x1d8, "bad struct");
_Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!"); _Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!");
@ -357,21 +359,16 @@ _Static_assert(offsetof(struct esf_buf, length) == 0x16, "bad struct");
// ieee80211_output_pbuf and perhaps elsewhere. The value is just passed through // ieee80211_output_pbuf and perhaps elsewhere. The value is just passed through
// lwip and and not used by lwip so just ensure this slot is at the expected // lwip and and not used by lwip so just ensure this slot is at the expected
// offset. // offset.
_Static_assert(offsetof(struct netif, state) == 28, "netif->state offset wrong!"); _Static_assert(offsetof(struct netif, state) == 4, "netif->state offset wrong!");
// Some sdk uses of netif->hwaddr have been converted to source code, but many // Some sdk uses of netif->hwaddr have been converted to source code, but many
// remain, but the content of this slot should not change in future versions of // remain, but the content of this slot should not change in future versions of
// lwip, so just ensure it is at the expected offset. // lwip, so just ensure it is at the expected offset. Note the sdk binary
_Static_assert(offsetof(struct netif, hwaddr) == 41, "netif->hwaddr offset wrong!"); // libraries have been patched to move this offset from 41 to 42 to keep it
// 16-bit aligned to keep lwip v2 happy.
_Static_assert(offsetof(struct netif, hwaddr) == 8, "netif->hwaddr offset wrong!");
// Most sdk uses of the netif->flags have been converted to source code. One _Static_assert(offsetof(struct pbuf, esf_buf) == 16, "pbuf->esf_buf offset wrong!");
// known sdk binary read of the flags remains in wl_cnx.o:sdk_cnx_sta_leave
// which checks the NETIF_FLAG_DHCP flag. The NETIF_FLAG_DHCP has been removed
// in lwip v2, so some lwip hacks are needed to handle this for now until
// wl_cnx.o is converted so source code too.
_Static_assert(offsetof(struct netif, flags) == 47, "netif->flags offset wrong!");
_Static_assert(offsetof(struct pbuf, eb) == 16, "pbuf->eb offset wrong!");
/// Misc. /// Misc.

View file

@ -21,14 +21,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef __ESP_SPIFFS_FLASH_H__ #ifndef __SPIFLASH_H__
#define __ESP_SPIFFS_FLASH_H__ #define __SPIFLASH_H__
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "common_macros.h" #include "common_macros.h"
#define ESP_SPIFFS_FLASH_OK 0 #define SPI_FLASH_SECTOR_SIZE 4096
#define ESP_SPIFFS_FLASH_ERROR 1
/** /**
* Read data from SPI flash. * Read data from SPI flash.
@ -37,9 +37,9 @@
* @param buf Buffer to read to. Doesn't have to be aligned. * @param buf Buffer to read to. Doesn't have to be aligned.
* @param size Size of data to read. Buffer size must be >= than data size. * @param size Size of data to read. Buffer size must be >= than data size.
* *
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR * @return true if success, otherwise false
*/ */
uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size); bool IRAM spiflash_read(uint32_t addr, uint8_t *buf, uint32_t size);
/** /**
* Write data to SPI flash. * Write data to SPI flash.
@ -48,17 +48,17 @@ uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size);
* @param buf Buffer of data to write to flash. Doesn't have to be aligned. * @param buf Buffer of data to write to flash. Doesn't have to be aligned.
* @param size Size of data to write. Buffer size must be >= than data size. * @param size Size of data to write. Buffer size must be >= than data size.
* *
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR * @return true if success, otherwise false
*/ */
uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size); bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size);
/** /**
* Erase a sector. * Erase a sector.
* *
* @param addr Address of sector to erase. Must be sector aligned. * @param addr Address of sector to erase. Must be sector aligned.
* *
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR * @return true if success, otherwise false
*/ */
uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr); bool IRAM spiflash_erase_sector(uint32_t addr);
#endif // __ESP_SPIFFS_FLASH_H__ #endif // __SPIFLASH_H__

View file

@ -180,24 +180,20 @@ sysparam_status_t sysparam_compact();
*/ */
sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *actual_length, bool *is_binary); sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *actual_length, bool *is_binary);
/** Get the value associated with a key (static buffers only) /** Get the value associated with a key (static value buffer)
* *
* This performs the same function as sysparam_get_data() but without * This performs the same function as sysparam_get_data() but without
* performing any memory allocations. It can thus be used before the heap has * allocating memory for the result value. It can thus be used before the heap
* been configured or in other cases where using the heap would be a problem * has been configured or in other cases where using the heap would be a
* (i.e. in an OOM handler, etc). It requires that the caller pass in a * problem (i.e. in an OOM handler, etc). It requires that the caller pass in
* suitably sized buffer for the value to be read (if the supplied buffer is * a suitably sized buffer for the value to be read (if the supplied buffer is
* not large enough, the returned value will be truncated and the full * not large enough, the returned value will be truncated and the full required
* required length will be returned in `actual_length`). * length will be returned in `actual_length`).
*
* NOTE: In addition to being large enough for the value, the supplied buffer
* must also be at least as large as the length of the key being requested.
* If it is not, an error will be returned.
* *
* @param[in] key Key name (zero-terminated string) * @param[in] key Key name (zero-terminated string)
* @param[in] buffer Pointer to a buffer to hold the returned value * @param[in] dest Pointer to a buffer to hold the returned value.
* @param[in] buffer_size Length of the supplied buffer in bytes * @param[in] dest_size Length of the supplied buffer in bytes.
* @param[out] actual_length pointer to a location to hold the actual length * @param[out] actual_length Pointer to a location to hold the actual length
* of the data which was associated with the key * of the data which was associated with the key
* (may be NULL). * (may be NULL).
* @param[out] is_binary Pointer to a bool to hold whether the returned * @param[out] is_binary Pointer to a bool to hold whether the returned
@ -210,7 +206,7 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
* @retval ::SYSPARAM_ERR_CORRUPT Sysparam region has bad/corrupted data * @retval ::SYSPARAM_ERR_CORRUPT Sysparam region has bad/corrupted data
* @retval ::SYSPARAM_ERR_IO I/O error reading/writing flash * @retval ::SYSPARAM_ERR_IO I/O error reading/writing flash
*/ */
sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, size_t buffer_size, size_t *actual_length, bool *is_binary); sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *dest, size_t dest_size, size_t *actual_length, bool *is_binary);
/** Get the string value associated with a key /** Get the string value associated with a key
* *
@ -242,7 +238,8 @@ sysparam_status_t sysparam_get_string(const char *key, char **destptr);
/** Get the int32_t value associated with a key /** Get the int32_t value associated with a key
* *
* This routine can be used if you know that the value in a key will (or at * This routine can be used if you know that the value in a key will (or at
* least should) be an int32_t value. * least should) be an int32_t value. This is done without allocating any
* memory.
* *
* Note: If the status result is anything other than ::SYSPARAM_OK, the value * Note: If the status result is anything other than ::SYSPARAM_OK, the value
* in `result` is not changed. This means it is possible to set a default * in `result` is not changed. This means it is possible to set a default
@ -266,7 +263,8 @@ sysparam_status_t sysparam_get_int32(const char *key, int32_t *result);
/** Get the int8_t value associated with a key /** Get the int8_t value associated with a key
* *
* This routine can be used if you know that the value in a key will (or at * This routine can be used if you know that the value in a key will (or at
* least should) be a uint8_t binary value. * least should) be a uint8_t binary value. This is done without allocating any
* memory.
* *
* Note: If the status result is anything other than ::SYSPARAM_OK, the value * Note: If the status result is anything other than ::SYSPARAM_OK, the value
* in `result` is not changed. This means it is possible to set a default * in `result` is not changed. This means it is possible to set a default
@ -320,7 +318,7 @@ sysparam_status_t sysparam_get_bool(const char *key, bool *result);
* *
* The supplied value can be any data, up to 255 bytes in length. If `value` * The supplied value can be any data, up to 255 bytes in length. If `value`
* is NULL or `value_len` is 0, this is treated as a request to delete any * is NULL or `value_len` is 0, this is treated as a request to delete any
* current entry matching `key`. * current entry matching `key`. This is done without allocating any memory.
* *
* If `binary` is true, the data will be considered binary (unprintable) data, * If `binary` is true, the data will be considered binary (unprintable) data,
* and this will be annotated in the saved entry. This does not affect the * and this will be annotated in the saved entry. This does not affect the
@ -368,7 +366,8 @@ sysparam_status_t sysparam_set_string(const char *key, const char *value);
/** Set a key's value as a number /** Set a key's value as a number
* *
* Write an int32_t binary value to the specified key. This does the inverse of * Write an int32_t binary value to the specified key. This does the inverse of
* the sysparam_get_int32() function. * the sysparam_get_int32() function. This is done without allocating any
* memory.
* *
* @param[in] key Key name (zero-terminated string) * @param[in] key Key name (zero-terminated string)
* @param[in] value Value to set * @param[in] value Value to set
@ -386,10 +385,8 @@ sysparam_status_t sysparam_set_int32(const char *key, int32_t value);
/** Set a key's value as a number /** Set a key's value as a number
* *
* Write an int8_t binary value to the specified key. This does the inverse of * Write an int8_t binary value to the specified key. This does the inverse of
* the sysparam_get_int8() function. * the sysparam_get_int8() function. This is done without allocating any
* * memory.
* Note that if the key already contains a value which parses to the same
* boolean (true/false) value, it is left unchanged.
* *
* @param[in] key Key name (zero-terminated string) * @param[in] key Key name (zero-terminated string)
* @param[in] value Value to set * @param[in] value Value to set

View file

@ -0,0 +1,9 @@
/* Allows the user to set their own exception handler. */
#ifndef _USER_EXCEPTION_H
#define _USER_EXCEPTION_H
void set_user_exception_handler(void (*fn)(void));
#endif

View file

@ -13,6 +13,7 @@
#include <esp/uart.h> #include <esp/uart.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdout_redirect.h> #include <stdout_redirect.h>
#include <sys/time.h>
extern void *xPortSupervisorStackPointer; extern void *xPortSupervisorStackPointer;
@ -135,6 +136,14 @@ int _stat_r(struct _reent *r, const char *pathname, void *buf);
__attribute__((weak, alias("syscall_returns_enosys"))) __attribute__((weak, alias("syscall_returns_enosys")))
off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence); off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
__attribute__((weak, alias("_gettimeofday_r")))
int _gettimeofday_r _PARAMS ((struct _reent *r, struct timeval *now, void *p)) {
now->tv_sec = 0;
now->tv_usec = 0;
errno = ENOSYS;
return -1;
}
/* Generic stub for any newlib syscall that fails with errno ENOSYS /* Generic stub for any newlib syscall that fails with errno ENOSYS
("Function not implemented") and a return value equivalent to ("Function not implemented") and a return value equivalent to
(int)-1. */ (int)-1. */

View file

@ -21,12 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "esp_spiffs_flash.h" #include "include/spiflash.h"
#include "flashchip.h"
#include "espressif/spi_flash.h" #include "include/flashchip.h"
#include "FreeRTOS.h" #include "include/esp/rom.h"
#include "esp/rom.h" #include "include/esp/spi_regs.h"
#include "esp/spi_regs.h"
#include <FreeRTOS.h>
#include <string.h> #include <string.h>
/** /**
@ -52,25 +53,6 @@
#define SPI_READ_MAX_SIZE 60 #define SPI_READ_MAX_SIZE 60
/**
* Copy unaligned data to 4-byte aligned destination buffer.
*
* @param words Number of 4-byte words to write.
*
* @see unaligned_memcpy.S
*/
void memcpy_unaligned_src(volatile uint32_t *dst, uint8_t *src, uint8_t words);
/**
* Copy 4-byte aligned source data to unaligned destination buffer.
*
* @param bytes Number of byte to copy to dst.
*
* @see unaligned_memcpy.S
*/
void memcpy_unaligned_dst(uint8_t *dst, volatile uint32_t *src, uint8_t bytes);
/** /**
* Low level SPI flash write. Write block of data up to 64 bytes. * Low level SPI flash write. Write block of data up to 64 bytes.
*/ */
@ -86,7 +68,9 @@ static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24); SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
memcpy_unaligned_src(SPI(0).W, buf, words); memcpy((void*)SPI(0).W, buf, words<<2);
__asm__ volatile("memw");
SPI_write_enable(chip); SPI_write_enable(chip);
@ -97,16 +81,16 @@ static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
/** /**
* Write a page of flash. Data block should not cross page boundary. * Write a page of flash. Data block should not cross page boundary.
*/ */
static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr, static bool IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr,
uint8_t *buf, uint32_t size) uint8_t *buf, uint32_t size)
{ {
// check if block to write doesn't cross page boundary // check if block to write doesn't cross page boundary
if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) { if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
if (size < 1) { if (size < 1) {
return ESP_SPIFFS_FLASH_OK; return true;
} }
while (size >= SPI_WRITE_MAX_SIZE) { while (size >= SPI_WRITE_MAX_SIZE) {
@ -117,58 +101,58 @@ static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_ad
buf += SPI_WRITE_MAX_SIZE; buf += SPI_WRITE_MAX_SIZE;
if (size < 1) { if (size < 1) {
return ESP_SPIFFS_FLASH_OK; return true;
} }
} }
spi_write_data(flashchip, dest_addr, buf, size); spi_write_data(flashchip, dest_addr, buf, size);
return ESP_SPIFFS_FLASH_OK; return true;
} }
/** /**
* Split block of data into pages and write pages. * Split block of data into pages and write pages.
*/ */
static uint32_t IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size) static bool IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
{ {
if (sdk_flashchip.chip_size < (addr + size)) { if (sdk_flashchip.chip_size < (addr + size)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
uint32_t write_bytes_to_page = sdk_flashchip.page_size - uint32_t write_bytes_to_page = sdk_flashchip.page_size -
(addr % sdk_flashchip.page_size); // TODO: place for optimization (addr % sdk_flashchip.page_size); // TODO: place for optimization
if (size < write_bytes_to_page) { if (size < write_bytes_to_page) {
if (spi_write_page(&sdk_flashchip, addr, dst, size)) { if (!spi_write_page(&sdk_flashchip, addr, dst, size)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
} else { } else {
if (spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) { if (!spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
uint32_t offset = write_bytes_to_page; uint32_t offset = write_bytes_to_page;
uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size; uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
for (uint8_t i = 0; i != pages_to_write; i++) { for (uint32_t i = 0; i < pages_to_write; i++) {
if (spi_write_page(&sdk_flashchip, addr + offset, if (!spi_write_page(&sdk_flashchip, addr + offset,
dst + offset, sdk_flashchip.page_size)) { dst + offset, sdk_flashchip.page_size)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
offset += sdk_flashchip.page_size; offset += sdk_flashchip.page_size;
} }
if (spi_write_page(&sdk_flashchip, addr + offset, if (!spi_write_page(&sdk_flashchip, addr + offset,
dst + offset, size - offset)) { dst + offset, size - offset)) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
} }
return ESP_SPIFFS_FLASH_OK; return true;
} }
uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size) bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size)
{ {
uint32_t result = ESP_SPIFFS_FLASH_ERROR; bool result = false;
if (buf) { if (buf) {
vPortEnterCritical(); vPortEnterCritical();
@ -197,21 +181,23 @@ static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr,
while (SPI(0).CMD) {}; while (SPI(0).CMD) {};
memcpy_unaligned_dst(buf, SPI(0).W, size); __asm__ volatile("memw");
memcpy(buf, (const void*)SPI(0).W, size);
} }
/** /**
* Read SPI flash data. Data region doesn't need to be page aligned. * Read SPI flash data. Data region doesn't need to be page aligned.
*/ */
static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr, static inline bool IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
uint8_t *dst, uint32_t size) uint8_t *dst, uint32_t size)
{ {
if (size < 1) { if (size < 1) {
return ESP_SPIFFS_FLASH_OK; return true;
} }
if ((addr + size) > flashchip->chip_size) { if ((addr + size) > flashchip->chip_size) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
while (size >= SPI_READ_MAX_SIZE) { while (size >= SPI_READ_MAX_SIZE) {
@ -225,12 +211,12 @@ static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
read_block(flashchip, addr, dst, size); read_block(flashchip, addr, dst, size);
} }
return ESP_SPIFFS_FLASH_OK; return true;
} }
uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size) bool IRAM spiflash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size)
{ {
uint32_t result = ESP_SPIFFS_FLASH_ERROR; bool result = false;
if (buf) { if (buf) {
vPortEnterCritical(); vPortEnterCritical();
@ -245,14 +231,14 @@ uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t s
return result; return result;
} }
uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr) bool IRAM spiflash_erase_sector(uint32_t addr)
{ {
if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) { if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
if (addr & 0xFFF) { if (addr & 0xFFF) {
return ESP_SPIFFS_FLASH_ERROR; return false;
} }
vPortEnterCritical(); vPortEnterCritical();
@ -269,5 +255,5 @@ uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr)
Cache_Read_Enable(0, 0, 1); Cache_Read_Enable(0, 0, 1);
vPortExitCritical(); vPortExitCritical();
return ESP_SPIFFS_FLASH_OK; return true;
} }

View file

@ -8,14 +8,12 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sysparam.h> #include <sysparam.h>
#include <espressif/spi_flash.h> #include "spiflash.h"
#include "flashchip.h"
#include <common_macros.h> #include <common_macros.h>
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "semphr.h" #include "semphr.h"
//TODO: make this properly threadsafe
//TODO: reduce stack usage
/* The "magic" value that indicates the start of a sysparam region in flash. /* The "magic" value that indicates the start of a sysparam region in flash.
*/ */
#define SYSPARAM_MAGIC 0x70524f45 // "EORp" in little-endian #define SYSPARAM_MAGIC 0x70524f45 // "EORp" in little-endian
@ -33,11 +31,14 @@
*/ */
#define SCAN_BUFFER_SIZE 8 // words #define SCAN_BUFFER_SIZE 8 // words
/* The size of the temporary buffer used for reading back and verifying data /* The size in words of the buffer used for reading keys when searching for a
* written to flash. Making this larger will make the write-and-verify * match, for reading payloads to check if the value has changed, and reading
* operation slightly faster, but will use more heap during writes * back from the flash to verify writes. Will work well if big enough for
* commonly used keys, and must be at least one word. Stack allocated so not too
* large!
*/ */
#define VERIFY_BUF_SIZE 64 #define BOUNCE_BUFFER_WORDS 3
#define BOUNCE_BUFFER_SIZE (BOUNCE_BUFFER_WORDS * sizeof(uint32_t))
/* Size of region/entry headers. These should not normally need tweaking (and /* Size of region/entry headers. These should not normally need tweaking (and
* will probably require some code changes if they are tweaked). * will probably require some code changes if they are tweaked).
@ -76,14 +77,16 @@
/******************************* Useful Macros *******************************/ /******************************* Useful Macros *******************************/
#define ROUND_TO_WORD_BOUNDARY(x) (((x) + 3) & 0xfffffffc) #define ROUND_TO_WORD_BOUNDARY(x) (((x) + 3) & 0xfffffffc)
#define ENTRY_SIZE(payload_len) (ENTRY_HEADER_SIZE + ROUND_TO_WORD_BOUNDARY(payload_len)) #define ENTRY_SIZE(payload_len) (ENTRY_HEADER_SIZE + payload_len)
#define max(x, y) ((x) > (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y)) #define min(x, y) ((x) < (y) ? (x) : (y))
#define debug(level, format, ...) if (SYSPARAM_DEBUG >= (level)) { printf("%s" format "\n", "sysparam: ", ## __VA_ARGS__); } #define debug(level, format, ...) if (SYSPARAM_DEBUG >= (level)) { printf("%s" format "\n", "sysparam: ", ## __VA_ARGS__); }
#define CHECK_FLASH_OP(x) do { int __x = (x); if ((__x) != SPI_FLASH_RESULT_OK) { debug(1, "FLASH ERR: %d", __x); return SYSPARAM_ERR_IO; } } while (0); #define CHECK_FLASH_OP(x) do { bool __x = (x); if (!(__x)) { \
debug(1, "FLASH ERR: %d", __x); return SYSPARAM_ERR_IO; \
} } while (0);
/********************* Internal datatypes and structures *********************/ /********************* Internal datatypes and structures *********************/
@ -119,50 +122,28 @@ static struct {
/***************************** Internal routines *****************************/ /***************************** Internal routines *****************************/
static inline IRAM sysparam_status_t _do_write(uint32_t addr, const void *data, size_t data_size) { static sysparam_status_t _write_and_verify(uint32_t addr, const void *data, size_t data_size) {
CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) data, data_size)); uint8_t bounce[BOUNCE_BUFFER_SIZE];
return SYSPARAM_OK;
}
static inline IRAM sysparam_status_t _do_verify(uint32_t addr, const void *data, void *buffer, size_t len) { for (int i = 0; i < data_size; i += BOUNCE_BUFFER_SIZE) {
CHECK_FLASH_OP(sdk_spi_flash_read(addr, buffer, len)); size_t count = min(data_size - i, BOUNCE_BUFFER_SIZE);
if (memcmp(data, buffer, len)) { memcpy(bounce, data + i, count);
CHECK_FLASH_OP(spiflash_write(addr + i, bounce, count));
CHECK_FLASH_OP(spiflash_read(addr + i, bounce, count));
if (memcmp(data + i, bounce, count) != 0) {
debug(1, "Flash write (@ 0x%08x) verify failed!", addr);
return SYSPARAM_ERR_IO; return SYSPARAM_ERR_IO;
} }
}
return SYSPARAM_OK; return SYSPARAM_OK;
} }
/*FIXME: Eventually, this should probably be implemented down at the SPI flash library layer, where it can just compare bytes/words straight from the SPI hardware buffer instead of allocating a whole separate temp buffer, reading chunks into that, and then doing a memcmp.. */
static IRAM sysparam_status_t _write_and_verify(uint32_t addr, const void *data, size_t data_size) {
int i;
size_t count;
sysparam_status_t status = SYSPARAM_OK;
uint8_t *verify_buf = malloc(VERIFY_BUF_SIZE);
if (!verify_buf) return SYSPARAM_ERR_NOMEM;
do {
status = _do_write(addr, data, data_size);
if (status != SYSPARAM_OK) break;
for (i = 0; i < data_size; i += VERIFY_BUF_SIZE) {
count = min(data_size - i, VERIFY_BUF_SIZE);
status = _do_verify(addr + i, data + i, verify_buf, count);
if (status != SYSPARAM_OK) {
debug(1, "Flash write (@ 0x%08x) verify failed!", addr);
break;
}
}
} while (false);
free(verify_buf);
return status;
}
/** Erase the sectors of a region */ /** Erase the sectors of a region */
static sysparam_status_t _format_region(uint32_t addr, uint16_t num_sectors) { static sysparam_status_t _format_region(uint32_t addr, uint16_t num_sectors) {
uint16_t sector = addr / sdk_flashchip.sector_size;
int i; int i;
for (i = 0; i < num_sectors; i++) { for (i = 0; i < num_sectors; i++) {
CHECK_FLASH_OP(sdk_spi_flash_erase_sector(sector + i)); CHECK_FLASH_OP(spiflash_erase_sector(addr + (i * SPI_FLASH_SECTOR_SIZE)));
} }
return SYSPARAM_OK; return SYSPARAM_OK;
} }
@ -212,7 +193,7 @@ static sysparam_status_t init_write_context(struct sysparam_context *ctx) {
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
ctx->addr = _sysparam_info.end_addr; ctx->addr = _sysparam_info.end_addr;
debug(3, "read entry header @ 0x%08x", ctx->addr); debug(3, "read entry header @ 0x%08x", ctx->addr);
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE)); CHECK_FLASH_OP(spiflash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
return SYSPARAM_OK; return SYSPARAM_OK;
} }
@ -238,7 +219,10 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
// workaround is to make sure that the next write operation // workaround is to make sure that the next write operation
// will always start with a compaction, which will leave off // will always start with a compaction, which will leave off
// the invalid data at the end and fix the issue going forward. // the invalid data at the end and fix the issue going forward.
debug(1, "Encountered entry with invalid length (0x%04x) @ 0x%08x (region end is 0x%08x). Truncating entries.", ctx->entry.len, ctx->addr, _sysparam_info.end_addr); debug(1, "Encountered entry with invalid length (0x%04x) @ 0x%08x (region end is 0x%08x). Truncating entries.",
ctx->entry.len,
ctx->addr, _sysparam_info.end_addr);
_sysparam_info.force_compact = true; _sysparam_info.force_compact = true;
break; break;
} }
@ -251,7 +235,7 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
} }
debug(3, "read entry header @ 0x%08x", ctx->addr); debug(3, "read entry header @ 0x%08x", ctx->addr);
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE)); CHECK_FLASH_OP(spiflash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
debug(3, " idflags = 0x%04x", ctx->entry.idflags); debug(3, " idflags = 0x%04x", ctx->entry.idflags);
if (ctx->entry.idflags == 0xffff) { if (ctx->entry.idflags == 0xffff) {
// 0xffff is never a valid id field, so this means we've hit the // 0xffff is never a valid id field, so this means we've hit the
@ -295,17 +279,39 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
} }
/** Read the payload from the current entry pointed to by `ctx` */ /** Read the payload from the current entry pointed to by `ctx` */
static inline sysparam_status_t _read_payload(struct sysparam_context *ctx, uint8_t *buffer, size_t buffer_size) { static inline sysparam_status_t _read_payload(struct sysparam_context *ctx, uint8_t *buffer, size_t buffer_size) {
debug(3, "read payload (%d) @ 0x%08x", min(buffer_size, ctx->entry.len), ctx->addr); uint32_t addr = ctx->addr + ENTRY_HEADER_SIZE;
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr + ENTRY_HEADER_SIZE, (void*) buffer, min(buffer_size, ctx->entry.len))); size_t size = min(buffer_size, ctx->entry.len);
debug(3, "read payload (%d) @ 0x%08x", size, addr);
CHECK_FLASH_OP(spiflash_read(addr, buffer, buffer_size));
return SYSPARAM_OK;
}
static inline sysparam_status_t _compare_payload(struct sysparam_context *ctx, uint8_t *value, size_t size) {
debug(3, "compare payload (%d) @ 0x%08x", size, ctx->addr);
if (ctx->entry.len != size) return SYSPARAM_NOTFOUND;
uint32_t bounce[BOUNCE_BUFFER_WORDS];
uint32_t addr = ctx->addr + ENTRY_HEADER_SIZE;
int i;
for (i = 0; i < size; i += BOUNCE_BUFFER_SIZE) {
int len = min(size - i, BOUNCE_BUFFER_SIZE);
CHECK_FLASH_OP(spiflash_read(addr + i, (void*)bounce, len));
if (memcmp(value + i, bounce, len)) {
// Mismatch.
return SYSPARAM_NOTFOUND;
}
}
return SYSPARAM_OK; return SYSPARAM_OK;
} }
/** Find the entry corresponding to the specified key name */ /** Find the entry corresponding to the specified key name */
static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key, uint16_t key_len, uint8_t *buffer) { static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key, uint16_t key_len) {
sysparam_status_t status; sysparam_status_t status;
debug(3, "find key: %s", key ? key : "(null)"); debug(3, "find key len %d: %s", key_len, key ? key : "(null)");
while (true) { while (true) {
// Find the next key entry // Find the next key entry
status = _find_entry(ctx, ENTRY_ID_ANY, false); status = _find_entry(ctx, ENTRY_ID_ANY, false);
@ -316,12 +322,12 @@ static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key
break; break;
} }
if (ctx->entry.len == key_len) { if (ctx->entry.len == key_len) {
status = _read_payload(ctx, buffer, key_len); status = _compare_payload(ctx, (uint8_t *)key, key_len);
if (status < 0) return status; if (status == SYSPARAM_OK) {
if (!memcmp(key, buffer, key_len)) {
// We have a match // We have a match
break; break;
} }
if (status != SYSPARAM_NOTFOUND) return status;
debug(3, "entry payload does not match"); debug(3, "entry payload does not match");
} else { } else {
debug(3, "key length (%d) does not match (%d)", ctx->entry.len, key_len); debug(3, "key length (%d) does not match (%d)", ctx->entry.len, key_len);
@ -394,13 +400,11 @@ static inline sysparam_status_t _delete_entry(uint32_t addr) {
debug(2, "Deleting entry @ 0x%08x", addr); debug(2, "Deleting entry @ 0x%08x", addr);
debug(3, "read entry header @ 0x%08x", addr); debug(3, "read entry header @ 0x%08x", addr);
CHECK_FLASH_OP(sdk_spi_flash_read(addr, (void*) &entry, ENTRY_HEADER_SIZE)); CHECK_FLASH_OP(spiflash_read(addr, (uint8_t*) &entry, ENTRY_HEADER_SIZE));
// Set the ID to zero to mark it as "deleted" // Set the ID to zero to mark it as "deleted"
entry.idflags &= ~ENTRY_FLAG_ALIVE; entry.idflags &= ~ENTRY_FLAG_ALIVE;
debug(3, "write entry header @ 0x%08x", addr); debug(3, "write entry header @ 0x%08x", addr);
CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) &entry, ENTRY_HEADER_SIZE)); return _write_and_verify(addr, &entry, ENTRY_HEADER_SIZE);
return SYSPARAM_OK;
} }
/** Compact the current region, removing all deleted/unused entries, and write /** Compact the current region, removing all deleted/unused entries, and write
@ -424,7 +428,11 @@ static sysparam_status_t _compact_params(struct sysparam_context *ctx, int *key_
uint16_t binary_flag; uint16_t binary_flag;
uint16_t num_sectors = _sysparam_info.region_size / sdk_flashchip.sector_size; uint16_t num_sectors = _sysparam_info.region_size / sdk_flashchip.sector_size;
debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...", _sysparam_info.end_addr - _sysparam_info.cur_base, ctx ? ctx->compactable : 0, (ctx && ctx->unused_keys > 0) ? "+ (unused keys present)" : ""); debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...",
_sysparam_info.end_addr - _sysparam_info.cur_base,
ctx ? ctx->compactable : 0,
(ctx && ctx->unused_keys > 0) ? "+ (unused keys present)" : "");
status = _format_region(new_base, num_sectors); status = _format_region(new_base, num_sectors);
if (status < 0) return status; if (status < 0) return status;
status = sysparam_iter_start(&iter); status = sysparam_iter_start(&iter);
@ -505,7 +513,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr) {
top_addr = base_addr + sdk_flashchip.sector_size; top_addr = base_addr + sdk_flashchip.sector_size;
} }
for (addr0 = base_addr; addr0 < top_addr; addr0 += sdk_flashchip.sector_size) { for (addr0 = base_addr; addr0 < top_addr; addr0 += sdk_flashchip.sector_size) {
CHECK_FLASH_OP(sdk_spi_flash_read(addr0, (void*) &header0, REGION_HEADER_SIZE)); CHECK_FLASH_OP(spiflash_read(addr0, (void*) &header0, REGION_HEADER_SIZE));
if (header0.magic == SYSPARAM_MAGIC) { if (header0.magic == SYSPARAM_MAGIC) {
// Found a starting point... // Found a starting point...
break; break;
@ -523,7 +531,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr) {
} else { } else {
addr1 = addr0 + num_sectors * sdk_flashchip.sector_size; addr1 = addr0 + num_sectors * sdk_flashchip.sector_size;
} }
CHECK_FLASH_OP(sdk_spi_flash_read(addr1, (void*) &header1, REGION_HEADER_SIZE)); CHECK_FLASH_OP(spiflash_read(addr1, (uint8_t*) &header1, REGION_HEADER_SIZE));
if (header1.magic == SYSPARAM_MAGIC) { if (header1.magic == SYSPARAM_MAGIC) {
// Yay! Found the other one. Sanity-check it.. // Yay! Found the other one. Sanity-check it..
@ -600,7 +608,7 @@ sysparam_status_t sysparam_create_area(uint32_t base_addr, uint16_t num_sectors,
// we're not going to be clobbering something else important. // we're not going to be clobbering something else important.
for (addr = base_addr; addr < base_addr + region_size * 2; addr += SCAN_BUFFER_SIZE) { for (addr = base_addr; addr < base_addr + region_size * 2; addr += SCAN_BUFFER_SIZE) {
debug(3, "read %d words @ 0x%08x", SCAN_BUFFER_SIZE, addr); debug(3, "read %d words @ 0x%08x", SCAN_BUFFER_SIZE, addr);
CHECK_FLASH_OP(sdk_spi_flash_read(addr, buffer, SCAN_BUFFER_SIZE * 4)); CHECK_FLASH_OP(spiflash_read(addr, (uint8_t*)buffer, SCAN_BUFFER_SIZE * 4));
for (i = 0; i < SCAN_BUFFER_SIZE; i++) { for (i = 0; i < SCAN_BUFFER_SIZE; i++) {
if (buffer[i] != 0xffffffff) { if (buffer[i] != 0xffffffff) {
// Uh oh, not empty. // Uh oh, not empty.
@ -655,29 +663,35 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
sysparam_status_t status; sysparam_status_t status;
size_t key_len = strlen(key); size_t key_len = strlen(key);
uint8_t *buffer; uint8_t *buffer;
uint8_t *newbuf;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT; xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
if (actual_length) *actual_length = 0;
if (!_sysparam_info.cur_base) {
status = SYSPARAM_ERR_NOINIT;
goto done;
}
buffer = malloc(key_len + 2);
if (!buffer) return SYSPARAM_ERR_NOMEM;
do {
_init_context(&ctx); _init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer); status = _find_key(&ctx, key, key_len);
if (status != SYSPARAM_OK) break; if (status != SYSPARAM_OK) goto done;
// Find the associated value // Find the associated value
status = _find_value(&ctx, ctx.entry.idflags); status = _find_value(&ctx, ctx.entry.idflags);
if (status != SYSPARAM_OK) break; if (status != SYSPARAM_OK) goto done;
newbuf = realloc(buffer, ctx.entry.len + 1); buffer = malloc(ctx.entry.len + 1);
if (!newbuf) { if (!buffer) {
status = SYSPARAM_ERR_NOMEM; status = SYSPARAM_ERR_NOMEM;
break; goto done;
} }
buffer = newbuf;
status = _read_payload(&ctx, buffer, ctx.entry.len); status = _read_payload(&ctx, buffer, ctx.entry.len);
if (status != SYSPARAM_OK) break; if (status != SYSPARAM_OK) {
free(buffer);
goto done;
}
// Zero-terminate the result, just in case (doesn't hurt anything for // Zero-terminate the result, just in case (doesn't hurt anything for
// non-string data, and can avoid nasty mistakes if the caller wants to // non-string data, and can avoid nasty mistakes if the caller wants to
@ -687,38 +701,41 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
*destptr = buffer; *destptr = buffer;
if (actual_length) *actual_length = ctx.entry.len; if (actual_length) *actual_length = ctx.entry.len;
if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY); if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
return SYSPARAM_OK; status = SYSPARAM_OK;
} while (false);
free(buffer); done:
if (actual_length) *actual_length = 0; xSemaphoreGive(_sysparam_info.sem);
return status; return status;
} }
sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, size_t buffer_size, size_t *actual_length, bool *is_binary) { sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *dest, size_t dest_size, size_t *actual_length, bool *is_binary) {
struct sysparam_context ctx; struct sysparam_context ctx;
sysparam_status_t status = SYSPARAM_OK; sysparam_status_t status = SYSPARAM_OK;
size_t key_len = strlen(key); size_t key_len = strlen(key);
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT; xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
// Supplied buffer must be at least as large as the key, or 2 bytes,
// whichever is larger.
if (buffer_size < max(key_len, 2)) return SYSPARAM_ERR_NOMEM;
if (actual_length) *actual_length = 0; if (actual_length) *actual_length = 0;
if (!_sysparam_info.cur_base) {
status = SYSPARAM_ERR_NOINIT;
goto done;
}
_init_context(&ctx); _init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer); status = _find_key(&ctx, key, key_len);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) goto done;
status = _find_value(&ctx, ctx.entry.idflags); status = _find_value(&ctx, ctx.entry.idflags);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) goto done;
status = _read_payload(&ctx, buffer, buffer_size); status = _read_payload(&ctx, dest, dest_size);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) goto done;
if (actual_length) *actual_length = ctx.entry.len; if (actual_length) *actual_length = ctx.entry.len;
if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY); if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
return SYSPARAM_OK;
done:
xSemaphoreGive(_sysparam_info.sem);
return status;
} }
sysparam_status_t sysparam_get_string(const char *key, char **destptr) { sysparam_status_t sysparam_get_string(const char *key, char **destptr) {
@ -741,63 +758,82 @@ sysparam_status_t sysparam_get_string(const char *key, char **destptr) {
} }
sysparam_status_t sysparam_get_int32(const char *key, int32_t *result) { sysparam_status_t sysparam_get_int32(const char *key, int32_t *result) {
char *buffer;
char *endptr;
int32_t value; int32_t value;
size_t actual_length;
bool is_binary;
sysparam_status_t status; sysparam_status_t status;
status = sysparam_get_string(key, &buffer); status = sysparam_get_data_static(key, (uint8_t *)&value, sizeof(int32_t),
&actual_length, &is_binary);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) return status;
value = strtol(buffer, &endptr, 0); if (!is_binary || actual_length != sizeof(int32_t))
if (*endptr) {
// There was extra crap at the end of the string.
free(buffer);
return SYSPARAM_PARSEFAILED; return SYSPARAM_PARSEFAILED;
}
*result = value; *result = value;
free(buffer); return status;
return SYSPARAM_OK;
} }
sysparam_status_t sysparam_get_int8(const char *key, int8_t *result) { sysparam_status_t sysparam_get_int8(const char *key, int8_t *result) {
int32_t value; int8_t value;
size_t actual_length;
bool is_binary;
sysparam_status_t status; sysparam_status_t status;
status = sysparam_get_int32(key, &value); status = sysparam_get_data_static(key, (uint8_t *)&value, sizeof(int8_t),
if (status == SYSPARAM_OK) { &actual_length, &is_binary);
if (status != SYSPARAM_OK) return status;
if (!is_binary || actual_length != sizeof(int8_t))
return SYSPARAM_PARSEFAILED;
*result = value; *result = value;
}
return status; return status;
} }
sysparam_status_t sysparam_get_bool(const char *key, bool *result) { sysparam_status_t sysparam_get_bool(const char *key, bool *result) {
char *buffer; const size_t buf_size = 8;
char buf[buf_size + 1]; // extra byte for zero termination
size_t data_len = 0;
bool binary = false;
sysparam_status_t status; sysparam_status_t status;
status = sysparam_get_string(key, &buffer); status = sysparam_get_data_static(key, (uint8_t*)buf,
buf_size, &data_len, &binary);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) return status;
do { do {
if (!strcasecmp(buffer, "y") || if (binary) {
!strcasecmp(buffer, "yes") || if (data_len == 1) { // int8 value
!strcasecmp(buffer, "t") || uint8_t value;
!strcasecmp(buffer, "true") || memcpy(&value, buf, sizeof(value));
!strcmp(buffer, "1")) { *result = value ? true : false;
} else if (data_len == 4) { // int32 value
uint32_t value;
memcpy(&value, buf, sizeof(value));
*result = value ? true : false;
} else {
status = SYSPARAM_PARSEFAILED;
}
break;
}
buf[data_len] = 0;
if (!strcasecmp(buf, "y") ||
!strcasecmp(buf, "yes") ||
!strcasecmp(buf, "t") ||
!strcasecmp(buf, "true") ||
!strcmp(buf, "1")) {
*result = true; *result = true;
break; break;
} }
if (!strcasecmp(buffer, "n") || if (!strcasecmp(buf, "n") ||
!strcasecmp(buffer, "no") || !strcasecmp(buf, "no") ||
!strcasecmp(buffer, "f") || !strcasecmp(buf, "f") ||
!strcasecmp(buffer, "false") || !strcasecmp(buf, "false") ||
!strcmp(buffer, "0")) { !strcmp(buf, "0")) {
*result = false; *result = false;
break; break;
} }
status = SYSPARAM_PARSEFAILED; status = SYSPARAM_PARSEFAILED;
} while (0); } while (0);
free(buffer);
return status; return status;
} }
@ -806,48 +842,30 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
struct sysparam_context write_ctx; struct sysparam_context write_ctx;
sysparam_status_t status = SYSPARAM_OK; sysparam_status_t status = SYSPARAM_OK;
uint16_t key_len = strlen(key); uint16_t key_len = strlen(key);
uint8_t *buffer;
uint8_t *newbuf;
size_t free_space; size_t free_space;
size_t needed_space; size_t needed_space;
bool free_value = false;
int key_id = -1; int key_id = -1;
uint32_t old_value_addr = 0; uint32_t old_value_addr = 0;
uint16_t binary_flag; uint16_t binary_flag;
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
if (!key_len) return SYSPARAM_ERR_BADVALUE; if (!key_len) return SYSPARAM_ERR_BADVALUE;
if (key_len > MAX_KEY_LEN) return SYSPARAM_ERR_BADVALUE; if (key_len > MAX_KEY_LEN) return SYSPARAM_ERR_BADVALUE;
if (value_len > MAX_VALUE_LEN) return SYSPARAM_ERR_BADVALUE; if (value_len > MAX_VALUE_LEN) return SYSPARAM_ERR_BADVALUE;
xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
if (!value) value_len = 0; if (!value) value_len = 0;
debug(1, "updating value for '%s' (%d bytes)", key, value_len); debug(1, "updating value for '%s' (%d bytes)", key, value_len);
if (value_len && ((intptr_t)value & 0x3)) {
// The passed value isn't word-aligned. This will be a problem later xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
// when calling `sdk_spi_flash_write`, so make a word-aligned copy.
buffer = malloc(value_len); if (!_sysparam_info.cur_base) {
if (!buffer) { status = SYSPARAM_ERR_NOINIT;
status = SYSPARAM_ERR_NOMEM;
goto done;
}
memcpy(buffer, value, value_len);
value = buffer;
free_value = true;
}
// Create a working buffer for `_find_key` to use.
buffer = malloc(key_len);
if (!buffer) {
if (free_value) free((void *)value);
status = SYSPARAM_ERR_NOMEM;
goto done; goto done;
} }
do { do {
_init_context(&ctx); _init_context(&ctx);
status = _find_key(&ctx, key, key_len, buffer); status = _find_key(&ctx, key, key_len);
if (status == SYSPARAM_OK) { if (status == SYSPARAM_OK) {
// Key already exists, see if there's a current value. // Key already exists, see if there's a current value.
key_id = ctx.entry.idflags & ENTRY_MASK_ID; key_id = ctx.entry.idflags & ENTRY_MASK_ID;
@ -862,24 +880,17 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
if (value_len) { if (value_len) {
if (old_value_addr) { if (old_value_addr) {
if ((ctx.entry.idflags & ENTRY_FLAG_BINARY) == binary_flag && ctx.entry.len == value_len) { if ((ctx.entry.idflags & ENTRY_FLAG_BINARY) == binary_flag &&
ctx.entry.len == value_len) {
// Are we trying to write the same value that's already there? // Are we trying to write the same value that's already there?
if (value_len > key_len) { status = _compare_payload(&ctx, (uint8_t *)value, value_len);
newbuf = realloc(buffer, value_len); if (status == SYSPARAM_OK) {
if (!newbuf) {
status = SYSPARAM_ERR_NOMEM;
break;
}
buffer = newbuf;
}
status = _read_payload(&ctx, buffer, value_len);
if (status < 0) break;
if (!memcmp(buffer, value, value_len)) {
// Yup, it's a match! No need to do anything further, // Yup, it's a match! No need to do anything further,
// just leave the current value as-is. // just leave the current value as-is.
status = SYSPARAM_OK; status = SYSPARAM_OK;
break; break;
} }
if (status != SYSPARAM_NOTFOUND) goto done;
} }
// Since we will be deleting the old value (if any) make sure // Since we will be deleting the old value (if any) make sure
@ -981,9 +992,6 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
debug(1, "New addr is 0x%08x (%d bytes remaining)", _sysparam_info.end_addr, _sysparam_info.cur_base + _sysparam_info.region_size - _sysparam_info.end_addr); debug(1, "New addr is 0x%08x (%d bytes remaining)", _sysparam_info.end_addr, _sysparam_info.cur_base + _sysparam_info.region_size - _sysparam_info.end_addr);
} while (false); } while (false);
if (free_value) free((void *)value);
free(buffer);
done: done:
xSemaphoreGive(_sysparam_info.sem); xSemaphoreGive(_sysparam_info.sem);
@ -995,15 +1003,11 @@ sysparam_status_t sysparam_set_string(const char *key, const char *value) {
} }
sysparam_status_t sysparam_set_int32(const char *key, int32_t value) { sysparam_status_t sysparam_set_int32(const char *key, int32_t value) {
uint8_t buffer[12]; return sysparam_set_data(key, (const uint8_t *)&value, sizeof(value), true);
int len;
len = snprintf((char *)buffer, 12, "%d", value);
return sysparam_set_data(key, buffer, len, false);
} }
sysparam_status_t sysparam_set_int8(const char *key, int8_t value) { sysparam_status_t sysparam_set_int8(const char *key, int8_t value) {
return sysparam_set_int32(key, value); return sysparam_set_data(key, (const uint8_t *)&value, sizeof(value), true);
} }
sysparam_status_t sysparam_set_bool(const char *key, bool value) { sysparam_status_t sysparam_set_bool(const char *key, bool value) {
@ -1043,7 +1047,6 @@ sysparam_status_t sysparam_iter_start(sysparam_iter_t *iter) {
} }
sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) { sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
uint8_t buffer[2];
sysparam_status_t status; sysparam_status_t status;
size_t required_len; size_t required_len;
struct sysparam_context *ctx = iter->ctx; struct sysparam_context *ctx = iter->ctx;
@ -1052,7 +1055,7 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
char *newbuf; char *newbuf;
while (true) { while (true) {
status = _find_key(ctx, NULL, 0, buffer); status = _find_key(ctx, NULL, 0);
if (status != SYSPARAM_OK) return status; if (status != SYSPARAM_OK) return status;
memcpy(&value_ctx, ctx, sizeof(value_ctx)); memcpy(&value_ctx, ctx, sizeof(value_ctx));
@ -1060,7 +1063,7 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
if (status < 0) return status; if (status < 0) return status;
if (status == SYSPARAM_NOTFOUND) continue; if (status == SYSPARAM_NOTFOUND) continue;
key_space = ROUND_TO_WORD_BOUNDARY(ctx->entry.len + 1); key_space = ctx->entry.len + 1;
required_len = key_space + value_ctx.entry.len + 1; required_len = key_space + value_ctx.entry.len + 1;
if (required_len > iter->bufsize) { if (required_len > iter->bufsize) {
newbuf = realloc(iter->key, required_len); newbuf = realloc(iter->key, required_len);

View file

@ -48,7 +48,7 @@ void user_init(void)
}; };
sdk_wifi_softap_set_config(&ap_config); sdk_wifi_softap_set_config(&ap_config);
ip_addr_t first_client_ip; ip4_addr_t first_client_ip;
IP4_ADDR(&first_client_ip, 172, 16, 0, 2); IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
dhcpserver_start(&first_client_ip, 4); dhcpserver_start(&first_client_ip, 4);
@ -65,14 +65,14 @@ static void telnetTask(void *pvParameters)
printf("Status monitor: Failed to allocate socket.\r\n"); printf("Status monitor: Failed to allocate socket.\r\n");
return; return;
} }
netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT); netconn_bind(nc, IP_ANY_TYPE, TELNET_PORT);
netconn_listen(nc); netconn_listen(nc);
while(1) { while(1) {
struct netconn *client = NULL; struct netconn *client = NULL;
err_t err = netconn_accept(nc, &client); err_t err = netconn_accept(nc, &client);
if ( err != ERR_OK ) { if (err != ERR_OK) {
if(client) if(client)
netconn_delete(client); netconn_delete(client);
continue; continue;
@ -88,9 +88,8 @@ static void telnetTask(void *pvParameters)
netconn_write(client, buf, strlen(buf), NETCONN_COPY); netconn_write(client, buf, strlen(buf), NETCONN_COPY);
snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize()); snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize());
netconn_write(client, buf, strlen(buf), NETCONN_COPY); netconn_write(client, buf, strlen(buf), NETCONN_COPY);
snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d\r\n\r\n", char abuf[40];
ip4_addr1(&client_addr), ip4_addr2(&client_addr), snprintf(buf, sizeof(buf), "Your address is %s\r\n\r\n", ipaddr_ntoa_r(&client_addr, abuf, sizeof(abuf)));
ip4_addr3(&client_addr), ip4_addr4(&client_addr));
netconn_write(client, buf, strlen(buf), NETCONN_COPY); netconn_write(client, buf, strlen(buf), NETCONN_COPY);
netconn_delete(client); netconn_delete(client);
} }

4
examples/ad770x/Makefile Normal file
View file

@ -0,0 +1,4 @@
PROGRAM = ad770x
EXTRA_COMPONENTS = extras/ad770x
#ESPBAUD = 460800
include ../../common.mk

49
examples/ad770x/main.c Normal file
View file

@ -0,0 +1,49 @@
/*
* Example of using AD7705/AD7706 driver
*
* Part of esp-open-rtos
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* BSD Licensed as described in the file LICENSE
*/
#include <esp/uart.h>
#include <espressif/esp_common.h>
#include <stdio.h>
#include <ad770x/ad770x.h>
#include <FreeRTOS.h>
#include <task.h>
#define CS_PIN 2
#define AIN_CHANNEL 0 // AIN1+,AIN1- for AD7705
static const ad770x_params_t dev = {
.cs_pin = CS_PIN,
.master_clock = AD770X_MCLK_4_9152MHz, // 4.9152 MHz
.bipolar = false, // Unipolar mode
.gain = AD770X_GAIN_1, // No gain
.update_rate = AD770X_RATE_50 // 50 Hz output update rate
};
void user_init(void)
{
uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version());
while (ad770x_init(&dev, AIN_CHANNEL) != 0)
{
printf("Cannot initialize AD7705\n");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
while (true)
{
// wait for data
while (!ad770x_data_ready(&dev, AIN_CHANNEL)) {}
// Read result
uint16_t raw = ad770x_raw_adc_value(&dev, AIN_CHANNEL);
printf("Raw ADC value: %d\n", raw);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}

View file

@ -17,6 +17,7 @@
// Connect ADDR pin to GND // Connect ADDR pin to GND
#define ADDR ADS111X_ADDR_GND #define ADDR ADS111X_ADDR_GND
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
@ -28,23 +29,27 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_dev_t dev = {
.addr = ADDR,
.bus = I2C_BUS,
};
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
ads111x_set_mode(ADDR, ADS111X_MODE_CONTUNOUS); ads111x_set_mode(&dev, ADS111X_MODE_CONTUNOUS);
ads111x_set_data_rate(ADDR, ADS111X_DATA_RATE_32); ads111x_set_data_rate(&dev, ADS111X_DATA_RATE_32);
ads111x_set_input_mux(ADDR, ADS111X_MUX_0_GND); ads111x_set_input_mux(&dev, ADS111X_MUX_0_GND);
ads111x_set_gain(ADDR, GAIN); ads111x_set_gain(&dev, GAIN);
float gain_val = ads111x_gain_values[GAIN]; float gain_val = ads111x_gain_values[GAIN];
while (true) while (true)
{ {
// wait for conversion end // wait for conversion end
while (ads111x_busy(ADDR)) {} while (ads111x_busy(&dev)) {}
// Read result // Read result
int16_t raw = ads111x_get_value(ADDR); int16_t raw = ads111x_get_value(&dev);
float voltage = gain_val / ADS111X_MAX_VALUE * raw; float voltage = gain_val / ADS111X_MAX_VALUE * raw;

View file

@ -4,7 +4,7 @@
// this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced // this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced
#include "mbedtls/config.h" #include "mbedtls/config.h"
#include "mbedtls/net.h" #include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
#include "mbedtls/ssl.h" #include "mbedtls/ssl.h"
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"

3
examples/bh1750/Makefile Normal file
View file

@ -0,0 +1,3 @@
PROGRAM=bh1750_example
EXTRA_COMPONENTS = extras/i2c extras/bh1750
include ../../common.mk

View file

@ -0,0 +1,44 @@
#include <stdio.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "i2c/i2c.h"
#include "bh1750/bh1750.h"
#define SCL_PIN 5
#define SDA_PIN 4
#define I2C_BUS 0
static void measure(void *pvParameters)
{
i2c_dev_t dev = {
.addr = BH1750_ADDR_LO,
.bus = I2C_BUS,
};
bh1750_configure(&dev, BH1750_CONTINUOUS_MODE | BH1750_HIGH_RES_MODE);
while (1) {
while(1) {
vTaskDelay(200 / portTICK_PERIOD_MS);
printf("Lux: %d\n", bh1750_read(&dev));
}
}
}
void user_init(void)
{
uart_set_baud(0, 115200);
// Just some information
printf("\n");
printf("SDK version : %s\n", sdk_system_get_sdk_version());
printf("GIT version : %s\n", GITSHORTREV);
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
xTaskCreate(measure, "measure_task", 256, NULL, 2, NULL);
}

View file

@ -17,13 +17,13 @@ const int freq_frc2 = 10;
static volatile uint32_t frc1_count; static volatile uint32_t frc1_count;
static volatile uint32_t frc2_count; static volatile uint32_t frc2_count;
void frc1_interrupt_handler(void) void frc1_interrupt_handler(void *arg)
{ {
frc1_count++; frc1_count++;
gpio_toggle(gpio_frc1); gpio_toggle(gpio_frc1);
} }
void frc2_interrupt_handler(void) void frc2_interrupt_handler(void *arg)
{ {
/* FRC2 needs the match register updated on each timer interrupt */ /* FRC2 needs the match register updated on each timer interrupt */
timer_set_frequency(FRC2, freq_frc2); timer_set_frequency(FRC2, freq_frc2);
@ -47,8 +47,8 @@ void user_init(void)
timer_set_run(FRC2, false); timer_set_run(FRC2, false);
/* set up ISRs */ /* set up ISRs */
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler); _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler, NULL);
/* configure timer frequencies */ /* configure timer frequencies */
timer_set_frequency(FRC1, freq_frc1); timer_set_frequency(FRC1, freq_frc1);

View file

@ -13,18 +13,25 @@
// BMP180 driver // BMP180 driver
#include "bmp180/bmp180.h" #include "bmp180/bmp180.h"
#define MY_EVT_TIMER 0x01 #define I2C_BUS 0
#define MY_EVT_BMP180 0x02
#define SCL_PIN GPIO_ID_PIN((0)) #define SCL_PIN GPIO_ID_PIN((0))
#define SDA_PIN GPIO_ID_PIN((2)) #define SDA_PIN GPIO_ID_PIN((2))
#define MY_EVT_TIMER 0x01
#define MY_EVT_BMP180 0x02
typedef struct typedef struct
{ {
uint8_t event_type; uint8_t event_type;
bmp180_result_t bmp180_data; bmp180_result_t bmp180_data;
} my_event_t; } my_event_t;
//device descriptor
i2c_dev_t dev = {
.addr = BMP180_DEVICE_ADDRESS,
.bus = I2C_BUS,
};
// Communication Queue // Communication Queue
static QueueHandle_t mainqueue; static QueueHandle_t mainqueue;
static TimerHandle_t timerHandle; static TimerHandle_t timerHandle;
@ -70,7 +77,7 @@ void bmp180_task(void *pvParameters)
case MY_EVT_TIMER: case MY_EVT_TIMER:
printf("%s: Received Timer Event\n", __FUNCTION__); printf("%s: Received Timer Event\n", __FUNCTION__);
bmp180_trigger_measurement(com_queue); bmp180_trigger_measurement(&dev, com_queue);
break; break;
case MY_EVT_BMP180: case MY_EVT_BMP180:
printf("%s: Received BMP180 Event temp:=%d.%dC press=%d.%02dhPa\n", __FUNCTION__, \ printf("%s: Received BMP180 Event temp:=%d.%dC press=%d.%02dhPa\n", __FUNCTION__, \
@ -91,6 +98,9 @@ void user_setup(void)
// Give the UART some time to settle // Give the UART some time to settle
sdk_os_delay_us(500); sdk_os_delay_us(500);
// Init I2C bus Interface
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
} }
void user_init(void) void user_init(void)
@ -107,7 +117,7 @@ void user_init(void)
bmp180_informUser = bmp180_i2c_informUser; bmp180_informUser = bmp180_i2c_informUser;
// Init BMP180 Interface // Init BMP180 Interface
bmp180_init(SCL_PIN, SDA_PIN); bmp180_init(&dev);
// Create Main Communication Queue // Create Main Communication Queue
mainqueue = xQueueCreate(10, sizeof(my_event_t)); mainqueue = xQueueCreate(10, sizeof(my_event_t));

View file

@ -12,7 +12,7 @@
// In forced mode user initiate measurement each time. // In forced mode user initiate measurement each time.
// In normal mode measurement is done continuously with specified standby time. // In normal mode measurement is done continuously with specified standby time.
// #define MODE_FORCED // #define MODE_FORCED
const uint8_t i2c_bus = 0;
const uint8_t scl_pin = 0; const uint8_t scl_pin = 0;
const uint8_t sda_pin = 2; const uint8_t sda_pin = 2;
@ -26,7 +26,8 @@ static void bmp280_task_forced(void *pvParameters)
params.mode = BMP280_MODE_FORCED; params.mode = BMP280_MODE_FORCED;
bmp280_t bmp280_dev; bmp280_t bmp280_dev;
bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; bmp280_dev.i2c_dev.bus = i2c_bus;
bmp280_dev.i2c_dev.addr = BMP280_I2C_ADDRESS_0;
while (1) { while (1) {
while (!bmp280_init(&bmp280_dev, &params)) { while (!bmp280_init(&bmp280_dev, &params)) {
@ -67,7 +68,8 @@ static void bmp280_task_normal(void *pvParameters)
bmp280_init_default_params(&params); bmp280_init_default_params(&params);
bmp280_t bmp280_dev; bmp280_t bmp280_dev;
bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0; bmp280_dev.i2c_dev.bus = i2c_bus;
bmp280_dev.i2c_dev.addr = BMP280_I2C_ADDRESS_0;
while (1) { while (1) {
while (!bmp280_init(&bmp280_dev, &params)) { while (!bmp280_init(&bmp280_dev, &params)) {
@ -103,7 +105,7 @@ void user_init(void)
printf("SDK version : %s\n", sdk_system_get_sdk_version()); printf("SDK version : %s\n", sdk_system_get_sdk_version());
printf("GIT version : %s\n", GITSHORTREV); printf("GIT version : %s\n", GITSHORTREV);
i2c_init(scl_pin, sda_pin); i2c_init(i2c_bus, scl_pin, sda_pin, I2C_FREQ_400K);
#ifdef MODE_FORCED #ifdef MODE_FORCED
xTaskCreate(bmp280_task_forced, "bmp280_task", 256, NULL, 2, NULL); xTaskCreate(bmp280_task_forced, "bmp280_task", 256, NULL, 2, NULL);

View file

@ -11,6 +11,7 @@
#include <ds1307/ds1307.h> #include <ds1307/ds1307.h>
#include <stdio.h> #include <stdio.h>
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
@ -19,8 +20,12 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
ds1307_start(true); i2c_dev_t dev = {
.addr = DS1307_ADDR,
.bus = I2C_BUS,
};
ds1307_start(&dev, true);
// setup datetime: 2016-10-09 13:50:10 // setup datetime: 2016-10-09 13:50:10
struct tm time = { struct tm time = {
@ -31,11 +36,11 @@ void user_init(void)
.tm_min = 50, .tm_min = 50,
.tm_sec = 10 .tm_sec = 10
}; };
ds1307_set_time(&time); ds1307_set_time(&dev, &time);
while (true) while (true)
{ {
ds1307_get_time(&time); ds1307_get_time(&dev, &time);
printf("%04d-%02d-%02d %02d:%02d:%02d\n", time.tm_year, time.tm_mon + 1, printf("%04d-%02d-%02d %02d:%02d:%02d\n", time.tm_year, time.tm_mon + 1,
time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);

View file

@ -12,15 +12,21 @@
#include "ds3231/ds3231.h" #include "ds3231/ds3231.h"
#define ADDR DS3231_ADDR
#define I2C_BUS 0
void task1(void *pvParameters) void task1(void *pvParameters)
{ {
struct tm time; struct tm time;
float tempFloat; float tempFloat;
i2c_dev_t dev = {
.addr = ADDR,
.bus = I2C_BUS,
};
while(1) { while(1) {
vTaskDelay(100); vTaskDelay(100);
ds3231_getTime(&time); ds3231_getTime(&dev, &time);
ds3231_getTempFloat(&tempFloat); ds3231_getTempFloat(&dev, &tempFloat);
printf("TIME:%d:%d:%d, TEMPERATURE:%.2f DegC\r\n", time.tm_hour, time.tm_min, time.tm_sec, tempFloat); printf("TIME:%d:%d:%d, TEMPERATURE:%.2f DegC\r\n", time.tm_hour, time.tm_min, time.tm_sec, tempFloat);
} }
} }
@ -35,7 +41,7 @@ void user_init(void)
printf("SDK version : %s\n", sdk_system_get_sdk_version()); printf("SDK version : %s\n", sdk_system_get_sdk_version());
printf("GIT version : %s\n", GITSHORTREV); printf("GIT version : %s\n", GITSHORTREV);
ds3231_Init(scl, sda); i2c_init(0,scl,sda,I2C_FREQ_400K);
xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL); xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL);
} }

View file

@ -97,7 +97,7 @@ void timerRegTask(void *pvParameters)
} }
} }
IRAM void frc1_handler(void) IRAM void frc1_handler(void *arg)
{ {
frc1_handler_call_count++; frc1_handler_call_count++;
frc1_last_count_val = TIMER(0).COUNT; frc1_last_count_val = TIMER(0).COUNT;
@ -106,7 +106,7 @@ IRAM void frc1_handler(void)
//TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000; //TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
} }
void frc2_handler(void) void frc2_handler(void *arg)
{ {
frc2_handler_call_count++; frc2_handler_call_count++;
frc2_last_count_val = TIMER(1).COUNT; frc2_last_count_val = TIMER(1).COUNT;
@ -127,9 +127,9 @@ void user_init(void)
TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256); TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256);
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1; DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1;
_xt_isr_attach(INUM_TIMER_FRC1, frc1_handler); _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler, NULL);
_xt_isr_unmask(1<<INUM_TIMER_FRC1); _xt_isr_unmask(1<<INUM_TIMER_FRC1);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler); _xt_isr_attach(INUM_TIMER_FRC2, frc2_handler, NULL);
_xt_isr_unmask(1<<INUM_TIMER_FRC2); _xt_isr_unmask(1<<INUM_TIMER_FRC2);
TIMER(0).CTRL |= TIMER_CTRL_RUN; TIMER(0).CTRL |= TIMER_CTRL_RUN;

View file

@ -237,7 +237,7 @@ static volatile bool frc1_ran;
static volatile bool frc1_finished; static volatile bool frc1_finished;
static volatile char frc1_buf[80]; static volatile char frc1_buf[80];
static void frc1_interrupt_handler(void) static void frc1_interrupt_handler(void *arg)
{ {
frc1_ran = true; frc1_ran = true;
timer_set_run(FRC1, false); timer_set_run(FRC1, false);
@ -250,7 +250,7 @@ static void test_isr()
printf("Testing behaviour inside ISRs...\r\n"); printf("Testing behaviour inside ISRs...\r\n");
timer_set_interrupts(FRC1, false); timer_set_interrupts(FRC1, false);
timer_set_run(FRC1, false); timer_set_run(FRC1, false);
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
timer_set_frequency(FRC1, 1000); timer_set_frequency(FRC1, 1000);
timer_set_interrupts(FRC1, true); timer_set_interrupts(FRC1, true);
timer_set_run(FRC1, true); timer_set_run(FRC1, true);

View file

@ -18,6 +18,7 @@
#define CS_GPIO_PIN 2 #define CS_GPIO_PIN 2
// ds1307 // ds1307
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
@ -29,7 +30,11 @@
uint32_t get_fattime() uint32_t get_fattime()
{ {
struct tm time; struct tm time;
ds1307_get_time(&time); i2c_dev_t dev = {
.addr = DS1307_ADDR,
.bus = I2C_BUS,
};
ds1307_get_time(&dev, &time);
return ((uint32_t)(time.tm_year - 1980) << 25) return ((uint32_t)(time.tm_year - 1980) << 25)
| ((uint32_t)time.tm_mon << 21) | ((uint32_t)time.tm_mon << 21)
@ -127,7 +132,7 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
i2c_init (SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
xTaskCreate(rewrite_file_task, "task1", 512, NULL, 2, NULL); xTaskCreate(rewrite_file_task, "task1", 512, NULL, 2, NULL);
} }

View file

@ -11,6 +11,7 @@
#include <i2c/i2c.h> #include <i2c/i2c.h>
#include <hmc5883l/hmc5883l.h> #include <hmc5883l/hmc5883l.h>
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
@ -19,20 +20,24 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
i2c_dev_t dev = {
.addr = HMC5883L_ADDR,
.bus = I2C_BUS,
};
while (!hmc5883l_init()) while (!hmc5883l_init(&dev))
printf("Device not found\n"); printf("Device not found\n");
hmc5883l_set_operating_mode(HMC5883L_MODE_CONTINUOUS); hmc5883l_set_operating_mode(&dev, HMC5883L_MODE_CONTINUOUS);
hmc5883l_set_samples_averaged(HMC5883L_SAMPLES_8); hmc5883l_set_samples_averaged(&dev, HMC5883L_SAMPLES_8);
hmc5883l_set_data_rate(HMC5883L_DATA_RATE_07_50); hmc5883l_set_data_rate(&dev, HMC5883L_DATA_RATE_07_50);
hmc5883l_set_gain(HMC5883L_GAIN_1090); hmc5883l_set_gain(&dev, HMC5883L_GAIN_1090);
while (true) while (true)
{ {
hmc5883l_data_t data; hmc5883l_data_t data;
hmc5883l_get_data(&data); hmc5883l_get_data(&dev, &data);
printf("Magnetic data: X:%.2f mG, Y:%.2f mG, Z:%.2f mG\n", data.x, data.y, data.z); printf("Magnetic data: X:%.2f mG, Y:%.2f mG, Z:%.2f mG\n", data.x, data.y, data.z);
for (uint32_t i = 0; i < 1000; i++) for (uint32_t i = 0; i < 1000; i++)

View file

@ -20,9 +20,9 @@
#include "ssid_config.h" #include "ssid_config.h"
#define WEB_SERVER "chainxor.org" #define WEB_SERVER "ipv6.google.com"
#define WEB_PORT 80 #define WEB_PORT 80
#define WEB_URL "http://chainxor.org/" #define WEB_PATH "/"
void http_get_task(void *pvParameters) void http_get_task(void *pvParameters)
{ {
@ -31,7 +31,7 @@ void http_get_task(void *pvParameters)
while(1) { while(1) {
const struct addrinfo hints = { const struct addrinfo hints = {
.ai_family = AF_INET, .ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM, .ai_socktype = SOCK_STREAM,
}; };
struct addrinfo *res; struct addrinfo *res;
@ -39,7 +39,7 @@ void http_get_task(void *pvParameters)
printf("Running DNS lookup for %s...\r\n", WEB_SERVER); printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
int err = getaddrinfo(WEB_SERVER, "80", &hints, &res); int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
if(err != 0 || res == NULL) { if (err != 0 || res == NULL) {
printf("DNS lookup failed err=%d res=%p\r\n", err, res); printf("DNS lookup failed err=%d res=%p\r\n", err, res);
if(res) if(res)
freeaddrinfo(res); freeaddrinfo(res);
@ -47,9 +47,28 @@ void http_get_task(void *pvParameters)
failures++; failures++;
continue; continue;
} }
/* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; #if LWIP_IPV6
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr)); {
struct netif *netif = sdk_system_get_netif(0);
int i;
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
printf(" ip6 %d state %x\n", i, netif_ip6_addr_state(netif, i));
if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)))
printf(" ip6 addr %d = %s\n", i, ip6addr_ntoa(netif_ip6_addr(netif, i)));
}
}
#endif
struct sockaddr *sa = res->ai_addr;
if (sa->sa_family == AF_INET) {
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr));
}
#if LWIP_IPV6
if (sa->sa_family == AF_INET6) {
printf("DNS lookup succeeded. IP=%s\r\n", inet6_ntoa(((struct sockaddr_in6 *)sa)->sin6_addr));
}
#endif
int s = socket(res->ai_family, res->ai_socktype, 0); int s = socket(res->ai_family, res->ai_socktype, 0);
if(s < 0) { if(s < 0) {
@ -75,8 +94,10 @@ void http_get_task(void *pvParameters)
freeaddrinfo(res); freeaddrinfo(res);
const char *req = const char *req =
"GET "WEB_URL"\r\n" "GET "WEB_PATH" HTTP/1.1\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-open-rtos/0.1 esp8266\r\n" "User-Agent: esp-open-rtos/0.1 esp8266\r\n"
"Connection: close\r\n"
"\r\n"; "\r\n";
if (write(s, req, strlen(req)) < 0) { if (write(s, req, strlen(req)) < 0) {
printf("... socket send failed\r\n"); printf("... socket send failed\r\n");
@ -126,6 +147,6 @@ void user_init(void)
sdk_wifi_set_opmode(STATION_MODE); sdk_wifi_set_opmode(STATION_MODE);
sdk_wifi_station_set_config(&config); sdk_wifi_station_set_config(&config);
xTaskCreate(&http_get_task, "get_task", 256, NULL, 2, NULL); xTaskCreate(&http_get_task, "get_task", 384, NULL, 2, NULL);
} }

View file

@ -33,7 +33,7 @@
errors at link time if functions don't exist.) */ errors at link time if functions don't exist.) */
#include "mbedtls/config.h" #include "mbedtls/config.h"
#include "mbedtls/net.h" #include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
#include "mbedtls/ssl.h" #include "mbedtls/ssl.h"
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"

View file

@ -19,7 +19,7 @@
<h1>About</h1> <h1>About</h1>
<p>This server is based on httpd from LwIP.</p> <p>This server is based on httpd from LwIP.</p>
<p>To enable debugging compile with flags -DLWIP_DEBUG=1 -DHTTPD_DEBUG=LWIP_DBG_ON.</p> <p>To enable debugging compile with flags -DLWIP_DEBUG=1 -DHTTPD_DEBUG=LWIP_DBG_ON.</p>
<p>For more info see <a href="http://www.nongnu.org/lwip/2_0_0/group__httpd.html">HTTP Server documentation</a>.</p> <p>For more info see <a href="http://www.nongnu.org/lwip/2_0_x/group__httpd.html">HTTP Server documentation</a>.</p>
</div> </div>
</body> </body>
</html> </html>

View file

@ -13,6 +13,7 @@
#include <hd44780/hd44780.h> #include <hd44780/hd44780.h>
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
#define ADDR 0x27 #define ADDR 0x27
@ -27,10 +28,11 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
hd44780_t lcd = { hd44780_t lcd = {
.addr = ADDR, .i2c_dev.bus = I2C_BUS,
.i2c_dev.addr = ADDR,
.font = HD44780_FONT_5X8, .font = HD44780_FONT_5X8,
.lines = 2, .lines = 2,
.pins = { .pins = {

View file

@ -88,7 +88,7 @@ static inline void init_descriptors_list()
} }
// DMA interrupt handler. It is called each time a DMA block is finished processing. // DMA interrupt handler. It is called each time a DMA block is finished processing.
static void dma_isr_handler(void) static void dma_isr_handler(void *args)
{ {
portBASE_TYPE task_awoken = pdFALSE; portBASE_TYPE task_awoken = pdFALSE;
@ -168,7 +168,7 @@ void play_task(void *pvParameters)
i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true}; i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true};
i2s_dma_init(dma_isr_handler, clock_div, i2s_pins); i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins);
while (1) { while (1) {
init_descriptors_list(); init_descriptors_list();

View file

@ -13,6 +13,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "ina3221/ina3221.h" #include "ina3221/ina3221.h"
#define I2C_BUS 0
#define PIN_SCL 5 #define PIN_SCL 5
#define PIN_SDA 2 #define PIN_SDA 2
#define ADDR INA3221_ADDR_0 #define ADDR INA3221_ADDR_0
@ -33,7 +34,8 @@ void ina_measure(void *pvParameters)
// Create ina3221 device // Create ina3221 device
ina3221_t dev = { ina3221_t dev = {
.addr = ADDR, .i2c_dev.bus = I2C_BUS,
.i2c_dev.addr = ADDR,
.shunt = { 100 ,100 ,100 }, // shunt values are 100 mOhm for each channel .shunt = { 100 ,100 ,100 }, // shunt values are 100 mOhm for each channel
.mask.mask_register = INA3221_DEFAULT_MASK, // Init .mask.mask_register = INA3221_DEFAULT_MASK, // Init
.config.config_register = INA3221_DEFAULT_CONFIG, // Init .config.config_register = INA3221_DEFAULT_CONFIG, // Init
@ -120,7 +122,7 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(PIN_SCL,PIN_SDA); i2c_init(I2C_BUS, PIN_SCL, PIN_SDA, I2C_FREQ_400K);
xTaskCreate(ina_measure, "Measurements_task", 512, NULL, 2, NULL); xTaskCreate(ina_measure, "Measurements_task", 512, NULL, 2, NULL);
} }

View file

@ -14,14 +14,15 @@
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h> #include <task.h>
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
#define ADDR MCP4725A0_ADDR0 #define ADDR MCP4725A0_ADDR0
#define VDD 3.3 #define VDD 3.3
inline static void wait_for_eeprom() inline static void wait_for_eeprom(i2c_dev_t* dev)
{ {
while (mcp4725_eeprom_busy(ADDR)) while (mcp4725_eeprom_busy(dev))
{ {
printf("...DAC is busy, waiting...\n"); printf("...DAC is busy, waiting...\n");
vTaskDelay(1); vTaskDelay(1);
@ -33,21 +34,25 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
i2c_dev_t dev = {
.addr = ADDR,
.bus = I2C_BUS,
};
// setup EEPROM values // setup EEPROM values
if (mcp4725_get_power_mode(ADDR, true) != MCP4725_PM_NORMAL) if (mcp4725_get_power_mode(&dev, true) != MCP4725_PM_NORMAL)
{ {
printf("DAC was sleeping... Wake up Neo!\n"); printf("DAC was sleeping... Wake up Neo!\n");
mcp4725_set_power_mode(ADDR, MCP4725_PM_NORMAL, true); mcp4725_set_power_mode(&dev, MCP4725_PM_NORMAL, true);
wait_for_eeprom(); wait_for_eeprom(&dev);
} }
printf("Set default DAC ouptut value to MAX...\n"); printf("Set default DAC ouptut value to MAX...\n");
mcp4725_set_raw_output(ADDR, MCP4725_MAX_VALUE, true); mcp4725_set_raw_output(&dev, MCP4725_MAX_VALUE, true);
wait_for_eeprom(); wait_for_eeprom(&dev);
printf("And now default DAC output value is 0x%03x\n", mcp4725_get_raw_output(ADDR, true)); printf("And now default DAC output value is 0x%03x\n", mcp4725_get_raw_output(&dev, true));
printf("Now let's generate the sawtooth wave in slow manner\n"); printf("Now let's generate the sawtooth wave in slow manner\n");
@ -58,7 +63,7 @@ void user_init(void)
if (vout > VDD) vout = 0; if (vout > VDD) vout = 0;
printf("Vout: %.02f\n", vout); printf("Vout: %.02f\n", vout);
mcp4725_set_voltage(ADDR, VDD, vout, false); mcp4725_set_voltage(&dev, VDD, vout, false);
// It will be very low freq wave // It will be very low freq wave
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);

View file

@ -13,18 +13,20 @@
#include <i2c/i2c.h> #include <i2c/i2c.h>
#include <ms561101ba03/ms561101ba03.h> #include <ms561101ba03/ms561101ba03.h>
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
void user_init(void) void user_init(void)
{ {
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
ms561101ba03_t device = { ms561101ba03_t device = {
.addr = MS561101BA03_ADDR_CSB_LOW, .i2c_dev.bus = I2C_BUS,
.i2c_dev.addr = MS561101BA03_ADDR_CSB_LOW,
.osr = MS561101BA03_OSR_4096, .osr = MS561101BA03_OSR_4096,
}; };

View file

@ -11,8 +11,9 @@
#include <pca9685/pca9685.h> #include <pca9685/pca9685.h>
#include <stdio.h> #include <stdio.h>
#define ADDR 0x40 #define ADDR PCA9685_ADDR_BASE
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
@ -23,19 +24,23 @@ void user_init(void)
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
i2c_dev_t dev = {
.addr = ADDR,
.bus = I2C_BUS,
};
pca9685_init(ADDR); pca9685_init(&dev);
pca9685_set_pwm_frequency(ADDR, 1000); pca9685_set_pwm_frequency(&dev, 1000);
printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(ADDR)); printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(&dev));
uint16_t val = 0; uint16_t val = 0;
while (true) while (true)
{ {
printf("Set ch0 to %d, ch4 to %d\n", val, 4096 - val); printf("Set ch0 to %d, ch4 to %d\n", val, 4096 - val);
pca9685_set_pwm_value(ADDR, 0, val); pca9685_set_pwm_value(&dev, 0, val);
pca9685_set_pwm_value(ADDR, 4, 4096 - val); pca9685_set_pwm_value(&dev, 4, 4096 - val);
if (val++ == 4096) if (val++ == 4096)
val = 0; val = 0;

View file

@ -0,0 +1,3 @@
PROGRAM = pcf8591
EXTRA_COMPONENTS = extras/i2c extras/pcf8591
include ../../common.mk

42
examples/pcf8591/main.c Normal file
View file

@ -0,0 +1,42 @@
#include <stdio.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "i2c/i2c.h"
#include "pcf8591/pcf8591.h"
#define ADDR PCF8591_DEFAULT_ADDRESS
#define I2C_BUS 0
#define SCL_PIN 5
#define SDA_PIN 4
static void measure(void *pvParameters)
{
i2c_dev_t dev = {
.addr = ADDR,
.bus = I2C_BUS,
};
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("Value: %d\n", pcf8591_read(&dev, 0x03));
}
}
void user_init(void)
{
uart_set_baud(0, 115200);
// Just some information
printf("\n");
printf("SDK version : %s\n", sdk_system_get_sdk_version());
printf("GIT version : %s\n", GITSHORTREV);
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
xTaskCreate(measure, "measure_task", 256, NULL, 2, NULL);
}

23
examples/softuart/LICENSE Normal file
View file

@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
Copyright (c) 2015 plieningerweb
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.

View file

@ -0,0 +1,4 @@
PROGRAM = softuart
EXTRA_COMPONENTS = extras/softuart
ESPBAUD = 460800
include ../../common.mk

40
examples/softuart/main.c Normal file
View file

@ -0,0 +1,40 @@
/*
* Softuart example
*
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
* Copyright (c) 2015 plieningerweb
*
* MIT Licensed as described in the file LICENSE
*/
#include <esp/gpio.h>
#include <esp/uart.h>
#include <espressif/esp_common.h>
#include <stdio.h>
//#include <FreeRTOS.h>
//#include <task.h>
#include <softuart/softuart.h>
#define RX_PIN 5
#define TX_PIN 4
void user_init(void)
{
// setup real UART for now
uart_set_baud(0, 115200);
printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
// setup software uart to 9600 8n1
softuart_open(0, 9600, RX_PIN, TX_PIN);
while (true)
{
if (!softuart_available(0))
continue;
char c = softuart_read(0);
printf("input: %c, 0x%02x\n", c, c);
softuart_puts(0, "start\r\n");
}
}

View file

@ -23,6 +23,7 @@
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
#define PROTOCOL SSD1306_PROTO_I2C #define PROTOCOL SSD1306_PROTO_I2C
#define ADDR SSD1306_I2C_ADDR_0 #define ADDR SSD1306_I2C_ADDR_0
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
#else #else
@ -35,7 +36,8 @@
static const ssd1306_t dev = { static const ssd1306_t dev = {
.protocol = PROTOCOL, .protocol = PROTOCOL,
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
.addr = ADDR, .i2c_dev.bus = I2C_BUS,
.i2c_dev.addr = ADDR,
#else #else
.cs_pin = CS_PIN, .cs_pin = CS_PIN,
.dc_pin = DC_PIN, .dc_pin = DC_PIN,
@ -97,7 +99,7 @@ void user_init(void)
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
#endif #endif
while (ssd1306_init(&dev) != 0) while (ssd1306_init(&dev) != 0)

View file

@ -29,6 +29,7 @@
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
#define PROTOCOL SSD1306_PROTO_I2C #define PROTOCOL SSD1306_PROTO_I2C
#define ADDR SSD1306_I2C_ADDR_0 #define ADDR SSD1306_I2C_ADDR_0
#define I2C_BUS 0
#define SCL_PIN 5 #define SCL_PIN 5
#define SDA_PIN 4 #define SDA_PIN 4
#else #else
@ -43,7 +44,8 @@
static const ssd1306_t dev = { static const ssd1306_t dev = {
.protocol = PROTOCOL, .protocol = PROTOCOL,
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
.addr = ADDR, .i2c_dev.bus = I2C_BUS,
.i2c_dev.addr = ADDR,
#else #else
.cs_pin = CS_PIN, .cs_pin = CS_PIN,
.dc_pin = DC_PIN, .dc_pin = DC_PIN,
@ -162,7 +164,7 @@ void user_init(void)
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
#ifdef I2C_CONNECTION #ifdef I2C_CONNECTION
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
#endif #endif
while (ssd1306_init(&dev) != 0) { while (ssd1306_init(&dev) != 0) {

View file

@ -8,7 +8,7 @@ include ../../common.mk
# `make dump-flash` can be used to view the current contents of the sysparam # `make dump-flash` can be used to view the current contents of the sysparam
# regions in flash. # regions in flash.
dump-flash: dump-flash:
esptool.py read_flash 0x1f8000 8192 r1.bin esptool.py read_flash 0x1f7000 8192 r1.bin
hexdump -C r1.bin hexdump -C r1.bin
esptool.py read_flash 0x1fa000 8192 r2.bin esptool.py read_flash 0x1f9000 8192 r2.bin
hexdump -C r2.bin hexdump -C r2.bin

View file

@ -45,7 +45,7 @@ size_t tty_readline(char *buffer, size_t buf_size, bool echo) {
while (true) { while (true) {
c = getchar(); c = getchar();
if (c == '\r') { if (c == '\r' || c == '\n') {
if (echo) putchar('\n'); if (echo) putchar('\n');
break; break;
} else if (c == '\b' || c == 0x7f) { } else if (c == '\b' || c == 0x7f) {
@ -173,7 +173,7 @@ void sysparam_editor_task(void *pvParameters) {
// stuff, so if the user uses this utility to reformat it, it will put // stuff, so if the user uses this utility to reformat it, it will put
// it somewhere the system will find it later // it somewhere the system will find it later
num_sectors = DEFAULT_SYSPARAM_SECTORS; num_sectors = DEFAULT_SYSPARAM_SECTORS;
base_addr = sdk_flashchip.chip_size - (4 + num_sectors) * sdk_flashchip.sector_size; base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size;
} }
while (true) { while (true) {
printf("==> "); printf("==> ");
@ -246,5 +246,7 @@ void user_init(void)
{ {
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
sdk_wifi_set_opmode(NULL_MODE);
xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL); xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL);
} }

View file

@ -0,0 +1,10 @@
/**
Configuration overrides for FreeRTOS.
**/
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#include_next "FreeRTOSConfig.h"

View file

@ -0,0 +1,3 @@
# Simple makefile for simple example
PROGRAM=simple
include ../../common.mk

View file

@ -0,0 +1,56 @@
/* Very basic example that just demonstrates we can run at all!
*/
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
void vApplicationIdleHook(void)
{
// Go to sleep; either deeply (waiting for an event to wake)
// or light, allowing FreeRTOS ticks to wake
sdk_wifi_set_sleep_type(WIFI_SLEEP_MODEM);
}
void vApplicationTickHook(void)
{
// Called every tick
}
void task1(void *pvParameters)
{
QueueHandle_t *queue = (QueueHandle_t *)pvParameters;
printf("Hello from task1!\r\n");
uint32_t count = 0;
while(1) {
vTaskDelay(100);
xQueueSend(*queue, &count, 0);
count++;
}
}
void task2(void *pvParameters)
{
printf("Hello from task 2!\r\n");
QueueHandle_t *queue = (QueueHandle_t *)pvParameters;
while(1) {
uint32_t count;
if(xQueueReceive(*queue, &count, 1000)) {
printf("Got %u\n", count);
} else {
printf("No msg :(\n");
}
}
}
static QueueHandle_t mainqueue;
void user_init(void)
{
uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version());
mainqueue = xQueueCreate(10, sizeof(uint32_t));
xTaskCreate(task1, "tsk1", 256, &mainqueue, 2, NULL);
xTaskCreate(task2, "tsk2", 256, &mainqueue, 2, NULL);
}

View file

@ -43,7 +43,7 @@ extern const char *server_key;
errors at link time if functions don't exist.) */ errors at link time if functions don't exist.) */
#include "mbedtls/config.h" #include "mbedtls/config.h"
#include "mbedtls/net.h" #include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
#include "mbedtls/ssl.h" #include "mbedtls/ssl.h"
#include "mbedtls/entropy.h" #include "mbedtls/entropy.h"
@ -202,9 +202,8 @@ void tls_server_task(void *pvParameters)
socklen_t peer_addr_len = sizeof(struct sockaddr_in); socklen_t peer_addr_len = sizeof(struct sockaddr_in);
getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len); getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
unsigned char buf[256]; unsigned char buf[256];
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\nFree heap size is %d bytes\n", int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\nFree heap size is %d bytes\n",
ip4_addr1(&peer_addr.sin_addr), ip4_addr2(&peer_addr.sin_addr), IP2STR((ip4_addr_t *)&peer_addr.sin_addr.s_addr),
ip4_addr3(&peer_addr.sin_addr), ip4_addr4(&peer_addr.sin_addr),
peer_addr.sin_port, xPortGetFreeHeapSize()); peer_addr.sin_port, xPortGetFreeHeapSize());
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
{ {
@ -216,6 +215,7 @@ void tls_server_task(void *pvParameters)
} }
len = ret; len = ret;
ret = 0;
printf(" %d bytes written. Closing socket on client.\n\n%s", len, (char *) buf); printf(" %d bytes written. Closing socket on client.\n\n%s", len, (char *) buf);
mbedtls_ssl_close_notify(&ssl); mbedtls_ssl_close_notify(&ssl);

View file

@ -146,9 +146,8 @@ void tls_server_task(void *pvParameters)
/* Prepare a message to the client */ /* Prepare a message to the client */
unsigned char buf[100]; unsigned char buf[100];
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\r\nFree heap size is %d bytes\r\n", int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\r\nFree heap size is %d bytes\r\n",
ip4_addr1(&sa.sin_addr), ip4_addr2(&sa.sin_addr), IP2STR((ip4_addr_t *)&sa.sin_addr.s_addr),
ip4_addr3(&sa.sin_addr), ip4_addr4(&sa.sin_addr),
ntohs(sa.sin_port), xPortGetFreeHeapSize()); ntohs(sa.sin_port), xPortGetFreeHeapSize());
/* Send the message and close the connection */ /* Send the message and close the connection */

View file

@ -16,6 +16,7 @@
* Connect 3.3v from the ESP to Vin and GND to GND * Connect 3.3v from the ESP to Vin and GND to GND
*/ */
#define I2C_BUS (0)
#define SCL_PIN (2) #define SCL_PIN (2)
#define SDA_PIN (0) #define SDA_PIN (0)
@ -27,7 +28,8 @@ void tsl2561MeasurementTask(void *pvParameters)
// TSL2561_I2C_ADDR_VCC (0x49) // TSL2561_I2C_ADDR_VCC (0x49)
// TSL2561_I2C_ADDR_GND (0x29) // TSL2561_I2C_ADDR_GND (0x29)
// TSL2561_I2C_ADDR_FLOAT (0x39) Default // TSL2561_I2C_ADDR_FLOAT (0x39) Default
lightSensor.i2c_addr = TSL2561_I2C_ADDR_FLOAT; lightSensor.i2c_dev.bus = I2C_BUS;
lightSensor.i2c_dev.addr = TSL2561_I2C_ADDR_FLOAT;
tsl2561_init(&lightSensor); tsl2561_init(&lightSensor);
@ -63,7 +65,7 @@ void tsl2561MeasurementTask(void *pvParameters)
void user_init(void) void user_init(void)
{ {
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
i2c_init(SCL_PIN, SDA_PIN); i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
xTaskCreate(tsl2561MeasurementTask, "tsl2561MeasurementTask", 256, NULL, 2, NULL); xTaskCreate(tsl2561MeasurementTask, "tsl2561MeasurementTask", 256, NULL, 2, NULL);
} }

View file

@ -0,0 +1,3 @@
PROGRAM=tsl4531_example
EXTRA_COMPONENTS = extras/i2c extras/tsl4531
include ../../common.mk

View file

@ -0,0 +1,57 @@
/*
* This sample code is in the public domain.
*/
#include <stdio.h>
#include <stdlib.h>
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "i2c/i2c.h"
#include "task.h"
#include "tsl4531/tsl4531.h"
/* An example using the TSL4531 light sensor
* to read and print lux values from a sensor
* attached to GPIO pin 2 (SCL) and GPIO pin 0 (SDA)
* Connect 3.3v from the ESP to Vin and GND to GND
*/
#define I2C_BUS (0)
#define SCL_PIN (2)
#define SDA_PIN (0)
void tsl4531MeasurementTask(void *pvParameters)
{
tsl4531_t lightSensor;
lightSensor.i2c_dev.bus= I2C_BUS;
lightSensor.i2c_dev.addr= TSL4531_I2C_ADDR;
tsl4531_init(&lightSensor);
tsl4531_set_integration_time(&lightSensor, TSL4531_INTEGRATION_400MS);
tsl4531_set_power_save_skip(&lightSensor, true);
uint16_t lux = 0;
while (1)
{
if (tsl4531_read_lux(&lightSensor, &lux))
{
printf("Lux: %u\n", lux);
}
else
{
printf("Could not read data from TSL4531\n");
}
// 0.05 second delay
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
void user_init(void)
{
uart_set_baud(0, 115200);
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
xTaskCreate(tsl4531MeasurementTask, "tsl4531MeasurementTask", 256, NULL, 2, NULL);
}

5
examples/upnp/Makefile Normal file
View file

@ -0,0 +1,5 @@
PROGRAM=upnp_test
OTA=1
EXTRA_COMPONENTS=extras/rboot-ota
include ../../common.mk

3
examples/upnp/README.md Normal file
View file

@ -0,0 +1,3 @@
# upnp Example
This is an example to generate an upnp server and emulate a WeMo switch recognizable by Amazon echo Dot.

53
examples/upnp/httpd.c Normal file
View file

@ -0,0 +1,53 @@
#include <lwip/api.h>
#include <string.h>
#include <espressif/esp_common.h>
void httpd_task(void *pvParameters)
{
struct netconn *client = NULL;
struct netconn *nc = netconn_new(NETCONN_TCP);
if (nc == NULL) {
printf("Failed to allocate socket\n");
vTaskDelete(NULL);
}
netconn_bind(nc, IP_ADDR_ANY, 80);
netconn_listen(nc);
while (1) {
err_t err = netconn_accept(nc, &client);
if (err == ERR_OK) {
struct netbuf *nb;
if ((err = netconn_recv(client, &nb)) == ERR_OK) {
struct sdk_station_config config;
sdk_wifi_station_get_config(&config);
char * buf =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<root>\
<device>\
<deviceType>urn:Belkin:device:controllee:1</deviceType>\
<friendlyName>hello</friendlyName>\
<manufacturer>Belkin International Inc.</manufacturer>\
<modelName>Emulated Socket</modelName>\
<modelNumber>3.1415</modelNumber>\
<UDN>uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0</UDN>\
<serialNumber>221517K0101769</serialNumber>\
<binaryState>0</binaryState>\
<serviceList>\
<service>\
<serviceType>urn:Belkin:service:basicevent:1</serviceType>\
<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>\
<controlURL>/upnp/control/basicevent1</controlURL>\
<eventSubURL>/upnp/event/basicevent1</eventSubURL>\
<SCPDURL>/eventservice.xml</SCPDURL>\
</service>\
</serviceList>\
</device>\
</root>";
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
}
netbuf_delete(nb);
}
printf("Closing connection\n");
netconn_close(client);
netconn_delete(client);
}
}

3
examples/upnp/httpd.h Normal file
View file

@ -0,0 +1,3 @@
#include <lwip/api.h>
void httpd_task(void *pvParameters);

5
examples/upnp/lwipopts.h Normal file
View file

@ -0,0 +1,5 @@
#define LWIP_IGMP 1
/* Use the defaults for everything else */
#include_next <lwipopts.h>

135
examples/upnp/upnp.c Normal file
View file

@ -0,0 +1,135 @@
#include <string.h>
#include <lwip/udp.h>
#include <lwip/igmp.h>
#include <lwip/ip_addr.h>
#include <espressif/esp_common.h>
#include "upnp.h"
#define UPNP_MCAST_GRP ("239.255.255.250")
#define UPNP_MCAST_PORT (1900)
static const char* get_my_ip(void)
{
static char ip[16] = "0.0.0.0";
ip[0] = 0;
struct ip_info ipinfo;
(void) sdk_wifi_get_ip_info(STATION_IF, &ipinfo);
snprintf(ip, sizeof(ip), IPSTR, IP2STR(&ipinfo.ip));
return (char*) ip;
}
/**
* @brief This function joins a multicast group with the specified ip/port
* @param group_ip the specified multicast group ip
* @param group_port the specified multicast port number
* @param recv the lwip UDP callback
* @retval udp_pcb* or NULL if joining failed
*/
static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port))
{
bool status = false;
struct udp_pcb *upcb;
printf("Joining mcast group %s:%d\n", group_ip, group_port);
do {
upcb = udp_new();
if (!upcb) {
printf("Error, udp_new failed");
break;
}
udp_bind(upcb, IP4_ADDR_ANY, group_port);
struct netif* netif = sdk_system_get_netif(STATION_IF);
if (!netif) {
printf("Error, netif is null");
break;
}
if (!(netif->flags & NETIF_FLAG_IGMP)) {
netif->flags |= NETIF_FLAG_IGMP;
igmp_start(netif);
}
ip4_addr_t ipgroup;
ip4addr_aton(group_ip, &ipgroup);
err_t err = igmp_joingroup_netif(netif, &ipgroup);
if (ERR_OK != err) {
printf("Failed to join multicast group: %d", err);
break;
}
status = true;
} while(0);
if (status) {
printf("Join successs\n");
udp_recv(upcb, recv, upcb);
} else {
if (upcb) {
udp_remove(upcb);
}
upcb = NULL;
}
return upcb;
}
static void send_udp(struct udp_pcb *upcb, const ip_addr_t *addr, u16_t port)
{
struct pbuf *p;
char msg[500];
snprintf(msg, sizeof(msg),
"HTTP/1.1 200 OK\r\n"
"CACHE-CONTROL: max-age=86400\r\n"
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
"EXT:\r\n"
"LOCATION: http://%s:80/setup.xml\r\n"
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
"ST: urn:Belkin:device:**\r\n"
"USN: uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0::urn:Belkin:device:**\r\n"
"X-User-Agent: redsonic\r\n\r\n", get_my_ip());
p = pbuf_alloc(PBUF_TRANSPORT, strlen(msg)+1, PBUF_RAM);
if (!p) {
printf("Failed to allocate transport buffer\n");
} else {
memcpy(p->payload, msg, strlen(msg)+1);
err_t err = udp_sendto(upcb, p, addr, port);
if (err < 0) {
printf("Error sending message: %s (%d)\n", lwip_strerr(err), err);
} else {
printf("Sent message '%s'\n", msg);
}
pbuf_free(p);
}
}
/**
* @brief This function is called when an UDP datagrm has been received on the port UDP_PORT.
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @param port the remote port from which the packet was received
* @retval None
*/
static void receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
if (p) {
printf("Msg received port:%d len:%d\n", port, p->len);
uint8_t *buf = (uint8_t*) p->payload;
printf("Msg received port:%d len:%d\nbuf: %s\n", port, p->len, buf);
send_udp(upcb, addr, port);
pbuf_free(p);
}
}
/**
* @brief Initialize the upnp server
* @retval true if init was succcessful
*/
bool upnp_server_init(void)
{
struct udp_pcb *upcb = mcast_join_group(UPNP_MCAST_GRP, UPNP_MCAST_PORT, receive_callback);
return (upcb != NULL);
}

2
examples/upnp/upnp.h Normal file
View file

@ -0,0 +1,2 @@
bool upnp_server_init(void);

114
examples/upnp/upnp_test.c Normal file
View file

@ -0,0 +1,114 @@
#include <esp8266.h>
#include <espressif/esp_common.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <esp8266.h>
#include <esp/uart.h>
#include <stdio.h>
#include <FreeRTOS.h>
#include <semphr.h>
#include <task.h>
#include <timers.h>
#include <queue.h>
#include <ota-tftp.h>
#include <rboot-api.h>
#include <lwip/pbuf.h>
#include <lwip/udp.h>
#include <lwip/tcp.h>
#include <lwip/ip_addr.h>
#include <lwip/api.h>
#include <lwip/netbuf.h>
#include <lwip/igmp.h>
#include <ssid_config.h>
#include <espressif/esp_wifi.h>
#include "lwipopts.h"
#include "upnp.h"
#include "httpd.h"
/** User friendly FreeRTOS delay macro */
#define delay_ms(ms) vTaskDelay(ms / portTICK_PERIOD_MS)
/** Semaphore to signal wifi availability */
static SemaphoreHandle_t wifi_alive;
/**
* @brief This is the multicast task
* @param arg user supplied argument from xTaskCreate
* @retval None
*/
static void mcast_task(void *arg)
{
xSemaphoreTake(wifi_alive, portMAX_DELAY);
xSemaphoreGive(wifi_alive);
(void) upnp_server_init();
while(1) {
delay_ms(2000);
}
}
/**
* @brief This is the wifi connection task
* @param arg user supplied argument from xTaskCreate
* @retval None
*/
static void wifi_task(void *pvParameters)
{
uint8_t status = 0;
uint8_t retries = 30;
struct sdk_station_config config = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
};
xSemaphoreTake(wifi_alive, portMAX_DELAY);
printf("WiFi: connecting to WiFi\n");
sdk_wifi_set_opmode(STATION_MODE);
sdk_wifi_station_set_config(&config);
while(1) {
while (status != STATION_GOT_IP && retries) {
status = sdk_wifi_station_get_connect_status();
if(status == STATION_WRONG_PASSWORD) {
printf("WiFi: wrong password\n");
break;
} else if(status == STATION_NO_AP_FOUND) {
printf("WiFi: AP not found\n");
break;
} else if(status == STATION_CONNECT_FAIL) {
printf("WiFi: connection failed\n");
break;
}
delay_ms(1000);
retries--;
}
if (status == STATION_GOT_IP) {
printf("WiFi: connected\n");
xSemaphoreGive(wifi_alive);
taskYIELD();
}
while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) {
xSemaphoreGive(wifi_alive);
taskYIELD();
}
printf("WiFi: disconnected\n");
sdk_wifi_station_disconnect();
delay_ms(1000);
}
}
void user_init(void)
{
uart_set_baud(0, 115200);
vSemaphoreCreateBinary(wifi_alive);
ota_tftp_init_server(TFTP_PORT);
xTaskCreate(&wifi_task, "wifi_task", 256, NULL, 2, NULL);
delay_ms(250);
xTaskCreate(&httpd_task, "http_server", 1024, NULL, 4, NULL);
xTaskCreate(&mcast_task, "mcast_task", 1024, NULL, 4, NULL);
}

1
examples/wificfg/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
!local.mk

View file

@ -0,0 +1,7 @@
#define configUSE_TRACE_FACILITY 1
#define configGENERATE_RUN_TIME_STATS 1
#define portGET_RUN_TIME_COUNTER_VALUE() (RTC.COUNTER)
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() {}
/* Use the defaults for everything else */
#include_next<FreeRTOSConfig.h>

View file

@ -0,0 +1,5 @@
# Makefile for wificfg example
PROGRAM=wificfg
EXTRA_COMPONENTS=extras/dhcpserver extras/wificfg
include ../../common.mk

View file

@ -0,0 +1,18 @@
"<!DOCTYPE html><html lang=\"en\">"
"<head>"
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
"<script src=\"/script.js\"></script>"
"<title>",
"</title>"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"</head>"
"<body>"
"<ul class=\"topnav\" id=\"myTopnav\">"
"<li class=\"active\"><a href=\"/\">Home</a></li>"
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
"<li><a href=\"/tasks.html\">Tasks</a></li>"
"<li class=\"icon\">"
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">&#9776;</a>"
"</li>"
"</ul>",
"</body></html>"

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