Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
56ba21c081
299 changed files with 16208 additions and 13185 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,6 +1,6 @@
|
|||
[submodule "lwip/lwip"]
|
||||
path = lwip/lwip
|
||||
url = https://github.com/SuperHouse/esp-lwip.git
|
||||
url = https://github.com/ourairquality/lwip.git
|
||||
[submodule "extras/mbedtls/mbedtls"]
|
||||
path = extras/mbedtls/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls.git
|
||||
|
|
|
@ -2,7 +2,7 @@ language: c
|
|||
sudo: false
|
||||
env:
|
||||
# Target commit for https://github.com/pfalcon/esp-open-sdk/
|
||||
OPENSDK_COMMIT=a48b12f
|
||||
OPENSDK_COMMIT=b069537
|
||||
CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}"
|
||||
CROSS_BINDIR="${CROSS_ROOT}/bin"
|
||||
CROSS="ccache xtensa-lx106-elf-"
|
||||
|
@ -29,12 +29,14 @@ addons:
|
|||
- libncurses5-dev
|
||||
- libexpat1-dev
|
||||
- python
|
||||
- python-serial
|
||||
- python-pip
|
||||
- sed
|
||||
- git
|
||||
- help2man
|
||||
- vim-common
|
||||
|
||||
before_install:
|
||||
- pip install --user pyserial
|
||||
- travis_wait 30 utils/travis_build/install_toolchain.sh
|
||||
|
||||
script:
|
||||
|
|
|
@ -1,65 +1,61 @@
|
|||
The FreeRTOS.org source code is licensed by the *modified* GNU General Public
|
||||
License (GPL), text provided below. 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 FreeRTOS open source license covers the FreeRTOS source files,
|
||||
which are located in the /FreeRTOS/Source directory of the official FreeRTOS
|
||||
download. It also covers most of the source files in the demo application
|
||||
projects, which are located in the /FreeRTOS/Demo directory of the official
|
||||
FreeRTOS download. The demo projects may also include third party software that
|
||||
is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of
|
||||
third party software includes header files provided by chip or tools vendors,
|
||||
linker scripts, peripheral drivers, etc. All the software in subdirectories of
|
||||
the /FreeRTOS directory is either open source or distributed with permission,
|
||||
and is free for use. For the avoidance of doubt, refer to the comments at the
|
||||
top of each source file.
|
||||
|
||||
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
|
||||
of each source and header file for license and copyright information.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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).
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
that is was unblocked due to its required bits matching, rather
|
||||
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
|
||||
|
@ -633,9 +643,9 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
|
|||
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
||||
{
|
||||
/* Unblock the task, returning 0 as the event list is being deleted
|
||||
and cannot therefore have any bits set. */
|
||||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
and cannot therefore have any bits set. */
|
||||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
}
|
||||
|
||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||
|
|
|
@ -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
|
||||
|
||||
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.
|
||||
#endif
|
||||
|
||||
#if configMAX_PRIORITIES < 1
|
||||
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
|
||||
#endif
|
||||
|
||||
#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.
|
||||
#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.
|
||||
#endif
|
||||
|
||||
#ifndef configMAX_PRIORITIES
|
||||
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
|
||||
#endif
|
||||
|
||||
#ifndef configUSE_CO_ROUTINES
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#endif
|
||||
|
@ -408,6 +408,14 @@ extern "C" {
|
|||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||
#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. */
|
||||
|
||||
#ifndef traceMOVED_TASK_TO_READY_STATE
|
||||
|
@ -708,6 +716,10 @@ extern "C" {
|
|||
#define configUSE_TICKLESS_IDLE 0
|
||||
#endif
|
||||
|
||||
#ifndef configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING
|
||||
#define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( x )
|
||||
#endif
|
||||
|
||||
#ifndef configPRE_SLEEP_PROCESSING
|
||||
#define configPRE_SLEEP_PROCESSING( x )
|
||||
#endif
|
||||
|
@ -724,6 +736,10 @@ extern "C" {
|
|||
#define portTASK_USES_FLOATING_POINT()
|
||||
#endif
|
||||
|
||||
#ifndef portTASK_CALLS_SECURE_FUNCTIONS
|
||||
#define portTASK_CALLS_SECURE_FUNCTIONS()
|
||||
#endif
|
||||
|
||||
#ifndef configUSE_TIME_SLICING
|
||||
#define configUSE_TIME_SLICING 1
|
||||
#endif
|
||||
|
@ -782,6 +798,12 @@ extern "C" {
|
|||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#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. */
|
||||
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||
#if( INCLUDE_vTaskSuspend != 1 )
|
||||
|
@ -797,6 +819,10 @@ extern "C" {
|
|||
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
||||
#endif
|
||||
|
||||
#ifndef configINITIAL_TICK_COUNT
|
||||
#define configINITIAL_TICK_COUNT 0
|
||||
#endif
|
||||
|
||||
#if( portTICK_TYPE_IS_ATOMIC == 0 )
|
||||
/* Either variables of tick type cannot be read atomically, or
|
||||
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
|
||||
|
@ -917,7 +943,7 @@ typedef struct xSTATIC_TCB
|
|||
UBaseType_t uxDummy5;
|
||||
void *pxDummy6;
|
||||
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||
void *pxDummy8;
|
||||
#endif
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
@ -945,10 +971,14 @@ typedef struct xSTATIC_TCB
|
|||
uint32_t ulDummy18;
|
||||
uint8_t ucDummy19;
|
||||
#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;
|
||||
#endif
|
||||
|
||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||
uint8_t ucDummy21;
|
||||
#endif
|
||||
|
||||
} StaticTask_t;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
FreeRTOSConfig.h file in your program directory.
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
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.
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
The "blink" example in "examples/blink" provides an example of how
|
||||
to do this.
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
|
||||
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
|
||||
#define __DEFAULT_FREERTOS_CONFIG_H
|
||||
|
||||
|
@ -20,7 +43,7 @@
|
|||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html.
|
||||
*----------------------------------------------------------*/
|
||||
|
@ -47,7 +70,7 @@
|
|||
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
|
||||
#endif
|
||||
#ifndef configMAX_PRIORITIES
|
||||
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 )
|
||||
#define configMAX_PRIORITIES ( 15 )
|
||||
#endif
|
||||
#ifndef configMINIMAL_STACK_SIZE
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short )256 )
|
||||
|
@ -108,6 +131,10 @@
|
|||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
#endif
|
||||
|
||||
#ifndef configUSE_NEWLIB_REENTRANT
|
||||
#define configUSE_NEWLIB_REENTRANT 1
|
||||
#endif
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#ifndef INCLUDE_vTaskPrioritySet
|
||||
|
@ -144,5 +171,10 @@ to exclude the API function. */
|
|||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||
#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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
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
|
||||
{
|
||||
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 (). */
|
||||
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. */
|
||||
|
|
|
@ -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
|
||||
|
||||
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 );
|
||||
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_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
||||
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
|
||||
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
|
||||
void MPU_vTaskDelay( const TickType_t xTicksToDelay );
|
||||
|
@ -124,7 +125,9 @@ BaseType_t MPU_xTaskGetSchedulerState( void );
|
|||
|
||||
/* MPU versions of queue.h API function. */
|
||||
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
|
||||
BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek );
|
||||
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_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
|
||||
void MPU_vQueueDelete( QueueHandle_t xQueue );
|
||||
|
|
|
@ -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
|
||||
|
||||
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. */
|
||||
#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 uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
|
||||
#define vQueueDelete MPU_vQueueDelete
|
||||
|
@ -177,8 +179,11 @@ only for ports that are using the MPU. */
|
|||
#define xEventGroupSync MPU_xEventGroupSync
|
||||
#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_DATA __attribute__((section("privileged_data")))
|
||||
|
||||
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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
|
||||
|
||||
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>
|
||||
BaseType_t xQueuePeek(
|
||||
QueueHandle_t xQueue,
|
||||
void *pvBuffer,
|
||||
void * const pvBuffer,
|
||||
TickType_t xTicksToWait
|
||||
);</pre>
|
||||
*
|
||||
* This is a macro that calls the xQueueGenericReceive() function.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xQueueReceive xQueueReceive
|
||||
* \defgroup xQueuePeek xQueuePeek
|
||||
* \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
|
||||
|
@ -829,8 +827,6 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
|
|||
TickType_t xTicksToWait
|
||||
);</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
|
||||
* adequate size must be provided. The number of bytes copied into the buffer
|
||||
* was defined when the queue was created.
|
||||
|
@ -911,106 +907,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
|
|||
* \defgroup xQueueReceive xQueueReceive
|
||||
* \ingroup QueueManagement
|
||||
*/
|
||||
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
||||
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* For internal use only. Use xSemaphoreTakeMutexRecursive() or
|
||||
|
|
|
@ -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
|
||||
|
||||
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
|
||||
* \ingroup Semaphores
|
||||
*/
|
||||
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
|
||||
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
|
||||
|
||||
/**
|
||||
* semphr. h
|
||||
|
@ -392,23 +392,23 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||
|
||||
// ...
|
||||
// For some reason due to the nature of the code further calls to
|
||||
// xSemaphoreTakeRecursive() are made on the same mutex. In real
|
||||
// code these would not be just sequential calls as this would make
|
||||
// no sense. Instead the calls are likely to be buried inside
|
||||
// a more complex call structure.
|
||||
// xSemaphoreTakeRecursive() are made on the same mutex. In real
|
||||
// code these would not be just sequential calls as this would make
|
||||
// no sense. Instead the calls are likely to be buried inside
|
||||
// a more complex call structure.
|
||||
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
||||
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
||||
|
||||
// The mutex has now been 'taken' three times, so will not be
|
||||
// available to another task until it has also been given back
|
||||
// three times. Again it is unlikely that real code would have
|
||||
// these calls sequentially, but instead buried in a more complex
|
||||
// call structure. This is just for illustrative purposes.
|
||||
// available to another task until it has also been given back
|
||||
// three times. Again it is unlikely that real code would have
|
||||
// these calls sequentially, but instead buried in a more complex
|
||||
// call structure. This is just for illustrative purposes.
|
||||
xSemaphoreGiveRecursive( xMutex );
|
||||
xSemaphoreGiveRecursive( xMutex );
|
||||
xSemaphoreGiveRecursive( xMutex );
|
||||
xSemaphoreGiveRecursive( xMutex );
|
||||
xSemaphoreGiveRecursive( xMutex );
|
||||
|
||||
// Now the mutex can be taken by other tasks.
|
||||
// Now the mutex can be taken by other tasks.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1154,6 +1154,17 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
|||
*/
|
||||
#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
|
||||
* <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre>
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
@ -160,6 +160,9 @@ typedef struct xTASK_PARAMETERS
|
|||
UBaseType_t uxPriority;
|
||||
StackType_t *puxStackBuffer;
|
||||
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
|
||||
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||
StaticTask_t * const pxTaskBuffer;
|
||||
#endif
|
||||
} TaskParameters_t;
|
||||
|
||||
/* Used with the uxTaskGetSystemState() function to return the state of each task
|
||||
|
@ -269,7 +272,7 @@ is used in assert() statements. */
|
|||
BaseType_t xTaskCreate(
|
||||
TaskFunction_t pvTaskCode,
|
||||
const char * const pcName,
|
||||
uint16_t usStackDepth,
|
||||
configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void *pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *pvCreatedTask
|
||||
|
@ -358,11 +361,11 @@ is used in assert() statements. */
|
|||
*/
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint16_t usStackDepth,
|
||||
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -474,12 +477,12 @@ is used in assert() statements. */
|
|||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
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,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t * const puxStackBuffer,
|
||||
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
/**
|
||||
|
@ -487,6 +490,8 @@ is used in assert() statements. */
|
|||
*<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
|
||||
* implementation.
|
||||
*
|
||||
|
@ -494,6 +499,9 @@ is used in assert() statements. */
|
|||
* The function parameters define the memory regions and associated access
|
||||
* 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
|
||||
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
|
||||
* 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;
|
||||
#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
|
||||
*<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
|
||||
* 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
|
||||
* expires.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* priority. In this case the event list item value is updated to the value
|
||||
* passed in the xItemValue parameter.
|
||||
|
@ -2157,7 +2253,7 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
|
|||
* making the call, otherwise pdFALSE.
|
||||
*/
|
||||
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
|
||||
|
@ -2207,7 +2303,7 @@ BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
|
|||
* 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.
|
||||
*/
|
||||
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
|
||||
|
@ -2215,6 +2311,16 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -2258,6 +2364,13 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( 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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
||||
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"
|
||||
#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. */
|
||||
#include "task.h"
|
||||
/*lint +e537 */
|
||||
/*lint -restore */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -266,11 +266,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
|||
* @endverbatim
|
||||
*/
|
||||
#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 UBaseType_t uxAutoReload,
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -396,12 +396,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
|||
* @endverbatim
|
||||
*/
|
||||
#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 UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -73,10 +73,12 @@
|
|||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <xtensa_ops.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "xtensa_rtos.h"
|
||||
|
||||
unsigned cpu_sr;
|
||||
|
@ -91,6 +93,13 @@ char level1_int_disabled;
|
|||
*/
|
||||
void *xPortSupervisorStackPointer;
|
||||
|
||||
void vAssertCalled(const char * pcFile, unsigned long ulLine)
|
||||
{
|
||||
printf("rtos assert %s %lu\n", pcFile, ulLine);
|
||||
abort();
|
||||
//for (;;);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack initialization
|
||||
*/
|
||||
|
@ -100,7 +109,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
|
|||
portSTACK_TYPE *sp, *tp;
|
||||
|
||||
/* 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) */
|
||||
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_maclayer_sv;
|
||||
|
||||
/* PendSV is called in place of vPortYield() to request a supervisor
|
||||
call.
|
||||
|
||||
The portYIELD macro calls pendSV if it's a software request.
|
||||
|
||||
The libpp and libudhcp libraries also call this function, assuming
|
||||
always with arg==2 (but maybe sometimes with arg==1?)
|
||||
|
||||
In the original esp_iot_rtos_sdk implementation, arg was a char. Using an
|
||||
enum is ABI-compatible, though.
|
||||
*/
|
||||
/*
|
||||
* 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
|
||||
* are enabled which might be after exiting the critical region below.
|
||||
*
|
||||
* The wdev NMI calls this function from pp_post() with SVC_MACLayer to set a
|
||||
* pending interrupt service callback which flushs the queue of messages that
|
||||
* the NMI stashes away. This interrupt will be triggered after the return from
|
||||
* the NMI and when interrupts are enabled. The NMI can not touch the FreeRTOS
|
||||
* 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)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
|
||||
if(req == SVC_Software)
|
||||
{
|
||||
pending_soft_sv = 1;
|
||||
}
|
||||
else if(req == SVC_MACLayer)
|
||||
pending_maclayer_sv= 1;
|
||||
|
||||
WSR(BIT(INUM_SOFT), interrupt);
|
||||
vPortExitCritical();
|
||||
if (req == SVC_Software) {
|
||||
vPortEnterCritical();
|
||||
pending_soft_sv = 1;
|
||||
WSR(BIT(INUM_SOFT), interrupt);
|
||||
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
|
||||
|
@ -153,31 +161,24 @@ void IRAM PendSV(enum SVC_ReqType req)
|
|||
*/
|
||||
extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void);
|
||||
|
||||
void IRAM SV_ISR(void)
|
||||
void IRAM SV_ISR(void *arg)
|
||||
{
|
||||
portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE ;
|
||||
if(pending_maclayer_sv)
|
||||
{
|
||||
xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
|
||||
pending_maclayer_sv = 0;
|
||||
}
|
||||
if( xHigherPriorityTaskWoken || pending_soft_sv)
|
||||
{
|
||||
sdk__xt_timer_int1();
|
||||
pending_soft_sv = 0;
|
||||
}
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE ;
|
||||
if (pending_maclayer_sv) {
|
||||
xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
|
||||
pending_maclayer_sv = 0;
|
||||
}
|
||||
if (xHigherPriorityTaskWoken || pending_soft_sv) {
|
||||
sdk__xt_timer_int1();
|
||||
pending_soft_sv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void xPortSysTickHandle (void)
|
||||
{
|
||||
//CloseNMI();
|
||||
{
|
||||
if(xTaskIncrementTick() !=pdFALSE )
|
||||
{
|
||||
vTaskSwitchContext();
|
||||
}
|
||||
}
|
||||
//OpenNMI();
|
||||
if (xTaskIncrementTick() != pdFALSE) {
|
||||
vTaskSwitchContext();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -185,11 +186,11 @@ void xPortSysTickHandle (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));
|
||||
|
||||
/* 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));
|
||||
sdk__xt_tick_timer_init();
|
||||
|
||||
|
@ -221,8 +222,10 @@ size_t xPortGetFreeHeapSize( void )
|
|||
uint32_t brk_val = (uint32_t) sbrk(0);
|
||||
|
||||
intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
|
||||
if(sp == 0) /* scheduler not started */
|
||||
if (sp == 0) {
|
||||
/* scheduler not started */
|
||||
SP(sp);
|
||||
}
|
||||
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;
|
||||
|
||||
/* 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
|
||||
* with a save/restore of interrupt level, although it's difficult as
|
||||
* 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();
|
||||
uxCriticalNesting++;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void IRAM vPortExitCritical( void )
|
||||
{
|
||||
void IRAM vPortExitCritical(void) {
|
||||
uxCriticalNesting--;
|
||||
if( uxCriticalNesting == 0 )
|
||||
portENABLE_INTERRUPTS();
|
||||
if (uxCriticalNesting == 0)
|
||||
portENABLE_INTERRUPTS();
|
||||
}
|
||||
|
||||
/* Backward compatibility with libmain.a and libpp.a and can remove when these are open. */
|
||||
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 )
|
||||
{
|
||||
(void)puxStackBuffer; (void)xRegions;
|
||||
return xTaskCreate( pxTaskCode, (const char * const)pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
|
||||
/* 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) {
|
||||
(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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that has become a de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly and support the FreeRTOS *
|
||||
* project by purchasing a FreeRTOS tutorial book, reference *
|
||||
* manual, or both from: http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
* Thank you! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
>>! NOTE: The modification to the GPL is included to allow you to distribute
|
||||
>>! a combined work that includes FreeRTOS without being obliged to provide
|
||||
>>! the source code for proprietary components outside of the FreeRTOS
|
||||
>>! kernel.
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available from the following
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Having a problem? Start by reading the FAQ "My application does *
|
||||
* not run, what could be wrong?" *
|
||||
* *
|
||||
* 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 portLONG long
|
||||
#define portSHORT short
|
||||
#define portSTACK_TYPE unsigned portLONG
|
||||
#define portSTACK_TYPE uint32_t
|
||||
#define portBASE_TYPE long
|
||||
#define portPOINTER_SIZE_TYPE unsigned portLONG
|
||||
|
||||
typedef portSTACK_TYPE StackType_t;
|
||||
typedef portBASE_TYPE BaseType_t;
|
||||
typedef unsigned portBASE_TYPE UBaseType_t;
|
||||
|
||||
typedef uint32_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffff
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||
|
||||
/* Architecture specifics. */
|
||||
#define portSTACK_GROWTH ( -1 )
|
||||
|
@ -156,6 +119,9 @@ extern unsigned cpu_sr;
|
|||
prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
|
||||
the ps value in a local variable - that approach is recursive-safe
|
||||
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)
|
||||
{
|
||||
|
@ -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. */
|
||||
#define portTASK_FUNCTION_PROTO( 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
|
||||
|
|
20
FreeRTOS/Source/portable/readme.txt
Normal file
20
FreeRTOS/Source/portable/readme.txt
Normal 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.
|
||||
|
|
@ -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
|
||||
|
||||
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;
|
||||
#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 );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceQUEUE_CREATE_FAILED( ucQueueType );
|
||||
}
|
||||
|
||||
return pxNewQueue;
|
||||
}
|
||||
|
@ -422,6 +436,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
|
||||
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceQUEUE_CREATE_FAILED( ucQueueType );
|
||||
}
|
||||
|
||||
return pxNewQueue;
|
||||
}
|
||||
|
@ -567,6 +585,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
|||
#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 )
|
||||
|
||||
BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
|
||||
|
@ -643,7 +687,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
|||
}
|
||||
else
|
||||
{
|
||||
xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );
|
||||
xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait );
|
||||
|
||||
/* pdPASS will only be returned if the mutex was successfully
|
||||
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
|
||||
configure the timeout structure. */
|
||||
vTaskSetTimeOutState( &xTimeOut );
|
||||
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||
xEntryTimeSet = pdTRUE;
|
||||
}
|
||||
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
|
||||
priority disinheritance is needed. Simply increase the count of
|
||||
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
|
||||
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;
|
||||
TimeOut_t xTimeOut;
|
||||
int8_t *pcOriginalReadPosition;
|
||||
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
|
||||
configASSERT( pxQueue );
|
||||
configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
|
||||
/* 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. */
|
||||
|
@ -1263,44 +1313,19 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
must be the highest priority task wanting to access the queue. */
|
||||
if( uxMessagesWaiting > ( UBaseType_t ) 0 )
|
||||
{
|
||||
/* Remember the read position in case the queue is only being
|
||||
peeked. */
|
||||
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
|
||||
|
||||
/* Data available, remove one item. */
|
||||
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
||||
traceQUEUE_RECEIVE( pxQueue );
|
||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
|
||||
|
||||
if( xJustPeeking == pdFALSE )
|
||||
/* There is now space in the queue, were any tasks waiting to
|
||||
post to the queue? If so, unblock the highest priority waiting
|
||||
task. */
|
||||
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
|
||||
{
|
||||
traceQUEUE_RECEIVE( pxQueue );
|
||||
|
||||
/* Actually removing data, not just peeking. */
|
||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
|
||||
{
|
||||
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( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
|
||||
{
|
||||
queueYIELD_IF_USING_PREEMPTION();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
queueYIELD_IF_USING_PREEMPTION();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1309,30 +1334,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
}
|
||||
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();
|
||||
}
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
taskEXIT_CRITICAL();
|
||||
|
@ -1352,7 +1354,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
{
|
||||
/* The queue was empty and a block time was specified so
|
||||
configure the timeout structure. */
|
||||
vTaskSetTimeOutState( &xTimeOut );
|
||||
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||
xEntryTimeSet = pdTRUE;
|
||||
}
|
||||
else
|
||||
|
@ -1373,6 +1375,182 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
/* Update the timeout state to see if it has expired yet. */
|
||||
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 )
|
||||
{
|
||||
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
|
||||
|
@ -1383,7 +1561,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
{
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
||||
xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
@ -1407,13 +1585,193 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Try again. */
|
||||
/* There was no timeout and the semaphore count was not 0, so
|
||||
attempt to take the semaphore again. */
|
||||
prvUnlockQueue( pxQueue );
|
||||
( void ) xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
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 );
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
|
@ -1468,7 +1826,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
|||
traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
|
||||
|
||||
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.
|
||||
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 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#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 )
|
||||
{
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
|
@ -1767,7 +2152,7 @@ UBaseType_t uxMessagesWaiting;
|
|||
}
|
||||
}
|
||||
|
||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
|
||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
@ -2316,7 +2701,7 @@ BaseType_t xReturn;
|
|||
}
|
||||
|
||||
return pcReturn;
|
||||
}
|
||||
} /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */
|
||||
|
||||
#endif /* configQUEUE_REGISTRY_SIZE */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
@ -2395,7 +2780,7 @@ BaseType_t xReturn;
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
@ -2478,7 +2863,7 @@ BaseType_t xReturn;
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +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.
|
||||
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 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
|
||||
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 FreeRTOS/Source/include directory contains the real time kernel header
|
||||
files.
|
||||
+ 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.
|
||||
|
||||
See the readme file in the FreeRTOS/Source/Portable directory for more
|
||||
information.
|
|
@ -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
|
||||
|
||||
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
|
||||
task to be created using either statically or dynamically allocated RAM. Note
|
||||
that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
|
||||
a statically allocated stack and a dynamically allocated TCB. */
|
||||
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
|
||||
a statically allocated stack and a dynamically allocated TCB.
|
||||
!!!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 tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
|
||||
#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.
|
||||
*/
|
||||
|
@ -153,6 +164,12 @@ a statically allocated stack and a dynamically allocated TCB. */
|
|||
#define static
|
||||
#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 is 0 then task selection is
|
||||
|
@ -304,8 +321,8 @@ typedef struct tskTaskControlBlock
|
|||
StackType_t *pxStack; /*< Points to the start of the stack. */
|
||||
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
|
||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
|
||||
#endif
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
@ -327,7 +344,7 @@ typedef struct tskTaskControlBlock
|
|||
#endif
|
||||
|
||||
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
|
||||
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||
#endif
|
||||
|
||||
#if( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
@ -352,7 +369,7 @@ typedef struct tskTaskControlBlock
|
|||
|
||||
/* See the comments above the definition of
|
||||
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. */
|
||||
#endif
|
||||
|
||||
|
@ -366,8 +383,8 @@ typedef struct tskTaskControlBlock
|
|||
below to enable the use of older kernel aware debuggers. */
|
||||
typedef tskTCB TCB_t;
|
||||
|
||||
/*lint -e956 A manual analysis and inspection has been used to determine which
|
||||
static variables must be declared volatile. */
|
||||
/*lint -save -e956 A manual analysis and inspection has been used to determine
|
||||
which static variables must be declared volatile. */
|
||||
|
||||
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
|
||||
|
||||
|
@ -394,7 +411,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r
|
|||
|
||||
/* Other file private variables. --------------------------------*/
|
||||
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
|
||||
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U;
|
||||
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
|
||||
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
|
||||
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
|
||||
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
|
||||
|
@ -421,21 +438,27 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
|
|||
|
||||
#endif
|
||||
|
||||
/*lint +e956 */
|
||||
/*lint -restore */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Callback function prototypes. --------------------------*/
|
||||
#if( configCHECK_FOR_STACK_OVERFLOW > 0 )
|
||||
|
||||
extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
|
||||
|
||||
#endif
|
||||
|
||||
#if( configUSE_TICK_HOOK > 0 )
|
||||
|
||||
extern void vApplicationTickHook( void );
|
||||
|
||||
#endif
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
|
||||
|
||||
#endif
|
||||
|
||||
/* File private functions. --------------------------------*/
|
||||
|
@ -446,7 +469,9 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
|
|||
* is in any other state.
|
||||
*/
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif /* INCLUDE_vTaskSuspend */
|
||||
|
||||
/*
|
||||
|
@ -565,13 +590,13 @@ static void prvResetNextTaskUnblockTime( void );
|
|||
* dynamically to fill in the structure's members.
|
||||
*/
|
||||
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,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask,
|
||||
TCB_t *pxNewTCB,
|
||||
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* 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 )
|
||||
|
||||
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,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t * const puxStackBuffer,
|
||||
StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
StaticTask_t * const pxTaskBuffer )
|
||||
{
|
||||
TCB_t *pxNewTCB;
|
||||
TaskHandle_t xReturn;
|
||||
|
@ -597,6 +633,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
|||
configASSERT( puxStackBuffer != 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 ) )
|
||||
{
|
||||
/* 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->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
|
||||
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 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#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 )
|
||||
{
|
||||
|
@ -674,11 +767,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
|||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
|
||||
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint16_t usStackDepth,
|
||||
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void * const pvParameters,
|
||||
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;
|
||||
BaseType_t xReturn;
|
||||
|
@ -741,7 +834,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
|||
|
||||
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
|
||||
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,
|
||||
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,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask,
|
||||
TCB_t *pxNewTCB,
|
||||
const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
const MemoryRegion_t * const xRegions )
|
||||
{
|
||||
StackType_t *pxTopOfStack;
|
||||
UBaseType_t x;
|
||||
|
@ -791,12 +884,12 @@ UBaseType_t x;
|
|||
#endif /* portUSING_MPU_WRAPPERS == 1 */
|
||||
|
||||
/* Avoid dependency on memset() if it is not required. */
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||
#if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
|
||||
{
|
||||
/* Fill the stack with a known value to assist debugging. */
|
||||
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
|
||||
}
|
||||
#endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
|
||||
#endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
|
||||
|
||||
/* 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.
|
||||
|
@ -809,6 +902,14 @@ UBaseType_t x;
|
|||
|
||||
/* Check the alignment of the calculated top of stack is correct. */
|
||||
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 */
|
||||
{
|
||||
|
@ -936,7 +1037,7 @@ UBaseType_t x;
|
|||
/* Initialize the TCB stack to look as if the task was already running,
|
||||
but had been interrupted by the scheduler. The return address is set
|
||||
to the start of the task function. Once the stack has been initialised
|
||||
the top of stack variable is updated. */
|
||||
the top of stack variable is updated. */
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
{
|
||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
||||
|
@ -1515,14 +1616,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
|||
}
|
||||
|
||||
/* 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
|
||||
in the list appropriate to its new priority. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||
{
|
||||
/* The task is currently in its ready list - remove before adding
|
||||
it to it's new ready list. As we are in a critical section we
|
||||
can do this even if the scheduler is suspended. */
|
||||
/* The task is currently in its ready list - remove before
|
||||
adding it to it's new ready list. As we are in a critical
|
||||
section we can do this even if the scheduler is suspended. */
|
||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||
{
|
||||
/* 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 ) );
|
||||
|
||||
#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();
|
||||
|
||||
|
@ -1672,7 +1784,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
|||
{
|
||||
/* Is it in the suspended list because it is in the Suspended
|
||||
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;
|
||||
}
|
||||
|
@ -1716,12 +1828,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
|||
{
|
||||
traceTASK_RESUME( pxTCB );
|
||||
|
||||
/* As we are in a critical section we can access the ready
|
||||
lists even if the scheduler is suspended. */
|
||||
/* The ready list can be accessed even if the scheduler is
|
||||
suspended because this is inside a critical section. */
|
||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||
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 )
|
||||
{
|
||||
/* 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. */
|
||||
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
|
||||
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
|
||||
"IDLE",
|
||||
configIDLE_TASK_NAME,
|
||||
ulIdleTaskStackSize,
|
||||
( void * ) NULL,
|
||||
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
|
||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||
pxIdleTaskStackBuffer,
|
||||
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. */
|
||||
xReturn = xTaskCreate( prvIdleTask,
|
||||
"IDLE", configMINIMAL_STACK_SIZE,
|
||||
configIDLE_TASK_NAME,
|
||||
configMINIMAL_STACK_SIZE,
|
||||
( void * ) NULL,
|
||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
||||
|
@ -1880,6 +1993,15 @@ BaseType_t xReturn;
|
|||
|
||||
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
|
||||
before or during the call to xPortStartScheduler(). The stacks of
|
||||
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
|
||||
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();
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
TCB_t *pxTCB = ( TCB_t * ) xTask;
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
BaseType_t xReturn;
|
||||
|
||||
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. */
|
||||
if( eTaskGetState( xTask ) == eBlocked )
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
|
||||
/* Remove the reference to the task from the blocked list. An
|
||||
interrupt won't touch the xStateListItem because the
|
||||
scheduler is suspended. */
|
||||
|
@ -2485,10 +2612,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
|||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
@ -2510,13 +2637,13 @@ BaseType_t xSwitchRequired = pdFALSE;
|
|||
{
|
||||
/* Minor optimisation. The tick count cannot change in this
|
||||
block. */
|
||||
const TickType_t xConstTickCount = xTickCount + 1;
|
||||
const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
|
||||
|
||||
/* Increment the RTOS tick, switching the delayed and overflowed
|
||||
delayed lists if it wraps to 0. */
|
||||
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();
|
||||
}
|
||||
|
@ -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;
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
|
||||
the event flags implementation. */
|
||||
|
@ -2985,28 +3111,30 @@ BaseType_t xReturn;
|
|||
|
||||
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Return true if the task removed from the event list has
|
||||
a higher priority than the calling task. This allows
|
||||
the calling task to know if it should force a context
|
||||
switch now. */
|
||||
xReturn = pdTRUE;
|
||||
|
||||
/* Mark that a yield is pending in case the user is not using the
|
||||
"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
|
||||
/* The unblocked task has a priority above that of the calling task, so
|
||||
a context switch is required. This function is called with the
|
||||
scheduler suspended so xYieldPending is set so the context switch
|
||||
occurs immediately that the scheduler is resumed (unsuspended). */
|
||||
xYieldPending = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskSetTimeOutState( TimeOut_t * const 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->xTimeOnEntering = xTickCount;
|
||||
}
|
||||
|
@ -3023,6 +3151,7 @@ BaseType_t xReturn;
|
|||
{
|
||||
/* Minor optimisation. The tick count cannot change in this block. */
|
||||
const TickType_t xConstTickCount = xTickCount;
|
||||
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
|
||||
|
||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
|
||||
|
@ -3055,11 +3184,11 @@ BaseType_t xReturn;
|
|||
was called. */
|
||||
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. */
|
||||
*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
|
||||
vTaskSetTimeOutState( pxTimeOut );
|
||||
*pxTicksToWait -= xElapsedTime;
|
||||
vTaskInternalSetTimeOutState( pxTimeOut );
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
|
@ -3136,6 +3265,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
|||
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
|
||||
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( ;; )
|
||||
{
|
||||
/* 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 );
|
||||
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 )
|
||||
{
|
||||
traceLOW_POWER_IDLE_BEGIN();
|
||||
|
@ -3369,37 +3508,22 @@ static void prvCheckTasksWaitingTermination( void )
|
|||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
BaseType_t xListIsEmpty;
|
||||
TCB_t *pxTCB;
|
||||
|
||||
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
||||
too often in the idle task. */
|
||||
/* uxDeletedTasksWaitingCleanUp is used to prevent vTaskSuspendAll()
|
||||
being called too often in the idle task. */
|
||||
while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
|
||||
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
|
||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxDeletedTasksWaitingCleanUp;
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
if( xListIsEmpty == pdFALSE )
|
||||
{
|
||||
TCB_t *pxTCB;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
|
||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxDeletedTasksWaitingCleanUp;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
prvDeleteTCB( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
prvDeleteTCB( pxTCB );
|
||||
}
|
||||
}
|
||||
#endif /* INCLUDE_vTaskDelete */
|
||||
|
@ -3421,25 +3545,6 @@ static void prvCheckTasksWaitingTermination( void )
|
|||
pxTaskStatus->pxStackBase = pxTCB->pxStack;
|
||||
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 )
|
||||
{
|
||||
pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
|
||||
|
@ -3460,12 +3565,38 @@ static void prvCheckTasksWaitingTermination( void )
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Obtaining the task state is a little fiddly, so is only done if the value
|
||||
of eState passed into this function is eInvalid - otherwise the state is
|
||||
just set to whatever is passed in. */
|
||||
/* Obtaining the task state is a little fiddly, so is only done if the
|
||||
value of eState passed into this function is eInvalid - otherwise the
|
||||
state is just set to whatever is passed in. */
|
||||
if( eState != eInvalid )
|
||||
{
|
||||
pxTaskStatus->eCurrentState = eState;
|
||||
if( pxTCB == pxCurrentTCB )
|
||||
{
|
||||
pxTaskStatus->eCurrentState = eRunning;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
|
@ -3499,7 +3630,7 @@ static void prvCheckTasksWaitingTermination( void )
|
|||
|
||||
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;
|
||||
|
||||
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
|
||||
|
@ -3600,7 +3731,7 @@ static void prvCheckTasksWaitingTermination( void )
|
|||
vPortFree( pxTCB->pxStack );
|
||||
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
|
||||
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
|
||||
nothing needs to be freed. */
|
||||
configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB )
|
||||
configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
|
@ -3703,25 +3834,27 @@ TCB_t *pxTCB;
|
|||
|
||||
#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
|
||||
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 the holder of the mutex has a priority below the priority of
|
||||
the task attempting to obtain the mutex then it will temporarily
|
||||
inherit the priority of the task attempting to obtain the mutex. */
|
||||
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||
if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Adjust the mutex holder state to account for its new
|
||||
priority. 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 )
|
||||
not being used for anything else. */
|
||||
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
|
||||
{
|
||||
|
@ -3730,11 +3863,11 @@ TCB_t *pxTCB;
|
|||
|
||||
/* If the task being modified is in the ready state it will need
|
||||
to be moved into a new list. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||
if( 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
|
||||
{
|
||||
|
@ -3742,26 +3875,45 @@ TCB_t *pxTCB;
|
|||
}
|
||||
|
||||
/* Inherit the priority before being moved into the new list. */
|
||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
prvAddTaskToReadyList( pxTCB );
|
||||
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
prvAddTaskToReadyList( pxMutexHolderTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
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
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* configUSE_MUTEXES */
|
||||
|
@ -3781,7 +3933,6 @@ TCB_t *pxTCB;
|
|||
interrupt, and if a mutex is given by the holding task then it must
|
||||
be the running state task. */
|
||||
configASSERT( pxTCB == pxCurrentTCB );
|
||||
|
||||
configASSERT( pxTCB->uxMutexesHeld );
|
||||
( pxTCB->uxMutexesHeld )--;
|
||||
|
||||
|
@ -3795,8 +3946,8 @@ TCB_t *pxTCB;
|
|||
/* A task can only have an inherited priority if it holds
|
||||
the mutex. If the mutex is held by a task then it cannot be
|
||||
given from an interrupt, and if a mutex is given by the
|
||||
holding task then it must be the running state task. Remove
|
||||
the holding task from the ready list. */
|
||||
holding task then it must be the running state task. Remove
|
||||
the holding task from the ready list. */
|
||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||
{
|
||||
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
||||
|
@ -3848,6 +3999,108 @@ TCB_t *pxTCB;
|
|||
#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 )
|
||||
|
||||
void vTaskEnterCritical( void )
|
||||
|
@ -3937,7 +4190,7 @@ TCB_t *pxTCB;
|
|||
#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 )
|
||||
{
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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 )
|
||||
|
@ -4240,7 +4493,7 @@ TickType_t uxReturn;
|
|||
}
|
||||
else
|
||||
{
|
||||
pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
|
||||
pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4315,7 +4568,7 @@ TickType_t uxReturn;
|
|||
blocked state (because a notification was already pending) or the
|
||||
task unblocked because of a notification. Otherwise the task
|
||||
unblocked because of a timeout. */
|
||||
if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
|
||||
if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
|
||||
{
|
||||
/* A notification was not received. */
|
||||
xReturn = pdFALSE;
|
||||
|
@ -4800,8 +5053,24 @@ const TickType_t xConstTickCount = xTickCount;
|
|||
#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
|
||||
#include "tasks_test_access_functions.h"
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
||||
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. */
|
||||
#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. */
|
||||
typedef struct tmrTimerControl
|
||||
{
|
||||
|
@ -158,8 +164,8 @@ typedef struct tmrTimerQueueMessage
|
|||
} u;
|
||||
} DaemonTaskMessage_t;
|
||||
|
||||
/*lint -e956 A manual analysis and inspection has been used to determine which
|
||||
static variables must be declared volatile. */
|
||||
/*lint -save -e956 A manual analysis and inspection has been used to determine
|
||||
which static variables must be declared volatile. */
|
||||
|
||||
/* 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
|
||||
|
@ -173,7 +179,7 @@ PRIVILEGED_DATA static List_t *pxOverflowTimerList;
|
|||
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = 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
|
||||
* 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 UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xTimerCreateTimerTask( void )
|
||||
|
@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
|
|||
|
||||
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
||||
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
||||
"Tmr Svc",
|
||||
configTIMER_SERVICE_TASK_NAME,
|
||||
ulTimerTaskStackSize,
|
||||
NULL,
|
||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||
|
@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
|
|||
#else
|
||||
{
|
||||
xReturn = xTaskCreate( prvTimerTask,
|
||||
"Tmr Svc",
|
||||
configTIMER_SERVICE_TASK_NAME,
|
||||
configTIMER_TASK_STACK_DEPTH,
|
||||
NULL,
|
||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||
|
@ -311,11 +317,11 @@ BaseType_t xReturn = pdFAIL;
|
|||
|
||||
#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 UBaseType_t uxAutoReload,
|
||||
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;
|
||||
|
||||
|
@ -343,12 +349,12 @@ BaseType_t xReturn = pdFAIL;
|
|||
|
||||
#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 UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
StaticTimer_t *pxTimerBuffer )
|
||||
{
|
||||
Timer_t *pxNewTimer;
|
||||
|
||||
|
@ -356,7 +362,7 @@ BaseType_t xReturn = pdFAIL;
|
|||
{
|
||||
/* Sanity check that the size of the structure used to declare a
|
||||
variable of type StaticTimer_t equals the size of the real timer
|
||||
structures. */
|
||||
structure. */
|
||||
volatile size_t xSize = sizeof( StaticTimer_t );
|
||||
configASSERT( xSize == sizeof( Timer_t ) );
|
||||
}
|
||||
|
@ -385,12 +391,12 @@ BaseType_t xReturn = pdFAIL;
|
|||
#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 UBaseType_t uxAutoReload,
|
||||
void * const pvTimerID,
|
||||
TimerCallbackFunction_t pxCallbackFunction,
|
||||
Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
Timer_t *pxNewTimer )
|
||||
{
|
||||
/* 0 is not a valid value for xTimerPeriodInTicks. */
|
||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
||||
|
@ -760,7 +766,7 @@ TickType_t xTimeNow;
|
|||
software timer. */
|
||||
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. */
|
||||
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
|
||||
|
@ -945,10 +951,10 @@ static void prvCheckForValidListAndQueue( void )
|
|||
{
|
||||
/* The timer queue is allocated statically in case
|
||||
configSUPPORT_DYNAMIC_ALLOCATION is 0. */
|
||||
static StaticQueue_t xStaticTimerQueue;
|
||||
static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ];
|
||||
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[ ( 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
|
||||
{
|
||||
|
@ -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
|
||||
it is referenced from either the current or the overflow timer lists in
|
||||
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();
|
||||
|
||||
|
|
|
@ -78,8 +78,8 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
|
|||
## Open Source Components
|
||||
|
||||
* [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.
|
||||
* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
|
||||
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v2.0.3, with [some modifications](https://github.com/ourairquality/lwip/).
|
||||
* [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).
|
||||
|
||||
|
|
24
common.mk
24
common.mk
|
@ -160,6 +160,26 @@ endif
|
|||
-include $$($(1)_OBJ_FILES:.o=.d)
|
||||
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
|
||||
## SDK libraries are preprocessed to:
|
||||
# - remove object files named in <libname>.remove
|
||||
|
@ -208,9 +228,9 @@ $(foreach component,$(COMPONENTS), \
|
|||
)
|
||||
|
||||
# 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 $@"
|
||||
$(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:
|
||||
$(Q) mkdir -p $@
|
||||
|
|
|
@ -214,8 +214,8 @@ void IRAM sdk_user_start(void) {
|
|||
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
|
||||
// top of the flash space
|
||||
sysparam_addr = flash_size - (4 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
|
||||
// top of the flash space, and allowing one extra sector spare.
|
||||
sysparam_addr = flash_size - (5 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
|
||||
status = sysparam_init(sysparam_addr, flash_size);
|
||||
if (status == SYSPARAM_NOTFOUND) {
|
||||
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
|
||||
void IRAM vApplicationIdleHook(void) {
|
||||
void __attribute__((weak)) IRAM vApplicationIdleHook(void) {
|
||||
printf("idle %u\n", WDEV.SYS_TIME);
|
||||
}
|
||||
|
||||
// .text+0x404
|
||||
void IRAM vApplicationTickHook(void) {
|
||||
void __attribute__((weak)) IRAM vApplicationTickHook(void) {
|
||||
printf("tick %u\n", WDEV.SYS_TIME);
|
||||
}
|
||||
|
||||
|
@ -311,8 +311,8 @@ static void init_g_ic(void) {
|
|||
if (sdk_g_ic.s._unknown310 > 4) {
|
||||
sdk_g_ic.s._unknown310 = 4;
|
||||
}
|
||||
if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) {
|
||||
bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4));
|
||||
if (sdk_g_ic.s.sta_ssid.ssid_length == 0xffffffff) {
|
||||
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));
|
||||
}
|
||||
sdk_g_ic.s.wifi_led_enable = 0;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "esp/dport_regs.h"
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esplibs/libmain.h"
|
||||
#include "user_exception.h"
|
||||
|
||||
/* Forward declarations */
|
||||
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 void (*user_exception_handler)(void) = NULL;
|
||||
|
||||
/* fatal_exception_handler called from any unhandled user exception
|
||||
*
|
||||
* (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_Enable(0, 0, 1);
|
||||
|
||||
if (user_exception_handler != NULL) {
|
||||
user_exception_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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();
|
||||
post_crash_reset();
|
||||
}
|
||||
|
||||
void set_user_exception_handler(void (*fn)(void))
|
||||
{
|
||||
user_exception_handler = fn;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
void __attribute__((weak)) IRAM gpio_interrupt_handler(void)
|
||||
void __attribute__((weak)) IRAM gpio_interrupt_handler(void *arg)
|
||||
{
|
||||
uint32_t status_reg = GPIO.STATUS;
|
||||
GPIO.STATUS_CLEAR = status_reg;
|
||||
|
||||
uint8_t gpio_idx;
|
||||
while((gpio_idx = __builtin_ffs(status_reg)))
|
||||
while ((gpio_idx = __builtin_ffs(status_reg)))
|
||||
{
|
||||
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];
|
||||
if (handler) {
|
||||
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.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
|
||||
if(int_type != GPIO_INTTYPE_NONE) {
|
||||
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
|
||||
if (int_type != GPIO_INTTYPE_NONE) {
|
||||
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler, NULL);
|
||||
_xt_isr_unmask(1<<INUM_GPIO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,13 @@
|
|||
#include <esp/wdev_regs.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Return a random 32-bit number */
|
||||
uint32_t hwrand(void)
|
||||
/* Return a random 32-bit number.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,19 @@
|
|||
*/
|
||||
#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;
|
||||
|
||||
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.
|
||||
|
@ -25,17 +31,20 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset)
|
|||
esp_in_isr = true;
|
||||
|
||||
/* WDT has highest priority (occasional WDT resets otherwise) */
|
||||
if(intset & BIT(INUM_WDT)) {
|
||||
if (intset & BIT(INUM_WDT)) {
|
||||
_xt_clear_ints(BIT(INUM_WDT));
|
||||
isr[INUM_WDT]();
|
||||
isr[INUM_WDT].handler(NULL);
|
||||
intset -= BIT(INUM_WDT);
|
||||
}
|
||||
|
||||
while(intset) {
|
||||
while (intset) {
|
||||
uint8_t index = __builtin_ffs(intset) - 1;
|
||||
uint16_t mask = BIT(index);
|
||||
_xt_clear_ints(mask);
|
||||
isr[index]();
|
||||
_xt_isr handler = isr[index].handler;
|
||||
if (handler) {
|
||||
handler(isr[index].arg);
|
||||
}
|
||||
intset -= mask;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,22 @@ inline static void _start(uint8_t bus)
|
|||
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)
|
||||
{
|
||||
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);
|
||||
size_t bytes = len * (uint8_t)word_size;
|
||||
_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);
|
||||
_start(bus);
|
||||
_wait(bus);
|
||||
|
@ -221,23 +237,36 @@ uint32_t spi_transfer_32(uint8_t bus, uint32_t data)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void _rearm_extras_bit(uint8_t bus, bool arm) {
|
||||
|
||||
if(!_minimal_pins[bus]) return ;
|
||||
static uint8_t status[2] ;
|
||||
static void _rearm_extras_bit(uint8_t bus, bool arm)
|
||||
{
|
||||
if (!_minimal_pins[bus]) return;
|
||||
static uint8_t status[2];
|
||||
|
||||
if (arm)
|
||||
{
|
||||
if (status[bus] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR) ;
|
||||
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] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR);
|
||||
if (status[bus] & 0x02) SPI(bus).USER0 |= (SPI_USER0_COMMAND);
|
||||
if (status[bus] & 0x04)
|
||||
SPI(bus).USER0 |= (SPI_USER0_DUMMY | SPI_USER0_MISO);
|
||||
status[bus] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SPI(bus).USER0 & SPI_USER0_ADDR) { 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 ; }
|
||||
if (SPI(bus).USER0 & SPI_USER0_ADDR)
|
||||
{
|
||||
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;
|
||||
_spi_buf_transfer(bus, (const uint8_t *)out_data + offset,
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
if (blocks) _rearm_extras_bit(bus, true) ;
|
||||
if (blocks) _rearm_extras_bit(bus, true);
|
||||
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 ;
|
||||
while(*repeats > 0)
|
||||
uint8_t i = 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);
|
||||
if (i) _rearm_extras_bit(bus, false) ;
|
||||
_set_size(bus,bytes_to_transfer);
|
||||
for(i = 0; i < (bytes_to_transfer + 3) / 4;i++)
|
||||
if (i) _rearm_extras_bit(bus, false);
|
||||
_set_size(bus, bytes_to_transfer);
|
||||
for (i = 0; i < (bytes_to_transfer + 3) / 4; i++)
|
||||
SPI(bus).W[i] = *dword; //need test with memcpy !
|
||||
_start(bus);
|
||||
*repeats -= (bytes_to_transfer / size ) ;
|
||||
*repeats -= (bytes_to_transfer / size);
|
||||
}
|
||||
_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;
|
||||
_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;
|
||||
_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);
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num);
|
|||
*
|
||||
* Example:
|
||||
*
|
||||
* void IRAM gpio_interrupt_handler(void) {
|
||||
* void IRAM gpio_interrupt_handler(void *arg) {
|
||||
* // check GPIO.STATUS
|
||||
* // write GPIO.STATUS_CLEAR
|
||||
* // Do something when GPIO changes
|
||||
|
|
|
@ -35,19 +35,37 @@ typedef enum {
|
|||
INUM_TIMER_FRC2 = 10,
|
||||
} xt_isr_num_t;
|
||||
|
||||
void sdk__xt_int_exit (void);
|
||||
void _xt_user_exit (void);
|
||||
void sdk__xt_tick_timer_init (void);
|
||||
void sdk__xt_timer_int(void);
|
||||
void sdk__xt_int_exit(void);
|
||||
void _xt_user_exit(void);
|
||||
void sdk__xt_tick_timer_init(void);
|
||||
void sdk__xt_timer_int(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)
|
||||
{
|
||||
uint32_t level;
|
||||
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
|
||||
return level;
|
||||
__asm__ volatile("rsr %0, ps" : "=a"(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
|
||||
_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));
|
||||
}
|
||||
|
||||
/* ESPTODO: the mask/unmask functions aren't thread safe */
|
||||
|
||||
static inline void _xt_isr_unmask(uint32_t unmask)
|
||||
static inline uint32_t _xt_isr_unmask(uint32_t unmask)
|
||||
{
|
||||
uint32_t old_level = _xt_disable_interrupts();
|
||||
uint32_t intenable;
|
||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||
intenable |= unmask;
|
||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
||||
asm volatile ("wsr %0, intenable;" :: "a" (intenable | unmask));
|
||||
_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;
|
||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||
intenable &= ~mask;
|
||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
||||
asm volatile ("wsr %0, intenable;" :: "a" (intenable & ~mask));
|
||||
_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;
|
||||
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));
|
||||
}
|
||||
|
||||
typedef void (* _xt_isr)(void);
|
||||
/* This function is implemeneted in FreeRTOS port.c at the moment,
|
||||
should be moved or converted to an inline */
|
||||
void _xt_isr_attach (uint8_t i, _xt_isr func);
|
||||
typedef void (* _xt_isr)(void *arg);
|
||||
void _xt_isr_attach (uint8_t i, _xt_isr func, void *arg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,4 +36,6 @@ typedef struct {
|
|||
uint32_t status_mask;
|
||||
} sdk_flashchip_t;
|
||||
|
||||
extern sdk_flashchip_t sdk_flashchip;
|
||||
|
||||
#endif /* _FLASHCHIP_H */
|
||||
|
|
|
@ -14,25 +14,25 @@
|
|||
// 'info' is declared in app_main.o at .bss+0x4
|
||||
|
||||
struct sdk_info_st {
|
||||
ip_addr_t softap_ipaddr; // 0x00
|
||||
ip_addr_t softap_netmask; // 0x04
|
||||
ip_addr_t softap_gw; // 0x08
|
||||
ip_addr_t sta_ipaddr; // 0x0c
|
||||
ip_addr_t sta_netmask; // 0x10
|
||||
ip_addr_t sta_gw; // 0x14
|
||||
ip4_addr_t softap_ipaddr; // 0x00
|
||||
ip4_addr_t softap_netmask; // 0x04
|
||||
ip4_addr_t softap_gw; // 0x08
|
||||
ip4_addr_t sta_ipaddr; // 0x0c
|
||||
ip4_addr_t sta_netmask; // 0x10
|
||||
ip4_addr_t sta_gw; // 0x14
|
||||
uint8_t softap_mac_addr[6]; // 0x18
|
||||
uint8_t sta_mac_addr[6]; // 0x1e
|
||||
};
|
||||
|
||||
|
||||
struct _unknown_info1 {
|
||||
struct wl_channel {
|
||||
uint8_t _unknown00;
|
||||
uint8_t _unknown01;
|
||||
uint8_t _unknown02;
|
||||
uint8_t _unknown03;
|
||||
uint8_t _unknown04;
|
||||
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 _unknown07[2];
|
||||
|
||||
|
@ -98,17 +98,19 @@ struct sdk_netif_conninfo {
|
|||
|
||||
uint32_t _unknown1c[23];
|
||||
|
||||
struct _unknown_info1 *_unknown78; // eagle_auth_done
|
||||
struct wl_channel *channel; // 0x78 eagle_auth_done
|
||||
|
||||
uint32_t _unknown7c[8];
|
||||
|
||||
uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called.
|
||||
uint16_t _unknown9e;
|
||||
|
||||
uint32_t _unknowna0[18];
|
||||
uint32_t _unknowna0[17];
|
||||
|
||||
int8_t _unknowne8; //
|
||||
int8_t _unknowne9; // ppInstallKey
|
||||
void *_unknowne4;
|
||||
|
||||
uint8_t _unknowne8; //
|
||||
uint8_t _unknowne9; // ppInstallKey
|
||||
int8_t _unknownea;
|
||||
int8_t _unknowneb;
|
||||
|
||||
|
@ -128,9 +130,9 @@ struct sdk_g_ic_netif_info {
|
|||
uint32_t _unknown48; // 0x48
|
||||
uint8_t _unknown4c; // 0x4c
|
||||
uint8_t _unknown4d[59]; // 0x4d - 0x88
|
||||
struct sdk_netif_conninfo *_unknown88; // 0x88
|
||||
struct sdk_cnx_node *_unknown88; // 0x88
|
||||
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
|
||||
struct _unknown_softap1 *_unknownb4;
|
||||
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 {
|
||||
uint16_t _unknown1e4; // sdk_wpa_config_profile
|
||||
uint16_t _unknown1e6; // sdk_wpa_config_profile
|
||||
uint8_t sta_ssid[32]; // 0x1e8 Station ssid. Null terminated string.
|
||||
struct sdk_g_ic_ssid_with_length {
|
||||
uint32_t ssid_length; // 0x1e4 sdk_wpa_config_profile
|
||||
uint8_t 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
|
||||
|
@ -224,7 +225,8 @@ struct sdk_g_ic_saved_st {
|
|||
uint8_t wifi_led_gpio;
|
||||
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 _unknown209; // sdk_wpa_config_profile
|
||||
|
@ -260,7 +262,7 @@ struct sdk_g_ic_saved_st {
|
|||
uint8_t _unknown30d; // result of ieee80211_chan2ieee
|
||||
uint8_t _unknown30e;
|
||||
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];
|
||||
|
||||
|
@ -320,7 +322,7 @@ struct esf_buf {
|
|||
_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 _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(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(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct");
|
||||
|
||||
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown78) == 0x78, "bad struct");
|
||||
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown108) == 0x108, "bad struct");
|
||||
_Static_assert(offsetof(struct sdk_cnx_node, channel) == 0x78, "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");
|
||||
|
||||
|
@ -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(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(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
|
||||
// lwip and and not used by lwip so just ensure this slot is at the expected
|
||||
// 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
|
||||
// remain, but the content of this slot should not change in future versions of
|
||||
// lwip, so just ensure it is at the expected offset.
|
||||
_Static_assert(offsetof(struct netif, hwaddr) == 41, "netif->hwaddr offset wrong!");
|
||||
// lwip, so just ensure it is at the expected offset. Note the sdk binary
|
||||
// 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
|
||||
// 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!");
|
||||
_Static_assert(offsetof(struct pbuf, esf_buf) == 16, "pbuf->esf_buf offset wrong!");
|
||||
|
||||
|
||||
/// Misc.
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __ESP_SPIFFS_FLASH_H__
|
||||
#define __ESP_SPIFFS_FLASH_H__
|
||||
#ifndef __SPIFLASH_H__
|
||||
#define __SPIFLASH_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "common_macros.h"
|
||||
|
||||
#define ESP_SPIFFS_FLASH_OK 0
|
||||
#define ESP_SPIFFS_FLASH_ERROR 1
|
||||
#define SPI_FLASH_SECTOR_SIZE 4096
|
||||
|
||||
/**
|
||||
* Read data from SPI flash.
|
||||
|
@ -37,9 +37,9 @@
|
|||
* @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.
|
||||
*
|
||||
* @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.
|
||||
|
@ -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 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.
|
||||
*
|
||||
* @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__
|
|
@ -119,7 +119,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr);
|
|||
* you reformat the area currently being used, you will also need to call
|
||||
* sysparam_init() again afterward before you will be able to continue using
|
||||
* it.
|
||||
*/
|
||||
*/
|
||||
sysparam_status_t sysparam_create_area(uint32_t base_addr, uint16_t num_sectors, bool force);
|
||||
|
||||
/** Get the start address and size of the currently active sysparam area
|
||||
|
@ -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);
|
||||
|
||||
/** 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
|
||||
* performing any memory allocations. It can thus be used before the heap has
|
||||
* been configured or in other cases where using the heap would be a problem
|
||||
* (i.e. in an OOM handler, etc). It requires that the caller pass in 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
|
||||
* required 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.
|
||||
* allocating memory for the result value. It can thus be used before the heap
|
||||
* has been configured or in other cases where using the heap would be a
|
||||
* problem (i.e. in an OOM handler, etc). It requires that the caller pass in
|
||||
* 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 required
|
||||
* length will be returned in `actual_length`).
|
||||
*
|
||||
* @param[in] key Key name (zero-terminated string)
|
||||
* @param[in] buffer Pointer to a buffer to hold the returned value
|
||||
* @param[in] buffer_size Length of the supplied buffer in bytes
|
||||
* @param[out] actual_length pointer to a location to hold the actual length
|
||||
* @param[in] dest Pointer to a buffer to hold the returned value.
|
||||
* @param[in] dest_size Length of the supplied buffer in bytes.
|
||||
* @param[out] actual_length Pointer to a location to hold the actual length
|
||||
* of the data which was associated with the key
|
||||
* (may be NULL).
|
||||
* @param[out] is_binary Pointer to a bool to hold whether the returned
|
||||
|
@ -210,10 +206,10 @@ 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_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
|
||||
*
|
||||
*
|
||||
* This routine can be used if you know that the value in a key will (or at
|
||||
* least should) be a string. It will return a zero-terminated char buffer
|
||||
* containing the value retrieved.
|
||||
|
@ -240,9 +236,10 @@ sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, siz
|
|||
sysparam_status_t sysparam_get_string(const char *key, char **destptr);
|
||||
|
||||
/** 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
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* in `result` is not changed. This means it is possible to set a default
|
||||
|
@ -288,7 +286,7 @@ sysparam_status_t sysparam_get_int32(const char *key, int32_t *result);
|
|||
sysparam_status_t sysparam_get_int8(const char *key, int8_t *result);
|
||||
|
||||
/** Get the boolean value associated with a key
|
||||
*
|
||||
*
|
||||
* This routine can be used if you know that the value in a key will (or at
|
||||
* least should) be a boolean setting. It will read the specified value as a
|
||||
* text string and attempt to parse it as a boolean value.
|
||||
|
@ -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`
|
||||
* 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,
|
||||
* 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
|
||||
*
|
||||
* 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] 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
|
||||
*
|
||||
* Write an int8_t binary value to the specified key. This does the inverse of
|
||||
* the sysparam_get_int8() function.
|
||||
*
|
||||
* Note that if the key already contains a value which parses to the same
|
||||
* boolean (true/false) value, it is left unchanged.
|
||||
* the sysparam_get_int8() function. This is done without allocating any
|
||||
* memory.
|
||||
*
|
||||
* @param[in] key Key name (zero-terminated string)
|
||||
* @param[in] value Value to set
|
||||
|
|
9
core/include/user_exception.h
Normal file
9
core/include/user_exception.h
Normal 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
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <esp/uart.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdout_redirect.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern void *xPortSupervisorStackPointer;
|
||||
|
||||
|
@ -135,6 +136,14 @@ int _stat_r(struct _reent *r, const char *pathname, void *buf);
|
|||
__attribute__((weak, alias("syscall_returns_enosys")))
|
||||
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
|
||||
("Function not implemented") and a return value equivalent to
|
||||
(int)-1. */
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "esp_spiffs_flash.h"
|
||||
#include "flashchip.h"
|
||||
#include "espressif/spi_flash.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "esp/rom.h"
|
||||
#include "esp/spi_regs.h"
|
||||
#include "include/spiflash.h"
|
||||
|
||||
#include "include/flashchip.h"
|
||||
#include "include/esp/rom.h"
|
||||
#include "include/esp/spi_regs.h"
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
|
@ -52,25 +53,6 @@
|
|||
#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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
memcpy_unaligned_src(SPI(0).W, buf, words);
|
||||
memcpy((void*)SPI(0).W, buf, words<<2);
|
||||
|
||||
__asm__ volatile("memw");
|
||||
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
// check if block to write doesn't cross page boundary
|
||||
if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
spi_write_data(flashchip, dest_addr, buf, size);
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t write_bytes_to_page = sdk_flashchip.page_size -
|
||||
(addr % sdk_flashchip.page_size); // TODO: place for optimization
|
||||
|
||||
if (size < write_bytes_to_page) {
|
||||
if (spi_write_page(&sdk_flashchip, addr, dst, size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
if (!spi_write_page(&sdk_flashchip, addr, dst, size)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
if (!spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t offset = write_bytes_to_page;
|
||||
uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
|
||||
for (uint8_t i = 0; i != pages_to_write; i++) {
|
||||
if (spi_write_page(&sdk_flashchip, addr + offset,
|
||||
for (uint32_t i = 0; i < pages_to_write; i++) {
|
||||
if (!spi_write_page(&sdk_flashchip, addr + offset,
|
||||
dst + offset, sdk_flashchip.page_size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
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)) {
|
||||
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) {
|
||||
vPortEnterCritical();
|
||||
|
@ -197,21 +181,23 @@ static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr,
|
|||
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((addr + size) > flashchip->chip_size) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
vPortEnterCritical();
|
||||
|
@ -245,14 +231,14 @@ uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t s
|
|||
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) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addr & 0xFFF) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
vPortEnterCritical();
|
||||
|
@ -269,5 +255,5 @@ uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr)
|
|||
Cache_Read_Enable(0, 0, 1);
|
||||
vPortExitCritical();
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
return true;
|
||||
}
|
375
core/sysparam.c
375
core/sysparam.c
|
@ -8,14 +8,12 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sysparam.h>
|
||||
#include <espressif/spi_flash.h>
|
||||
#include "spiflash.h"
|
||||
#include "flashchip.h"
|
||||
#include <common_macros.h>
|
||||
#include "FreeRTOS.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.
|
||||
*/
|
||||
#define SYSPARAM_MAGIC 0x70524f45 // "EORp" in little-endian
|
||||
|
@ -33,11 +31,14 @@
|
|||
*/
|
||||
#define SCAN_BUFFER_SIZE 8 // words
|
||||
|
||||
/* The size of the temporary buffer used for reading back and verifying data
|
||||
* written to flash. Making this larger will make the write-and-verify
|
||||
* operation slightly faster, but will use more heap during writes
|
||||
/* The size in words of the buffer used for reading keys when searching for a
|
||||
* match, for reading payloads to check if the value has changed, and reading
|
||||
* 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
|
||||
* will probably require some code changes if they are tweaked).
|
||||
|
@ -76,14 +77,16 @@
|
|||
/******************************* Useful Macros *******************************/
|
||||
|
||||
#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 min(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
#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 *********************/
|
||||
|
||||
|
@ -119,50 +122,28 @@ static struct {
|
|||
|
||||
/***************************** Internal routines *****************************/
|
||||
|
||||
static inline IRAM sysparam_status_t _do_write(uint32_t addr, const void *data, size_t data_size) {
|
||||
CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) data, data_size));
|
||||
return SYSPARAM_OK;
|
||||
}
|
||||
static sysparam_status_t _write_and_verify(uint32_t addr, const void *data, size_t data_size) {
|
||||
uint8_t bounce[BOUNCE_BUFFER_SIZE];
|
||||
|
||||
static inline IRAM sysparam_status_t _do_verify(uint32_t addr, const void *data, void *buffer, size_t len) {
|
||||
CHECK_FLASH_OP(sdk_spi_flash_read(addr, buffer, len));
|
||||
if (memcmp(data, buffer, len)) {
|
||||
return SYSPARAM_ERR_IO;
|
||||
for (int i = 0; i < data_size; i += BOUNCE_BUFFER_SIZE) {
|
||||
size_t count = min(data_size - i, BOUNCE_BUFFER_SIZE);
|
||||
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_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 */
|
||||
static sysparam_status_t _format_region(uint32_t addr, uint16_t num_sectors) {
|
||||
uint16_t sector = addr / sdk_flashchip.sector_size;
|
||||
int 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;
|
||||
}
|
||||
|
@ -212,7 +193,7 @@ static sysparam_status_t init_write_context(struct sysparam_context *ctx) {
|
|||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->addr = _sysparam_info.end_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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// will always start with a compaction, which will leave off
|
||||
// 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;
|
||||
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);
|
||||
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);
|
||||
if (ctx->entry.idflags == 0xffff) {
|
||||
// 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` */
|
||||
|
||||
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);
|
||||
CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr + ENTRY_HEADER_SIZE, (void*) buffer, min(buffer_size, ctx->entry.len)));
|
||||
uint32_t addr = ctx->addr + ENTRY_HEADER_SIZE;
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
|
||||
debug(3, "find key: %s", key ? key : "(null)");
|
||||
debug(3, "find key len %d: %s", key_len, key ? key : "(null)");
|
||||
while (true) {
|
||||
// Find the next key entry
|
||||
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;
|
||||
}
|
||||
if (ctx->entry.len == key_len) {
|
||||
status = _read_payload(ctx, buffer, key_len);
|
||||
if (status < 0) return status;
|
||||
if (!memcmp(key, buffer, key_len)) {
|
||||
status = _compare_payload(ctx, (uint8_t *)key, key_len);
|
||||
if (status == SYSPARAM_OK) {
|
||||
// We have a match
|
||||
break;
|
||||
}
|
||||
if (status != SYSPARAM_NOTFOUND) return status;
|
||||
debug(3, "entry payload does not match");
|
||||
} else {
|
||||
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(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"
|
||||
entry.idflags &= ~ENTRY_FLAG_ALIVE;
|
||||
debug(3, "write entry header @ 0x%08x", addr);
|
||||
CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) &entry, ENTRY_HEADER_SIZE));
|
||||
|
||||
return SYSPARAM_OK;
|
||||
return _write_and_verify(addr, &entry, ENTRY_HEADER_SIZE);
|
||||
}
|
||||
|
||||
/** 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 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);
|
||||
if (status < 0) return status;
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
// Found a starting point...
|
||||
break;
|
||||
|
@ -523,7 +531,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr) {
|
|||
} else {
|
||||
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) {
|
||||
// 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.
|
||||
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);
|
||||
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++) {
|
||||
if (buffer[i] != 0xffffffff) {
|
||||
// Uh oh, not empty.
|
||||
|
@ -655,70 +663,79 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
|
|||
sysparam_status_t status;
|
||||
size_t key_len = strlen(key);
|
||||
uint8_t *buffer;
|
||||
uint8_t *newbuf;
|
||||
|
||||
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
|
||||
|
||||
buffer = malloc(key_len + 2);
|
||||
if (!buffer) return SYSPARAM_ERR_NOMEM;
|
||||
do {
|
||||
_init_context(&ctx);
|
||||
status = _find_key(&ctx, key, key_len, buffer);
|
||||
if (status != SYSPARAM_OK) break;
|
||||
xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
|
||||
|
||||
// Find the associated value
|
||||
status = _find_value(&ctx, ctx.entry.idflags);
|
||||
if (status != SYSPARAM_OK) break;
|
||||
|
||||
newbuf = realloc(buffer, ctx.entry.len + 1);
|
||||
if (!newbuf) {
|
||||
status = SYSPARAM_ERR_NOMEM;
|
||||
break;
|
||||
}
|
||||
buffer = newbuf;
|
||||
status = _read_payload(&ctx, buffer, ctx.entry.len);
|
||||
if (status != SYSPARAM_OK) break;
|
||||
|
||||
// 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
|
||||
// interpret the result as a string).
|
||||
buffer[ctx.entry.len] = 0;
|
||||
|
||||
*destptr = buffer;
|
||||
if (actual_length) *actual_length = ctx.entry.len;
|
||||
if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
|
||||
return SYSPARAM_OK;
|
||||
} while (false);
|
||||
|
||||
free(buffer);
|
||||
if (actual_length) *actual_length = 0;
|
||||
|
||||
if (!_sysparam_info.cur_base) {
|
||||
status = SYSPARAM_ERR_NOINIT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
_init_context(&ctx);
|
||||
status = _find_key(&ctx, key, key_len);
|
||||
if (status != SYSPARAM_OK) goto done;
|
||||
|
||||
// Find the associated value
|
||||
status = _find_value(&ctx, ctx.entry.idflags);
|
||||
if (status != SYSPARAM_OK) goto done;
|
||||
|
||||
buffer = malloc(ctx.entry.len + 1);
|
||||
if (!buffer) {
|
||||
status = SYSPARAM_ERR_NOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = _read_payload(&ctx, buffer, ctx.entry.len);
|
||||
if (status != SYSPARAM_OK) {
|
||||
free(buffer);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// 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
|
||||
// interpret the result as a string).
|
||||
buffer[ctx.entry.len] = 0;
|
||||
|
||||
*destptr = buffer;
|
||||
if (actual_length) *actual_length = ctx.entry.len;
|
||||
if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
|
||||
status = SYSPARAM_OK;
|
||||
|
||||
done:
|
||||
xSemaphoreGive(_sysparam_info.sem);
|
||||
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;
|
||||
sysparam_status_t status = SYSPARAM_OK;
|
||||
size_t key_len = strlen(key);
|
||||
|
||||
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
|
||||
|
||||
// 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;
|
||||
xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
|
||||
|
||||
if (actual_length) *actual_length = 0;
|
||||
|
||||
if (!_sysparam_info.cur_base) {
|
||||
status = SYSPARAM_ERR_NOINIT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
_init_context(&ctx);
|
||||
status = _find_key(&ctx, key, key_len, buffer);
|
||||
if (status != SYSPARAM_OK) return status;
|
||||
status = _find_key(&ctx, key, key_len);
|
||||
if (status != SYSPARAM_OK) goto done;
|
||||
status = _find_value(&ctx, ctx.entry.idflags);
|
||||
if (status != SYSPARAM_OK) return status;
|
||||
status = _read_payload(&ctx, buffer, buffer_size);
|
||||
if (status != SYSPARAM_OK) return status;
|
||||
if (status != SYSPARAM_OK) goto done;
|
||||
status = _read_payload(&ctx, dest, dest_size);
|
||||
if (status != SYSPARAM_OK) goto done;
|
||||
|
||||
if (actual_length) *actual_length = ctx.entry.len;
|
||||
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) {
|
||||
|
@ -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) {
|
||||
char *buffer;
|
||||
char *endptr;
|
||||
int32_t value;
|
||||
size_t actual_length;
|
||||
bool is_binary;
|
||||
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;
|
||||
value = strtol(buffer, &endptr, 0);
|
||||
if (*endptr) {
|
||||
// There was extra crap at the end of the string.
|
||||
free(buffer);
|
||||
if (!is_binary || actual_length != sizeof(int32_t))
|
||||
return SYSPARAM_PARSEFAILED;
|
||||
}
|
||||
|
||||
*result = value;
|
||||
free(buffer);
|
||||
return SYSPARAM_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
status = sysparam_get_int32(key, &value);
|
||||
if (status == SYSPARAM_OK) {
|
||||
*result = value;
|
||||
}
|
||||
status = sysparam_get_data_static(key, (uint8_t *)&value, sizeof(int8_t),
|
||||
&actual_length, &is_binary);
|
||||
if (status != SYSPARAM_OK) return status;
|
||||
if (!is_binary || actual_length != sizeof(int8_t))
|
||||
return SYSPARAM_PARSEFAILED;
|
||||
*result = value;
|
||||
return status;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
do {
|
||||
if (!strcasecmp(buffer, "y") ||
|
||||
!strcasecmp(buffer, "yes") ||
|
||||
!strcasecmp(buffer, "t") ||
|
||||
!strcasecmp(buffer, "true") ||
|
||||
!strcmp(buffer, "1")) {
|
||||
if (binary) {
|
||||
if (data_len == 1) { // int8 value
|
||||
uint8_t value;
|
||||
memcpy(&value, buf, sizeof(value));
|
||||
*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;
|
||||
break;
|
||||
}
|
||||
if (!strcasecmp(buffer, "n") ||
|
||||
!strcasecmp(buffer, "no") ||
|
||||
!strcasecmp(buffer, "f") ||
|
||||
!strcasecmp(buffer, "false") ||
|
||||
!strcmp(buffer, "0")) {
|
||||
if (!strcasecmp(buf, "n") ||
|
||||
!strcasecmp(buf, "no") ||
|
||||
!strcasecmp(buf, "f") ||
|
||||
!strcasecmp(buf, "false") ||
|
||||
!strcmp(buf, "0")) {
|
||||
*result = false;
|
||||
break;
|
||||
}
|
||||
status = SYSPARAM_PARSEFAILED;
|
||||
} while (0);
|
||||
|
||||
free(buffer);
|
||||
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;
|
||||
sysparam_status_t status = SYSPARAM_OK;
|
||||
uint16_t key_len = strlen(key);
|
||||
uint8_t *buffer;
|
||||
uint8_t *newbuf;
|
||||
size_t free_space;
|
||||
size_t needed_space;
|
||||
bool free_value = false;
|
||||
int key_id = -1;
|
||||
uint32_t old_value_addr = 0;
|
||||
uint16_t binary_flag;
|
||||
|
||||
if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
|
||||
|
||||
if (!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;
|
||||
|
||||
xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
|
||||
|
||||
if (!value) value_len = 0;
|
||||
|
||||
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
|
||||
// when calling `sdk_spi_flash_write`, so make a word-aligned copy.
|
||||
buffer = malloc(value_len);
|
||||
if (!buffer) {
|
||||
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;
|
||||
|
||||
xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
|
||||
|
||||
if (!_sysparam_info.cur_base) {
|
||||
status = SYSPARAM_ERR_NOINIT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
do {
|
||||
_init_context(&ctx);
|
||||
status = _find_key(&ctx, key, key_len, buffer);
|
||||
status = _find_key(&ctx, key, key_len);
|
||||
if (status == SYSPARAM_OK) {
|
||||
// Key already exists, see if there's a current value.
|
||||
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 (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?
|
||||
if (value_len > key_len) {
|
||||
newbuf = realloc(buffer, value_len);
|
||||
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)) {
|
||||
status = _compare_payload(&ctx, (uint8_t *)value, value_len);
|
||||
if (status == SYSPARAM_OK) {
|
||||
// Yup, it's a match! No need to do anything further,
|
||||
// just leave the current value as-is.
|
||||
status = SYSPARAM_OK;
|
||||
break;
|
||||
}
|
||||
if (status != SYSPARAM_NOTFOUND) goto done;
|
||||
}
|
||||
|
||||
// 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);
|
||||
} while (false);
|
||||
|
||||
if (free_value) free((void *)value);
|
||||
free(buffer);
|
||||
|
||||
done:
|
||||
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) {
|
||||
uint8_t buffer[12];
|
||||
int len;
|
||||
|
||||
len = snprintf((char *)buffer, 12, "%d", value);
|
||||
return sysparam_set_data(key, buffer, len, false);
|
||||
return sysparam_set_data(key, (const uint8_t *)&value, sizeof(value), true);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -1043,7 +1047,6 @@ sysparam_status_t sysparam_iter_start(sysparam_iter_t *iter) {
|
|||
}
|
||||
|
||||
sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
|
||||
uint8_t buffer[2];
|
||||
sysparam_status_t status;
|
||||
size_t required_len;
|
||||
struct sysparam_context *ctx = iter->ctx;
|
||||
|
@ -1052,7 +1055,7 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
|
|||
char *newbuf;
|
||||
|
||||
while (true) {
|
||||
status = _find_key(ctx, NULL, 0, buffer);
|
||||
status = _find_key(ctx, NULL, 0);
|
||||
if (status != SYSPARAM_OK) return status;
|
||||
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 == 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;
|
||||
if (required_len > iter->bufsize) {
|
||||
newbuf = realloc(iter->key, required_len);
|
||||
|
|
|
@ -48,7 +48,7 @@ void user_init(void)
|
|||
};
|
||||
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);
|
||||
dhcpserver_start(&first_client_ip, 4);
|
||||
|
||||
|
@ -65,14 +65,14 @@ static void telnetTask(void *pvParameters)
|
|||
printf("Status monitor: Failed to allocate socket.\r\n");
|
||||
return;
|
||||
}
|
||||
netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT);
|
||||
netconn_bind(nc, IP_ANY_TYPE, TELNET_PORT);
|
||||
netconn_listen(nc);
|
||||
|
||||
while(1) {
|
||||
struct netconn *client = NULL;
|
||||
err_t err = netconn_accept(nc, &client);
|
||||
|
||||
if ( err != ERR_OK ) {
|
||||
if (err != ERR_OK) {
|
||||
if(client)
|
||||
netconn_delete(client);
|
||||
continue;
|
||||
|
@ -88,9 +88,8 @@ static void telnetTask(void *pvParameters)
|
|||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize());
|
||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d\r\n\r\n",
|
||||
ip4_addr1(&client_addr), ip4_addr2(&client_addr),
|
||||
ip4_addr3(&client_addr), ip4_addr4(&client_addr));
|
||||
char abuf[40];
|
||||
snprintf(buf, sizeof(buf), "Your address is %s\r\n\r\n", ipaddr_ntoa_r(&client_addr, abuf, sizeof(abuf)));
|
||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
netconn_delete(client);
|
||||
}
|
||||
|
|
4
examples/ad770x/Makefile
Normal file
4
examples/ad770x/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM = ad770x
|
||||
EXTRA_COMPONENTS = extras/ad770x
|
||||
#ESPBAUD = 460800
|
||||
include ../../common.mk
|
49
examples/ad770x/main.c
Normal file
49
examples/ad770x/main.c
Normal 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);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
// Connect ADDR pin to GND
|
||||
#define ADDR ADS111X_ADDR_GND
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
|
@ -28,23 +29,27 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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_data_rate(ADDR, ADS111X_DATA_RATE_32);
|
||||
ads111x_set_mode(&dev, ADS111X_MODE_CONTUNOUS);
|
||||
ads111x_set_data_rate(&dev, ADS111X_DATA_RATE_32);
|
||||
|
||||
ads111x_set_input_mux(ADDR, ADS111X_MUX_0_GND);
|
||||
ads111x_set_gain(ADDR, GAIN);
|
||||
ads111x_set_input_mux(&dev, ADS111X_MUX_0_GND);
|
||||
ads111x_set_gain(&dev, GAIN);
|
||||
|
||||
float gain_val = ads111x_gain_values[GAIN];
|
||||
|
||||
while (true)
|
||||
{
|
||||
// wait for conversion end
|
||||
while (ads111x_busy(ADDR)) {}
|
||||
while (ads111x_busy(&dev)) {}
|
||||
|
||||
// Read result
|
||||
int16_t raw = ads111x_get_value(ADDR);
|
||||
int16_t raw = ads111x_get_value(&dev);
|
||||
|
||||
float voltage = gain_val / ADS111X_MAX_VALUE * raw;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// 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/net.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
|
|
3
examples/bh1750/Makefile
Normal file
3
examples/bh1750/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=bh1750_example
|
||||
EXTRA_COMPONENTS = extras/i2c extras/bh1750
|
||||
include ../../common.mk
|
44
examples/bh1750/bh1750_example.c
Normal file
44
examples/bh1750/bh1750_example.c
Normal 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);
|
||||
}
|
|
@ -17,13 +17,13 @@ const int freq_frc2 = 10;
|
|||
static volatile uint32_t frc1_count;
|
||||
static volatile uint32_t frc2_count;
|
||||
|
||||
void frc1_interrupt_handler(void)
|
||||
void frc1_interrupt_handler(void *arg)
|
||||
{
|
||||
frc1_count++;
|
||||
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 */
|
||||
timer_set_frequency(FRC2, freq_frc2);
|
||||
|
@ -47,8 +47,8 @@ void user_init(void)
|
|||
timer_set_run(FRC2, false);
|
||||
|
||||
/* set up ISRs */
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler, NULL);
|
||||
|
||||
/* configure timer frequencies */
|
||||
timer_set_frequency(FRC1, freq_frc1);
|
||||
|
|
|
@ -13,18 +13,25 @@
|
|||
// BMP180 driver
|
||||
#include "bmp180/bmp180.h"
|
||||
|
||||
#define MY_EVT_TIMER 0x01
|
||||
#define MY_EVT_BMP180 0x02
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN GPIO_ID_PIN((0))
|
||||
#define SDA_PIN GPIO_ID_PIN((2))
|
||||
|
||||
#define MY_EVT_TIMER 0x01
|
||||
#define MY_EVT_BMP180 0x02
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t event_type;
|
||||
bmp180_result_t bmp180_data;
|
||||
} my_event_t;
|
||||
|
||||
//device descriptor
|
||||
i2c_dev_t dev = {
|
||||
.addr = BMP180_DEVICE_ADDRESS,
|
||||
.bus = I2C_BUS,
|
||||
};
|
||||
|
||||
// Communication Queue
|
||||
static QueueHandle_t mainqueue;
|
||||
static TimerHandle_t timerHandle;
|
||||
|
@ -70,7 +77,7 @@ void bmp180_task(void *pvParameters)
|
|||
case MY_EVT_TIMER:
|
||||
printf("%s: Received Timer Event\n", __FUNCTION__);
|
||||
|
||||
bmp180_trigger_measurement(com_queue);
|
||||
bmp180_trigger_measurement(&dev, com_queue);
|
||||
break;
|
||||
case MY_EVT_BMP180:
|
||||
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
|
||||
sdk_os_delay_us(500);
|
||||
|
||||
// Init I2C bus Interface
|
||||
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
|
@ -107,7 +117,7 @@ void user_init(void)
|
|||
bmp180_informUser = bmp180_i2c_informUser;
|
||||
|
||||
// Init BMP180 Interface
|
||||
bmp180_init(SCL_PIN, SDA_PIN);
|
||||
bmp180_init(&dev);
|
||||
|
||||
// Create Main Communication Queue
|
||||
mainqueue = xQueueCreate(10, sizeof(my_event_t));
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "bmp280/bmp280.h"
|
||||
|
||||
// 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
|
||||
|
||||
const uint8_t i2c_bus = 0;
|
||||
const uint8_t scl_pin = 0;
|
||||
const uint8_t sda_pin = 2;
|
||||
|
||||
|
@ -26,7 +26,8 @@ static void bmp280_task_forced(void *pvParameters)
|
|||
params.mode = BMP280_MODE_FORCED;
|
||||
|
||||
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 (!bmp280_init(&bmp280_dev, ¶ms)) {
|
||||
|
@ -67,7 +68,8 @@ static void bmp280_task_normal(void *pvParameters)
|
|||
bmp280_init_default_params(¶ms);
|
||||
|
||||
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 (!bmp280_init(&bmp280_dev, ¶ms)) {
|
||||
|
@ -103,7 +105,7 @@ void user_init(void)
|
|||
printf("SDK version : %s\n", sdk_system_get_sdk_version());
|
||||
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
|
||||
xTaskCreate(bmp280_task_forced, "bmp280_task", 256, NULL, 2, NULL);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <ds1307/ds1307.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
|
@ -19,8 +20,12 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
ds1307_start(true);
|
||||
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
|
||||
i2c_dev_t dev = {
|
||||
.addr = DS1307_ADDR,
|
||||
.bus = I2C_BUS,
|
||||
};
|
||||
ds1307_start(&dev, true);
|
||||
|
||||
// setup datetime: 2016-10-09 13:50:10
|
||||
struct tm time = {
|
||||
|
@ -31,11 +36,11 @@ void user_init(void)
|
|||
.tm_min = 50,
|
||||
.tm_sec = 10
|
||||
};
|
||||
ds1307_set_time(&time);
|
||||
ds1307_set_time(&dev, &time);
|
||||
|
||||
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,
|
||||
time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Test code for DS3231 high precision RTC module
|
||||
/* Test code for DS3231 high precision RTC module
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2016 Bhuvanchandra DV <bhuvanchandra.dv@gmail.com>
|
||||
|
@ -12,15 +12,21 @@
|
|||
|
||||
#include "ds3231/ds3231.h"
|
||||
|
||||
#define ADDR DS3231_ADDR
|
||||
#define I2C_BUS 0
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
struct tm time;
|
||||
float tempFloat;
|
||||
|
||||
i2c_dev_t dev = {
|
||||
.addr = ADDR,
|
||||
.bus = I2C_BUS,
|
||||
};
|
||||
while(1) {
|
||||
vTaskDelay(100);
|
||||
ds3231_getTime(&time);
|
||||
ds3231_getTempFloat(&tempFloat);
|
||||
ds3231_getTime(&dev, &time);
|
||||
ds3231_getTempFloat(&dev, &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("GIT version : %s\n", GITSHORTREV);
|
||||
|
||||
ds3231_Init(scl, sda);
|
||||
i2c_init(0,scl,sda,I2C_FREQ_400K);
|
||||
|
||||
xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ void timerRegTask(void *pvParameters)
|
|||
}
|
||||
}
|
||||
|
||||
IRAM void frc1_handler(void)
|
||||
IRAM void frc1_handler(void *arg)
|
||||
{
|
||||
frc1_handler_call_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;
|
||||
}
|
||||
|
||||
void frc2_handler(void)
|
||||
void frc2_handler(void *arg)
|
||||
{
|
||||
frc2_handler_call_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);
|
||||
|
||||
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_attach(INUM_TIMER_FRC2, frc2_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler, NULL);
|
||||
_xt_isr_unmask(1<<INUM_TIMER_FRC2);
|
||||
|
||||
TIMER(0).CTRL |= TIMER_CTRL_RUN;
|
||||
|
|
|
@ -237,7 +237,7 @@ static volatile bool frc1_ran;
|
|||
static volatile bool frc1_finished;
|
||||
static volatile char frc1_buf[80];
|
||||
|
||||
static void frc1_interrupt_handler(void)
|
||||
static void frc1_interrupt_handler(void *arg)
|
||||
{
|
||||
frc1_ran = true;
|
||||
timer_set_run(FRC1, false);
|
||||
|
@ -250,7 +250,7 @@ static void test_isr()
|
|||
printf("Testing behaviour inside ISRs...\r\n");
|
||||
timer_set_interrupts(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_interrupts(FRC1, true);
|
||||
timer_set_run(FRC1, true);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define CS_GPIO_PIN 2
|
||||
|
||||
// ds1307
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
|
@ -29,7 +30,11 @@
|
|||
uint32_t get_fattime()
|
||||
{
|
||||
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)
|
||||
| ((uint32_t)time.tm_mon << 21)
|
||||
|
@ -127,7 +132,7 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <i2c/i2c.h>
|
||||
#include <hmc5883l/hmc5883l.h>
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
|
@ -19,20 +20,24 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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");
|
||||
|
||||
hmc5883l_set_operating_mode(HMC5883L_MODE_CONTINUOUS);
|
||||
hmc5883l_set_samples_averaged(HMC5883L_SAMPLES_8);
|
||||
hmc5883l_set_data_rate(HMC5883L_DATA_RATE_07_50);
|
||||
hmc5883l_set_gain(HMC5883L_GAIN_1090);
|
||||
hmc5883l_set_operating_mode(&dev, HMC5883L_MODE_CONTINUOUS);
|
||||
hmc5883l_set_samples_averaged(&dev, HMC5883L_SAMPLES_8);
|
||||
hmc5883l_set_data_rate(&dev, HMC5883L_DATA_RATE_07_50);
|
||||
hmc5883l_set_gain(&dev, HMC5883L_GAIN_1090);
|
||||
|
||||
while (true)
|
||||
{
|
||||
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);
|
||||
|
||||
for (uint32_t i = 0; i < 1000; i++)
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
|
||||
#include "ssid_config.h"
|
||||
|
||||
#define WEB_SERVER "chainxor.org"
|
||||
#define WEB_SERVER "ipv6.google.com"
|
||||
#define WEB_PORT 80
|
||||
#define WEB_URL "http://chainxor.org/"
|
||||
#define WEB_PATH "/"
|
||||
|
||||
void http_get_task(void *pvParameters)
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ void http_get_task(void *pvParameters)
|
|||
|
||||
while(1) {
|
||||
const struct addrinfo hints = {
|
||||
.ai_family = AF_INET,
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
struct addrinfo *res;
|
||||
|
@ -39,7 +39,7 @@ void http_get_task(void *pvParameters)
|
|||
printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
|
||||
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);
|
||||
if(res)
|
||||
freeaddrinfo(res);
|
||||
|
@ -47,9 +47,28 @@ void http_get_task(void *pvParameters)
|
|||
failures++;
|
||||
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;
|
||||
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
|
||||
|
||||
#if LWIP_IPV6
|
||||
{
|
||||
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);
|
||||
if(s < 0) {
|
||||
|
@ -75,8 +94,10 @@ void http_get_task(void *pvParameters)
|
|||
freeaddrinfo(res);
|
||||
|
||||
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"
|
||||
"Connection: close\r\n"
|
||||
"\r\n";
|
||||
if (write(s, req, strlen(req)) < 0) {
|
||||
printf("... socket send failed\r\n");
|
||||
|
@ -126,6 +147,6 @@ void user_init(void)
|
|||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
errors at link time if functions don't exist.) */
|
||||
#include "mbedtls/config.h"
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<h1>About</h1>
|
||||
<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>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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <hd44780/hd44780.h>
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
#define ADDR 0x27
|
||||
|
@ -27,10 +28,11 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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 = {
|
||||
.addr = ADDR,
|
||||
.i2c_dev.bus = I2C_BUS,
|
||||
.i2c_dev.addr = ADDR,
|
||||
.font = HD44780_FONT_5X8,
|
||||
.lines = 2,
|
||||
.pins = {
|
||||
|
|
|
@ -88,7 +88,7 @@ static inline void init_descriptors_list()
|
|||
}
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -168,7 +168,7 @@ void play_task(void *pvParameters)
|
|||
|
||||
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) {
|
||||
init_descriptors_list();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdbool.h>
|
||||
#include "ina3221/ina3221.h"
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define PIN_SCL 5
|
||||
#define PIN_SDA 2
|
||||
#define ADDR INA3221_ADDR_0
|
||||
|
@ -33,7 +34,8 @@ void ina_measure(void *pvParameters)
|
|||
|
||||
// Create ina3221 device
|
||||
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
|
||||
.mask.mask_register = INA3221_DEFAULT_MASK, // Init
|
||||
.config.config_register = INA3221_DEFAULT_CONFIG, // Init
|
||||
|
@ -120,7 +122,7 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,15 @@
|
|||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
#define ADDR MCP4725A0_ADDR0
|
||||
#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");
|
||||
vTaskDelay(1);
|
||||
|
@ -33,21 +34,25 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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
|
||||
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");
|
||||
mcp4725_set_power_mode(ADDR, MCP4725_PM_NORMAL, true);
|
||||
wait_for_eeprom();
|
||||
mcp4725_set_power_mode(&dev, MCP4725_PM_NORMAL, true);
|
||||
wait_for_eeprom(&dev);
|
||||
}
|
||||
|
||||
printf("Set default DAC ouptut value to MAX...\n");
|
||||
mcp4725_set_raw_output(ADDR, MCP4725_MAX_VALUE, true);
|
||||
wait_for_eeprom();
|
||||
mcp4725_set_raw_output(&dev, MCP4725_MAX_VALUE, true);
|
||||
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");
|
||||
|
||||
|
@ -58,7 +63,7 @@ void user_init(void)
|
|||
if (vout > VDD) vout = 0;
|
||||
|
||||
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
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
|
|
|
@ -13,18 +13,20 @@
|
|||
#include <i2c/i2c.h>
|
||||
#include <ms561101ba03/ms561101ba03.h>
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
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);
|
||||
printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
|
||||
|
||||
ms561101ba03_t device = {
|
||||
.addr = MS561101BA03_ADDR_CSB_LOW,
|
||||
.i2c_dev.bus = I2C_BUS,
|
||||
.i2c_dev.addr = MS561101BA03_ADDR_CSB_LOW,
|
||||
.osr = MS561101BA03_OSR_4096,
|
||||
};
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
#include <pca9685/pca9685.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ADDR 0x40
|
||||
#define ADDR PCA9685_ADDR_BASE
|
||||
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
|
||||
|
@ -23,19 +24,23 @@ void user_init(void)
|
|||
uart_set_baud(0, 115200);
|
||||
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);
|
||||
printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(ADDR));
|
||||
pca9685_set_pwm_frequency(&dev, 1000);
|
||||
printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(&dev));
|
||||
|
||||
uint16_t val = 0;
|
||||
while (true)
|
||||
{
|
||||
printf("Set ch0 to %d, ch4 to %d\n", val, 4096 - val);
|
||||
pca9685_set_pwm_value(ADDR, 0, val);
|
||||
pca9685_set_pwm_value(ADDR, 4, 4096 - val);
|
||||
pca9685_set_pwm_value(&dev, 0, val);
|
||||
pca9685_set_pwm_value(&dev, 4, 4096 - val);
|
||||
|
||||
if (val++ == 4096)
|
||||
val = 0;
|
||||
|
|
3
examples/pcf8591/Makefile
Normal file
3
examples/pcf8591/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM = pcf8591
|
||||
EXTRA_COMPONENTS = extras/i2c extras/pcf8591
|
||||
include ../../common.mk
|
42
examples/pcf8591/main.c
Normal file
42
examples/pcf8591/main.c
Normal 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
23
examples/softuart/LICENSE
Normal 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.
|
||||
|
4
examples/softuart/Makefile
Normal file
4
examples/softuart/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM = softuart
|
||||
EXTRA_COMPONENTS = extras/softuart
|
||||
ESPBAUD = 460800
|
||||
include ../../common.mk
|
40
examples/softuart/main.c
Normal file
40
examples/softuart/main.c
Normal 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");
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#ifdef I2C_CONNECTION
|
||||
#define PROTOCOL SSD1306_PROTO_I2C
|
||||
#define ADDR SSD1306_I2C_ADDR_0
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
#else
|
||||
|
@ -35,7 +36,8 @@
|
|||
static const ssd1306_t dev = {
|
||||
.protocol = PROTOCOL,
|
||||
#ifdef I2C_CONNECTION
|
||||
.addr = ADDR,
|
||||
.i2c_dev.bus = I2C_BUS,
|
||||
.i2c_dev.addr = ADDR,
|
||||
#else
|
||||
.cs_pin = CS_PIN,
|
||||
.dc_pin = DC_PIN,
|
||||
|
@ -97,7 +99,7 @@ void user_init(void)
|
|||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
#ifdef I2C_CONNECTION
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
|
||||
#endif
|
||||
|
||||
while (ssd1306_init(&dev) != 0)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifdef I2C_CONNECTION
|
||||
#define PROTOCOL SSD1306_PROTO_I2C
|
||||
#define ADDR SSD1306_I2C_ADDR_0
|
||||
#define I2C_BUS 0
|
||||
#define SCL_PIN 5
|
||||
#define SDA_PIN 4
|
||||
#else
|
||||
|
@ -43,7 +44,8 @@
|
|||
static const ssd1306_t dev = {
|
||||
.protocol = PROTOCOL,
|
||||
#ifdef I2C_CONNECTION
|
||||
.addr = ADDR,
|
||||
.i2c_dev.bus = I2C_BUS,
|
||||
.i2c_dev.addr = ADDR,
|
||||
#else
|
||||
.cs_pin = CS_PIN,
|
||||
.dc_pin = DC_PIN,
|
||||
|
@ -162,7 +164,7 @@ void user_init(void)
|
|||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
#ifdef I2C_CONNECTION
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
|
||||
#endif
|
||||
|
||||
while (ssd1306_init(&dev) != 0) {
|
||||
|
|
|
@ -8,7 +8,7 @@ include ../../common.mk
|
|||
# `make dump-flash` can be used to view the current contents of the sysparam
|
||||
# regions in flash.
|
||||
dump-flash:
|
||||
esptool.py read_flash 0x1f8000 8192 r1.bin
|
||||
esptool.py read_flash 0x1f7000 8192 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
|
||||
|
|
|
@ -45,7 +45,7 @@ size_t tty_readline(char *buffer, size_t buf_size, bool echo) {
|
|||
|
||||
while (true) {
|
||||
c = getchar();
|
||||
if (c == '\r') {
|
||||
if (c == '\r' || c == '\n') {
|
||||
if (echo) putchar('\n');
|
||||
break;
|
||||
} 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
|
||||
// it somewhere the system will find it later
|
||||
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) {
|
||||
printf("==> ");
|
||||
|
@ -246,5 +246,7 @@ void user_init(void)
|
|||
{
|
||||
uart_set_baud(0, 115200);
|
||||
|
||||
sdk_wifi_set_opmode(NULL_MODE);
|
||||
|
||||
xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL);
|
||||
}
|
||||
|
|
10
examples/tick_idle_hooks/FreeRTOSConfig.h
Normal file
10
examples/tick_idle_hooks/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
|
||||
Configuration overrides for FreeRTOS.
|
||||
|
||||
**/
|
||||
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 1
|
||||
|
||||
#include_next "FreeRTOSConfig.h"
|
3
examples/tick_idle_hooks/Makefile
Normal file
3
examples/tick_idle_hooks/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Simple makefile for simple example
|
||||
PROGRAM=simple
|
||||
include ../../common.mk
|
56
examples/tick_idle_hooks/hooks_example.c
Normal file
56
examples/tick_idle_hooks/hooks_example.c
Normal 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);
|
||||
}
|
|
@ -43,7 +43,7 @@ extern const char *server_key;
|
|||
errors at link time if functions don't exist.) */
|
||||
#include "mbedtls/config.h"
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
|
@ -202,9 +202,8 @@ void tls_server_task(void *pvParameters)
|
|||
socklen_t peer_addr_len = sizeof(struct sockaddr_in);
|
||||
getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
|
||||
unsigned char buf[256];
|
||||
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\nFree heap size is %d bytes\n",
|
||||
ip4_addr1(&peer_addr.sin_addr), ip4_addr2(&peer_addr.sin_addr),
|
||||
ip4_addr3(&peer_addr.sin_addr), ip4_addr4(&peer_addr.sin_addr),
|
||||
int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\nFree heap size is %d bytes\n",
|
||||
IP2STR((ip4_addr_t *)&peer_addr.sin_addr.s_addr),
|
||||
peer_addr.sin_port, xPortGetFreeHeapSize());
|
||||
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
|
||||
{
|
||||
|
@ -216,6 +215,7 @@ void tls_server_task(void *pvParameters)
|
|||
}
|
||||
|
||||
len = ret;
|
||||
ret = 0;
|
||||
printf(" %d bytes written. Closing socket on client.\n\n%s", len, (char *) buf);
|
||||
|
||||
mbedtls_ssl_close_notify(&ssl);
|
||||
|
|
|
@ -146,9 +146,8 @@ void tls_server_task(void *pvParameters)
|
|||
|
||||
/* Prepare a message to the client */
|
||||
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",
|
||||
ip4_addr1(&sa.sin_addr), ip4_addr2(&sa.sin_addr),
|
||||
ip4_addr3(&sa.sin_addr), ip4_addr4(&sa.sin_addr),
|
||||
int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\r\nFree heap size is %d bytes\r\n",
|
||||
IP2STR((ip4_addr_t *)&sa.sin_addr.s_addr),
|
||||
ntohs(sa.sin_port), xPortGetFreeHeapSize());
|
||||
|
||||
/* Send the message and close the connection */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* Connect 3.3v from the ESP to Vin and GND to GND
|
||||
*/
|
||||
|
||||
#define I2C_BUS (0)
|
||||
#define SCL_PIN (2)
|
||||
#define SDA_PIN (0)
|
||||
|
||||
|
@ -27,7 +28,8 @@ void tsl2561MeasurementTask(void *pvParameters)
|
|||
// TSL2561_I2C_ADDR_VCC (0x49)
|
||||
// TSL2561_I2C_ADDR_GND (0x29)
|
||||
// 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);
|
||||
|
||||
|
@ -63,7 +65,7 @@ void tsl2561MeasurementTask(void *pvParameters)
|
|||
void user_init(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
3
examples/tsl4531/Makefile
Normal file
3
examples/tsl4531/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=tsl4531_example
|
||||
EXTRA_COMPONENTS = extras/i2c extras/tsl4531
|
||||
include ../../common.mk
|
57
examples/tsl4531/tsl4531_example.c
Normal file
57
examples/tsl4531/tsl4531_example.c
Normal 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
5
examples/upnp/Makefile
Normal 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
3
examples/upnp/README.md
Normal 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
53
examples/upnp/httpd.c
Normal 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
3
examples/upnp/httpd.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include <lwip/api.h>
|
||||
|
||||
void httpd_task(void *pvParameters);
|
5
examples/upnp/lwipopts.h
Normal file
5
examples/upnp/lwipopts.h
Normal 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
135
examples/upnp/upnp.c
Normal 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
2
examples/upnp/upnp.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
bool upnp_server_init(void);
|
114
examples/upnp/upnp_test.c
Normal file
114
examples/upnp/upnp_test.c
Normal 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
1
examples/wificfg/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!local.mk
|
7
examples/wificfg/FreeRTOSConfig.h
Normal file
7
examples/wificfg/FreeRTOSConfig.h
Normal 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>
|
5
examples/wificfg/Makefile
Normal file
5
examples/wificfg/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Makefile for wificfg example
|
||||
PROGRAM=wificfg
|
||||
EXTRA_COMPONENTS=extras/dhcpserver extras/wificfg
|
||||
|
||||
include ../../common.mk
|
18
examples/wificfg/content/index.html
Normal file
18
examples/wificfg/content/index.html
Normal 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()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>",
|
||||
"</body></html>"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue